ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.85
Committed: Fri May 19 03:49:47 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.84: +3 -2 lines
Log Message:
diddeldaddel

File Contents

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