ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.79
Committed: Sun May 14 22:24:14 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.78: +18 -6 lines
Log Message:
improved win32 support and enable auto-hinting (cairo enforces auto-hinting it seems, so be consistent)

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