ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.116
Committed: Thu Jun 15 08:29:16 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.115: +43 -16 lines
Log Message:
fix(?) map clicking, fow texture no longer in display list

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