ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.106
Committed: Mon Jun 5 03:48:49 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.105: +9 -6 lines
Log Message:
switch off cairo antialiasing on win32, its unbearable otherwise. re-enable pangofc, which was disabled by accident

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