ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.111
Committed: Mon Jun 12 13:26:14 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.110: +8 -1 lines
Log Message:
first round of npc dialog window, some ui bugfixes

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