ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.82
Committed: Mon May 15 00:15:08 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.81: +3 -1 lines
Log Message:
add a few more almost-hacks to simplify widget alignment

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