ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.105
Committed: Mon Jun 5 03:33:09 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.104: +17 -10 lines
Log Message:
tinkered with cairo some more

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