ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.83
Committed: Mon May 15 00:25:14 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.82: +3 -1 lines
Log Message:
each

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     SDL_GL_SetAttribute (SDL_GL_ACCUM_RED_SIZE, 0);
449     SDL_GL_SetAttribute (SDL_GL_ACCUM_GREEN_SIZE, 0);
450     SDL_GL_SetAttribute (SDL_GL_ACCUM_BLUE_SIZE, 0);
451     SDL_GL_SetAttribute (SDL_GL_ACCUM_ALPHA_SIZE, 0);
452    
453     SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
454     SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 15);
455     SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 0);
456    
457 root 1.53 SDL_EnableUNICODE (1);
458     SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
459    
460 root 1.51 m = SDL_ListModes (0, SDL_FULLSCREEN | SDL_OPENGL);
461    
462     if (m && m != (SDL_Rect **)-1)
463     while (*m)
464     {
465     AV *av = newAV ();
466     av_push (av, newSViv ((*m)->w));
467     av_push (av, newSViv ((*m)->h));
468     XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
469    
470     ++m;
471     }
472     }
473    
474     int
475     SDL_SetVideoMode (int w, int h, int fullscreen)
476     CODE:
477     RETVAL = !!SDL_SetVideoMode (
478     w, h, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)
479     );
480     SDL_WM_SetCaption ("Crossfire+ Client " VERSION, "Crossfire+");
481     OUTPUT:
482     RETVAL
483    
484 root 1.53 void
485 root 1.54 SDL_GL_SwapBuffers ()
486    
487     void
488 root 1.53 SDL_PollEvent ()
489     PPCODE:
490     {
491     SDL_Event ev;
492    
493     while (SDL_PollEvent (&ev))
494     {
495     HV *hv = newHV ();
496     hv_store (hv, "type", 4, newSViv (ev.type), 0);
497 root 1.70
498 root 1.53 switch (ev.type)
499     {
500     case SDL_KEYDOWN:
501     case SDL_KEYUP:
502     hv_store (hv, "state", 5, newSViv (ev.key.state), 0);
503     hv_store (hv, "sym", 3, newSViv (ev.key.keysym.sym), 0);
504     hv_store (hv, "mod", 3, newSViv (ev.key.keysym.mod), 0);
505     hv_store (hv, "unicode", 7, newSViv (ev.key.keysym.unicode), 0);
506     break;
507    
508     case SDL_ACTIVEEVENT:
509     hv_store (hv, "gain", 4, newSViv (ev.active.gain), 0);
510     hv_store (hv, "state", 5, newSViv (ev.active.state), 0);
511     break;
512    
513     case SDL_MOUSEMOTION:
514     hv_store (hv, "state", 5, newSViv (ev.motion.state), 0);
515     hv_store (hv, "x", 1, newSViv (ev.motion.x), 0);
516     hv_store (hv, "y", 1, newSViv (ev.motion.y), 0);
517     hv_store (hv, "xrel", 4, newSViv (ev.motion.xrel), 0);
518     hv_store (hv, "yrel", 4, newSViv (ev.motion.yrel), 0);
519     break;
520    
521     case SDL_MOUSEBUTTONDOWN:
522     case SDL_MOUSEBUTTONUP:
523     hv_store (hv, "button", 6, newSViv (ev.button.button), 0);
524     hv_store (hv, "state", 5, newSViv (ev.button.state), 0);
525     hv_store (hv, "x", 1, newSViv (ev.button.x), 0);
526     hv_store (hv, "y", 1, newSViv (ev.button.y), 0);
527 root 1.70 break;
528 root 1.72
529     case SDL_USEREVENT:
530     hv_store (hv, "code", 4, newSViv (ev.user.code), 0);
531     hv_store (hv, "data1", 5, newSViv ((IV)ev.user.data1), 0);
532     hv_store (hv, "data2", 5, newSViv ((IV)ev.user.data2), 0);
533     break;
534 root 1.53 }
535    
536     XPUSHs (sv_2mortal (newRV_noinc ((SV *)hv)));
537     }
538     }
539 root 1.52
540     int
541 root 1.73 Mix_OpenAudio (int frequency = 48000, int format = MIX_DEFAULT_FORMAT, int channels = 1, int chunksize = 2048)
542 root 1.56 POSTCALL:
543     Mix_HookMusicFinished (music_finished);
544 root 1.71 Mix_ChannelFinished (channel_finished);
545 root 1.52
546     void
547     Mix_CloseAudio ()
548    
549     int
550     Mix_AllocateChannels (int numchans = -1)
551    
552 root 1.10 void
553     lowdelay (int fd, int val = 1)
554     CODE:
555 root 1.48 #ifndef _WIN32
556 root 1.10 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
557 root 1.48 #endif
558 root 1.10
559 root 1.3 char *
560 root 1.4 gl_version ()
561     CODE:
562 root 1.5 RETVAL = (char *)glGetString (GL_VERSION);
563 root 1.4 OUTPUT:
564     RETVAL
565    
566     char *
567 root 1.3 gl_extensions ()
568     CODE:
569 root 1.5 RETVAL = (char *)glGetString (GL_EXTENSIONS);
570 root 1.3 OUTPUT:
571     RETVAL
572    
573 root 1.5 void
574 root 1.13 add_font (char *file)
575     CODE:
576     FcConfigAppFontAddFile (0, (const FcChar8 *)file); /* no idea wether this is required */
577 root 1.79 #ifdef _WIN32
578     // cairo... sigh... requires win2000
579     AddFontResourceEx (file, FR_PRIVATE, 0);
580     #endif
581 root 1.13
582     void
583 root 1.23 load_image_inline (SV *image_)
584     ALIAS:
585     load_image_file = 1
586     PPCODE:
587     {
588     STRLEN image_len;
589     char *image = (char *)SvPVbyte (image_, image_len);
590     SDL_Surface *surface, *surface2;
591     SDL_PixelFormat fmt;
592     SDL_RWops *rw = ix
593     ? SDL_RWFromFile (image, "r")
594     : SDL_RWFromConstMem (image, image_len);
595    
596     if (!rw)
597 root 1.41 croak ("load_image: %s", SDL_GetError ());
598 root 1.23
599     surface = IMG_Load_RW (rw, 1);
600     if (!surface)
601 root 1.41 croak ("load_image: %s", SDL_GetError ());
602 root 1.23
603     fmt.palette = NULL;
604     fmt.BitsPerPixel = 32;
605     fmt.BytesPerPixel = 4;
606 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
607 root 1.23 fmt.Rmask = 0x000000ff;
608     fmt.Gmask = 0x0000ff00;
609     fmt.Bmask = 0x00ff0000;
610     fmt.Amask = 0xff000000;
611 root 1.49 #else
612     fmt.Rmask = 0xff000000;
613     fmt.Gmask = 0x00ff0000;
614     fmt.Bmask = 0x0000ff00;
615     fmt.Amask = 0x000000ff;
616     #endif
617 root 1.23 fmt.Rloss = 0;
618     fmt.Gloss = 0;
619     fmt.Bloss = 0;
620     fmt.Aloss = 0;
621     fmt.Rshift = 0;
622     fmt.Gshift = 8;
623     fmt.Bshift = 16;
624     fmt.Ashift = 24;
625     fmt.colorkey = 0;
626     fmt.alpha = 0;
627    
628     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
629    
630 root 1.39 assert (surface2->pitch == surface2->w * 4);
631    
632 root 1.23 EXTEND (SP, 5);
633     PUSHs (sv_2mortal (newSViv (surface2->w)));
634     PUSHs (sv_2mortal (newSViv (surface2->h)));
635     SDL_LockSurface (surface2);
636     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
637     SDL_UnlockSurface (surface2);
638 root 1.24 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
639 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
640 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
641 root 1.23
642     SDL_FreeSurface (surface);
643     SDL_FreeSurface (surface2);
644     }
645    
646 root 1.25 void
647 root 1.39 average (int x, int y, uint32_t *data)
648     PPCODE:
649     {
650     uint32_t r = 0, g = 0, b = 0, a = 0;
651    
652     x = y = x * y;
653    
654     while (x--)
655     {
656     uint32_t p = *data++;
657    
658     r += (p ) & 255;
659     g += (p >> 8) & 255;
660     b += (p >> 16) & 255;
661     a += (p >> 24) & 255;
662     }
663    
664     EXTEND (SP, 4);
665 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
666     PUSHs (sv_2mortal (newSViv (g / y)));
667     PUSHs (sv_2mortal (newSViv (b / y)));
668     PUSHs (sv_2mortal (newSViv (a / y)));
669 root 1.39 }
670    
671     void
672 root 1.66 error (char *message)
673     CODE:
674     #ifdef _WIN32
675     MessageBox (0, message, "Crossfire+ Error", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
676     #else
677     fprintf (stderr, "ERROR: %s\n", message);
678     #endif
679    
680     void
681 root 1.25 fatal (char *message)
682     CODE:
683 root 1.50 #ifdef _WIN32
684 root 1.25 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
685     #else
686 root 1.40 fprintf (stderr, "FATAL: %s\n", message);
687 root 1.25 #endif
688     exit (1);
689    
690 root 1.61 MODULE = CFClient PACKAGE = CFClient::Font
691    
692     CFClient::Font
693 root 1.70 new_from_file (SV *class, char *path, int id = 0)
694 root 1.61 CODE:
695     {
696     int count;
697 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
698 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
699     FcPatternDestroy (pattern);
700     }
701     OUTPUT:
702     RETVAL
703    
704     void
705     DESTROY (CFClient::Font self)
706     CODE:
707     pango_font_description_free (self);
708    
709     void
710     make_default (CFClient::Font self)
711     CODE:
712     default_font = self;
713    
714 root 1.15 MODULE = CFClient PACKAGE = CFClient::Layout
715 root 1.14
716 root 1.15 CFClient::Layout
717 root 1.76 new (SV *class, int rgba = 0)
718 root 1.14 CODE:
719     New (0, RETVAL, 1, struct cf_layout);
720 root 1.76
721     RETVAL->pl = pango_layout_new (rgba ? cairo_context : ft2_context);
722     RETVAL->rgba = rgba;
723     RETVAL->r = 1.;
724     RETVAL->g = 1.;
725     RETVAL->b = 1.;
726     RETVAL->a = 1.;
727     RETVAL->base_height = MIN_FONT_HEIGHT;
728     RETVAL->font = 0;
729    
730 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
731 root 1.76 layout_update_font (RETVAL);
732 root 1.14 OUTPUT:
733     RETVAL
734    
735     void
736 root 1.15 DESTROY (CFClient::Layout self)
737 root 1.14 CODE:
738     g_object_unref (self->pl);
739     Safefree (self);
740 root 1.13
741 root 1.76 int
742     is_rgba (CFClient::Layout self)
743     CODE:
744     RETVAL = self->rgba;
745     OUTPUT:
746     RETVAL
747    
748 root 1.8 void
749 root 1.35 set_text (CFClient::Layout self, SV *text_)
750     CODE:
751     {
752     STRLEN textlen;
753     char *text = SvPVutf8 (text_, textlen);
754    
755     pango_layout_set_text (self->pl, text, textlen);
756     }
757    
758     void
759 root 1.15 set_markup (CFClient::Layout self, SV *text_)
760 root 1.14 CODE:
761 root 1.5 {
762     STRLEN textlen;
763     char *text = SvPVutf8 (text_, textlen);
764 root 1.14
765     pango_layout_set_markup (self->pl, text, textlen);
766     }
767    
768 root 1.46 SV *
769     get_text (CFClient::Layout self)
770     CODE:
771 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
772 root 1.46 SvUTF8_on (RETVAL);
773     OUTPUT:
774     RETVAL
775    
776 root 1.14 void
777 root 1.76 set_foreground (CFClient::Layout self, float r, float g, float b, float a = 1.)
778     CODE:
779     self->r = r;
780     self->g = g;
781     self->b = b;
782     self->a = a;
783    
784     void
785 root 1.61 set_font (CFClient::Layout self, CFClient::Font font = 0)
786     CODE:
787     if (self->font != font)
788     {
789     self->font = font;
790     layout_update_font (self);
791     }
792    
793     void
794 root 1.16 set_height (CFClient::Layout self, int base_height)
795     CODE:
796 root 1.61 if (self->base_height != base_height)
797     {
798     self->base_height = base_height;
799     layout_update_font (self);
800     }
801 root 1.16
802     void
803 root 1.15 set_width (CFClient::Layout self, int max_width = -1)
804 root 1.14 CODE:
805     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
806    
807     void
808 root 1.15 size (CFClient::Layout self)
809 root 1.14 PPCODE:
810     {
811     int w, h;
812    
813     layout_get_pixel_size (self, &w, &h);
814    
815     EXTEND (SP, 2);
816     PUSHs (sv_2mortal (newSViv (w)));
817     PUSHs (sv_2mortal (newSViv (h)));
818     }
819    
820 root 1.17 int
821     xy_to_index (CFClient::Layout self, int x, int y)
822     CODE:
823     {
824     int index, trailing;
825     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
826     RETVAL = index;
827     }
828     OUTPUT:
829     RETVAL
830    
831     void
832     cursor_pos (CFClient::Layout self, int index)
833     PPCODE:
834     {
835     PangoRectangle strong_pos;
836     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
837 root 1.30
838 root 1.17 EXTEND (SP, 3);
839     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
840     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
841     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
842     }
843    
844 root 1.14 void
845 root 1.15 render (CFClient::Layout self)
846 root 1.14 PPCODE:
847     {
848 root 1.5 SV *retval;
849     int w, h;
850    
851 root 1.14 layout_get_pixel_size (self, &w, &h);
852 root 1.5
853 root 1.76 if (self->rgba)
854     {
855     cairo_surface_t *surface;
856     cairo_t *cairo;
857    
858     retval = newSV (w * h * 4);
859     SvPOK_only (retval);
860     SvCUR_set (retval, w * h * 4);
861    
862     memset (SvPVX (retval), 0, w * h * 4);
863    
864     surface = cairo_image_surface_create_for_data (
865     (void*)SvPVX (retval), CAIRO_FORMAT_ARGB32, w, h, w * 4);
866     cairo = cairo_create (surface);
867     cairo_set_source_rgba (cairo, self->r, self->g, self->b, self->a);
868    
869     pango_cairo_show_layout (cairo, self->pl);
870    
871     cairo_destroy (cairo);
872     cairo_surface_destroy (surface);
873    
874     // what a mess, and its premultiplied, too :(
875     {
876     uint32_t *p = (uint32_t *)SvPVX (retval);
877     uint32_t *e = p + w * h;
878 root 1.5
879 root 1.76 while (p < e)
880     {
881     uint32_t rgba = *p;
882     rgba = (rgba >> 24) | (rgba << 8);
883     rgba = SDL_SwapBE32 (rgba);
884     *p++ = rgba;
885     }
886     }
887    
888     EXTEND (SP, 5);
889     PUSHs (sv_2mortal (newSViv (w)));
890     PUSHs (sv_2mortal (newSViv (h)));
891     PUSHs (sv_2mortal (retval));
892     PUSHs (sv_2mortal (newSViv (GL_RGBA)));
893     PUSHs (sv_2mortal (newSViv (GL_RGBA)));
894     }
895     else
896     {
897     FT_Bitmap bitmap;
898    
899     retval = newSV (w * h);
900     SvPOK_only (retval);
901     SvCUR_set (retval, w * h);
902    
903     bitmap.rows = h;
904     bitmap.width = w;
905     bitmap.pitch = w;
906     bitmap.buffer = (unsigned char*)SvPVX (retval);
907     bitmap.num_grays = 256;
908     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
909    
910     memset (bitmap.buffer, 0, w * h);
911    
912     pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
913 root 1.1
914 root 1.76 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_ALPHA)));
919     PUSHs (sv_2mortal (newSViv (GL_ALPHA)));
920     }
921 root 1.5 }
922 root 1.11
923 root 1.15 MODULE = CFClient PACKAGE = CFClient::Texture
924 root 1.11
925     void
926 root 1.37 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
927 root 1.12 PROTOTYPE: $$$;$$
928 root 1.76 ALIAS:
929     draw_quad_alpha = 1
930     draw_quad_alpha_premultiplied = 2
931 root 1.11 CODE:
932     {
933 root 1.12 HV *hv = (HV *)SvRV (self);
934 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
935     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
936 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
937 elmex 1.36 int wrap_mode = SvIV (*hv_fetch (hv, "wrap_mode", 9, 1));
938 root 1.12
939     if (items < 5)
940     {
941 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
942     h = SvNV (*hv_fetch (hv, "h", 1, 1));
943 root 1.12 }
944    
945 root 1.76 if (ix)
946     {
947     glEnable (GL_BLEND);
948     glBlendFunc (ix == 1 ? GL_SRC_ALPHA : GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
949     }
950    
951 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
952 root 1.76
953     if (wrap_mode)
954     {
955     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
956     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
957     }
958    
959 root 1.12 glBegin (GL_QUADS);
960 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
961     glTexCoord2f (0, t); glVertex2f (x , y + h);
962     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
963     glTexCoord2f (s, 0); glVertex2f (x + w, y );
964 root 1.12 glEnd ();
965 root 1.76
966     if (ix)
967     glDisable (GL_BLEND);
968 root 1.11 }
969 root 1.28
970     MODULE = CFClient PACKAGE = CFClient::Map
971    
972     CFClient::Map
973     new (SV *class, int map_width, int map_height)
974     CODE:
975     New (0, RETVAL, 1, struct map);
976 root 1.42 RETVAL->x = 0;
977     RETVAL->y = 0;
978     RETVAL->w = map_width;
979     RETVAL->h = map_height;
980     RETVAL->ox = 0;
981     RETVAL->oy = 0;
982 root 1.30 RETVAL->faces = 8192;
983     Newz (0, RETVAL->face, RETVAL->faces, mapface);
984 root 1.42 RETVAL->texs = 8192;
985     Newz (0, RETVAL->tex, RETVAL->texs, maptex);
986 root 1.28 RETVAL->rows = 0;
987     RETVAL->row = 0;
988     OUTPUT:
989     RETVAL
990    
991     void
992     DESTROY (CFClient::Map self)
993     CODE:
994     {
995 root 1.30 map_clear (self);
996 root 1.28 Safefree (self->face);
997 root 1.29 Safefree (self);
998     }
999    
1000     void
1001 root 1.30 clear (CFClient::Map self)
1002     CODE:
1003     map_clear (self);
1004    
1005     void
1006 root 1.42 set_face (CFClient::Map self, int face, int texid)
1007 root 1.29 CODE:
1008     {
1009 root 1.42 while (self->faces <= face)
1010 root 1.28 {
1011 root 1.30 Append (mapface, self->face, self->faces, self->faces);
1012 root 1.29 self->faces *= 2;
1013     }
1014 root 1.28
1015 root 1.42 self->face [face] = texid;
1016     }
1017    
1018     void
1019     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)
1020     CODE:
1021     {
1022     while (self->texs <= texid)
1023     {
1024     Append (maptex, self->tex, self->texs, self->texs);
1025     self->texs *= 2;
1026     }
1027    
1028 root 1.48 {
1029     maptex *tex = self->tex + texid;
1030 root 1.39
1031 root 1.48 tex->name = name;
1032     tex->w = w;
1033     tex->h = h;
1034     tex->s = s;
1035     tex->t = t;
1036     tex->r = r;
1037     tex->g = g;
1038     tex->b = b;
1039     tex->a = a;
1040     }
1041 root 1.29 }
1042    
1043 root 1.42 int
1044     ox (CFClient::Map self)
1045     ALIAS:
1046     oy = 1
1047     CODE:
1048     switch (ix)
1049     {
1050     case 0: RETVAL = self->ox; break;
1051     case 1: RETVAL = self->oy; break;
1052     }
1053     OUTPUT:
1054     RETVAL
1055    
1056 root 1.29 void
1057 root 1.43 scroll (CFClient::Map self, int dx, int dy)
1058     CODE:
1059     {
1060 root 1.44 if (dx > 0)
1061     map_blank (self, self->x, self->y, dx - 1, self->h);
1062     else if (dx < 0)
1063     map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
1064    
1065     if (dy > 0)
1066     map_blank (self, self->x, self->y, self->w, dy - 1);
1067     else if (dy < 0)
1068     map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
1069 root 1.43
1070 root 1.44 self->ox += dx; self->x += dx;
1071     self->oy += dy; self->y += dy;
1072 root 1.43
1073     while (self->y < 0)
1074     {
1075     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1076    
1077     self->rows += MAP_EXTEND_Y;
1078     self->y += MAP_EXTEND_Y;
1079     }
1080 root 1.44 }
1081 root 1.43
1082 root 1.44 void
1083     map1a_update (CFClient::Map self, SV *data_)
1084     CODE:
1085     {
1086 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1087     uint8_t *data_end = (uint8_t *)SvEND (data_);
1088 root 1.48 mapcell *cell;
1089     int x, y, flags;
1090 root 1.43
1091 root 1.29 while (data < data_end)
1092     {
1093 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1094 root 1.30
1095 root 1.48 x = ((flags >> 10) & 63) + self->x;
1096     y = ((flags >> 4) & 63) + self->y;
1097 root 1.29
1098 root 1.48 cell = map_get_cell (self, x, y);
1099 root 1.29
1100     if (flags & 15)
1101     {
1102 root 1.45 if (cell->darkness < 0)
1103 root 1.29 {
1104     cell->darkness = 0;
1105     cell->face [0] = 0;
1106     cell->face [1] = 0;
1107     cell->face [2] = 0;
1108     }
1109 root 1.45
1110 root 1.29 cell->darkness = flags & 8 ? *data++ : 255;
1111    
1112 root 1.42 //TODO: don't trust server data to be in-range(!)
1113    
1114 root 1.29 if (flags & 4)
1115     {
1116 root 1.42 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
1117 root 1.29 }
1118    
1119     if (flags & 2)
1120     {
1121 root 1.42 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
1122 root 1.29 }
1123    
1124     if (flags & 1)
1125     {
1126 root 1.42 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
1127 root 1.29 }
1128     }
1129     else
1130 root 1.31 cell->darkness = -1;
1131 root 1.29 }
1132 root 1.28 }
1133    
1134 root 1.40 SV *
1135 root 1.55 mapmap (CFClient::Map self, int x0, int y0, int w, int h)
1136 root 1.40 CODE:
1137     {
1138 root 1.55 int x1, x;
1139     int y1, y;
1140 root 1.40 int z;
1141     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1142     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1143    
1144     SvPOK_only (map_sv);
1145     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1146    
1147 root 1.55 x0 += self->x; x1 = x0 + w;
1148     y0 += self->y; y1 = y0 + h;
1149 root 1.40
1150     for (y = y0; y < y1; y++)
1151     {
1152     maprow *row = 0 <= y && y < self->rows
1153     ? self->row + y
1154     : 0;
1155    
1156     for (x = x0; x < x1; x++)
1157     {
1158     int r = 32, g = 32, b = 32, a = 192;
1159    
1160     if (row && row->c0 <= x && x < row->c1)
1161     {
1162     mapcell *cell = row->col + (x - row->c0);
1163    
1164     for (z = 0; z <= 0; z++)
1165     {
1166 root 1.42 mapface face = cell->face [z];
1167 root 1.40
1168     if (face)
1169     {
1170 root 1.42 maptex tex = self->tex [face];
1171 root 1.40 int a0 = 255 - tex.a;
1172     int a1 = tex.a;
1173    
1174     r = (r * a0 + tex.r * a1) / 255;
1175     g = (g * a0 + tex.g * a1) / 255;
1176     b = (b * a0 + tex.b * a1) / 255;
1177     a = (a * a0 + tex.a * a1) / 255;
1178     }
1179     }
1180     }
1181    
1182     *map++ = (r )
1183     | (g << 8)
1184     | (b << 16)
1185     | (a << 24);
1186     }
1187     }
1188    
1189     RETVAL = map_sv;
1190     }
1191     OUTPUT:
1192     RETVAL
1193    
1194 root 1.30 void
1195 root 1.38 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
1196 root 1.32 PPCODE:
1197 root 1.30 {
1198 root 1.48 int vx, vy;
1199     int x, y, z;
1200     int last_name;
1201     mapface face;
1202 root 1.32 int sw4 = (sw + 3) & ~3;
1203     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
1204 root 1.35 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
1205 root 1.48
1206 root 1.42 memset (darkness, 255, sw4 * sh);
1207 root 1.32 SvPOK_only (darkness_sv);
1208     SvCUR_set (darkness_sv, sw4 * sh);
1209    
1210 root 1.48 vx = self->x + (self->w - sw) / 2 - shift_x;
1211     vy = self->y + (self->h - sh) / 2 - shift_y;
1212 root 1.38
1213 root 1.42 /*
1214     int vx = self->vx = self->w >= sw
1215     ? self->x + (self->w - sw) / 2
1216     : MIN (self->x, MAX (self->x + self->w - sw + 1, self->vx));
1217    
1218     int vy = self->vy = self->h >= sh
1219     ? self->y + (self->h - sh) / 2
1220     : MIN (self->y, MAX (self->y + self->h - sh + 1, self->vy));
1221     */
1222 root 1.30
1223     glColor4ub (255, 255, 255, 255);
1224    
1225     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1226     glEnable (GL_BLEND);
1227     glEnable (GL_TEXTURE_2D);
1228     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1229    
1230 root 1.48 glBegin (GL_QUADS);
1231 root 1.30
1232 root 1.48 last_name = 0;
1233 root 1.30
1234     for (z = 0; z < 3; z++)
1235     for (y = 0; y < sh; y++)
1236     if (0 <= y + vy && y + vy < self->rows)
1237     {
1238     maprow *row = self->row + (y + vy);
1239    
1240     for (x = 0; x < sw; x++)
1241     if (row->c0 <= x + vx && x + vx < row->c1)
1242     {
1243     mapcell *cell = row->col + (x + vx - row->c0);
1244 root 1.32
1245     darkness[y * sw4 + x] = cell->darkness < 0
1246 root 1.33 ? 255 - FOW_DARKNESS
1247 root 1.32 : 255 - cell->darkness;
1248    
1249 root 1.48 face = cell->face [z];
1250 root 1.30
1251     if (face)
1252     {
1253 root 1.42 maptex tex = self->tex [face];
1254 root 1.30
1255     int px = (x + 1) * 32 - tex.w;
1256     int py = (y + 1) * 32 - tex.h;
1257    
1258     if (last_name != tex.name)
1259     {
1260     glEnd ();
1261     last_name = tex.name;
1262     glBindTexture (GL_TEXTURE_2D, last_name);
1263     glBegin (GL_QUADS);
1264     }
1265    
1266     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1267     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1268     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1269     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1270     }
1271     }
1272     }
1273    
1274     glEnd ();
1275 root 1.32
1276 root 1.34 glDisable (GL_TEXTURE_2D);
1277     glDisable (GL_BLEND);
1278    
1279 root 1.32 EXTEND (SP, 3);
1280     PUSHs (sv_2mortal (newSViv (sw4)));
1281     PUSHs (sv_2mortal (newSViv (sh)));
1282     PUSHs (darkness_sv);
1283 root 1.30 }
1284    
1285 root 1.42 SV *
1286     get_rect (CFClient::Map self, int x0, int y0, int w, int h)
1287     CODE:
1288     {
1289     int x, y, x1, y1;
1290     SV *data_sv = newSV (w * h * 7 + 5);
1291     uint8_t *data = (uint8_t *)SvPVX (data_sv);
1292    
1293     *data++ = 0; /* version 0 format */
1294     *data++ = w >> 8; *data++ = w;
1295     *data++ = h >> 8; *data++ = h;
1296    
1297     // we need to do this 'cause we don't keep an absolute coord system for rows
1298 root 1.55 // TODO: treat rows as we treat columns
1299 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1300     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1301    
1302     x0 += self->x - self->ox;
1303     y0 += self->y - self->oy;
1304    
1305     x1 = x0 + w;
1306     y1 = y0 + h;
1307    
1308     for (y = y0; y < y1; y++)
1309     {
1310     maprow *row = 0 <= y && y < self->rows
1311     ? self->row + y
1312     : 0;
1313    
1314     for (x = x0; x < x1; x++)
1315     {
1316     if (row && row->c0 <= x && x < row->c1)
1317     {
1318     mapcell *cell = row->col + (x - row->c0);
1319     uint8_t flags = 0;
1320    
1321     if (cell->face [0]) flags |= 1;
1322     if (cell->face [1]) flags |= 2;
1323     if (cell->face [2]) flags |= 4;
1324    
1325     *data++ = flags;
1326    
1327     if (flags & 1)
1328     {
1329     *data++ = cell->face [0] >> 8;
1330     *data++ = cell->face [0];
1331     }
1332    
1333     if (flags & 2)
1334     {
1335     *data++ = cell->face [1] >> 8;
1336     *data++ = cell->face [1];
1337     }
1338    
1339     if (flags & 4)
1340     {
1341     *data++ = cell->face [2] >> 8;
1342     *data++ = cell->face [2];
1343     }
1344     }
1345     else
1346     *data++ = 0;
1347     }
1348     }
1349    
1350     SvPOK_only (data_sv);
1351     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
1352     RETVAL = data_sv;
1353     }
1354     OUTPUT:
1355     RETVAL
1356    
1357     void
1358     set_rect (CFClient::Map self, int x0, int y0, uint8_t *data)
1359     PPCODE:
1360     {
1361     int x, y, z;
1362 root 1.48 int w, h;
1363 root 1.42 int x1, y1;
1364    
1365     if (*data++ != 0)
1366     return; /* version mismatch */
1367    
1368 root 1.48 w = *data++ << 8; w |= *data++;
1369     h = *data++ << 8; h |= *data++;
1370 root 1.42
1371     // we need to do this 'cause we don't keep an absolute coord system for rows
1372 root 1.55 // TODO: treat rows as we treat columns
1373 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1374     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1375    
1376     x0 += self->x - self->ox;
1377     y0 += self->y - self->oy;
1378    
1379     x1 = x0 + w;
1380     y1 = y0 + h;
1381    
1382     for (y = y0; y < y1; y++)
1383     {
1384     maprow *row = map_get_row (self, y);
1385    
1386     for (x = x0; x < x1; x++)
1387     {
1388     uint8_t flags = *data++;
1389    
1390     if (flags)
1391     {
1392     mapface face[3] = { 0, 0, 0 };
1393    
1394     mapcell *cell = row_get_cell (row, x);
1395    
1396     if (flags & 1) { face[0] = *data++ << 8; face[0] |= *data++; }
1397     if (flags & 2) { face[1] = *data++ << 8; face[1] |= *data++; }
1398     if (flags & 4) { face[2] = *data++ << 8; face[2] |= *data++; }
1399    
1400     if (cell->darkness <= 0)
1401     {
1402     cell->darkness = -1;
1403    
1404     for (z = 0; z <= 2; z++)
1405     {
1406     cell->face[z] = face[z];
1407    
1408     if (face[z] && (face[z] >= self->texs || !self->tex[face [z]].name))
1409     XPUSHs (sv_2mortal (newSViv (face[z])));
1410     }
1411     }
1412     }
1413     }
1414     }
1415     }
1416    
1417 root 1.52 MODULE = CFClient PACKAGE = CFClient::MixChunk
1418    
1419     CFClient::MixChunk
1420     new_from_file (SV *class, char *path)
1421     CODE:
1422     RETVAL = Mix_LoadWAV (path);
1423     OUTPUT:
1424     RETVAL
1425    
1426     void
1427     DESTROY (CFClient::MixChunk self)
1428     CODE:
1429     Mix_FreeChunk (self);
1430    
1431     int
1432     volume (CFClient::MixChunk self, int volume = -1)
1433     CODE:
1434     RETVAL = Mix_VolumeChunk (self, volume);
1435     OUTPUT:
1436     RETVAL
1437    
1438     int
1439     play (CFClient::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
1440     CODE:
1441     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
1442     OUTPUT:
1443     RETVAL
1444    
1445     MODULE = CFClient PACKAGE = CFClient::MixMusic
1446    
1447     int
1448     volume (int volume = -1)
1449     CODE:
1450     RETVAL = Mix_VolumeMusic (volume);
1451     OUTPUT:
1452     RETVAL
1453    
1454     CFClient::MixMusic
1455     new_from_file (SV *class, char *path)
1456     CODE:
1457     RETVAL = Mix_LoadMUS (path);
1458     OUTPUT:
1459     RETVAL
1460    
1461     void
1462     DESTROY (CFClient::MixMusic self)
1463     CODE:
1464     Mix_FreeMusic (self);
1465    
1466     int
1467     play (CFClient::MixMusic self, int loops = -1)
1468     CODE:
1469     RETVAL = Mix_PlayMusic (self, loops);
1470     OUTPUT:
1471     RETVAL
1472    
1473 root 1.54 MODULE = CFClient PACKAGE = CFClient::OpenGL
1474    
1475     BOOT:
1476     {
1477     HV *stash = gv_stashpv ("CFClient::OpenGL", 1);
1478     static const struct {
1479     const char *name;
1480     IV iv;
1481     } *civ, const_iv[] = {
1482     # define const_iv(name) { # name, (IV)name }
1483     const_iv (GL_COLOR_MATERIAL),
1484     const_iv (GL_SMOOTH),
1485     const_iv (GL_FLAT),
1486 root 1.69 const_iv (GL_DITHER),
1487 root 1.54 const_iv (GL_BLEND),
1488 root 1.69 const_iv (GL_SCISSOR_TEST),
1489 root 1.54 const_iv (GL_AND),
1490 root 1.67 const_iv (GL_ONE),
1491     const_iv (GL_ZERO),
1492 root 1.54 const_iv (GL_SRC_ALPHA),
1493 root 1.67 const_iv (GL_SRC_ALPHA_SATURATE),
1494 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
1495 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
1496 root 1.54 const_iv (GL_RGB),
1497     const_iv (GL_RGBA),
1498     const_iv (GL_UNSIGNED_BYTE),
1499     const_iv (GL_ALPHA),
1500 root 1.76 const_iv (GL_LUMINANCE),
1501 root 1.54 const_iv (GL_FLOAT),
1502     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
1503     const_iv (GL_COMPILE),
1504     const_iv (GL_TEXTURE_1D),
1505     const_iv (GL_TEXTURE_2D),
1506     const_iv (GL_TEXTURE_ENV),
1507     const_iv (GL_TEXTURE_MAG_FILTER),
1508     const_iv (GL_TEXTURE_MIN_FILTER),
1509     const_iv (GL_TEXTURE_ENV_MODE),
1510     const_iv (GL_TEXTURE_WRAP_S),
1511     const_iv (GL_TEXTURE_WRAP_T),
1512     const_iv (GL_CLAMP),
1513     const_iv (GL_REPEAT),
1514     const_iv (GL_NEAREST),
1515     const_iv (GL_LINEAR),
1516 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
1517     const_iv (GL_LINEAR_MIPMAP_NEAREST),
1518     const_iv (GL_NEAREST_MIPMAP_LINEAR),
1519     const_iv (GL_LINEAR_MIPMAP_LINEAR),
1520     const_iv (GL_GENERATE_MIPMAP),
1521 root 1.54 const_iv (GL_MODULATE),
1522 root 1.69 const_iv (GL_DECAL),
1523 root 1.54 const_iv (GL_REPLACE),
1524     const_iv (GL_COLOR_BUFFER_BIT),
1525     const_iv (GL_PROJECTION),
1526     const_iv (GL_MODELVIEW),
1527     const_iv (GL_COLOR_LOGIC_OP),
1528 root 1.69 const_iv (GL_SEPARABLE_2D),
1529 root 1.54 const_iv (GL_CONVOLUTION_2D),
1530     const_iv (GL_CONVOLUTION_BORDER_MODE),
1531     const_iv (GL_CONSTANT_BORDER),
1532     const_iv (GL_LINES),
1533     const_iv (GL_QUADS),
1534 root 1.55 const_iv (GL_LINE_LOOP),
1535 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
1536     const_iv (GL_FASTEST),
1537     # undef const_iv
1538     };
1539    
1540     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
1541     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
1542     }
1543    
1544     int glGetError ()
1545    
1546     void glClear (int mask)
1547    
1548     void glClearColor (float r, float g, float b, float a = 1.0)
1549     PROTOTYPE: @
1550    
1551     void glEnable (int cap)
1552    
1553     void glDisable (int cap)
1554    
1555     void glShadeModel (int mode)
1556    
1557     void glHint (int target, int mode)
1558    
1559     void glBlendFunc (int sfactor, int dfactor)
1560    
1561     void glLogicOp (int opcode)
1562    
1563 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
1564    
1565 root 1.54 void glMatrixMode (int mode)
1566    
1567     void glPushMatrix ()
1568    
1569     void glPopMatrix ()
1570    
1571     void glLoadIdentity ()
1572    
1573 root 1.64 # near and far are due to microsofts buggy c compiler
1574     void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
1575 root 1.54
1576     void glViewport (int x, int y, int width, int height)
1577    
1578 root 1.69 void glScissor (int x, int y, int width, int height)
1579    
1580 root 1.54 void glTranslate (float x, float y, float z = 0.)
1581     CODE:
1582     glTranslatef (x, y, z);
1583    
1584 root 1.62 void glScale (float x, float y, float z = 1.)
1585 root 1.54 CODE:
1586     glScalef (x, y, z);
1587    
1588     void glRotate (float angle, float x, float y, float z)
1589     CODE:
1590     glRotatef (angle, x, y, z);
1591    
1592     void glBegin (int mode)
1593    
1594     void glEnd ()
1595    
1596     void glColor (float r, float g, float b, float a = 1.0)
1597     PROTOTYPE: @
1598     CODE:
1599 root 1.81 glColor4ub (MIN ((int)(r * 255.f), 255),
1600     MIN ((int)(g * 255.f), 255),
1601     MIN ((int)(b * 255.f), 255),
1602     MIN ((int)(a * 255.f), 255));
1603 root 1.54
1604     void glVertex (float x, float y, float z = 0.)
1605     CODE:
1606     glVertex3f (x, y, z);
1607    
1608     void glTexCoord (float s, float t)
1609     CODE:
1610     glTexCoord2f (s, t);
1611    
1612     void glTexEnv (int target, int pname, float param)
1613     CODE:
1614     glTexEnvf (target, pname, param);
1615    
1616     void glTexParameter (int target, int pname, float param)
1617     CODE:
1618     glTexParameterf (target, pname, param);
1619    
1620     void glBindTexture (int target, int name)
1621    
1622     void glConvolutionParameter (int target, int pname, float params)
1623     CODE:
1624 root 1.64 GL_CALL (PFNGLCONVOLUTIONPARAMETERFEXTPROC, glConvolutionParameterf, (target, pname, params));
1625 root 1.54
1626     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
1627 root 1.64 CODE:
1628     GL_CALL (PFNGLCONVOLUTIONFILTER2DEXTPROC, glConvolutionFilter2D,
1629     (target, internalformat, width, height, format, type, data));
1630 root 1.54
1631 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
1632     CODE:
1633     GL_CALL (PFNGLSEPARABLEFILTER2DEXTPROC, glSeparableFilter2D,
1634     (target, internalformat, width, height, format, type, row, column));
1635    
1636 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
1637    
1638     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
1639    
1640 root 1.68 void glRasterPos (int x, int y)
1641     CODE:
1642     glRasterPos2i (x, y);
1643    
1644     void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
1645    
1646 root 1.54 int glGenTexture ()
1647     CODE:
1648     {
1649     GLuint name;
1650     glGenTextures (1, &name);
1651     RETVAL = name;
1652     }
1653     OUTPUT:
1654     RETVAL
1655    
1656     void glDeleteTexture (int name)
1657     CODE:
1658     {
1659     GLuint name_ = name;
1660     glDeleteTextures (1, &name_);
1661     }
1662    
1663     int glGenList ()
1664     CODE:
1665     RETVAL = glGenLists (1);
1666     OUTPUT:
1667     RETVAL
1668    
1669     void glDeleteList (int list)
1670     CODE:
1671     glDeleteLists (list, 1);
1672    
1673     void glNewList (int list, int mode = GL_COMPILE)
1674    
1675     void glEndList ()
1676    
1677     void glCallList (int list)
1678