ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.81
Committed: Sun May 14 23:19:14 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.80: +4 -4 lines
Log Message:
i can't get it right, either

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