ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.86
Committed: Fri May 19 16:43:56 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.85: +14 -9 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.48 #ifdef _WIN32
2 root 1.79 # define _WIN32_WINNT 0x0500 // needed to get win2000 api calls
3 root 1.48 # include <malloc.h>
4 root 1.79 # include <windows.h>
5 root 1.75 # pragma warning(disable:4244)
6 root 1.48 #endif
7    
8 root 1.1 #include "EXTERN.h"
9     #include "perl.h"
10     #include "XSUB.h"
11    
12 root 1.80 #include <math.h>
13 root 1.5 #include <string.h>
14 root 1.25 #include <stdio.h>
15 root 1.5
16 root 1.2 #include <SDL.h>
17 root 1.76 #include <SDL_endian.h>
18 root 1.23 #include <SDL_image.h>
19 root 1.52 #include <SDL_mixer.h>
20 root 1.3 #include <SDL_opengl.h>
21 root 1.5
22 root 1.30 #include <glib/gmacros.h>
23    
24 root 1.5 #include <pango/pango.h>
25 root 1.10 #include <pango/pangofc-fontmap.h>
26 root 1.5 #include <pango/pangoft2.h>
27 root 1.76 #include <pango/pangocairo.h>
28 root 1.5
29 root 1.48 #ifndef _WIN32
30     # include <sys/types.h>
31     # include <sys/socket.h>
32     # include <netinet/in.h>
33     # include <netinet/tcp.h>
34     # include <inttypes.h>
35     #else
36     typedef unsigned char uint8_t;
37     typedef unsigned short uint16_t;
38     typedef unsigned int uint32_t;
39     typedef signed char int8_t;
40     typedef signed short int16_t;
41     typedef signed int int32_t;
42     #endif
43 root 1.28
44 root 1.57 #include "glext.h"
45    
46 root 1.29 #define FOW_DARKNESS 32
47    
48     #define MAP_EXTEND_X 32
49     #define MAP_EXTEND_Y 512
50    
51 root 1.63 #define MIN_FONT_HEIGHT 10
52 root 1.58
53 root 1.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.86 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 16);
447 root 1.51
448 root 1.86 SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 64);
449 root 1.85 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 root 1.86 fprintf (stderr, "ERROR: %s\n", message);
676 root 1.66 #ifdef _WIN32
677 root 1.86 MessageBox (0, message, "Crossfire+ Error", MB_OK | MB_ICONERROR);
678 root 1.66 #endif
679    
680     void
681 root 1.25 fatal (char *message)
682     CODE:
683 root 1.86 fprintf (stderr, "FATAL: %s\n", message);
684 root 1.50 #ifdef _WIN32
685 root 1.86 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR);
686 root 1.25 #endif
687     exit (1);
688    
689 root 1.61 MODULE = CFClient PACKAGE = CFClient::Font
690    
691     CFClient::Font
692 root 1.70 new_from_file (SV *class, char *path, int id = 0)
693 root 1.61 CODE:
694     {
695     int count;
696 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
697 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
698     FcPatternDestroy (pattern);
699     }
700     OUTPUT:
701     RETVAL
702    
703     void
704     DESTROY (CFClient::Font self)
705     CODE:
706     pango_font_description_free (self);
707    
708     void
709     make_default (CFClient::Font self)
710     CODE:
711     default_font = self;
712    
713 root 1.15 MODULE = CFClient PACKAGE = CFClient::Layout
714 root 1.14
715 root 1.15 CFClient::Layout
716 root 1.76 new (SV *class, int rgba = 0)
717 root 1.14 CODE:
718     New (0, RETVAL, 1, struct cf_layout);
719 root 1.76
720     RETVAL->pl = pango_layout_new (rgba ? cairo_context : ft2_context);
721     RETVAL->rgba = rgba;
722     RETVAL->r = 1.;
723     RETVAL->g = 1.;
724     RETVAL->b = 1.;
725     RETVAL->a = 1.;
726     RETVAL->base_height = MIN_FONT_HEIGHT;
727     RETVAL->font = 0;
728    
729 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
730 root 1.76 layout_update_font (RETVAL);
731 root 1.14 OUTPUT:
732     RETVAL
733    
734     void
735 root 1.15 DESTROY (CFClient::Layout self)
736 root 1.14 CODE:
737     g_object_unref (self->pl);
738     Safefree (self);
739 root 1.13
740 root 1.76 int
741     is_rgba (CFClient::Layout self)
742     CODE:
743     RETVAL = self->rgba;
744     OUTPUT:
745     RETVAL
746    
747 root 1.8 void
748 root 1.35 set_text (CFClient::Layout self, SV *text_)
749     CODE:
750     {
751     STRLEN textlen;
752     char *text = SvPVutf8 (text_, textlen);
753    
754     pango_layout_set_text (self->pl, text, textlen);
755     }
756    
757     void
758 root 1.15 set_markup (CFClient::Layout self, SV *text_)
759 root 1.14 CODE:
760 root 1.5 {
761     STRLEN textlen;
762     char *text = SvPVutf8 (text_, textlen);
763 root 1.14
764     pango_layout_set_markup (self->pl, text, textlen);
765     }
766    
767 root 1.46 SV *
768     get_text (CFClient::Layout self)
769     CODE:
770 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
771 root 1.46 SvUTF8_on (RETVAL);
772     OUTPUT:
773     RETVAL
774    
775 root 1.14 void
776 root 1.76 set_foreground (CFClient::Layout self, float r, float g, float b, float a = 1.)
777     CODE:
778     self->r = r;
779     self->g = g;
780     self->b = b;
781     self->a = a;
782    
783     void
784 root 1.61 set_font (CFClient::Layout self, CFClient::Font font = 0)
785     CODE:
786     if (self->font != font)
787     {
788     self->font = font;
789     layout_update_font (self);
790     }
791    
792     void
793 root 1.16 set_height (CFClient::Layout self, int base_height)
794     CODE:
795 root 1.61 if (self->base_height != base_height)
796     {
797     self->base_height = base_height;
798     layout_update_font (self);
799     }
800 root 1.16
801     void
802 root 1.15 set_width (CFClient::Layout self, int max_width = -1)
803 root 1.14 CODE:
804     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
805    
806     void
807 root 1.84 set_indent (CFClient::Layout self, int indent)
808     CODE:
809     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
810    
811     void
812     set_spacing (CFClient::Layout self, int spacing)
813     CODE:
814     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
815    
816     void
817     set_ellipsise (CFClient::Layout self, int ellipsise)
818     CODE:
819     pango_layout_set_ellipsize (self->pl,
820     ellipsise == 1 ? PANGO_ELLIPSIZE_START
821     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
822     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
823     : PANGO_ELLIPSIZE_NONE
824     );
825    
826     void
827     set_single_paragraph_mode (CFClient::Layout self, int spm)
828     CODE:
829     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
830    
831     void
832 root 1.15 size (CFClient::Layout self)
833 root 1.14 PPCODE:
834     {
835     int w, h;
836    
837     layout_get_pixel_size (self, &w, &h);
838    
839     EXTEND (SP, 2);
840     PUSHs (sv_2mortal (newSViv (w)));
841     PUSHs (sv_2mortal (newSViv (h)));
842     }
843    
844 root 1.17 int
845     xy_to_index (CFClient::Layout self, int x, int y)
846     CODE:
847     {
848     int index, trailing;
849     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
850     RETVAL = index;
851     }
852     OUTPUT:
853     RETVAL
854    
855     void
856     cursor_pos (CFClient::Layout self, int index)
857     PPCODE:
858     {
859     PangoRectangle strong_pos;
860     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
861 root 1.30
862 root 1.17 EXTEND (SP, 3);
863     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
864     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
865     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
866     }
867    
868 root 1.14 void
869 root 1.15 render (CFClient::Layout self)
870 root 1.14 PPCODE:
871     {
872 root 1.5 SV *retval;
873     int w, h;
874    
875 root 1.14 layout_get_pixel_size (self, &w, &h);
876 root 1.5
877 root 1.76 if (self->rgba)
878     {
879     cairo_surface_t *surface;
880     cairo_t *cairo;
881    
882     retval = newSV (w * h * 4);
883     SvPOK_only (retval);
884     SvCUR_set (retval, w * h * 4);
885    
886     memset (SvPVX (retval), 0, w * h * 4);
887    
888     surface = cairo_image_surface_create_for_data (
889     (void*)SvPVX (retval), CAIRO_FORMAT_ARGB32, w, h, w * 4);
890     cairo = cairo_create (surface);
891     cairo_set_source_rgba (cairo, self->r, self->g, self->b, self->a);
892    
893     pango_cairo_show_layout (cairo, self->pl);
894    
895     cairo_destroy (cairo);
896     cairo_surface_destroy (surface);
897    
898     // what a mess, and its premultiplied, too :(
899     {
900     uint32_t *p = (uint32_t *)SvPVX (retval);
901     uint32_t *e = p + w * h;
902 root 1.5
903 root 1.76 while (p < e)
904     {
905     uint32_t rgba = *p;
906     rgba = (rgba >> 24) | (rgba << 8);
907     rgba = SDL_SwapBE32 (rgba);
908     *p++ = rgba;
909     }
910     }
911    
912     EXTEND (SP, 5);
913     PUSHs (sv_2mortal (newSViv (w)));
914     PUSHs (sv_2mortal (newSViv (h)));
915     PUSHs (sv_2mortal (retval));
916     PUSHs (sv_2mortal (newSViv (GL_RGBA)));
917     PUSHs (sv_2mortal (newSViv (GL_RGBA)));
918     }
919     else
920     {
921     FT_Bitmap bitmap;
922    
923     retval = newSV (w * h);
924     SvPOK_only (retval);
925     SvCUR_set (retval, w * h);
926    
927     bitmap.rows = h;
928     bitmap.width = w;
929     bitmap.pitch = w;
930     bitmap.buffer = (unsigned char*)SvPVX (retval);
931     bitmap.num_grays = 256;
932     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
933    
934     memset (bitmap.buffer, 0, w * h);
935    
936     pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
937 root 1.1
938 root 1.76 EXTEND (SP, 5);
939     PUSHs (sv_2mortal (newSViv (w)));
940     PUSHs (sv_2mortal (newSViv (h)));
941     PUSHs (sv_2mortal (retval));
942     PUSHs (sv_2mortal (newSViv (GL_ALPHA)));
943     PUSHs (sv_2mortal (newSViv (GL_ALPHA)));
944     }
945 root 1.5 }
946 root 1.11
947 root 1.15 MODULE = CFClient PACKAGE = CFClient::Texture
948 root 1.11
949     void
950 root 1.37 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
951 root 1.12 PROTOTYPE: $$$;$$
952 root 1.76 ALIAS:
953     draw_quad_alpha = 1
954     draw_quad_alpha_premultiplied = 2
955 root 1.11 CODE:
956     {
957 root 1.12 HV *hv = (HV *)SvRV (self);
958 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
959     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
960 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
961 elmex 1.36 int wrap_mode = SvIV (*hv_fetch (hv, "wrap_mode", 9, 1));
962 root 1.12
963     if (items < 5)
964     {
965 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
966     h = SvNV (*hv_fetch (hv, "h", 1, 1));
967 root 1.12 }
968    
969 root 1.76 if (ix)
970     {
971     glEnable (GL_BLEND);
972     glBlendFunc (ix == 1 ? GL_SRC_ALPHA : GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
973 root 1.86 glEnable (GL_ALPHA_TEST);
974     glAlphaFunc (GL_GREATER, 0.01f);
975 root 1.76 }
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 root 1.86 {
994     glDisable (GL_ALPHA_TEST);
995     glDisable (GL_BLEND);
996     }
997 root 1.11 }
998 root 1.28
999     MODULE = CFClient PACKAGE = CFClient::Map
1000    
1001     CFClient::Map
1002     new (SV *class, int map_width, int map_height)
1003     CODE:
1004     New (0, RETVAL, 1, struct map);
1005 root 1.42 RETVAL->x = 0;
1006     RETVAL->y = 0;
1007     RETVAL->w = map_width;
1008     RETVAL->h = map_height;
1009     RETVAL->ox = 0;
1010     RETVAL->oy = 0;
1011 root 1.30 RETVAL->faces = 8192;
1012     Newz (0, RETVAL->face, RETVAL->faces, mapface);
1013 root 1.42 RETVAL->texs = 8192;
1014     Newz (0, RETVAL->tex, RETVAL->texs, maptex);
1015 root 1.28 RETVAL->rows = 0;
1016     RETVAL->row = 0;
1017     OUTPUT:
1018     RETVAL
1019    
1020     void
1021     DESTROY (CFClient::Map self)
1022     CODE:
1023     {
1024 root 1.30 map_clear (self);
1025 root 1.28 Safefree (self->face);
1026 root 1.29 Safefree (self);
1027     }
1028    
1029     void
1030 root 1.30 clear (CFClient::Map self)
1031     CODE:
1032     map_clear (self);
1033    
1034     void
1035 root 1.42 set_face (CFClient::Map self, int face, int texid)
1036 root 1.29 CODE:
1037     {
1038 root 1.42 while (self->faces <= face)
1039 root 1.28 {
1040 root 1.30 Append (mapface, self->face, self->faces, self->faces);
1041 root 1.29 self->faces *= 2;
1042     }
1043 root 1.28
1044 root 1.42 self->face [face] = texid;
1045     }
1046    
1047     void
1048     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)
1049     CODE:
1050     {
1051     while (self->texs <= texid)
1052     {
1053     Append (maptex, self->tex, self->texs, self->texs);
1054     self->texs *= 2;
1055     }
1056    
1057 root 1.48 {
1058     maptex *tex = self->tex + texid;
1059 root 1.39
1060 root 1.48 tex->name = name;
1061     tex->w = w;
1062     tex->h = h;
1063     tex->s = s;
1064     tex->t = t;
1065     tex->r = r;
1066     tex->g = g;
1067     tex->b = b;
1068     tex->a = a;
1069     }
1070 root 1.29 }
1071    
1072 root 1.42 int
1073     ox (CFClient::Map self)
1074     ALIAS:
1075     oy = 1
1076     CODE:
1077     switch (ix)
1078     {
1079     case 0: RETVAL = self->ox; break;
1080     case 1: RETVAL = self->oy; break;
1081     }
1082     OUTPUT:
1083     RETVAL
1084    
1085 root 1.29 void
1086 root 1.43 scroll (CFClient::Map self, int dx, int dy)
1087     CODE:
1088     {
1089 root 1.44 if (dx > 0)
1090     map_blank (self, self->x, self->y, dx - 1, self->h);
1091     else if (dx < 0)
1092     map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
1093    
1094     if (dy > 0)
1095     map_blank (self, self->x, self->y, self->w, dy - 1);
1096     else if (dy < 0)
1097     map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
1098 root 1.43
1099 root 1.44 self->ox += dx; self->x += dx;
1100     self->oy += dy; self->y += dy;
1101 root 1.43
1102     while (self->y < 0)
1103     {
1104     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1105    
1106     self->rows += MAP_EXTEND_Y;
1107     self->y += MAP_EXTEND_Y;
1108     }
1109 root 1.44 }
1110 root 1.43
1111 root 1.44 void
1112     map1a_update (CFClient::Map self, SV *data_)
1113     CODE:
1114     {
1115 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1116     uint8_t *data_end = (uint8_t *)SvEND (data_);
1117 root 1.48 mapcell *cell;
1118     int x, y, flags;
1119 root 1.43
1120 root 1.29 while (data < data_end)
1121     {
1122 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1123 root 1.30
1124 root 1.48 x = ((flags >> 10) & 63) + self->x;
1125     y = ((flags >> 4) & 63) + self->y;
1126 root 1.29
1127 root 1.48 cell = map_get_cell (self, x, y);
1128 root 1.29
1129     if (flags & 15)
1130     {
1131 root 1.45 if (cell->darkness < 0)
1132 root 1.29 {
1133     cell->darkness = 0;
1134     cell->face [0] = 0;
1135     cell->face [1] = 0;
1136     cell->face [2] = 0;
1137     }
1138 root 1.45
1139 root 1.29 cell->darkness = flags & 8 ? *data++ : 255;
1140    
1141 root 1.42 //TODO: don't trust server data to be in-range(!)
1142    
1143 root 1.29 if (flags & 4)
1144     {
1145 root 1.42 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
1146 root 1.29 }
1147    
1148     if (flags & 2)
1149     {
1150 root 1.42 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
1151 root 1.29 }
1152    
1153     if (flags & 1)
1154     {
1155 root 1.42 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
1156 root 1.29 }
1157     }
1158     else
1159 root 1.31 cell->darkness = -1;
1160 root 1.29 }
1161 root 1.28 }
1162    
1163 root 1.40 SV *
1164 root 1.55 mapmap (CFClient::Map self, int x0, int y0, int w, int h)
1165 root 1.40 CODE:
1166     {
1167 root 1.55 int x1, x;
1168     int y1, y;
1169 root 1.40 int z;
1170     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1171     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1172    
1173     SvPOK_only (map_sv);
1174     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1175    
1176 root 1.55 x0 += self->x; x1 = x0 + w;
1177     y0 += self->y; y1 = y0 + h;
1178 root 1.40
1179     for (y = y0; y < y1; y++)
1180     {
1181     maprow *row = 0 <= y && y < self->rows
1182     ? self->row + y
1183     : 0;
1184    
1185     for (x = x0; x < x1; x++)
1186     {
1187     int r = 32, g = 32, b = 32, a = 192;
1188    
1189     if (row && row->c0 <= x && x < row->c1)
1190     {
1191     mapcell *cell = row->col + (x - row->c0);
1192    
1193     for (z = 0; z <= 0; z++)
1194     {
1195 root 1.42 mapface face = cell->face [z];
1196 root 1.40
1197     if (face)
1198     {
1199 root 1.42 maptex tex = self->tex [face];
1200 root 1.40 int a0 = 255 - tex.a;
1201     int a1 = tex.a;
1202    
1203     r = (r * a0 + tex.r * a1) / 255;
1204     g = (g * a0 + tex.g * a1) / 255;
1205     b = (b * a0 + tex.b * a1) / 255;
1206     a = (a * a0 + tex.a * a1) / 255;
1207     }
1208     }
1209     }
1210    
1211     *map++ = (r )
1212     | (g << 8)
1213     | (b << 16)
1214     | (a << 24);
1215     }
1216     }
1217    
1218     RETVAL = map_sv;
1219     }
1220     OUTPUT:
1221     RETVAL
1222    
1223 root 1.30 void
1224 root 1.38 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
1225 root 1.32 PPCODE:
1226 root 1.30 {
1227 root 1.48 int vx, vy;
1228     int x, y, z;
1229     int last_name;
1230     mapface face;
1231 root 1.32 int sw4 = (sw + 3) & ~3;
1232     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
1233 root 1.35 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
1234 root 1.48
1235 root 1.42 memset (darkness, 255, sw4 * sh);
1236 root 1.32 SvPOK_only (darkness_sv);
1237     SvCUR_set (darkness_sv, sw4 * sh);
1238    
1239 root 1.48 vx = self->x + (self->w - sw) / 2 - shift_x;
1240     vy = self->y + (self->h - sh) / 2 - shift_y;
1241 root 1.38
1242 root 1.42 /*
1243     int vx = self->vx = self->w >= sw
1244     ? self->x + (self->w - sw) / 2
1245     : MIN (self->x, MAX (self->x + self->w - sw + 1, self->vx));
1246    
1247     int vy = self->vy = self->h >= sh
1248     ? self->y + (self->h - sh) / 2
1249     : MIN (self->y, MAX (self->y + self->h - sh + 1, self->vy));
1250     */
1251 root 1.30
1252     glColor4ub (255, 255, 255, 255);
1253    
1254     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1255     glEnable (GL_BLEND);
1256     glEnable (GL_TEXTURE_2D);
1257     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1258    
1259 root 1.48 glBegin (GL_QUADS);
1260 root 1.30
1261 root 1.48 last_name = 0;
1262 root 1.30
1263     for (z = 0; z < 3; z++)
1264     for (y = 0; y < sh; y++)
1265     if (0 <= y + vy && y + vy < self->rows)
1266     {
1267     maprow *row = self->row + (y + vy);
1268    
1269     for (x = 0; x < sw; x++)
1270     if (row->c0 <= x + vx && x + vx < row->c1)
1271     {
1272     mapcell *cell = row->col + (x + vx - row->c0);
1273 root 1.32
1274     darkness[y * sw4 + x] = cell->darkness < 0
1275 root 1.33 ? 255 - FOW_DARKNESS
1276 root 1.32 : 255 - cell->darkness;
1277    
1278 root 1.48 face = cell->face [z];
1279 root 1.30
1280     if (face)
1281     {
1282 root 1.42 maptex tex = self->tex [face];
1283 root 1.30
1284     int px = (x + 1) * 32 - tex.w;
1285     int py = (y + 1) * 32 - tex.h;
1286    
1287     if (last_name != tex.name)
1288     {
1289     glEnd ();
1290     last_name = tex.name;
1291     glBindTexture (GL_TEXTURE_2D, last_name);
1292     glBegin (GL_QUADS);
1293     }
1294    
1295     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1296     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1297     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1298     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1299     }
1300     }
1301     }
1302    
1303     glEnd ();
1304 root 1.32
1305 root 1.34 glDisable (GL_TEXTURE_2D);
1306     glDisable (GL_BLEND);
1307    
1308 root 1.32 EXTEND (SP, 3);
1309     PUSHs (sv_2mortal (newSViv (sw4)));
1310     PUSHs (sv_2mortal (newSViv (sh)));
1311     PUSHs (darkness_sv);
1312 root 1.30 }
1313    
1314 root 1.42 SV *
1315     get_rect (CFClient::Map self, int x0, int y0, int w, int h)
1316     CODE:
1317     {
1318     int x, y, x1, y1;
1319     SV *data_sv = newSV (w * h * 7 + 5);
1320     uint8_t *data = (uint8_t *)SvPVX (data_sv);
1321    
1322     *data++ = 0; /* version 0 format */
1323     *data++ = w >> 8; *data++ = w;
1324     *data++ = h >> 8; *data++ = h;
1325    
1326     // we need to do this 'cause we don't keep an absolute coord system for rows
1327 root 1.55 // TODO: treat rows as we treat columns
1328 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1329     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1330    
1331     x0 += self->x - self->ox;
1332     y0 += self->y - self->oy;
1333    
1334     x1 = x0 + w;
1335     y1 = y0 + h;
1336    
1337     for (y = y0; y < y1; y++)
1338     {
1339     maprow *row = 0 <= y && y < self->rows
1340     ? self->row + y
1341     : 0;
1342    
1343     for (x = x0; x < x1; x++)
1344     {
1345     if (row && row->c0 <= x && x < row->c1)
1346     {
1347     mapcell *cell = row->col + (x - row->c0);
1348     uint8_t flags = 0;
1349    
1350     if (cell->face [0]) flags |= 1;
1351     if (cell->face [1]) flags |= 2;
1352     if (cell->face [2]) flags |= 4;
1353    
1354     *data++ = flags;
1355    
1356     if (flags & 1)
1357     {
1358     *data++ = cell->face [0] >> 8;
1359     *data++ = cell->face [0];
1360     }
1361    
1362     if (flags & 2)
1363     {
1364     *data++ = cell->face [1] >> 8;
1365     *data++ = cell->face [1];
1366     }
1367    
1368     if (flags & 4)
1369     {
1370     *data++ = cell->face [2] >> 8;
1371     *data++ = cell->face [2];
1372     }
1373     }
1374     else
1375     *data++ = 0;
1376     }
1377     }
1378    
1379     SvPOK_only (data_sv);
1380     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
1381     RETVAL = data_sv;
1382     }
1383     OUTPUT:
1384     RETVAL
1385    
1386     void
1387     set_rect (CFClient::Map self, int x0, int y0, uint8_t *data)
1388     PPCODE:
1389     {
1390     int x, y, z;
1391 root 1.48 int w, h;
1392 root 1.42 int x1, y1;
1393    
1394     if (*data++ != 0)
1395     return; /* version mismatch */
1396    
1397 root 1.48 w = *data++ << 8; w |= *data++;
1398     h = *data++ << 8; h |= *data++;
1399 root 1.42
1400     // we need to do this 'cause we don't keep an absolute coord system for rows
1401 root 1.55 // TODO: treat rows as we treat columns
1402 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1403     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1404    
1405     x0 += self->x - self->ox;
1406     y0 += self->y - self->oy;
1407    
1408     x1 = x0 + w;
1409     y1 = y0 + h;
1410    
1411     for (y = y0; y < y1; y++)
1412     {
1413     maprow *row = map_get_row (self, y);
1414    
1415     for (x = x0; x < x1; x++)
1416     {
1417     uint8_t flags = *data++;
1418    
1419     if (flags)
1420     {
1421     mapface face[3] = { 0, 0, 0 };
1422    
1423     mapcell *cell = row_get_cell (row, x);
1424    
1425     if (flags & 1) { face[0] = *data++ << 8; face[0] |= *data++; }
1426     if (flags & 2) { face[1] = *data++ << 8; face[1] |= *data++; }
1427     if (flags & 4) { face[2] = *data++ << 8; face[2] |= *data++; }
1428    
1429     if (cell->darkness <= 0)
1430     {
1431     cell->darkness = -1;
1432    
1433     for (z = 0; z <= 2; z++)
1434     {
1435     cell->face[z] = face[z];
1436    
1437     if (face[z] && (face[z] >= self->texs || !self->tex[face [z]].name))
1438     XPUSHs (sv_2mortal (newSViv (face[z])));
1439     }
1440     }
1441     }
1442     }
1443     }
1444     }
1445    
1446 root 1.52 MODULE = CFClient PACKAGE = CFClient::MixChunk
1447    
1448     CFClient::MixChunk
1449     new_from_file (SV *class, char *path)
1450     CODE:
1451     RETVAL = Mix_LoadWAV (path);
1452     OUTPUT:
1453     RETVAL
1454    
1455     void
1456     DESTROY (CFClient::MixChunk self)
1457     CODE:
1458     Mix_FreeChunk (self);
1459    
1460     int
1461     volume (CFClient::MixChunk self, int volume = -1)
1462     CODE:
1463     RETVAL = Mix_VolumeChunk (self, volume);
1464     OUTPUT:
1465     RETVAL
1466    
1467     int
1468     play (CFClient::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
1469     CODE:
1470     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
1471     OUTPUT:
1472     RETVAL
1473    
1474     MODULE = CFClient PACKAGE = CFClient::MixMusic
1475    
1476     int
1477     volume (int volume = -1)
1478     CODE:
1479     RETVAL = Mix_VolumeMusic (volume);
1480     OUTPUT:
1481     RETVAL
1482    
1483     CFClient::MixMusic
1484     new_from_file (SV *class, char *path)
1485     CODE:
1486     RETVAL = Mix_LoadMUS (path);
1487     OUTPUT:
1488     RETVAL
1489    
1490     void
1491     DESTROY (CFClient::MixMusic self)
1492     CODE:
1493     Mix_FreeMusic (self);
1494    
1495     int
1496     play (CFClient::MixMusic self, int loops = -1)
1497     CODE:
1498     RETVAL = Mix_PlayMusic (self, loops);
1499     OUTPUT:
1500     RETVAL
1501    
1502 root 1.54 MODULE = CFClient PACKAGE = CFClient::OpenGL
1503    
1504     BOOT:
1505     {
1506     HV *stash = gv_stashpv ("CFClient::OpenGL", 1);
1507     static const struct {
1508     const char *name;
1509     IV iv;
1510     } *civ, const_iv[] = {
1511     # define const_iv(name) { # name, (IV)name }
1512     const_iv (GL_COLOR_MATERIAL),
1513     const_iv (GL_SMOOTH),
1514     const_iv (GL_FLAT),
1515 root 1.69 const_iv (GL_DITHER),
1516 root 1.54 const_iv (GL_BLEND),
1517 root 1.69 const_iv (GL_SCISSOR_TEST),
1518 root 1.54 const_iv (GL_AND),
1519 root 1.67 const_iv (GL_ONE),
1520     const_iv (GL_ZERO),
1521 root 1.54 const_iv (GL_SRC_ALPHA),
1522 root 1.67 const_iv (GL_SRC_ALPHA_SATURATE),
1523 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
1524 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
1525 root 1.54 const_iv (GL_RGB),
1526     const_iv (GL_RGBA),
1527     const_iv (GL_UNSIGNED_BYTE),
1528     const_iv (GL_ALPHA),
1529 root 1.86 const_iv (GL_INTENSITY),
1530 root 1.76 const_iv (GL_LUMINANCE),
1531 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
1532 root 1.54 const_iv (GL_FLOAT),
1533     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
1534     const_iv (GL_COMPILE),
1535     const_iv (GL_TEXTURE_1D),
1536     const_iv (GL_TEXTURE_2D),
1537     const_iv (GL_TEXTURE_ENV),
1538     const_iv (GL_TEXTURE_MAG_FILTER),
1539     const_iv (GL_TEXTURE_MIN_FILTER),
1540     const_iv (GL_TEXTURE_ENV_MODE),
1541     const_iv (GL_TEXTURE_WRAP_S),
1542     const_iv (GL_TEXTURE_WRAP_T),
1543     const_iv (GL_CLAMP),
1544     const_iv (GL_REPEAT),
1545     const_iv (GL_NEAREST),
1546     const_iv (GL_LINEAR),
1547 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
1548     const_iv (GL_LINEAR_MIPMAP_NEAREST),
1549     const_iv (GL_NEAREST_MIPMAP_LINEAR),
1550     const_iv (GL_LINEAR_MIPMAP_LINEAR),
1551     const_iv (GL_GENERATE_MIPMAP),
1552 root 1.54 const_iv (GL_MODULATE),
1553 root 1.69 const_iv (GL_DECAL),
1554 root 1.54 const_iv (GL_REPLACE),
1555     const_iv (GL_COLOR_BUFFER_BIT),
1556     const_iv (GL_PROJECTION),
1557     const_iv (GL_MODELVIEW),
1558     const_iv (GL_COLOR_LOGIC_OP),
1559 root 1.69 const_iv (GL_SEPARABLE_2D),
1560 root 1.54 const_iv (GL_CONVOLUTION_2D),
1561     const_iv (GL_CONVOLUTION_BORDER_MODE),
1562     const_iv (GL_CONSTANT_BORDER),
1563     const_iv (GL_LINES),
1564     const_iv (GL_QUADS),
1565 root 1.55 const_iv (GL_LINE_LOOP),
1566 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
1567     const_iv (GL_FASTEST),
1568     # undef const_iv
1569     };
1570    
1571     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
1572     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
1573     }
1574    
1575     int glGetError ()
1576    
1577     void glClear (int mask)
1578    
1579     void glClearColor (float r, float g, float b, float a = 1.0)
1580     PROTOTYPE: @
1581    
1582     void glEnable (int cap)
1583    
1584     void glDisable (int cap)
1585    
1586     void glShadeModel (int mode)
1587    
1588     void glHint (int target, int mode)
1589    
1590     void glBlendFunc (int sfactor, int dfactor)
1591    
1592     void glLogicOp (int opcode)
1593    
1594 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
1595    
1596 root 1.54 void glMatrixMode (int mode)
1597    
1598     void glPushMatrix ()
1599    
1600     void glPopMatrix ()
1601    
1602     void glLoadIdentity ()
1603    
1604 root 1.64 # near and far are due to microsofts buggy c compiler
1605     void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
1606 root 1.54
1607     void glViewport (int x, int y, int width, int height)
1608    
1609 root 1.69 void glScissor (int x, int y, int width, int height)
1610    
1611 root 1.54 void glTranslate (float x, float y, float z = 0.)
1612     CODE:
1613     glTranslatef (x, y, z);
1614    
1615 root 1.62 void glScale (float x, float y, float z = 1.)
1616 root 1.54 CODE:
1617     glScalef (x, y, z);
1618    
1619     void glRotate (float angle, float x, float y, float z)
1620     CODE:
1621     glRotatef (angle, x, y, z);
1622    
1623     void glBegin (int mode)
1624    
1625     void glEnd ()
1626    
1627     void glColor (float r, float g, float b, float a = 1.0)
1628     PROTOTYPE: @
1629     CODE:
1630 root 1.81 glColor4ub (MIN ((int)(r * 255.f), 255),
1631     MIN ((int)(g * 255.f), 255),
1632     MIN ((int)(b * 255.f), 255),
1633     MIN ((int)(a * 255.f), 255));
1634 root 1.54
1635     void glVertex (float x, float y, float z = 0.)
1636     CODE:
1637     glVertex3f (x, y, z);
1638    
1639     void glTexCoord (float s, float t)
1640     CODE:
1641     glTexCoord2f (s, t);
1642    
1643     void glTexEnv (int target, int pname, float param)
1644     CODE:
1645     glTexEnvf (target, pname, param);
1646    
1647     void glTexParameter (int target, int pname, float param)
1648     CODE:
1649     glTexParameterf (target, pname, param);
1650    
1651     void glBindTexture (int target, int name)
1652    
1653     void glConvolutionParameter (int target, int pname, float params)
1654     CODE:
1655 root 1.64 GL_CALL (PFNGLCONVOLUTIONPARAMETERFEXTPROC, glConvolutionParameterf, (target, pname, params));
1656 root 1.54
1657     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
1658 root 1.64 CODE:
1659     GL_CALL (PFNGLCONVOLUTIONFILTER2DEXTPROC, glConvolutionFilter2D,
1660     (target, internalformat, width, height, format, type, data));
1661 root 1.54
1662 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
1663     CODE:
1664     GL_CALL (PFNGLSEPARABLEFILTER2DEXTPROC, glSeparableFilter2D,
1665     (target, internalformat, width, height, format, type, row, column));
1666    
1667 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
1668    
1669     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
1670    
1671 root 1.68 void glRasterPos (int x, int y)
1672     CODE:
1673     glRasterPos2i (x, y);
1674    
1675     void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
1676    
1677 root 1.54 int glGenTexture ()
1678     CODE:
1679     {
1680     GLuint name;
1681     glGenTextures (1, &name);
1682     RETVAL = name;
1683     }
1684     OUTPUT:
1685     RETVAL
1686    
1687     void glDeleteTexture (int name)
1688     CODE:
1689     {
1690     GLuint name_ = name;
1691     glDeleteTextures (1, &name_);
1692     }
1693    
1694     int glGenList ()
1695     CODE:
1696     RETVAL = glGenLists (1);
1697     OUTPUT:
1698     RETVAL
1699    
1700     void glDeleteList (int list)
1701     CODE:
1702     glDeleteLists (list, 1);
1703    
1704     void glNewList (int list, int mode = GL_COMPILE)
1705    
1706     void glEndList ()
1707    
1708     void glCallList (int list)
1709