ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.109
Committed: Wed Jun 7 23:29:13 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.108: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

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