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