ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.92
Committed: Tue May 23 17:30:18 2006 UTC (17 years, 11 months ago) by elmex
Branch: MAIN
Changes since 1.91: +7 -0 lines
Log Message:
ATI gfx card workaround for NPOT

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