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