ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.84
Committed: Wed May 17 15:18:57 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.83: +25 -0 lines
Log Message:
better text layout, minor fixes

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