ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.76
Committed: Thu May 11 23:41:45 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.75: +128 -34 lines
Log Message:
implement rgba layouts using the cairo backend

File Contents

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