ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.96
Committed: Wed May 24 22:28:43 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.95: +1 -1 lines
Log Message:
re-enable cairo on windows: looks like shit, but otherwise breaks textview

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