ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.110
Committed: Sat Jun 10 02:22:33 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.109: +2 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.48 #ifdef _WIN32
2 root 1.79 # define _WIN32_WINNT 0x0500 // needed to get win2000 api calls
3 root 1.48 # include <malloc.h>
4 root 1.79 # include <windows.h>
5 root 1.75 # pragma warning(disable:4244)
6 root 1.48 #endif
7    
8 root 1.1 #include "EXTERN.h"
9     #include "perl.h"
10     #include "XSUB.h"
11    
12 root 1.80 #include <math.h>
13 root 1.5 #include <string.h>
14 root 1.25 #include <stdio.h>
15 root 1.5
16 root 1.2 #include <SDL.h>
17 root 1.76 #include <SDL_endian.h>
18 root 1.23 #include <SDL_image.h>
19 root 1.52 #include <SDL_mixer.h>
20 root 1.3 #include <SDL_opengl.h>
21 root 1.5
22 root 1.30 #include <glib/gmacros.h>
23    
24 root 1.5 #include <pango/pango.h>
25 root 1.10 #include <pango/pangofc-fontmap.h>
26 root 1.5 #include <pango/pangoft2.h>
27 root 1.76 #include <pango/pangocairo.h>
28 root 1.5
29 root 1.48 #ifndef _WIN32
30     # include <sys/types.h>
31     # include <sys/socket.h>
32     # include <netinet/in.h>
33     # include <netinet/tcp.h>
34     # include <inttypes.h>
35     #else
36     typedef unsigned char uint8_t;
37     typedef unsigned short uint16_t;
38     typedef unsigned int uint32_t;
39     typedef signed char int8_t;
40     typedef signed short int16_t;
41     typedef signed int int32_t;
42     #endif
43 root 1.28
44 root 1.57 #include "glext.h"
45    
46 root 1.29 #define FOW_DARKNESS 32
47    
48     #define MAP_EXTEND_X 32
49     #define MAP_EXTEND_Y 512
50    
51 root 1.63 #define MIN_FONT_HEIGHT 10
52 root 1.58
53 root 1.103 static struct
54     {
55     #define GL_FUNC(ptr,name) ptr name;
56     #include "glfunc.h"
57     #undef GL_FUNC
58     } gl;
59    
60     static void gl_BlendFuncSeparate (GLenum sa, GLenum da, GLenum saa, GLenum daa)
61     {
62     if (gl.BlendFuncSeparate)
63     gl.BlendFuncSeparate (sa, da, saa, daa);
64     else if (gl.BlendFuncSeparateEXT)
65     gl.BlendFuncSeparateEXT (sa, da, saa, daa);
66     else
67     glBlendFunc (sa, da);
68     }
69 root 1.64
70 root 1.52 typedef Mix_Chunk *CFClient__MixChunk;
71     typedef Mix_Music *CFClient__MixMusic;
72    
73 root 1.61 typedef PangoFontDescription *CFClient__Font;
74 root 1.2
75 root 1.14 typedef struct cf_layout {
76 root 1.76 PangoLayout *pl; // either derived from a cairo or ft2 context
77     int rgba; // wether we use rgba (cairo) or grayscale (ft2)
78     float r, g, b, a; // default color for rgba mode
79 root 1.14 int base_height;
80 root 1.61 CFClient__Font font;
81 root 1.15 } *CFClient__Layout;
82 root 1.14
83 root 1.61 static CFClient__Font default_font;
84 root 1.76 static PangoContext *ft2_context, *cairo_context;
85     static PangoFontMap *ft2_fontmap, *cairo_fontmap;
86 root 1.61
87 root 1.14 static void
88 root 1.19 substitute_func (FcPattern *pattern, gpointer data)
89     {
90 root 1.108 FcPatternAddBool (pattern, FC_HINTING, 1);
91 root 1.110 #ifdef FC_HINT_STYLE
92 root 1.109 FcPatternAddBool (pattern, FC_HINT_STYLE, FC_HINT_FULL);
93 root 1.110 #endif
94 root 1.106 #ifdef _WIN32
95     FcPatternAddBool (pattern, FC_AUTOHINT, 1);
96     #else
97 root 1.82 FcPatternAddBool (pattern, FC_AUTOHINT, 0);
98 root 1.106 #endif
99 root 1.19 }
100    
101     static void
102 root 1.61 layout_update_font (CFClient__Layout self)
103 root 1.17 {
104 root 1.19 /* use a random scale factor to account for unknown descenders, 0.8 works
105     * reasonably well with bitstream vera
106     */
107 root 1.61 PangoFontDescription *font = self->font ? self->font : default_font;
108 root 1.46
109 root 1.61 pango_font_description_set_absolute_size (font,
110     MAX (MIN_FONT_HEIGHT, self->base_height) * (PANGO_SCALE * 8 / 10));
111 root 1.58
112 root 1.61 pango_layout_set_font_description (self->pl, font);
113 root 1.17 }
114    
115     static void
116 root 1.15 layout_get_pixel_size (CFClient__Layout self, int *w, int *h)
117 root 1.14 {
118     pango_layout_get_pixel_size (self->pl, w, h);
119    
120     if (!*w) *w = 1;
121     if (!*h) *h = 1;
122 root 1.76
123     *w = (*w + 3) & ~3;
124 root 1.14 }
125    
126 root 1.42 typedef uint16_t mapface;
127    
128 root 1.28 typedef struct {
129 root 1.30 GLint name;
130     int w, h;
131     float s, t;
132 root 1.39 uint8_t r, g, b, a;
133 root 1.42 } maptex;
134 root 1.30
135     typedef struct {
136 root 1.29 int16_t darkness;
137 root 1.42 mapface face[3];
138 root 1.28 } mapcell;
139    
140     typedef struct {
141 root 1.30 int32_t c0, c1;
142 root 1.28 mapcell *col;
143     } maprow;
144    
145     typedef struct map {
146     int x, y, w, h;
147 root 1.42 int ox, oy; /* offset to virtual global coordinate system */
148 root 1.28 int faces;
149 root 1.30 mapface *face;
150 root 1.28
151 root 1.42 int texs;
152     maptex *tex;
153    
154 root 1.48 int32_t rows;
155 root 1.28 maprow *row;
156     } *CFClient__Map;
157    
158 root 1.30 static char *
159     prepend (char *ptr, int sze, int inc)
160     {
161     char *p;
162    
163     New (0, p, sze + inc, char);
164     Zero (p, inc, char);
165     Move (ptr, p + inc, sze, char);
166     Safefree (ptr);
167    
168     return p;
169     }
170    
171     static char *
172     append (char *ptr, int sze, int inc)
173     {
174     Renew (ptr, sze + inc, char);
175     Zero (ptr + sze, inc, char);
176    
177     return ptr;
178     }
179    
180     #define Append(type,ptr,sze,inc) (ptr) = (type *)append ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
181     #define Prepend(type,ptr,sze,inc) (ptr) = (type *)prepend ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
182    
183 root 1.42 static maprow *
184     map_get_row (CFClient__Map self, int y)
185     {
186     if (0 > y)
187     {
188     int extend = - y + MAP_EXTEND_Y;
189     Prepend (maprow, self->row, self->rows, extend);
190    
191     self->rows += extend;
192     self->y += extend;
193     y += extend;
194     }
195     else if (y >= self->rows)
196     {
197     int extend = y - self->rows + MAP_EXTEND_Y;
198     Append (maprow, self->row, self->rows, extend);
199     self->rows += extend;
200     }
201    
202     return self->row + y;
203     }
204    
205     static mapcell *
206     row_get_cell (maprow *row, int x)
207     {
208     if (!row->col)
209     {
210     Newz (0, row->col, MAP_EXTEND_X, mapcell);
211     row->c0 = x - MAP_EXTEND_X / 4;
212     row->c1 = row->c0 + MAP_EXTEND_X;
213     }
214    
215     if (row->c0 > x)
216     {
217     int extend = row->c0 - x + MAP_EXTEND_X;
218     Prepend (mapcell, row->col, row->c1 - row->c0, extend);
219     row->c0 -= extend;
220     }
221     else if (x >= row->c1)
222     {
223     int extend = x - row->c1 + MAP_EXTEND_X;
224     Append (mapcell, row->col, row->c1 - row->c0, extend);
225     row->c1 += extend;
226     }
227    
228     return row->col + (x - row->c0);
229     }
230    
231     static mapcell *
232     map_get_cell (CFClient__Map self, int x, int y)
233     {
234     return row_get_cell (map_get_row (self, y), x);
235     }
236    
237 root 1.30 static void
238     map_clear (CFClient__Map self)
239     {
240     int r;
241    
242     for (r = 0; r < self->rows; r++)
243     Safefree (self->row[r].col);
244    
245     Safefree (self->row);
246    
247     self->x = 0;
248     self->y = 0;
249 root 1.42 self->ox = 0;
250     self->oy = 0;
251 root 1.30 self->row = 0;
252     self->rows = 0;
253     }
254    
255 root 1.29 static void
256     map_blank (CFClient__Map self, int x0, int y0, int w, int h)
257     {
258     int x, y;
259 root 1.48 maprow *row;
260 root 1.29
261     for (y = y0; y < y0 + h; y++)
262 root 1.30 if (y >= 0)
263     {
264     if (y >= self->rows)
265     break;
266    
267 root 1.48 row = self->row + y;
268 root 1.30
269     for (x = x0; x < x0 + w; x++)
270     if (x >= row->c0)
271     {
272     if (x >= row->c1)
273     break;
274 root 1.29
275 root 1.31 row->col[x - row->c0].darkness = -1;
276 root 1.30 }
277     }
278 root 1.29 }
279    
280 root 1.56 static void
281 root 1.75 music_finished (void)
282 root 1.56 {
283     SDL_UserEvent ev;
284    
285     ev.type = SDL_USEREVENT;
286     ev.code = 0;
287     ev.data1 = 0;
288     ev.data2 = 0;
289    
290 root 1.57 SDL_PushEvent ((SDL_Event *)&ev);
291 root 1.56 }
292    
293 root 1.71 static void
294     channel_finished (int channel)
295     {
296     SDL_UserEvent ev;
297    
298     ev.type = SDL_USEREVENT;
299     ev.code = 1;
300 root 1.74 ev.data1 = (void *)(long)channel;
301 root 1.71 ev.data2 = 0;
302    
303     SDL_PushEvent ((SDL_Event *)&ev);
304     }
305    
306 root 1.15 MODULE = CFClient PACKAGE = CFClient
307 root 1.1
308 root 1.11 PROTOTYPES: ENABLE
309    
310 root 1.5 BOOT:
311     {
312 root 1.51 HV *stash = gv_stashpv ("CFClient", 1);
313     static const struct {
314     const char *name;
315     IV iv;
316     } *civ, const_iv[] = {
317     # define const_iv(name) { # name, (IV)name }
318     const_iv (SDL_ACTIVEEVENT),
319     const_iv (SDL_KEYDOWN),
320     const_iv (SDL_KEYUP),
321     const_iv (SDL_MOUSEMOTION),
322     const_iv (SDL_MOUSEBUTTONDOWN),
323     const_iv (SDL_MOUSEBUTTONUP),
324     const_iv (SDL_JOYAXISMOTION),
325     const_iv (SDL_JOYBALLMOTION),
326     const_iv (SDL_JOYHATMOTION),
327     const_iv (SDL_JOYBUTTONDOWN),
328     const_iv (SDL_JOYBUTTONUP),
329     const_iv (SDL_QUIT),
330     const_iv (SDL_SYSWMEVENT),
331     const_iv (SDL_EVENT_RESERVEDA),
332     const_iv (SDL_EVENT_RESERVEDB),
333     const_iv (SDL_VIDEORESIZE),
334     const_iv (SDL_VIDEOEXPOSE),
335     const_iv (SDL_USEREVENT),
336     const_iv (SDLK_KP0),
337     const_iv (SDLK_KP1),
338     const_iv (SDLK_KP2),
339     const_iv (SDLK_KP3),
340     const_iv (SDLK_KP4),
341     const_iv (SDLK_KP5),
342     const_iv (SDLK_KP6),
343     const_iv (SDLK_KP7),
344     const_iv (SDLK_KP8),
345     const_iv (SDLK_KP9),
346     const_iv (SDLK_KP_PERIOD),
347     const_iv (SDLK_KP_DIVIDE),
348     const_iv (SDLK_KP_MULTIPLY),
349     const_iv (SDLK_KP_MINUS),
350     const_iv (SDLK_KP_PLUS),
351     const_iv (SDLK_KP_ENTER),
352     const_iv (SDLK_KP_EQUALS),
353     const_iv (SDLK_UP),
354     const_iv (SDLK_DOWN),
355     const_iv (SDLK_RIGHT),
356     const_iv (SDLK_LEFT),
357     const_iv (SDLK_INSERT),
358     const_iv (SDLK_HOME),
359     const_iv (SDLK_END),
360     const_iv (SDLK_PAGEUP),
361     const_iv (SDLK_PAGEDOWN),
362     const_iv (SDLK_F1),
363     const_iv (SDLK_F2),
364     const_iv (SDLK_F3),
365     const_iv (SDLK_F4),
366     const_iv (SDLK_F5),
367     const_iv (SDLK_F6),
368     const_iv (SDLK_F7),
369     const_iv (SDLK_F8),
370     const_iv (SDLK_F9),
371     const_iv (SDLK_F10),
372     const_iv (SDLK_F11),
373     const_iv (SDLK_F12),
374     const_iv (SDLK_F13),
375     const_iv (SDLK_F14),
376     const_iv (SDLK_F15),
377     const_iv (SDLK_NUMLOCK),
378     const_iv (SDLK_CAPSLOCK),
379     const_iv (SDLK_SCROLLOCK),
380     const_iv (SDLK_RSHIFT),
381     const_iv (SDLK_LSHIFT),
382     const_iv (SDLK_RCTRL),
383     const_iv (SDLK_LCTRL),
384     const_iv (SDLK_RALT),
385     const_iv (SDLK_LALT),
386     const_iv (SDLK_RMETA),
387     const_iv (SDLK_LMETA),
388     const_iv (SDLK_LSUPER),
389     const_iv (SDLK_RSUPER),
390     const_iv (SDLK_MODE),
391     const_iv (SDLK_COMPOSE),
392     const_iv (SDLK_HELP),
393     const_iv (SDLK_PRINT),
394     const_iv (SDLK_SYSREQ),
395     const_iv (SDLK_BREAK),
396     const_iv (SDLK_MENU),
397     const_iv (SDLK_POWER),
398     const_iv (SDLK_EURO),
399     const_iv (SDLK_UNDO),
400     const_iv (KMOD_NONE),
401     const_iv (KMOD_LSHIFT),
402     const_iv (KMOD_RSHIFT),
403     const_iv (KMOD_LCTRL),
404     const_iv (KMOD_RCTRL),
405     const_iv (KMOD_LALT),
406     const_iv (KMOD_RALT),
407     const_iv (KMOD_LMETA),
408     const_iv (KMOD_RMETA),
409     const_iv (KMOD_NUM),
410     const_iv (KMOD_CAPS),
411     const_iv (KMOD_MODE),
412     const_iv (KMOD_CTRL),
413     const_iv (KMOD_SHIFT),
414     const_iv (KMOD_ALT),
415     const_iv (KMOD_META)
416     # undef const_iv
417     };
418    
419     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
420     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
421 root 1.79 }
422 root 1.51
423 root 1.79 void
424     pango_init ()
425     CODE:
426 root 1.105 // delayed, so it can pick up new fonts added by AddFontResourceEx
427 root 1.79 {
428 root 1.105 {
429     ft2_fontmap = pango_ft2_font_map_new ();
430     pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)ft2_fontmap, substitute_func, 0, 0);
431     ft2_context = pango_ft2_font_map_create_context ((PangoFT2FontMap *)ft2_fontmap);
432     }
433     {
434     cairo_font_options_t *fopt = cairo_font_options_create ();
435     cairo_fontmap = pango_cairo_font_map_get_default ();
436     cairo_context = pango_cairo_font_map_create_context ((PangoCairoFontMap *)cairo_fontmap);
437 root 1.106 #ifdef _WIN32
438     // cairo looks like shit eaten twice on windows
439     cairo_font_options_set_antialias (fopt, CAIRO_ANTIALIAS_NONE);
440     #else
441 root 1.105 cairo_font_options_set_antialias (fopt, CAIRO_ANTIALIAS_GRAY);
442 root 1.106 #endif
443 root 1.105 cairo_font_options_set_hint_style (fopt, CAIRO_HINT_STYLE_FULL);
444     cairo_font_options_set_hint_metrics (fopt, CAIRO_HINT_METRICS_ON);
445     pango_cairo_context_set_font_options (cairo_context, fopt);
446     cairo_font_options_destroy (fopt);
447     }
448 root 1.5 }
449    
450 root 1.51 int
451     SDL_Init (U32 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO)
452    
453     void
454     SDL_Quit ()
455    
456     void
457     SDL_ListModes ()
458     PPCODE:
459     {
460     SDL_Rect **m;
461    
462     SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
463     SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
464     SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
465 root 1.88 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 1);
466 root 1.51
467 root 1.88 SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 15);
468 root 1.89 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 16);
469 root 1.85
470 root 1.51 SDL_GL_SetAttribute (SDL_GL_ACCUM_RED_SIZE, 0);
471     SDL_GL_SetAttribute (SDL_GL_ACCUM_GREEN_SIZE, 0);
472     SDL_GL_SetAttribute (SDL_GL_ACCUM_BLUE_SIZE, 0);
473     SDL_GL_SetAttribute (SDL_GL_ACCUM_ALPHA_SIZE, 0);
474    
475     SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
476    
477 root 1.53 SDL_EnableUNICODE (1);
478     SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
479    
480 root 1.51 m = SDL_ListModes (0, SDL_FULLSCREEN | SDL_OPENGL);
481    
482     if (m && m != (SDL_Rect **)-1)
483     while (*m)
484     {
485     AV *av = newAV ();
486     av_push (av, newSViv ((*m)->w));
487     av_push (av, newSViv ((*m)->h));
488     XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
489    
490     ++m;
491     }
492     }
493    
494 root 1.88 char *
495     SDL_GetError ()
496    
497 root 1.51 int
498     SDL_SetVideoMode (int w, int h, int fullscreen)
499     CODE:
500     RETVAL = !!SDL_SetVideoMode (
501     w, h, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)
502     );
503 root 1.103 if (RETVAL)
504     {
505     SDL_WM_SetCaption ("Crossfire+ Client " VERSION, "Crossfire+");
506     # define GL_FUNC(ptr,name) gl.name = (ptr)SDL_GL_GetProcAddress ("gl" # name);
507     # include "glfunc.h"
508     # undef GL_FUNC
509     }
510 root 1.51 OUTPUT:
511     RETVAL
512    
513 root 1.53 void
514 root 1.54 SDL_GL_SwapBuffers ()
515    
516 root 1.94 char *
517     SDL_GetKeyName (int sym)
518    
519 root 1.54 void
520 root 1.53 SDL_PollEvent ()
521     PPCODE:
522     {
523     SDL_Event ev;
524    
525     while (SDL_PollEvent (&ev))
526     {
527     HV *hv = newHV ();
528     hv_store (hv, "type", 4, newSViv (ev.type), 0);
529 root 1.70
530 root 1.53 switch (ev.type)
531     {
532     case SDL_KEYDOWN:
533     case SDL_KEYUP:
534     hv_store (hv, "state", 5, newSViv (ev.key.state), 0);
535     hv_store (hv, "sym", 3, newSViv (ev.key.keysym.sym), 0);
536     hv_store (hv, "mod", 3, newSViv (ev.key.keysym.mod), 0);
537     hv_store (hv, "unicode", 7, newSViv (ev.key.keysym.unicode), 0);
538     break;
539    
540     case SDL_ACTIVEEVENT:
541     hv_store (hv, "gain", 4, newSViv (ev.active.gain), 0);
542     hv_store (hv, "state", 5, newSViv (ev.active.state), 0);
543     break;
544    
545     case SDL_MOUSEMOTION:
546 root 1.94 hv_store (hv, "mod", 3, newSViv (SDL_GetModState ()), 0);
547 root 1.93
548 root 1.53 hv_store (hv, "state", 5, newSViv (ev.motion.state), 0);
549     hv_store (hv, "x", 1, newSViv (ev.motion.x), 0);
550     hv_store (hv, "y", 1, newSViv (ev.motion.y), 0);
551     hv_store (hv, "xrel", 4, newSViv (ev.motion.xrel), 0);
552     hv_store (hv, "yrel", 4, newSViv (ev.motion.yrel), 0);
553     break;
554    
555     case SDL_MOUSEBUTTONDOWN:
556     case SDL_MOUSEBUTTONUP:
557 root 1.94 hv_store (hv, "mod", 3, newSViv (SDL_GetModState ()), 0);
558 root 1.93
559 root 1.53 hv_store (hv, "button", 6, newSViv (ev.button.button), 0);
560     hv_store (hv, "state", 5, newSViv (ev.button.state), 0);
561     hv_store (hv, "x", 1, newSViv (ev.button.x), 0);
562     hv_store (hv, "y", 1, newSViv (ev.button.y), 0);
563 root 1.70 break;
564 root 1.72
565     case SDL_USEREVENT:
566     hv_store (hv, "code", 4, newSViv (ev.user.code), 0);
567     hv_store (hv, "data1", 5, newSViv ((IV)ev.user.data1), 0);
568     hv_store (hv, "data2", 5, newSViv ((IV)ev.user.data2), 0);
569     break;
570 root 1.53 }
571    
572     XPUSHs (sv_2mortal (newRV_noinc ((SV *)hv)));
573     }
574     }
575 root 1.52
576     int
577 root 1.73 Mix_OpenAudio (int frequency = 48000, int format = MIX_DEFAULT_FORMAT, int channels = 1, int chunksize = 2048)
578 root 1.56 POSTCALL:
579     Mix_HookMusicFinished (music_finished);
580 root 1.71 Mix_ChannelFinished (channel_finished);
581 root 1.52
582     void
583     Mix_CloseAudio ()
584    
585     int
586     Mix_AllocateChannels (int numchans = -1)
587    
588 root 1.10 void
589     lowdelay (int fd, int val = 1)
590     CODE:
591 root 1.48 #ifndef _WIN32
592 root 1.10 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
593 root 1.48 #endif
594 root 1.10
595 root 1.5 void
596 root 1.13 add_font (char *file)
597     CODE:
598     FcConfigAppFontAddFile (0, (const FcChar8 *)file); /* no idea wether this is required */
599 root 1.79 #ifdef _WIN32
600     // cairo... sigh... requires win2000
601     AddFontResourceEx (file, FR_PRIVATE, 0);
602     #endif
603 root 1.13
604     void
605 root 1.23 load_image_inline (SV *image_)
606     ALIAS:
607     load_image_file = 1
608     PPCODE:
609     {
610     STRLEN image_len;
611     char *image = (char *)SvPVbyte (image_, image_len);
612     SDL_Surface *surface, *surface2;
613     SDL_PixelFormat fmt;
614     SDL_RWops *rw = ix
615     ? SDL_RWFromFile (image, "r")
616     : SDL_RWFromConstMem (image, image_len);
617    
618     if (!rw)
619 root 1.41 croak ("load_image: %s", SDL_GetError ());
620 root 1.23
621     surface = IMG_Load_RW (rw, 1);
622     if (!surface)
623 root 1.41 croak ("load_image: %s", SDL_GetError ());
624 root 1.23
625     fmt.palette = NULL;
626     fmt.BitsPerPixel = 32;
627     fmt.BytesPerPixel = 4;
628 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
629 root 1.23 fmt.Rmask = 0x000000ff;
630     fmt.Gmask = 0x0000ff00;
631     fmt.Bmask = 0x00ff0000;
632     fmt.Amask = 0xff000000;
633 root 1.49 #else
634     fmt.Rmask = 0xff000000;
635     fmt.Gmask = 0x00ff0000;
636     fmt.Bmask = 0x0000ff00;
637     fmt.Amask = 0x000000ff;
638     #endif
639 root 1.23 fmt.Rloss = 0;
640     fmt.Gloss = 0;
641     fmt.Bloss = 0;
642     fmt.Aloss = 0;
643     fmt.Rshift = 0;
644     fmt.Gshift = 8;
645     fmt.Bshift = 16;
646     fmt.Ashift = 24;
647     fmt.colorkey = 0;
648     fmt.alpha = 0;
649    
650     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
651    
652 root 1.39 assert (surface2->pitch == surface2->w * 4);
653    
654 root 1.23 EXTEND (SP, 5);
655     PUSHs (sv_2mortal (newSViv (surface2->w)));
656     PUSHs (sv_2mortal (newSViv (surface2->h)));
657     SDL_LockSurface (surface2);
658     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
659     SDL_UnlockSurface (surface2);
660 root 1.24 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
661 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
662 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
663 root 1.23
664     SDL_FreeSurface (surface);
665     SDL_FreeSurface (surface2);
666     }
667    
668 root 1.25 void
669 root 1.39 average (int x, int y, uint32_t *data)
670     PPCODE:
671     {
672     uint32_t r = 0, g = 0, b = 0, a = 0;
673    
674     x = y = x * y;
675    
676     while (x--)
677     {
678     uint32_t p = *data++;
679    
680     r += (p ) & 255;
681     g += (p >> 8) & 255;
682     b += (p >> 16) & 255;
683     a += (p >> 24) & 255;
684     }
685    
686     EXTEND (SP, 4);
687 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
688     PUSHs (sv_2mortal (newSViv (g / y)));
689     PUSHs (sv_2mortal (newSViv (b / y)));
690     PUSHs (sv_2mortal (newSViv (a / y)));
691 root 1.39 }
692    
693     void
694 root 1.66 error (char *message)
695     CODE:
696 root 1.86 fprintf (stderr, "ERROR: %s\n", message);
697 root 1.66 #ifdef _WIN32
698 root 1.86 MessageBox (0, message, "Crossfire+ Error", MB_OK | MB_ICONERROR);
699 root 1.66 #endif
700    
701     void
702 root 1.25 fatal (char *message)
703     CODE:
704 root 1.86 fprintf (stderr, "FATAL: %s\n", message);
705 root 1.50 #ifdef _WIN32
706 root 1.86 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR);
707 root 1.25 #endif
708     exit (1);
709    
710 root 1.61 MODULE = CFClient PACKAGE = CFClient::Font
711    
712     CFClient::Font
713 root 1.70 new_from_file (SV *class, char *path, int id = 0)
714 root 1.61 CODE:
715     {
716     int count;
717 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
718 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
719     FcPatternDestroy (pattern);
720     }
721     OUTPUT:
722     RETVAL
723    
724     void
725     DESTROY (CFClient::Font self)
726     CODE:
727     pango_font_description_free (self);
728    
729     void
730     make_default (CFClient::Font self)
731     CODE:
732     default_font = self;
733    
734 root 1.15 MODULE = CFClient PACKAGE = CFClient::Layout
735 root 1.14
736 root 1.15 CFClient::Layout
737 root 1.76 new (SV *class, int rgba = 0)
738 root 1.14 CODE:
739     New (0, RETVAL, 1, struct cf_layout);
740 root 1.76
741     RETVAL->pl = pango_layout_new (rgba ? cairo_context : ft2_context);
742     RETVAL->rgba = rgba;
743     RETVAL->r = 1.;
744     RETVAL->g = 1.;
745     RETVAL->b = 1.;
746     RETVAL->a = 1.;
747     RETVAL->base_height = MIN_FONT_HEIGHT;
748     RETVAL->font = 0;
749    
750 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
751 root 1.76 layout_update_font (RETVAL);
752 root 1.14 OUTPUT:
753     RETVAL
754    
755     void
756 root 1.15 DESTROY (CFClient::Layout self)
757 root 1.14 CODE:
758     g_object_unref (self->pl);
759     Safefree (self);
760 root 1.13
761 root 1.76 int
762     is_rgba (CFClient::Layout self)
763     CODE:
764     RETVAL = self->rgba;
765     OUTPUT:
766     RETVAL
767    
768 root 1.8 void
769 root 1.35 set_text (CFClient::Layout self, SV *text_)
770     CODE:
771     {
772     STRLEN textlen;
773     char *text = SvPVutf8 (text_, textlen);
774    
775     pango_layout_set_text (self->pl, text, textlen);
776     }
777    
778     void
779 root 1.15 set_markup (CFClient::Layout self, SV *text_)
780 root 1.14 CODE:
781 root 1.5 {
782     STRLEN textlen;
783     char *text = SvPVutf8 (text_, textlen);
784 root 1.14
785     pango_layout_set_markup (self->pl, text, textlen);
786     }
787    
788 root 1.46 SV *
789     get_text (CFClient::Layout self)
790     CODE:
791 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
792 root 1.107 sv_utf8_decode (RETVAL);
793 root 1.46 OUTPUT:
794     RETVAL
795    
796 root 1.14 void
797 root 1.76 set_foreground (CFClient::Layout self, float r, float g, float b, float a = 1.)
798     CODE:
799     self->r = r;
800     self->g = g;
801     self->b = b;
802     self->a = a;
803    
804     void
805 root 1.61 set_font (CFClient::Layout self, CFClient::Font font = 0)
806     CODE:
807     if (self->font != font)
808     {
809     self->font = font;
810     layout_update_font (self);
811     }
812    
813     void
814 root 1.16 set_height (CFClient::Layout self, int base_height)
815     CODE:
816 root 1.61 if (self->base_height != base_height)
817     {
818     self->base_height = base_height;
819     layout_update_font (self);
820     }
821 root 1.16
822     void
823 root 1.15 set_width (CFClient::Layout self, int max_width = -1)
824 root 1.14 CODE:
825     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
826    
827     void
828 root 1.84 set_indent (CFClient::Layout self, int indent)
829     CODE:
830     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
831    
832     void
833     set_spacing (CFClient::Layout self, int spacing)
834     CODE:
835     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
836    
837     void
838     set_ellipsise (CFClient::Layout self, int ellipsise)
839     CODE:
840     pango_layout_set_ellipsize (self->pl,
841     ellipsise == 1 ? PANGO_ELLIPSIZE_START
842     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
843     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
844     : PANGO_ELLIPSIZE_NONE
845     );
846    
847     void
848     set_single_paragraph_mode (CFClient::Layout self, int spm)
849     CODE:
850     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
851    
852     void
853 root 1.15 size (CFClient::Layout self)
854 root 1.14 PPCODE:
855     {
856     int w, h;
857    
858     layout_get_pixel_size (self, &w, &h);
859    
860     EXTEND (SP, 2);
861     PUSHs (sv_2mortal (newSViv (w)));
862     PUSHs (sv_2mortal (newSViv (h)));
863     }
864    
865 root 1.17 int
866     xy_to_index (CFClient::Layout self, int x, int y)
867     CODE:
868     {
869     int index, trailing;
870     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
871     RETVAL = index;
872     }
873     OUTPUT:
874     RETVAL
875    
876     void
877     cursor_pos (CFClient::Layout self, int index)
878     PPCODE:
879     {
880     PangoRectangle strong_pos;
881     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
882 root 1.30
883 root 1.17 EXTEND (SP, 3);
884     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
885     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
886     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
887     }
888    
889 root 1.14 void
890 root 1.15 render (CFClient::Layout self)
891 root 1.14 PPCODE:
892     {
893 root 1.5 SV *retval;
894     int w, h;
895    
896 root 1.14 layout_get_pixel_size (self, &w, &h);
897 root 1.5
898 root 1.76 if (self->rgba)
899     {
900     cairo_surface_t *surface;
901     cairo_t *cairo;
902    
903     retval = newSV (w * h * 4);
904     SvPOK_only (retval);
905     SvCUR_set (retval, w * h * 4);
906    
907     memset (SvPVX (retval), 0, w * h * 4);
908    
909     surface = cairo_image_surface_create_for_data (
910     (void*)SvPVX (retval), CAIRO_FORMAT_ARGB32, w, h, w * 4);
911     cairo = cairo_create (surface);
912     cairo_set_source_rgba (cairo, self->r, self->g, self->b, self->a);
913    
914     pango_cairo_show_layout (cairo, self->pl);
915    
916     cairo_destroy (cairo);
917     cairo_surface_destroy (surface);
918    
919     // what a mess, and its premultiplied, too :(
920     {
921     uint32_t *p = (uint32_t *)SvPVX (retval);
922     uint32_t *e = p + w * h;
923 root 1.5
924 root 1.76 while (p < e)
925     {
926     uint32_t rgba = *p;
927     rgba = (rgba >> 24) | (rgba << 8);
928 root 1.87 #if 0
929     #ifdef _WIN32
930     {//D
931     uint8_t r = rgba >> 24;
932     uint8_t g = rgba >> 16;
933     uint8_t b = rgba >> 8;
934     uint8_t a = rgba >> 0;
935    
936     rgba = (rgba & 0xffffff00) | a;
937     }
938     #endif
939     #endif
940 root 1.76 rgba = SDL_SwapBE32 (rgba);
941     *p++ = rgba;
942     }
943     }
944    
945     EXTEND (SP, 5);
946     PUSHs (sv_2mortal (newSViv (w)));
947     PUSHs (sv_2mortal (newSViv (h)));
948     PUSHs (sv_2mortal (retval));
949     PUSHs (sv_2mortal (newSViv (GL_RGBA)));
950     PUSHs (sv_2mortal (newSViv (GL_RGBA)));
951     }
952     else
953     {
954     FT_Bitmap bitmap;
955    
956     retval = newSV (w * h);
957     SvPOK_only (retval);
958     SvCUR_set (retval, w * h);
959    
960     bitmap.rows = h;
961     bitmap.width = w;
962     bitmap.pitch = w;
963     bitmap.buffer = (unsigned char*)SvPVX (retval);
964     bitmap.num_grays = 256;
965     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
966    
967     memset (bitmap.buffer, 0, w * h);
968    
969     pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
970 root 1.1
971 root 1.76 EXTEND (SP, 5);
972     PUSHs (sv_2mortal (newSViv (w)));
973     PUSHs (sv_2mortal (newSViv (h)));
974     PUSHs (sv_2mortal (retval));
975     PUSHs (sv_2mortal (newSViv (GL_ALPHA)));
976     PUSHs (sv_2mortal (newSViv (GL_ALPHA)));
977     }
978 root 1.5 }
979 root 1.11
980 root 1.15 MODULE = CFClient PACKAGE = CFClient::Texture
981 root 1.11
982     void
983 root 1.37 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
984 root 1.12 PROTOTYPE: $$$;$$
985 root 1.76 ALIAS:
986     draw_quad_alpha = 1
987     draw_quad_alpha_premultiplied = 2
988 root 1.11 CODE:
989     {
990 root 1.12 HV *hv = (HV *)SvRV (self);
991 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
992     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
993 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
994    
995     if (items < 5)
996     {
997 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
998     h = SvNV (*hv_fetch (hv, "h", 1, 1));
999 root 1.12 }
1000    
1001 root 1.76 if (ix)
1002     {
1003     glEnable (GL_BLEND);
1004 root 1.103
1005     if (ix == 2)
1006     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1007     else
1008     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1009 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1010 root 1.103
1011 root 1.86 glEnable (GL_ALPHA_TEST);
1012     glAlphaFunc (GL_GREATER, 0.01f);
1013 root 1.76 }
1014    
1015 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1016 root 1.76
1017 root 1.12 glBegin (GL_QUADS);
1018 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1019     glTexCoord2f (0, t); glVertex2f (x , y + h);
1020     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1021     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1022 root 1.12 glEnd ();
1023 root 1.76
1024     if (ix)
1025 root 1.86 {
1026     glDisable (GL_ALPHA_TEST);
1027     glDisable (GL_BLEND);
1028     }
1029 root 1.11 }
1030 root 1.28
1031     MODULE = CFClient PACKAGE = CFClient::Map
1032    
1033     CFClient::Map
1034     new (SV *class, int map_width, int map_height)
1035     CODE:
1036     New (0, RETVAL, 1, struct map);
1037 root 1.42 RETVAL->x = 0;
1038     RETVAL->y = 0;
1039     RETVAL->w = map_width;
1040     RETVAL->h = map_height;
1041     RETVAL->ox = 0;
1042     RETVAL->oy = 0;
1043 root 1.30 RETVAL->faces = 8192;
1044     Newz (0, RETVAL->face, RETVAL->faces, mapface);
1045 root 1.42 RETVAL->texs = 8192;
1046     Newz (0, RETVAL->tex, RETVAL->texs, maptex);
1047 root 1.28 RETVAL->rows = 0;
1048     RETVAL->row = 0;
1049     OUTPUT:
1050     RETVAL
1051    
1052     void
1053     DESTROY (CFClient::Map self)
1054     CODE:
1055     {
1056 root 1.30 map_clear (self);
1057 root 1.28 Safefree (self->face);
1058 root 1.29 Safefree (self);
1059     }
1060    
1061     void
1062 root 1.30 clear (CFClient::Map self)
1063     CODE:
1064     map_clear (self);
1065    
1066     void
1067 root 1.42 set_face (CFClient::Map self, int face, int texid)
1068 root 1.29 CODE:
1069     {
1070 root 1.42 while (self->faces <= face)
1071 root 1.28 {
1072 root 1.30 Append (mapface, self->face, self->faces, self->faces);
1073 root 1.29 self->faces *= 2;
1074     }
1075 root 1.28
1076 root 1.42 self->face [face] = texid;
1077     }
1078    
1079     void
1080     set_texture (CFClient::Map self, int texid, int name, int w, int h, float s, float t, int r, int g, int b, int a)
1081     CODE:
1082     {
1083     while (self->texs <= texid)
1084     {
1085     Append (maptex, self->tex, self->texs, self->texs);
1086     self->texs *= 2;
1087     }
1088    
1089 root 1.48 {
1090     maptex *tex = self->tex + texid;
1091 root 1.39
1092 root 1.48 tex->name = name;
1093     tex->w = w;
1094     tex->h = h;
1095     tex->s = s;
1096     tex->t = t;
1097     tex->r = r;
1098     tex->g = g;
1099     tex->b = b;
1100     tex->a = a;
1101     }
1102 root 1.95
1103     // somewhat hackish, but for textures that require it, it really
1104     // improves the look, and most others don't suffer.
1105     glBindTexture (GL_TEXTURE_2D, name);
1106 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1107     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1108     // use uglier nearest interpolation because linear suffers
1109     // from transparent color bleeding and ugly wrapping effects.
1110     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1111 root 1.29 }
1112    
1113 root 1.42 int
1114     ox (CFClient::Map self)
1115     ALIAS:
1116     oy = 1
1117 root 1.101 x = 2
1118     y = 3
1119 root 1.102 w = 4
1120     h = 5
1121 root 1.42 CODE:
1122     switch (ix)
1123     {
1124     case 0: RETVAL = self->ox; break;
1125     case 1: RETVAL = self->oy; break;
1126 root 1.101 case 2: RETVAL = self->x; break;
1127     case 3: RETVAL = self->y; break;
1128 root 1.102 case 4: RETVAL = self->w; break;
1129     case 5: RETVAL = self->h; break;
1130 root 1.42 }
1131     OUTPUT:
1132     RETVAL
1133    
1134 root 1.29 void
1135 root 1.43 scroll (CFClient::Map self, int dx, int dy)
1136     CODE:
1137     {
1138 root 1.44 if (dx > 0)
1139     map_blank (self, self->x, self->y, dx - 1, self->h);
1140     else if (dx < 0)
1141     map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
1142    
1143     if (dy > 0)
1144     map_blank (self, self->x, self->y, self->w, dy - 1);
1145     else if (dy < 0)
1146     map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
1147 root 1.43
1148 root 1.44 self->ox += dx; self->x += dx;
1149     self->oy += dy; self->y += dy;
1150 root 1.43
1151     while (self->y < 0)
1152     {
1153     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1154    
1155     self->rows += MAP_EXTEND_Y;
1156     self->y += MAP_EXTEND_Y;
1157     }
1158 root 1.44 }
1159 root 1.43
1160 root 1.44 void
1161     map1a_update (CFClient::Map self, SV *data_)
1162     CODE:
1163     {
1164 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1165     uint8_t *data_end = (uint8_t *)SvEND (data_);
1166 root 1.48 mapcell *cell;
1167     int x, y, flags;
1168 root 1.43
1169 root 1.29 while (data < data_end)
1170     {
1171 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1172 root 1.30
1173 root 1.48 x = ((flags >> 10) & 63) + self->x;
1174     y = ((flags >> 4) & 63) + self->y;
1175 root 1.29
1176 root 1.48 cell = map_get_cell (self, x, y);
1177 root 1.29
1178     if (flags & 15)
1179     {
1180 root 1.45 if (cell->darkness < 0)
1181 root 1.29 {
1182     cell->darkness = 0;
1183     cell->face [0] = 0;
1184     cell->face [1] = 0;
1185     cell->face [2] = 0;
1186     }
1187 root 1.45
1188 root 1.29 cell->darkness = flags & 8 ? *data++ : 255;
1189    
1190 root 1.42 //TODO: don't trust server data to be in-range(!)
1191    
1192 root 1.29 if (flags & 4)
1193     {
1194 root 1.42 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
1195 root 1.29 }
1196    
1197     if (flags & 2)
1198     {
1199 root 1.42 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
1200 root 1.29 }
1201    
1202     if (flags & 1)
1203     {
1204 root 1.42 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
1205 root 1.29 }
1206     }
1207     else
1208 root 1.31 cell->darkness = -1;
1209 root 1.29 }
1210 root 1.28 }
1211    
1212 root 1.40 SV *
1213 root 1.55 mapmap (CFClient::Map self, int x0, int y0, int w, int h)
1214 root 1.40 CODE:
1215     {
1216 root 1.55 int x1, x;
1217     int y1, y;
1218 root 1.40 int z;
1219     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1220     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1221    
1222     SvPOK_only (map_sv);
1223     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1224    
1225 root 1.55 x0 += self->x; x1 = x0 + w;
1226     y0 += self->y; y1 = y0 + h;
1227 root 1.40
1228     for (y = y0; y < y1; y++)
1229     {
1230     maprow *row = 0 <= y && y < self->rows
1231     ? self->row + y
1232     : 0;
1233    
1234     for (x = x0; x < x1; x++)
1235     {
1236     int r = 32, g = 32, b = 32, a = 192;
1237    
1238     if (row && row->c0 <= x && x < row->c1)
1239     {
1240     mapcell *cell = row->col + (x - row->c0);
1241    
1242     for (z = 0; z <= 0; z++)
1243     {
1244 root 1.42 mapface face = cell->face [z];
1245 root 1.40
1246     if (face)
1247     {
1248 root 1.42 maptex tex = self->tex [face];
1249 root 1.40 int a0 = 255 - tex.a;
1250     int a1 = tex.a;
1251    
1252     r = (r * a0 + tex.r * a1) / 255;
1253     g = (g * a0 + tex.g * a1) / 255;
1254     b = (b * a0 + tex.b * a1) / 255;
1255     a = (a * a0 + tex.a * a1) / 255;
1256     }
1257     }
1258     }
1259    
1260     *map++ = (r )
1261     | (g << 8)
1262     | (b << 16)
1263     | (a << 24);
1264     }
1265     }
1266    
1267     RETVAL = map_sv;
1268     }
1269     OUTPUT:
1270     RETVAL
1271    
1272 root 1.30 void
1273 root 1.38 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
1274 root 1.32 PPCODE:
1275 root 1.30 {
1276 root 1.48 int vx, vy;
1277     int x, y, z;
1278     int last_name;
1279     mapface face;
1280 root 1.32 int sw4 = (sw + 3) & ~3;
1281     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
1282 root 1.35 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
1283 root 1.48
1284 root 1.42 memset (darkness, 255, sw4 * sh);
1285 root 1.32 SvPOK_only (darkness_sv);
1286     SvCUR_set (darkness_sv, sw4 * sh);
1287    
1288 root 1.48 vx = self->x + (self->w - sw) / 2 - shift_x;
1289     vy = self->y + (self->h - sh) / 2 - shift_y;
1290 root 1.38
1291 root 1.42 /*
1292     int vx = self->vx = self->w >= sw
1293     ? self->x + (self->w - sw) / 2
1294     : MIN (self->x, MAX (self->x + self->w - sw + 1, self->vx));
1295    
1296     int vy = self->vy = self->h >= sh
1297     ? self->y + (self->h - sh) / 2
1298     : MIN (self->y, MAX (self->y + self->h - sh + 1, self->vy));
1299     */
1300 root 1.30
1301     glColor4ub (255, 255, 255, 255);
1302    
1303     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1304     glEnable (GL_BLEND);
1305     glEnable (GL_TEXTURE_2D);
1306     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1307    
1308 root 1.48 glBegin (GL_QUADS);
1309 root 1.30
1310 root 1.48 last_name = 0;
1311 root 1.30
1312     for (z = 0; z < 3; z++)
1313     for (y = 0; y < sh; y++)
1314     if (0 <= y + vy && y + vy < self->rows)
1315     {
1316     maprow *row = self->row + (y + vy);
1317    
1318     for (x = 0; x < sw; x++)
1319     if (row->c0 <= x + vx && x + vx < row->c1)
1320     {
1321     mapcell *cell = row->col + (x + vx - row->c0);
1322 root 1.32
1323     darkness[y * sw4 + x] = cell->darkness < 0
1324 root 1.33 ? 255 - FOW_DARKNESS
1325 root 1.32 : 255 - cell->darkness;
1326    
1327 root 1.48 face = cell->face [z];
1328 root 1.30
1329     if (face)
1330     {
1331 root 1.42 maptex tex = self->tex [face];
1332 root 1.30
1333     int px = (x + 1) * 32 - tex.w;
1334     int py = (y + 1) * 32 - tex.h;
1335    
1336     if (last_name != tex.name)
1337     {
1338     glEnd ();
1339     last_name = tex.name;
1340     glBindTexture (GL_TEXTURE_2D, last_name);
1341     glBegin (GL_QUADS);
1342     }
1343    
1344     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1345     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1346     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1347     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1348     }
1349     }
1350     }
1351    
1352     glEnd ();
1353 root 1.32
1354 root 1.34 glDisable (GL_TEXTURE_2D);
1355     glDisable (GL_BLEND);
1356    
1357 root 1.32 EXTEND (SP, 3);
1358     PUSHs (sv_2mortal (newSViv (sw4)));
1359     PUSHs (sv_2mortal (newSViv (sh)));
1360     PUSHs (darkness_sv);
1361 root 1.30 }
1362    
1363 root 1.42 SV *
1364     get_rect (CFClient::Map self, int x0, int y0, int w, int h)
1365     CODE:
1366     {
1367     int x, y, x1, y1;
1368     SV *data_sv = newSV (w * h * 7 + 5);
1369     uint8_t *data = (uint8_t *)SvPVX (data_sv);
1370    
1371     *data++ = 0; /* version 0 format */
1372     *data++ = w >> 8; *data++ = w;
1373     *data++ = h >> 8; *data++ = h;
1374    
1375     // we need to do this 'cause we don't keep an absolute coord system for rows
1376 root 1.55 // TODO: treat rows as we treat columns
1377 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1378     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1379    
1380     x0 += self->x - self->ox;
1381     y0 += self->y - self->oy;
1382    
1383     x1 = x0 + w;
1384     y1 = y0 + h;
1385    
1386     for (y = y0; y < y1; y++)
1387     {
1388     maprow *row = 0 <= y && y < self->rows
1389     ? self->row + y
1390     : 0;
1391    
1392     for (x = x0; x < x1; x++)
1393     {
1394     if (row && row->c0 <= x && x < row->c1)
1395     {
1396     mapcell *cell = row->col + (x - row->c0);
1397     uint8_t flags = 0;
1398    
1399     if (cell->face [0]) flags |= 1;
1400     if (cell->face [1]) flags |= 2;
1401     if (cell->face [2]) flags |= 4;
1402    
1403     *data++ = flags;
1404    
1405     if (flags & 1)
1406     {
1407     *data++ = cell->face [0] >> 8;
1408     *data++ = cell->face [0];
1409     }
1410    
1411     if (flags & 2)
1412     {
1413     *data++ = cell->face [1] >> 8;
1414     *data++ = cell->face [1];
1415     }
1416    
1417     if (flags & 4)
1418     {
1419     *data++ = cell->face [2] >> 8;
1420     *data++ = cell->face [2];
1421     }
1422     }
1423     else
1424     *data++ = 0;
1425     }
1426     }
1427    
1428     SvPOK_only (data_sv);
1429     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
1430     RETVAL = data_sv;
1431     }
1432     OUTPUT:
1433     RETVAL
1434    
1435     void
1436     set_rect (CFClient::Map self, int x0, int y0, uint8_t *data)
1437     PPCODE:
1438     {
1439     int x, y, z;
1440 root 1.48 int w, h;
1441 root 1.42 int x1, y1;
1442    
1443     if (*data++ != 0)
1444     return; /* version mismatch */
1445    
1446 root 1.48 w = *data++ << 8; w |= *data++;
1447     h = *data++ << 8; h |= *data++;
1448 root 1.42
1449     // we need to do this 'cause we don't keep an absolute coord system for rows
1450 root 1.55 // TODO: treat rows as we treat columns
1451 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1452     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1453    
1454     x0 += self->x - self->ox;
1455     y0 += self->y - self->oy;
1456    
1457     x1 = x0 + w;
1458     y1 = y0 + h;
1459    
1460     for (y = y0; y < y1; y++)
1461     {
1462     maprow *row = map_get_row (self, y);
1463    
1464     for (x = x0; x < x1; x++)
1465     {
1466     uint8_t flags = *data++;
1467    
1468     if (flags)
1469     {
1470     mapface face[3] = { 0, 0, 0 };
1471    
1472     mapcell *cell = row_get_cell (row, x);
1473    
1474     if (flags & 1) { face[0] = *data++ << 8; face[0] |= *data++; }
1475     if (flags & 2) { face[1] = *data++ << 8; face[1] |= *data++; }
1476     if (flags & 4) { face[2] = *data++ << 8; face[2] |= *data++; }
1477    
1478     if (cell->darkness <= 0)
1479     {
1480     cell->darkness = -1;
1481    
1482     for (z = 0; z <= 2; z++)
1483     {
1484     cell->face[z] = face[z];
1485    
1486     if (face[z] && (face[z] >= self->texs || !self->tex[face [z]].name))
1487     XPUSHs (sv_2mortal (newSViv (face[z])));
1488     }
1489     }
1490     }
1491     }
1492     }
1493     }
1494    
1495 root 1.52 MODULE = CFClient PACKAGE = CFClient::MixChunk
1496    
1497     CFClient::MixChunk
1498     new_from_file (SV *class, char *path)
1499     CODE:
1500     RETVAL = Mix_LoadWAV (path);
1501     OUTPUT:
1502     RETVAL
1503    
1504     void
1505     DESTROY (CFClient::MixChunk self)
1506     CODE:
1507     Mix_FreeChunk (self);
1508    
1509     int
1510     volume (CFClient::MixChunk self, int volume = -1)
1511     CODE:
1512     RETVAL = Mix_VolumeChunk (self, volume);
1513     OUTPUT:
1514     RETVAL
1515    
1516     int
1517     play (CFClient::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
1518     CODE:
1519     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
1520     OUTPUT:
1521     RETVAL
1522    
1523     MODULE = CFClient PACKAGE = CFClient::MixMusic
1524    
1525     int
1526     volume (int volume = -1)
1527     CODE:
1528     RETVAL = Mix_VolumeMusic (volume);
1529     OUTPUT:
1530     RETVAL
1531    
1532     CFClient::MixMusic
1533     new_from_file (SV *class, char *path)
1534     CODE:
1535     RETVAL = Mix_LoadMUS (path);
1536     OUTPUT:
1537     RETVAL
1538    
1539     void
1540     DESTROY (CFClient::MixMusic self)
1541     CODE:
1542     Mix_FreeMusic (self);
1543    
1544     int
1545     play (CFClient::MixMusic self, int loops = -1)
1546     CODE:
1547     RETVAL = Mix_PlayMusic (self, loops);
1548     OUTPUT:
1549     RETVAL
1550    
1551 root 1.54 MODULE = CFClient PACKAGE = CFClient::OpenGL
1552    
1553     BOOT:
1554     {
1555     HV *stash = gv_stashpv ("CFClient::OpenGL", 1);
1556     static const struct {
1557     const char *name;
1558     IV iv;
1559     } *civ, const_iv[] = {
1560     # define const_iv(name) { # name, (IV)name }
1561     const_iv (GL_COLOR_MATERIAL),
1562     const_iv (GL_SMOOTH),
1563     const_iv (GL_FLAT),
1564 root 1.69 const_iv (GL_DITHER),
1565 root 1.54 const_iv (GL_BLEND),
1566 root 1.89 const_iv (GL_CULL_FACE),
1567 root 1.69 const_iv (GL_SCISSOR_TEST),
1568 root 1.89 const_iv (GL_DEPTH_TEST),
1569     const_iv (GL_ALPHA_TEST),
1570     const_iv (GL_NORMALIZE),
1571     const_iv (GL_RESCALE_NORMAL),
1572 root 1.54 const_iv (GL_AND),
1573 root 1.67 const_iv (GL_ONE),
1574     const_iv (GL_ZERO),
1575 root 1.54 const_iv (GL_SRC_ALPHA),
1576 root 1.104 const_iv (GL_DST_ALPHA),
1577 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
1578 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
1579 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
1580 root 1.54 const_iv (GL_RGB),
1581     const_iv (GL_RGBA),
1582     const_iv (GL_UNSIGNED_BYTE),
1583 root 1.89 const_iv (GL_UNSIGNED_SHORT),
1584     const_iv (GL_UNSIGNED_INT),
1585 root 1.54 const_iv (GL_ALPHA),
1586 root 1.86 const_iv (GL_INTENSITY),
1587 root 1.76 const_iv (GL_LUMINANCE),
1588 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
1589 root 1.54 const_iv (GL_FLOAT),
1590     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
1591     const_iv (GL_COMPILE),
1592     const_iv (GL_TEXTURE_1D),
1593     const_iv (GL_TEXTURE_2D),
1594     const_iv (GL_TEXTURE_ENV),
1595     const_iv (GL_TEXTURE_MAG_FILTER),
1596     const_iv (GL_TEXTURE_MIN_FILTER),
1597     const_iv (GL_TEXTURE_ENV_MODE),
1598     const_iv (GL_TEXTURE_WRAP_S),
1599     const_iv (GL_TEXTURE_WRAP_T),
1600 root 1.98 const_iv (GL_REPEAT),
1601 root 1.54 const_iv (GL_CLAMP),
1602 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
1603 root 1.54 const_iv (GL_NEAREST),
1604     const_iv (GL_LINEAR),
1605 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
1606     const_iv (GL_LINEAR_MIPMAP_NEAREST),
1607     const_iv (GL_NEAREST_MIPMAP_LINEAR),
1608     const_iv (GL_LINEAR_MIPMAP_LINEAR),
1609     const_iv (GL_GENERATE_MIPMAP),
1610 root 1.54 const_iv (GL_MODULATE),
1611 root 1.69 const_iv (GL_DECAL),
1612 root 1.54 const_iv (GL_REPLACE),
1613 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
1614 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
1615     const_iv (GL_PROJECTION),
1616     const_iv (GL_MODELVIEW),
1617     const_iv (GL_COLOR_LOGIC_OP),
1618 root 1.69 const_iv (GL_SEPARABLE_2D),
1619 root 1.54 const_iv (GL_CONVOLUTION_2D),
1620     const_iv (GL_CONVOLUTION_BORDER_MODE),
1621     const_iv (GL_CONSTANT_BORDER),
1622     const_iv (GL_LINES),
1623 root 1.89 const_iv (GL_LINE_LOOP),
1624 root 1.54 const_iv (GL_QUADS),
1625 root 1.89 const_iv (GL_QUAD_STRIP),
1626     const_iv (GL_TRIANGLES),
1627     const_iv (GL_TRIANGLE_STRIP),
1628     const_iv (GL_TRIANGLE_FAN),
1629 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
1630     const_iv (GL_FASTEST),
1631 root 1.89 const_iv (GL_V2F),
1632     const_iv (GL_V3F),
1633     const_iv (GL_T2F_V3F),
1634     const_iv (GL_T2F_N3F_V3F),
1635 root 1.54 # undef const_iv
1636     };
1637    
1638     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
1639     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
1640     }
1641    
1642 root 1.97 char *
1643     gl_vendor ()
1644     CODE:
1645     RETVAL = (char *)glGetString (GL_VENDOR);
1646     OUTPUT:
1647     RETVAL
1648    
1649     char *
1650     gl_version ()
1651     CODE:
1652     RETVAL = (char *)glGetString (GL_VERSION);
1653     OUTPUT:
1654     RETVAL
1655    
1656     char *
1657     gl_extensions ()
1658     CODE:
1659     RETVAL = (char *)glGetString (GL_EXTENSIONS);
1660     OUTPUT:
1661     RETVAL
1662    
1663 root 1.54 int glGetError ()
1664    
1665     void glClear (int mask)
1666    
1667     void glClearColor (float r, float g, float b, float a = 1.0)
1668     PROTOTYPE: @
1669    
1670     void glEnable (int cap)
1671    
1672     void glDisable (int cap)
1673    
1674     void glShadeModel (int mode)
1675    
1676     void glHint (int target, int mode)
1677    
1678     void glBlendFunc (int sfactor, int dfactor)
1679    
1680 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
1681     CODE:
1682     gl_BlendFuncSeparate (sa, da, saa, daa);
1683    
1684 root 1.89 void glDepthMask (int flag)
1685    
1686 root 1.54 void glLogicOp (int opcode)
1687    
1688 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
1689    
1690 root 1.54 void glMatrixMode (int mode)
1691    
1692     void glPushMatrix ()
1693    
1694     void glPopMatrix ()
1695    
1696     void glLoadIdentity ()
1697    
1698 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
1699     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
1700    
1701     # near_ and far_ are due to microsofts buggy "c" compiler
1702 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
1703 root 1.54
1704     void glViewport (int x, int y, int width, int height)
1705    
1706 root 1.69 void glScissor (int x, int y, int width, int height)
1707    
1708 root 1.54 void glTranslate (float x, float y, float z = 0.)
1709     CODE:
1710     glTranslatef (x, y, z);
1711    
1712 root 1.62 void glScale (float x, float y, float z = 1.)
1713 root 1.54 CODE:
1714     glScalef (x, y, z);
1715    
1716     void glRotate (float angle, float x, float y, float z)
1717     CODE:
1718     glRotatef (angle, x, y, z);
1719    
1720     void glBegin (int mode)
1721    
1722     void glEnd ()
1723    
1724     void glColor (float r, float g, float b, float a = 1.0)
1725     PROTOTYPE: @
1726 root 1.103 ALIAS:
1727     glColor_premultiply = 1
1728 root 1.54 CODE:
1729 root 1.103 if (ix)
1730     {
1731     r *= a;
1732     g *= a;
1733     b *= a;
1734     }
1735 root 1.90 // microsoft visual "c" rounds instead of truncating...
1736 root 1.100 glColor4ub (MIN ((int)(r * 256.f), 255),
1737     MIN ((int)(g * 256.f), 255),
1738     MIN ((int)(b * 256.f), 255),
1739     MIN ((int)(a * 256.f), 255));
1740 root 1.54
1741 root 1.89 void glInterleavedArrays (int format, int stride, char *data)
1742    
1743     void glDrawElements (int mode, int count, int type, char *indices)
1744    
1745     # 1.2 void glDrawRangeElements (int mode, int start, int end
1746    
1747 root 1.91 void glRasterPos (float x, float y, float z = 0.)
1748     CODE:
1749     glRasterPos3f (0, 0, z);
1750     glBitmap (0, 0, 0, 0, x, y, 0);
1751    
1752 root 1.54 void glVertex (float x, float y, float z = 0.)
1753     CODE:
1754     glVertex3f (x, y, z);
1755    
1756     void glTexCoord (float s, float t)
1757     CODE:
1758     glTexCoord2f (s, t);
1759    
1760     void glTexEnv (int target, int pname, float param)
1761     CODE:
1762     glTexEnvf (target, pname, param);
1763    
1764     void glTexParameter (int target, int pname, float param)
1765     CODE:
1766     glTexParameterf (target, pname, param);
1767    
1768     void glBindTexture (int target, int name)
1769    
1770     void glConvolutionParameter (int target, int pname, float params)
1771     CODE:
1772 root 1.103 if (gl.ConvolutionParameterf)
1773     gl.ConvolutionParameterf (target, pname, params);
1774 root 1.54
1775     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
1776 root 1.64 CODE:
1777 root 1.103 if (gl.ConvolutionFilter2D)
1778     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
1779 root 1.54
1780 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
1781     CODE:
1782 root 1.103 if (gl.SeparableFilter2D)
1783     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
1784 root 1.69
1785 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
1786    
1787     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
1788    
1789 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
1790 root 1.68
1791     void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
1792    
1793 root 1.54 int glGenTexture ()
1794     CODE:
1795     {
1796     GLuint name;
1797     glGenTextures (1, &name);
1798     RETVAL = name;
1799     }
1800     OUTPUT:
1801     RETVAL
1802    
1803     void glDeleteTexture (int name)
1804     CODE:
1805     {
1806     GLuint name_ = name;
1807     glDeleteTextures (1, &name_);
1808     }
1809    
1810     int glGenList ()
1811     CODE:
1812     RETVAL = glGenLists (1);
1813     OUTPUT:
1814     RETVAL
1815    
1816     void glDeleteList (int list)
1817     CODE:
1818     glDeleteLists (list, 1);
1819    
1820     void glNewList (int list, int mode = GL_COMPILE)
1821    
1822     void glEndList ()
1823    
1824     void glCallList (int list)
1825    
1826 root 1.89