ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.87
Committed: Fri May 19 18:39:06 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.86: +15 -0 lines
Log Message:
misc win32 workarounds

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.86 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 16);
447 root 1.51
448 root 1.86 SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 64);
449 root 1.85 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 0);
450    
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     int
476     SDL_SetVideoMode (int w, int h, int fullscreen)
477     CODE:
478     RETVAL = !!SDL_SetVideoMode (
479     w, h, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)
480     );
481     SDL_WM_SetCaption ("Crossfire+ Client " VERSION, "Crossfire+");
482     OUTPUT:
483     RETVAL
484    
485 root 1.53 void
486 root 1.54 SDL_GL_SwapBuffers ()
487    
488     void
489 root 1.53 SDL_PollEvent ()
490     PPCODE:
491     {
492     SDL_Event ev;
493    
494     while (SDL_PollEvent (&ev))
495     {
496     HV *hv = newHV ();
497     hv_store (hv, "type", 4, newSViv (ev.type), 0);
498 root 1.70
499 root 1.53 switch (ev.type)
500     {
501     case SDL_KEYDOWN:
502     case SDL_KEYUP:
503     hv_store (hv, "state", 5, newSViv (ev.key.state), 0);
504     hv_store (hv, "sym", 3, newSViv (ev.key.keysym.sym), 0);
505     hv_store (hv, "mod", 3, newSViv (ev.key.keysym.mod), 0);
506     hv_store (hv, "unicode", 7, newSViv (ev.key.keysym.unicode), 0);
507     break;
508    
509     case SDL_ACTIVEEVENT:
510     hv_store (hv, "gain", 4, newSViv (ev.active.gain), 0);
511     hv_store (hv, "state", 5, newSViv (ev.active.state), 0);
512     break;
513    
514     case SDL_MOUSEMOTION:
515     hv_store (hv, "state", 5, newSViv (ev.motion.state), 0);
516     hv_store (hv, "x", 1, newSViv (ev.motion.x), 0);
517     hv_store (hv, "y", 1, newSViv (ev.motion.y), 0);
518     hv_store (hv, "xrel", 4, newSViv (ev.motion.xrel), 0);
519     hv_store (hv, "yrel", 4, newSViv (ev.motion.yrel), 0);
520     break;
521    
522     case SDL_MOUSEBUTTONDOWN:
523     case SDL_MOUSEBUTTONUP:
524     hv_store (hv, "button", 6, newSViv (ev.button.button), 0);
525     hv_store (hv, "state", 5, newSViv (ev.button.state), 0);
526     hv_store (hv, "x", 1, newSViv (ev.button.x), 0);
527     hv_store (hv, "y", 1, newSViv (ev.button.y), 0);
528 root 1.70 break;
529 root 1.72
530     case SDL_USEREVENT:
531     hv_store (hv, "code", 4, newSViv (ev.user.code), 0);
532     hv_store (hv, "data1", 5, newSViv ((IV)ev.user.data1), 0);
533     hv_store (hv, "data2", 5, newSViv ((IV)ev.user.data2), 0);
534     break;
535 root 1.53 }
536    
537     XPUSHs (sv_2mortal (newRV_noinc ((SV *)hv)));
538     }
539     }
540 root 1.52
541     int
542 root 1.73 Mix_OpenAudio (int frequency = 48000, int format = MIX_DEFAULT_FORMAT, int channels = 1, int chunksize = 2048)
543 root 1.56 POSTCALL:
544     Mix_HookMusicFinished (music_finished);
545 root 1.71 Mix_ChannelFinished (channel_finished);
546 root 1.52
547     void
548     Mix_CloseAudio ()
549    
550     int
551     Mix_AllocateChannels (int numchans = -1)
552    
553 root 1.10 void
554     lowdelay (int fd, int val = 1)
555     CODE:
556 root 1.48 #ifndef _WIN32
557 root 1.10 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
558 root 1.48 #endif
559 root 1.10
560 root 1.3 char *
561 root 1.4 gl_version ()
562     CODE:
563 root 1.5 RETVAL = (char *)glGetString (GL_VERSION);
564 root 1.4 OUTPUT:
565     RETVAL
566    
567     char *
568 root 1.3 gl_extensions ()
569     CODE:
570 root 1.5 RETVAL = (char *)glGetString (GL_EXTENSIONS);
571 root 1.3 OUTPUT:
572     RETVAL
573    
574 root 1.5 void
575 root 1.13 add_font (char *file)
576     CODE:
577     FcConfigAppFontAddFile (0, (const FcChar8 *)file); /* no idea wether this is required */
578 root 1.79 #ifdef _WIN32
579     // cairo... sigh... requires win2000
580     AddFontResourceEx (file, FR_PRIVATE, 0);
581     #endif
582 root 1.13
583     void
584 root 1.23 load_image_inline (SV *image_)
585     ALIAS:
586     load_image_file = 1
587     PPCODE:
588     {
589     STRLEN image_len;
590     char *image = (char *)SvPVbyte (image_, image_len);
591     SDL_Surface *surface, *surface2;
592     SDL_PixelFormat fmt;
593     SDL_RWops *rw = ix
594     ? SDL_RWFromFile (image, "r")
595     : SDL_RWFromConstMem (image, image_len);
596    
597     if (!rw)
598 root 1.41 croak ("load_image: %s", SDL_GetError ());
599 root 1.23
600     surface = IMG_Load_RW (rw, 1);
601     if (!surface)
602 root 1.41 croak ("load_image: %s", SDL_GetError ());
603 root 1.23
604     fmt.palette = NULL;
605     fmt.BitsPerPixel = 32;
606     fmt.BytesPerPixel = 4;
607 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
608 root 1.23 fmt.Rmask = 0x000000ff;
609     fmt.Gmask = 0x0000ff00;
610     fmt.Bmask = 0x00ff0000;
611     fmt.Amask = 0xff000000;
612 root 1.49 #else
613     fmt.Rmask = 0xff000000;
614     fmt.Gmask = 0x00ff0000;
615     fmt.Bmask = 0x0000ff00;
616     fmt.Amask = 0x000000ff;
617     #endif
618 root 1.23 fmt.Rloss = 0;
619     fmt.Gloss = 0;
620     fmt.Bloss = 0;
621     fmt.Aloss = 0;
622     fmt.Rshift = 0;
623     fmt.Gshift = 8;
624     fmt.Bshift = 16;
625     fmt.Ashift = 24;
626     fmt.colorkey = 0;
627     fmt.alpha = 0;
628    
629     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
630    
631 root 1.39 assert (surface2->pitch == surface2->w * 4);
632    
633 root 1.23 EXTEND (SP, 5);
634     PUSHs (sv_2mortal (newSViv (surface2->w)));
635     PUSHs (sv_2mortal (newSViv (surface2->h)));
636     SDL_LockSurface (surface2);
637     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
638     SDL_UnlockSurface (surface2);
639 root 1.24 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
640 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
641 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
642 root 1.23
643     SDL_FreeSurface (surface);
644     SDL_FreeSurface (surface2);
645     }
646    
647 root 1.25 void
648 root 1.39 average (int x, int y, uint32_t *data)
649     PPCODE:
650     {
651     uint32_t r = 0, g = 0, b = 0, a = 0;
652    
653     x = y = x * y;
654    
655     while (x--)
656     {
657     uint32_t p = *data++;
658    
659     r += (p ) & 255;
660     g += (p >> 8) & 255;
661     b += (p >> 16) & 255;
662     a += (p >> 24) & 255;
663     }
664    
665     EXTEND (SP, 4);
666 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
667     PUSHs (sv_2mortal (newSViv (g / y)));
668     PUSHs (sv_2mortal (newSViv (b / y)));
669     PUSHs (sv_2mortal (newSViv (a / y)));
670 root 1.39 }
671    
672     void
673 root 1.66 error (char *message)
674     CODE:
675 root 1.86 fprintf (stderr, "ERROR: %s\n", message);
676 root 1.66 #ifdef _WIN32
677 root 1.86 MessageBox (0, message, "Crossfire+ Error", MB_OK | MB_ICONERROR);
678 root 1.66 #endif
679    
680     void
681 root 1.25 fatal (char *message)
682     CODE:
683 root 1.86 fprintf (stderr, "FATAL: %s\n", message);
684 root 1.50 #ifdef _WIN32
685 root 1.86 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR);
686 root 1.25 #endif
687     exit (1);
688    
689 root 1.61 MODULE = CFClient PACKAGE = CFClient::Font
690    
691     CFClient::Font
692 root 1.70 new_from_file (SV *class, char *path, int id = 0)
693 root 1.61 CODE:
694     {
695     int count;
696 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
697 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
698     FcPatternDestroy (pattern);
699     }
700     OUTPUT:
701     RETVAL
702    
703     void
704     DESTROY (CFClient::Font self)
705     CODE:
706     pango_font_description_free (self);
707    
708     void
709     make_default (CFClient::Font self)
710     CODE:
711     default_font = self;
712    
713 root 1.15 MODULE = CFClient PACKAGE = CFClient::Layout
714 root 1.14
715 root 1.15 CFClient::Layout
716 root 1.76 new (SV *class, int rgba = 0)
717 root 1.14 CODE:
718 root 1.87 #if _WIN32
719     rgba = 0;//D
720     #endif
721 root 1.14 New (0, RETVAL, 1, struct cf_layout);
722 root 1.76
723     RETVAL->pl = pango_layout_new (rgba ? cairo_context : ft2_context);
724     RETVAL->rgba = rgba;
725     RETVAL->r = 1.;
726     RETVAL->g = 1.;
727     RETVAL->b = 1.;
728     RETVAL->a = 1.;
729     RETVAL->base_height = MIN_FONT_HEIGHT;
730     RETVAL->font = 0;
731    
732 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
733 root 1.76 layout_update_font (RETVAL);
734 root 1.14 OUTPUT:
735     RETVAL
736    
737     void
738 root 1.15 DESTROY (CFClient::Layout self)
739 root 1.14 CODE:
740     g_object_unref (self->pl);
741     Safefree (self);
742 root 1.13
743 root 1.76 int
744     is_rgba (CFClient::Layout self)
745     CODE:
746     RETVAL = self->rgba;
747     OUTPUT:
748     RETVAL
749    
750 root 1.8 void
751 root 1.35 set_text (CFClient::Layout self, SV *text_)
752     CODE:
753     {
754     STRLEN textlen;
755     char *text = SvPVutf8 (text_, textlen);
756    
757     pango_layout_set_text (self->pl, text, textlen);
758     }
759    
760     void
761 root 1.15 set_markup (CFClient::Layout self, SV *text_)
762 root 1.14 CODE:
763 root 1.5 {
764     STRLEN textlen;
765     char *text = SvPVutf8 (text_, textlen);
766 root 1.14
767     pango_layout_set_markup (self->pl, text, textlen);
768     }
769    
770 root 1.46 SV *
771     get_text (CFClient::Layout self)
772     CODE:
773 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
774 root 1.46 SvUTF8_on (RETVAL);
775     OUTPUT:
776     RETVAL
777    
778 root 1.14 void
779 root 1.76 set_foreground (CFClient::Layout self, float r, float g, float b, float a = 1.)
780     CODE:
781     self->r = r;
782     self->g = g;
783     self->b = b;
784     self->a = a;
785    
786     void
787 root 1.61 set_font (CFClient::Layout self, CFClient::Font font = 0)
788     CODE:
789     if (self->font != font)
790     {
791     self->font = font;
792     layout_update_font (self);
793     }
794    
795     void
796 root 1.16 set_height (CFClient::Layout self, int base_height)
797     CODE:
798 root 1.61 if (self->base_height != base_height)
799     {
800     self->base_height = base_height;
801     layout_update_font (self);
802     }
803 root 1.16
804     void
805 root 1.15 set_width (CFClient::Layout self, int max_width = -1)
806 root 1.14 CODE:
807     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
808    
809     void
810 root 1.84 set_indent (CFClient::Layout self, int indent)
811     CODE:
812     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
813    
814     void
815     set_spacing (CFClient::Layout self, int spacing)
816     CODE:
817     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
818    
819     void
820     set_ellipsise (CFClient::Layout self, int ellipsise)
821     CODE:
822     pango_layout_set_ellipsize (self->pl,
823     ellipsise == 1 ? PANGO_ELLIPSIZE_START
824     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
825     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
826     : PANGO_ELLIPSIZE_NONE
827     );
828    
829     void
830     set_single_paragraph_mode (CFClient::Layout self, int spm)
831     CODE:
832     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
833    
834     void
835 root 1.15 size (CFClient::Layout self)
836 root 1.14 PPCODE:
837     {
838     int w, h;
839    
840     layout_get_pixel_size (self, &w, &h);
841    
842     EXTEND (SP, 2);
843     PUSHs (sv_2mortal (newSViv (w)));
844     PUSHs (sv_2mortal (newSViv (h)));
845     }
846    
847 root 1.17 int
848     xy_to_index (CFClient::Layout self, int x, int y)
849     CODE:
850     {
851     int index, trailing;
852     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
853     RETVAL = index;
854     }
855     OUTPUT:
856     RETVAL
857    
858     void
859     cursor_pos (CFClient::Layout self, int index)
860     PPCODE:
861     {
862     PangoRectangle strong_pos;
863     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
864 root 1.30
865 root 1.17 EXTEND (SP, 3);
866     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
867     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
868     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
869     }
870    
871 root 1.14 void
872 root 1.15 render (CFClient::Layout self)
873 root 1.14 PPCODE:
874     {
875 root 1.5 SV *retval;
876     int w, h;
877    
878 root 1.14 layout_get_pixel_size (self, &w, &h);
879 root 1.5
880 root 1.76 if (self->rgba)
881     {
882     cairo_surface_t *surface;
883     cairo_t *cairo;
884    
885     retval = newSV (w * h * 4);
886     SvPOK_only (retval);
887     SvCUR_set (retval, w * h * 4);
888    
889     memset (SvPVX (retval), 0, w * h * 4);
890    
891     surface = cairo_image_surface_create_for_data (
892     (void*)SvPVX (retval), CAIRO_FORMAT_ARGB32, w, h, w * 4);
893     cairo = cairo_create (surface);
894     cairo_set_source_rgba (cairo, self->r, self->g, self->b, self->a);
895    
896     pango_cairo_show_layout (cairo, self->pl);
897    
898     cairo_destroy (cairo);
899     cairo_surface_destroy (surface);
900    
901     // what a mess, and its premultiplied, too :(
902     {
903     uint32_t *p = (uint32_t *)SvPVX (retval);
904     uint32_t *e = p + w * h;
905 root 1.5
906 root 1.76 while (p < e)
907     {
908     uint32_t rgba = *p;
909     rgba = (rgba >> 24) | (rgba << 8);
910 root 1.87 #if 0
911     #ifdef _WIN32
912     {//D
913     uint8_t r = rgba >> 24;
914     uint8_t g = rgba >> 16;
915     uint8_t b = rgba >> 8;
916     uint8_t a = rgba >> 0;
917    
918     rgba = (rgba & 0xffffff00) | a;
919     }
920     #endif
921     #endif
922 root 1.76 rgba = SDL_SwapBE32 (rgba);
923     *p++ = rgba;
924     }
925     }
926    
927     EXTEND (SP, 5);
928     PUSHs (sv_2mortal (newSViv (w)));
929     PUSHs (sv_2mortal (newSViv (h)));
930     PUSHs (sv_2mortal (retval));
931     PUSHs (sv_2mortal (newSViv (GL_RGBA)));
932     PUSHs (sv_2mortal (newSViv (GL_RGBA)));
933     }
934     else
935     {
936     FT_Bitmap bitmap;
937    
938     retval = newSV (w * h);
939     SvPOK_only (retval);
940     SvCUR_set (retval, w * h);
941    
942     bitmap.rows = h;
943     bitmap.width = w;
944     bitmap.pitch = w;
945     bitmap.buffer = (unsigned char*)SvPVX (retval);
946     bitmap.num_grays = 256;
947     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
948    
949     memset (bitmap.buffer, 0, w * h);
950    
951     pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
952 root 1.1
953 root 1.76 EXTEND (SP, 5);
954     PUSHs (sv_2mortal (newSViv (w)));
955     PUSHs (sv_2mortal (newSViv (h)));
956     PUSHs (sv_2mortal (retval));
957     PUSHs (sv_2mortal (newSViv (GL_ALPHA)));
958     PUSHs (sv_2mortal (newSViv (GL_ALPHA)));
959     }
960 root 1.5 }
961 root 1.11
962 root 1.15 MODULE = CFClient PACKAGE = CFClient::Texture
963 root 1.11
964     void
965 root 1.37 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
966 root 1.12 PROTOTYPE: $$$;$$
967 root 1.76 ALIAS:
968     draw_quad_alpha = 1
969     draw_quad_alpha_premultiplied = 2
970 root 1.11 CODE:
971     {
972 root 1.12 HV *hv = (HV *)SvRV (self);
973 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
974     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
975 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
976 elmex 1.36 int wrap_mode = SvIV (*hv_fetch (hv, "wrap_mode", 9, 1));
977 root 1.12
978     if (items < 5)
979     {
980 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
981     h = SvNV (*hv_fetch (hv, "h", 1, 1));
982 root 1.12 }
983    
984 root 1.76 if (ix)
985     {
986     glEnable (GL_BLEND);
987     glBlendFunc (ix == 1 ? GL_SRC_ALPHA : GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
988 root 1.86 glEnable (GL_ALPHA_TEST);
989     glAlphaFunc (GL_GREATER, 0.01f);
990 root 1.76 }
991    
992 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
993 root 1.76
994     if (wrap_mode)
995     {
996     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
997     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
998     }
999    
1000 root 1.12 glBegin (GL_QUADS);
1001 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1002     glTexCoord2f (0, t); glVertex2f (x , y + h);
1003     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1004     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1005 root 1.12 glEnd ();
1006 root 1.76
1007     if (ix)
1008 root 1.86 {
1009     glDisable (GL_ALPHA_TEST);
1010     glDisable (GL_BLEND);
1011     }
1012 root 1.11 }
1013 root 1.28
1014     MODULE = CFClient PACKAGE = CFClient::Map
1015    
1016     CFClient::Map
1017     new (SV *class, int map_width, int map_height)
1018     CODE:
1019     New (0, RETVAL, 1, struct map);
1020 root 1.42 RETVAL->x = 0;
1021     RETVAL->y = 0;
1022     RETVAL->w = map_width;
1023     RETVAL->h = map_height;
1024     RETVAL->ox = 0;
1025     RETVAL->oy = 0;
1026 root 1.30 RETVAL->faces = 8192;
1027     Newz (0, RETVAL->face, RETVAL->faces, mapface);
1028 root 1.42 RETVAL->texs = 8192;
1029     Newz (0, RETVAL->tex, RETVAL->texs, maptex);
1030 root 1.28 RETVAL->rows = 0;
1031     RETVAL->row = 0;
1032     OUTPUT:
1033     RETVAL
1034    
1035     void
1036     DESTROY (CFClient::Map self)
1037     CODE:
1038     {
1039 root 1.30 map_clear (self);
1040 root 1.28 Safefree (self->face);
1041 root 1.29 Safefree (self);
1042     }
1043    
1044     void
1045 root 1.30 clear (CFClient::Map self)
1046     CODE:
1047     map_clear (self);
1048    
1049     void
1050 root 1.42 set_face (CFClient::Map self, int face, int texid)
1051 root 1.29 CODE:
1052     {
1053 root 1.42 while (self->faces <= face)
1054 root 1.28 {
1055 root 1.30 Append (mapface, self->face, self->faces, self->faces);
1056 root 1.29 self->faces *= 2;
1057     }
1058 root 1.28
1059 root 1.42 self->face [face] = texid;
1060     }
1061    
1062     void
1063     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)
1064     CODE:
1065     {
1066     while (self->texs <= texid)
1067     {
1068     Append (maptex, self->tex, self->texs, self->texs);
1069     self->texs *= 2;
1070     }
1071    
1072 root 1.48 {
1073     maptex *tex = self->tex + texid;
1074 root 1.39
1075 root 1.48 tex->name = name;
1076     tex->w = w;
1077     tex->h = h;
1078     tex->s = s;
1079     tex->t = t;
1080     tex->r = r;
1081     tex->g = g;
1082     tex->b = b;
1083     tex->a = a;
1084     }
1085 root 1.29 }
1086    
1087 root 1.42 int
1088     ox (CFClient::Map self)
1089     ALIAS:
1090     oy = 1
1091     CODE:
1092     switch (ix)
1093     {
1094     case 0: RETVAL = self->ox; break;
1095     case 1: RETVAL = self->oy; break;
1096     }
1097     OUTPUT:
1098     RETVAL
1099    
1100 root 1.29 void
1101 root 1.43 scroll (CFClient::Map self, int dx, int dy)
1102     CODE:
1103     {
1104 root 1.44 if (dx > 0)
1105     map_blank (self, self->x, self->y, dx - 1, self->h);
1106     else if (dx < 0)
1107     map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
1108    
1109     if (dy > 0)
1110     map_blank (self, self->x, self->y, self->w, dy - 1);
1111     else if (dy < 0)
1112     map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
1113 root 1.43
1114 root 1.44 self->ox += dx; self->x += dx;
1115     self->oy += dy; self->y += dy;
1116 root 1.43
1117     while (self->y < 0)
1118     {
1119     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1120    
1121     self->rows += MAP_EXTEND_Y;
1122     self->y += MAP_EXTEND_Y;
1123     }
1124 root 1.44 }
1125 root 1.43
1126 root 1.44 void
1127     map1a_update (CFClient::Map self, SV *data_)
1128     CODE:
1129     {
1130 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1131     uint8_t *data_end = (uint8_t *)SvEND (data_);
1132 root 1.48 mapcell *cell;
1133     int x, y, flags;
1134 root 1.43
1135 root 1.29 while (data < data_end)
1136     {
1137 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1138 root 1.30
1139 root 1.48 x = ((flags >> 10) & 63) + self->x;
1140     y = ((flags >> 4) & 63) + self->y;
1141 root 1.29
1142 root 1.48 cell = map_get_cell (self, x, y);
1143 root 1.29
1144     if (flags & 15)
1145     {
1146 root 1.45 if (cell->darkness < 0)
1147 root 1.29 {
1148     cell->darkness = 0;
1149     cell->face [0] = 0;
1150     cell->face [1] = 0;
1151     cell->face [2] = 0;
1152     }
1153 root 1.45
1154 root 1.29 cell->darkness = flags & 8 ? *data++ : 255;
1155    
1156 root 1.42 //TODO: don't trust server data to be in-range(!)
1157    
1158 root 1.29 if (flags & 4)
1159     {
1160 root 1.42 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
1161 root 1.29 }
1162    
1163     if (flags & 2)
1164     {
1165 root 1.42 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
1166 root 1.29 }
1167    
1168     if (flags & 1)
1169     {
1170 root 1.42 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
1171 root 1.29 }
1172     }
1173     else
1174 root 1.31 cell->darkness = -1;
1175 root 1.29 }
1176 root 1.28 }
1177    
1178 root 1.40 SV *
1179 root 1.55 mapmap (CFClient::Map self, int x0, int y0, int w, int h)
1180 root 1.40 CODE:
1181     {
1182 root 1.55 int x1, x;
1183     int y1, y;
1184 root 1.40 int z;
1185     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1186     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1187    
1188     SvPOK_only (map_sv);
1189     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1190    
1191 root 1.55 x0 += self->x; x1 = x0 + w;
1192     y0 += self->y; y1 = y0 + h;
1193 root 1.40
1194     for (y = y0; y < y1; y++)
1195     {
1196     maprow *row = 0 <= y && y < self->rows
1197     ? self->row + y
1198     : 0;
1199    
1200     for (x = x0; x < x1; x++)
1201     {
1202     int r = 32, g = 32, b = 32, a = 192;
1203    
1204     if (row && row->c0 <= x && x < row->c1)
1205     {
1206     mapcell *cell = row->col + (x - row->c0);
1207    
1208     for (z = 0; z <= 0; z++)
1209     {
1210 root 1.42 mapface face = cell->face [z];
1211 root 1.40
1212     if (face)
1213     {
1214 root 1.42 maptex tex = self->tex [face];
1215 root 1.40 int a0 = 255 - tex.a;
1216     int a1 = tex.a;
1217    
1218     r = (r * a0 + tex.r * a1) / 255;
1219     g = (g * a0 + tex.g * a1) / 255;
1220     b = (b * a0 + tex.b * a1) / 255;
1221     a = (a * a0 + tex.a * a1) / 255;
1222     }
1223     }
1224     }
1225    
1226     *map++ = (r )
1227     | (g << 8)
1228     | (b << 16)
1229     | (a << 24);
1230     }
1231     }
1232    
1233     RETVAL = map_sv;
1234     }
1235     OUTPUT:
1236     RETVAL
1237    
1238 root 1.30 void
1239 root 1.38 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
1240 root 1.32 PPCODE:
1241 root 1.30 {
1242 root 1.48 int vx, vy;
1243     int x, y, z;
1244     int last_name;
1245     mapface face;
1246 root 1.32 int sw4 = (sw + 3) & ~3;
1247     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
1248 root 1.35 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
1249 root 1.48
1250 root 1.42 memset (darkness, 255, sw4 * sh);
1251 root 1.32 SvPOK_only (darkness_sv);
1252     SvCUR_set (darkness_sv, sw4 * sh);
1253    
1254 root 1.48 vx = self->x + (self->w - sw) / 2 - shift_x;
1255     vy = self->y + (self->h - sh) / 2 - shift_y;
1256 root 1.38
1257 root 1.42 /*
1258     int vx = self->vx = self->w >= sw
1259     ? self->x + (self->w - sw) / 2
1260     : MIN (self->x, MAX (self->x + self->w - sw + 1, self->vx));
1261    
1262     int vy = self->vy = self->h >= sh
1263     ? self->y + (self->h - sh) / 2
1264     : MIN (self->y, MAX (self->y + self->h - sh + 1, self->vy));
1265     */
1266 root 1.30
1267     glColor4ub (255, 255, 255, 255);
1268    
1269     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1270     glEnable (GL_BLEND);
1271     glEnable (GL_TEXTURE_2D);
1272     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1273    
1274 root 1.48 glBegin (GL_QUADS);
1275 root 1.30
1276 root 1.48 last_name = 0;
1277 root 1.30
1278     for (z = 0; z < 3; z++)
1279     for (y = 0; y < sh; y++)
1280     if (0 <= y + vy && y + vy < self->rows)
1281     {
1282     maprow *row = self->row + (y + vy);
1283    
1284     for (x = 0; x < sw; x++)
1285     if (row->c0 <= x + vx && x + vx < row->c1)
1286     {
1287     mapcell *cell = row->col + (x + vx - row->c0);
1288 root 1.32
1289     darkness[y * sw4 + x] = cell->darkness < 0
1290 root 1.33 ? 255 - FOW_DARKNESS
1291 root 1.32 : 255 - cell->darkness;
1292    
1293 root 1.48 face = cell->face [z];
1294 root 1.30
1295     if (face)
1296     {
1297 root 1.42 maptex tex = self->tex [face];
1298 root 1.30
1299     int px = (x + 1) * 32 - tex.w;
1300     int py = (y + 1) * 32 - tex.h;
1301    
1302     if (last_name != tex.name)
1303     {
1304     glEnd ();
1305     last_name = tex.name;
1306     glBindTexture (GL_TEXTURE_2D, last_name);
1307     glBegin (GL_QUADS);
1308     }
1309    
1310     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1311     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1312     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1313     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1314     }
1315     }
1316     }
1317    
1318     glEnd ();
1319 root 1.32
1320 root 1.34 glDisable (GL_TEXTURE_2D);
1321     glDisable (GL_BLEND);
1322    
1323 root 1.32 EXTEND (SP, 3);
1324     PUSHs (sv_2mortal (newSViv (sw4)));
1325     PUSHs (sv_2mortal (newSViv (sh)));
1326     PUSHs (darkness_sv);
1327 root 1.30 }
1328    
1329 root 1.42 SV *
1330     get_rect (CFClient::Map self, int x0, int y0, int w, int h)
1331     CODE:
1332     {
1333     int x, y, x1, y1;
1334     SV *data_sv = newSV (w * h * 7 + 5);
1335     uint8_t *data = (uint8_t *)SvPVX (data_sv);
1336    
1337     *data++ = 0; /* version 0 format */
1338     *data++ = w >> 8; *data++ = w;
1339     *data++ = h >> 8; *data++ = h;
1340    
1341     // we need to do this 'cause we don't keep an absolute coord system for rows
1342 root 1.55 // TODO: treat rows as we treat columns
1343 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1344     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1345    
1346     x0 += self->x - self->ox;
1347     y0 += self->y - self->oy;
1348    
1349     x1 = x0 + w;
1350     y1 = y0 + h;
1351    
1352     for (y = y0; y < y1; y++)
1353     {
1354     maprow *row = 0 <= y && y < self->rows
1355     ? self->row + y
1356     : 0;
1357    
1358     for (x = x0; x < x1; x++)
1359     {
1360     if (row && row->c0 <= x && x < row->c1)
1361     {
1362     mapcell *cell = row->col + (x - row->c0);
1363     uint8_t flags = 0;
1364    
1365     if (cell->face [0]) flags |= 1;
1366     if (cell->face [1]) flags |= 2;
1367     if (cell->face [2]) flags |= 4;
1368    
1369     *data++ = flags;
1370    
1371     if (flags & 1)
1372     {
1373     *data++ = cell->face [0] >> 8;
1374     *data++ = cell->face [0];
1375     }
1376    
1377     if (flags & 2)
1378     {
1379     *data++ = cell->face [1] >> 8;
1380     *data++ = cell->face [1];
1381     }
1382    
1383     if (flags & 4)
1384     {
1385     *data++ = cell->face [2] >> 8;
1386     *data++ = cell->face [2];
1387     }
1388     }
1389     else
1390     *data++ = 0;
1391     }
1392     }
1393    
1394     SvPOK_only (data_sv);
1395     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
1396     RETVAL = data_sv;
1397     }
1398     OUTPUT:
1399     RETVAL
1400    
1401     void
1402     set_rect (CFClient::Map self, int x0, int y0, uint8_t *data)
1403     PPCODE:
1404     {
1405     int x, y, z;
1406 root 1.48 int w, h;
1407 root 1.42 int x1, y1;
1408    
1409     if (*data++ != 0)
1410     return; /* version mismatch */
1411    
1412 root 1.48 w = *data++ << 8; w |= *data++;
1413     h = *data++ << 8; h |= *data++;
1414 root 1.42
1415     // we need to do this 'cause we don't keep an absolute coord system for rows
1416 root 1.55 // TODO: treat rows as we treat columns
1417 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1418     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1419    
1420     x0 += self->x - self->ox;
1421     y0 += self->y - self->oy;
1422    
1423     x1 = x0 + w;
1424     y1 = y0 + h;
1425    
1426     for (y = y0; y < y1; y++)
1427     {
1428     maprow *row = map_get_row (self, y);
1429    
1430     for (x = x0; x < x1; x++)
1431     {
1432     uint8_t flags = *data++;
1433    
1434     if (flags)
1435     {
1436     mapface face[3] = { 0, 0, 0 };
1437    
1438     mapcell *cell = row_get_cell (row, x);
1439    
1440     if (flags & 1) { face[0] = *data++ << 8; face[0] |= *data++; }
1441     if (flags & 2) { face[1] = *data++ << 8; face[1] |= *data++; }
1442     if (flags & 4) { face[2] = *data++ << 8; face[2] |= *data++; }
1443    
1444     if (cell->darkness <= 0)
1445     {
1446     cell->darkness = -1;
1447    
1448     for (z = 0; z <= 2; z++)
1449     {
1450     cell->face[z] = face[z];
1451    
1452     if (face[z] && (face[z] >= self->texs || !self->tex[face [z]].name))
1453     XPUSHs (sv_2mortal (newSViv (face[z])));
1454     }
1455     }
1456     }
1457     }
1458     }
1459     }
1460    
1461 root 1.52 MODULE = CFClient PACKAGE = CFClient::MixChunk
1462    
1463     CFClient::MixChunk
1464     new_from_file (SV *class, char *path)
1465     CODE:
1466     RETVAL = Mix_LoadWAV (path);
1467     OUTPUT:
1468     RETVAL
1469    
1470     void
1471     DESTROY (CFClient::MixChunk self)
1472     CODE:
1473     Mix_FreeChunk (self);
1474    
1475     int
1476     volume (CFClient::MixChunk self, int volume = -1)
1477     CODE:
1478     RETVAL = Mix_VolumeChunk (self, volume);
1479     OUTPUT:
1480     RETVAL
1481    
1482     int
1483     play (CFClient::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
1484     CODE:
1485     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
1486     OUTPUT:
1487     RETVAL
1488    
1489     MODULE = CFClient PACKAGE = CFClient::MixMusic
1490    
1491     int
1492     volume (int volume = -1)
1493     CODE:
1494     RETVAL = Mix_VolumeMusic (volume);
1495     OUTPUT:
1496     RETVAL
1497    
1498     CFClient::MixMusic
1499     new_from_file (SV *class, char *path)
1500     CODE:
1501     RETVAL = Mix_LoadMUS (path);
1502     OUTPUT:
1503     RETVAL
1504    
1505     void
1506     DESTROY (CFClient::MixMusic self)
1507     CODE:
1508     Mix_FreeMusic (self);
1509    
1510     int
1511     play (CFClient::MixMusic self, int loops = -1)
1512     CODE:
1513     RETVAL = Mix_PlayMusic (self, loops);
1514     OUTPUT:
1515     RETVAL
1516    
1517 root 1.54 MODULE = CFClient PACKAGE = CFClient::OpenGL
1518    
1519     BOOT:
1520     {
1521     HV *stash = gv_stashpv ("CFClient::OpenGL", 1);
1522     static const struct {
1523     const char *name;
1524     IV iv;
1525     } *civ, const_iv[] = {
1526     # define const_iv(name) { # name, (IV)name }
1527     const_iv (GL_COLOR_MATERIAL),
1528     const_iv (GL_SMOOTH),
1529     const_iv (GL_FLAT),
1530 root 1.69 const_iv (GL_DITHER),
1531 root 1.54 const_iv (GL_BLEND),
1532 root 1.69 const_iv (GL_SCISSOR_TEST),
1533 root 1.54 const_iv (GL_AND),
1534 root 1.67 const_iv (GL_ONE),
1535     const_iv (GL_ZERO),
1536 root 1.54 const_iv (GL_SRC_ALPHA),
1537 root 1.67 const_iv (GL_SRC_ALPHA_SATURATE),
1538 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
1539 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
1540 root 1.54 const_iv (GL_RGB),
1541     const_iv (GL_RGBA),
1542     const_iv (GL_UNSIGNED_BYTE),
1543     const_iv (GL_ALPHA),
1544 root 1.86 const_iv (GL_INTENSITY),
1545 root 1.76 const_iv (GL_LUMINANCE),
1546 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
1547 root 1.54 const_iv (GL_FLOAT),
1548     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
1549     const_iv (GL_COMPILE),
1550     const_iv (GL_TEXTURE_1D),
1551     const_iv (GL_TEXTURE_2D),
1552     const_iv (GL_TEXTURE_ENV),
1553     const_iv (GL_TEXTURE_MAG_FILTER),
1554     const_iv (GL_TEXTURE_MIN_FILTER),
1555     const_iv (GL_TEXTURE_ENV_MODE),
1556     const_iv (GL_TEXTURE_WRAP_S),
1557     const_iv (GL_TEXTURE_WRAP_T),
1558     const_iv (GL_CLAMP),
1559     const_iv (GL_REPEAT),
1560     const_iv (GL_NEAREST),
1561     const_iv (GL_LINEAR),
1562 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
1563     const_iv (GL_LINEAR_MIPMAP_NEAREST),
1564     const_iv (GL_NEAREST_MIPMAP_LINEAR),
1565     const_iv (GL_LINEAR_MIPMAP_LINEAR),
1566     const_iv (GL_GENERATE_MIPMAP),
1567 root 1.54 const_iv (GL_MODULATE),
1568 root 1.69 const_iv (GL_DECAL),
1569 root 1.54 const_iv (GL_REPLACE),
1570     const_iv (GL_COLOR_BUFFER_BIT),
1571     const_iv (GL_PROJECTION),
1572     const_iv (GL_MODELVIEW),
1573     const_iv (GL_COLOR_LOGIC_OP),
1574 root 1.69 const_iv (GL_SEPARABLE_2D),
1575 root 1.54 const_iv (GL_CONVOLUTION_2D),
1576     const_iv (GL_CONVOLUTION_BORDER_MODE),
1577     const_iv (GL_CONSTANT_BORDER),
1578     const_iv (GL_LINES),
1579     const_iv (GL_QUADS),
1580 root 1.55 const_iv (GL_LINE_LOOP),
1581 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
1582     const_iv (GL_FASTEST),
1583     # undef const_iv
1584     };
1585    
1586     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
1587     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
1588     }
1589    
1590     int glGetError ()
1591    
1592     void glClear (int mask)
1593    
1594     void glClearColor (float r, float g, float b, float a = 1.0)
1595     PROTOTYPE: @
1596    
1597     void glEnable (int cap)
1598    
1599     void glDisable (int cap)
1600    
1601     void glShadeModel (int mode)
1602    
1603     void glHint (int target, int mode)
1604    
1605     void glBlendFunc (int sfactor, int dfactor)
1606    
1607     void glLogicOp (int opcode)
1608    
1609 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
1610    
1611 root 1.54 void glMatrixMode (int mode)
1612    
1613     void glPushMatrix ()
1614    
1615     void glPopMatrix ()
1616    
1617     void glLoadIdentity ()
1618    
1619 root 1.64 # near and far are due to microsofts buggy c compiler
1620     void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
1621 root 1.54
1622     void glViewport (int x, int y, int width, int height)
1623    
1624 root 1.69 void glScissor (int x, int y, int width, int height)
1625    
1626 root 1.54 void glTranslate (float x, float y, float z = 0.)
1627     CODE:
1628     glTranslatef (x, y, z);
1629    
1630 root 1.62 void glScale (float x, float y, float z = 1.)
1631 root 1.54 CODE:
1632     glScalef (x, y, z);
1633    
1634     void glRotate (float angle, float x, float y, float z)
1635     CODE:
1636     glRotatef (angle, x, y, z);
1637    
1638     void glBegin (int mode)
1639    
1640     void glEnd ()
1641    
1642     void glColor (float r, float g, float b, float a = 1.0)
1643     PROTOTYPE: @
1644     CODE:
1645 root 1.81 glColor4ub (MIN ((int)(r * 255.f), 255),
1646     MIN ((int)(g * 255.f), 255),
1647     MIN ((int)(b * 255.f), 255),
1648     MIN ((int)(a * 255.f), 255));
1649 root 1.54
1650     void glVertex (float x, float y, float z = 0.)
1651     CODE:
1652     glVertex3f (x, y, z);
1653    
1654     void glTexCoord (float s, float t)
1655     CODE:
1656     glTexCoord2f (s, t);
1657    
1658     void glTexEnv (int target, int pname, float param)
1659     CODE:
1660     glTexEnvf (target, pname, param);
1661    
1662     void glTexParameter (int target, int pname, float param)
1663     CODE:
1664     glTexParameterf (target, pname, param);
1665    
1666     void glBindTexture (int target, int name)
1667    
1668     void glConvolutionParameter (int target, int pname, float params)
1669     CODE:
1670 root 1.64 GL_CALL (PFNGLCONVOLUTIONPARAMETERFEXTPROC, glConvolutionParameterf, (target, pname, params));
1671 root 1.54
1672     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
1673 root 1.64 CODE:
1674     GL_CALL (PFNGLCONVOLUTIONFILTER2DEXTPROC, glConvolutionFilter2D,
1675     (target, internalformat, width, height, format, type, data));
1676 root 1.54
1677 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
1678     CODE:
1679     GL_CALL (PFNGLSEPARABLEFILTER2DEXTPROC, glSeparableFilter2D,
1680     (target, internalformat, width, height, format, type, row, column));
1681    
1682 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
1683    
1684     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
1685    
1686 root 1.68 void glRasterPos (int x, int y)
1687     CODE:
1688     glRasterPos2i (x, y);
1689    
1690     void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
1691    
1692 root 1.54 int glGenTexture ()
1693     CODE:
1694     {
1695     GLuint name;
1696     glGenTextures (1, &name);
1697     RETVAL = name;
1698     }
1699     OUTPUT:
1700     RETVAL
1701    
1702     void glDeleteTexture (int name)
1703     CODE:
1704     {
1705     GLuint name_ = name;
1706     glDeleteTextures (1, &name_);
1707     }
1708    
1709     int glGenList ()
1710     CODE:
1711     RETVAL = glGenLists (1);
1712     OUTPUT:
1713     RETVAL
1714    
1715     void glDeleteList (int list)
1716     CODE:
1717     glDeleteLists (list, 1);
1718    
1719     void glNewList (int list, int mode = GL_COMPILE)
1720    
1721     void glEndList ()
1722    
1723     void glCallList (int list)
1724