ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.197
Committed: Sun Jul 15 21:08:40 2007 UTC (16 years, 10 months ago) by root
Branch: MAIN
Changes since 1.196: +3 -2 lines
Log Message:
only invoke PumpEvents once per poll

File Contents

# User Rev Content
1 root 1.48 #ifdef _WIN32
2 root 1.131 # define WIN32_LEAN_AND_MEAN
3 root 1.170 # define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls
4 root 1.48 # include <malloc.h>
5 root 1.79 # include <windows.h>
6 root 1.157 # include <wininet.h>
7 root 1.75 # pragma warning(disable:4244)
8 root 1.162 # pragma warning(disable:4761)
9 root 1.48 #endif
10    
11 root 1.193 //#define DEBUG 1
12     #if DEBUG
13     # include <valgrind/memcheck.h>
14     #endif
15    
16 root 1.1 #include "EXTERN.h"
17     #include "perl.h"
18     #include "XSUB.h"
19    
20 root 1.131 #ifdef _WIN32
21     # undef pipe
22     #endif
23    
24 root 1.168 #include <assert.h>
25 root 1.80 #include <math.h>
26 root 1.5 #include <string.h>
27 root 1.25 #include <stdio.h>
28 root 1.111 #include <stdlib.h>
29 root 1.5
30 root 1.2 #include <SDL.h>
31 root 1.76 #include <SDL_endian.h>
32 root 1.23 #include <SDL_image.h>
33 root 1.52 #include <SDL_mixer.h>
34 root 1.3 #include <SDL_opengl.h>
35 root 1.5
36 root 1.124 #define PANGO_ENABLE_BACKEND
37     #define G_DISABLE_CAST_CHECKS
38    
39 root 1.30 #include <glib/gmacros.h>
40    
41 root 1.5 #include <pango/pango.h>
42    
43 root 1.48 #ifndef _WIN32
44     # include <sys/types.h>
45     # include <sys/socket.h>
46     # include <netinet/in.h>
47     # include <netinet/tcp.h>
48     # include <inttypes.h>
49     #endif
50 root 1.28
51 root 1.162 #define OBJ_STR "\xef\xbf\xbc" /* U+FFFC, object replacement character */
52 root 1.121
53 root 1.29 #define FOW_DARKNESS 32
54    
55     #define MAP_EXTEND_X 32
56     #define MAP_EXTEND_Y 512
57    
58 root 1.63 #define MIN_FONT_HEIGHT 10
59 root 1.58
60 root 1.127 #if 0
61 root 1.124 # define PARACHUTE SDL_INIT_NOPARACHUTE
62     #else
63     # define PARACHUTE 0
64     #endif
65    
66 root 1.188 static AV *texture_av;
67    
68 root 1.103 static struct
69     {
70     #define GL_FUNC(ptr,name) ptr name;
71     #include "glfunc.h"
72     #undef GL_FUNC
73     } gl;
74    
75 root 1.192 static void
76     gl_BlendFuncSeparate (GLenum sa, GLenum da, GLenum saa, GLenum daa)
77 root 1.103 {
78     if (gl.BlendFuncSeparate)
79     gl.BlendFuncSeparate (sa, da, saa, daa);
80     else if (gl.BlendFuncSeparateEXT)
81     gl.BlendFuncSeparateEXT (sa, da, saa, daa);
82     else
83     glBlendFunc (sa, da);
84     }
85 root 1.64
86 root 1.192 static GLuint
87     gen_texture ()
88     {
89     GLuint name;
90    
91     if (AvFILL (texture_av) >= 0)
92     name = (GLuint)(size_t)av_pop (texture_av);
93     else
94     glGenTextures (1, &name);
95    
96     return name;
97     }
98    
99     static void
100     del_texture (GLuint name)
101     {
102     /* make a half-assed attempt at returning the memory used by the texture */
103     /* textures are frequently being reused by cfplus anyway */
104     /*glBindTexture (GL_TEXTURE_2D, name);*/
105     /*glTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, 0, 0, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);*/
106     av_push (texture_av, (SV *)(size_t)name);
107     glDeleteTextures (1, &name);
108     }
109    
110 root 1.124 #include "texcache.c"
111    
112     #include "pango-font.c"
113     #include "pango-fontmap.c"
114     #include "pango-render.c"
115    
116 root 1.133 typedef Mix_Chunk *CFPlus__MixChunk;
117     typedef Mix_Music *CFPlus__MixMusic;
118 root 1.52
119 root 1.133 typedef PangoFontDescription *CFPlus__Font;
120 root 1.2
121 root 1.121 static int
122     shape_attr_p (PangoLayoutRun *run)
123     {
124     GSList *attrs = run->item->analysis.extra_attrs;
125    
126     while (attrs)
127     {
128     PangoAttribute *attr = attrs->data;
129    
130     if (attr->klass->type == PANGO_ATTR_SHAPE)
131     return 1;
132    
133     attrs = attrs->next;
134     }
135    
136     return 0;
137     }
138    
139 root 1.14 typedef struct cf_layout {
140 root 1.124 PangoLayout *pl;
141 root 1.76 float r, g, b, a; // default color for rgba mode
142 root 1.14 int base_height;
143 root 1.133 CFPlus__Font font;
144     } *CFPlus__Layout;
145 root 1.14
146 root 1.133 static CFPlus__Font default_font;
147 root 1.124 static PangoContext *opengl_context;
148     static PangoFontMap *opengl_fontmap;
149 root 1.61
150 root 1.14 static void
151 root 1.19 substitute_func (FcPattern *pattern, gpointer data)
152     {
153 root 1.108 FcPatternAddBool (pattern, FC_HINTING, 1);
154 root 1.110 #ifdef FC_HINT_STYLE
155 root 1.109 FcPatternAddBool (pattern, FC_HINT_STYLE, FC_HINT_FULL);
156 root 1.110 #endif
157 root 1.82 FcPatternAddBool (pattern, FC_AUTOHINT, 0);
158 root 1.19 }
159    
160     static void
161 root 1.133 layout_update_font (CFPlus__Layout self)
162 root 1.17 {
163 root 1.19 /* use a random scale factor to account for unknown descenders, 0.8 works
164     * reasonably well with bitstream vera
165     */
166 root 1.61 PangoFontDescription *font = self->font ? self->font : default_font;
167 root 1.46
168 root 1.61 pango_font_description_set_absolute_size (font,
169     MAX (MIN_FONT_HEIGHT, self->base_height) * (PANGO_SCALE * 8 / 10));
170 root 1.58
171 root 1.61 pango_layout_set_font_description (self->pl, font);
172 root 1.17 }
173    
174     static void
175 root 1.133 layout_get_pixel_size (CFPlus__Layout self, int *w, int *h)
176 root 1.14 {
177 root 1.139 PangoRectangle rect;
178 root 1.14
179 root 1.139 // get_pixel_* wrongly rounds down
180     pango_layout_get_extents (self->pl, 0, &rect);
181 root 1.76
182 root 1.139 rect.width = (rect.width + PANGO_SCALE - 1) / PANGO_SCALE;
183     rect.height = (rect.height + PANGO_SCALE - 1) / PANGO_SCALE;
184    
185     if (!rect.width) rect.width = 1;
186     if (!rect.height) rect.height = 1;
187    
188     *w = rect.width;
189     *h = rect.height;
190 root 1.14 }
191    
192 root 1.174 typedef uint16_t tileid;
193     typedef uint16_t faceid;
194 root 1.42
195 root 1.28 typedef struct {
196 root 1.174 int name;
197 root 1.30 int w, h;
198     float s, t;
199 root 1.39 uint8_t r, g, b, a;
200 root 1.176 tileid smoothtile;
201     uint8_t smoothlevel;
202 root 1.42 } maptex;
203 root 1.30
204     typedef struct {
205 root 1.153 uint32_t player;
206 root 1.174 tileid tile[3];
207 root 1.142 uint16_t darkness;
208 root 1.176 uint8_t stat_width, stat_hp, flags, smoothmax;
209 root 1.28 } mapcell;
210    
211     typedef struct {
212 root 1.30 int32_t c0, c1;
213 root 1.28 mapcell *col;
214     } maprow;
215    
216     typedef struct map {
217     int x, y, w, h;
218 root 1.42 int ox, oy; /* offset to virtual global coordinate system */
219 root 1.174 int faces; tileid *face2tile; // [faceid]
220     int texs; maptex *tex; // [tileid]
221 root 1.42
222 root 1.48 int32_t rows;
223 root 1.28 maprow *row;
224 root 1.133 } *CFPlus__Map;
225 root 1.28
226 root 1.30 static char *
227     prepend (char *ptr, int sze, int inc)
228     {
229     char *p;
230    
231     New (0, p, sze + inc, char);
232     Zero (p, inc, char);
233     Move (ptr, p + inc, sze, char);
234     Safefree (ptr);
235    
236     return p;
237     }
238    
239     static char *
240     append (char *ptr, int sze, int inc)
241     {
242     Renew (ptr, sze + inc, char);
243     Zero (ptr + sze, inc, char);
244    
245     return ptr;
246     }
247    
248     #define Append(type,ptr,sze,inc) (ptr) = (type *)append ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
249     #define Prepend(type,ptr,sze,inc) (ptr) = (type *)prepend ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
250    
251 root 1.174 static void
252     need_facenum (struct map *self, faceid face)
253     {
254     while (self->faces <= face)
255     {
256     Append (tileid, self->face2tile, self->faces, self->faces);
257     self->faces *= 2;
258     }
259     }
260    
261     static void
262     need_texid (struct map *self, int texid)
263     {
264     while (self->texs <= texid)
265     {
266     Append (maptex, self->tex, self->texs, self->texs);
267     self->texs *= 2;
268     }
269     }
270    
271 root 1.42 static maprow *
272 root 1.133 map_get_row (CFPlus__Map self, int y)
273 root 1.42 {
274     if (0 > y)
275     {
276     int extend = - y + MAP_EXTEND_Y;
277     Prepend (maprow, self->row, self->rows, extend);
278    
279     self->rows += extend;
280     self->y += extend;
281     y += extend;
282     }
283     else if (y >= self->rows)
284     {
285     int extend = y - self->rows + MAP_EXTEND_Y;
286     Append (maprow, self->row, self->rows, extend);
287     self->rows += extend;
288     }
289    
290     return self->row + y;
291     }
292    
293     static mapcell *
294     row_get_cell (maprow *row, int x)
295     {
296     if (!row->col)
297     {
298     Newz (0, row->col, MAP_EXTEND_X, mapcell);
299     row->c0 = x - MAP_EXTEND_X / 4;
300     row->c1 = row->c0 + MAP_EXTEND_X;
301     }
302    
303     if (row->c0 > x)
304     {
305     int extend = row->c0 - x + MAP_EXTEND_X;
306     Prepend (mapcell, row->col, row->c1 - row->c0, extend);
307     row->c0 -= extend;
308     }
309     else if (x >= row->c1)
310     {
311     int extend = x - row->c1 + MAP_EXTEND_X;
312     Append (mapcell, row->col, row->c1 - row->c0, extend);
313     row->c1 += extend;
314     }
315    
316     return row->col + (x - row->c0);
317     }
318    
319     static mapcell *
320 root 1.133 map_get_cell (CFPlus__Map self, int x, int y)
321 root 1.42 {
322     return row_get_cell (map_get_row (self, y), x);
323     }
324    
325 root 1.30 static void
326 root 1.133 map_clear (CFPlus__Map self)
327 root 1.30 {
328     int r;
329    
330     for (r = 0; r < self->rows; r++)
331     Safefree (self->row[r].col);
332    
333     Safefree (self->row);
334    
335     self->x = 0;
336     self->y = 0;
337 root 1.42 self->ox = 0;
338     self->oy = 0;
339 root 1.30 self->row = 0;
340     self->rows = 0;
341     }
342    
343 root 1.29 static void
344 root 1.133 map_blank (CFPlus__Map self, int x0, int y0, int w, int h)
345 root 1.29 {
346     int x, y;
347 root 1.48 maprow *row;
348 root 1.146 mapcell *cell;
349 root 1.29
350     for (y = y0; y < y0 + h; y++)
351 root 1.30 if (y >= 0)
352     {
353     if (y >= self->rows)
354     break;
355    
356 root 1.48 row = self->row + y;
357 root 1.30
358     for (x = x0; x < x0 + w; x++)
359     if (x >= row->c0)
360     {
361     if (x >= row->c1)
362     break;
363 root 1.29
364 root 1.146 cell = row->col + x - row->c0;
365    
366     cell->darkness = 0;
367     cell->stat_hp = 0;
368 root 1.154 cell->flags = 0;
369     cell->player = 0;
370 root 1.30 }
371     }
372 root 1.29 }
373    
374 root 1.176 typedef struct {
375     tileid tile;
376     uint8_t x, y, level;
377     } smooth_key;
378    
379     static void
380     smooth_or_bits (HV *hv, smooth_key *key, IV bits)
381     {
382 root 1.181 SV **sv = hv_fetch (hv, (char *)key, sizeof (*key), 1);
383 root 1.176
384     if (SvIOK (*sv))
385     SvIV_set (*sv, SvIVX (*sv) | bits);
386     else
387     sv_setiv (*sv, bits);
388     }
389    
390 root 1.56 static void
391 root 1.75 music_finished (void)
392 root 1.56 {
393     SDL_UserEvent ev;
394    
395     ev.type = SDL_USEREVENT;
396     ev.code = 0;
397     ev.data1 = 0;
398     ev.data2 = 0;
399    
400 root 1.57 SDL_PushEvent ((SDL_Event *)&ev);
401 root 1.56 }
402    
403 root 1.71 static void
404     channel_finished (int channel)
405     {
406     SDL_UserEvent ev;
407    
408     ev.type = SDL_USEREVENT;
409     ev.code = 1;
410 root 1.74 ev.data1 = (void *)(long)channel;
411 root 1.71 ev.data2 = 0;
412    
413     SDL_PushEvent ((SDL_Event *)&ev);
414     }
415    
416 root 1.113 static unsigned int
417     minpot (unsigned int n)
418     {
419     if (!n)
420     return 0;
421    
422     --n;
423    
424     n |= n >> 1;
425     n |= n >> 2;
426     n |= n >> 4;
427     n |= n >> 8;
428     n |= n >> 16;
429    
430     return n + 1;
431     }
432    
433 root 1.167 /* SDL should provide this, really. */
434     #define SDLK_MODIFIER_MIN 300
435     #define SDLK_MODIFIER_MAX 314
436    
437 root 1.133 MODULE = CFPlus PACKAGE = CFPlus
438 root 1.1
439 root 1.11 PROTOTYPES: ENABLE
440    
441 root 1.5 BOOT:
442     {
443 root 1.133 HV *stash = gv_stashpv ("CFPlus", 1);
444 root 1.51 static const struct {
445     const char *name;
446     IV iv;
447     } *civ, const_iv[] = {
448     # define const_iv(name) { # name, (IV)name }
449 root 1.167 const_iv (SDLK_MODIFIER_MIN),
450     const_iv (SDLK_MODIFIER_MAX),
451    
452 root 1.51 const_iv (SDL_ACTIVEEVENT),
453     const_iv (SDL_KEYDOWN),
454     const_iv (SDL_KEYUP),
455     const_iv (SDL_MOUSEMOTION),
456     const_iv (SDL_MOUSEBUTTONDOWN),
457     const_iv (SDL_MOUSEBUTTONUP),
458     const_iv (SDL_JOYAXISMOTION),
459     const_iv (SDL_JOYBALLMOTION),
460     const_iv (SDL_JOYHATMOTION),
461     const_iv (SDL_JOYBUTTONDOWN),
462     const_iv (SDL_JOYBUTTONUP),
463     const_iv (SDL_QUIT),
464     const_iv (SDL_SYSWMEVENT),
465     const_iv (SDL_EVENT_RESERVEDA),
466     const_iv (SDL_EVENT_RESERVEDB),
467     const_iv (SDL_VIDEORESIZE),
468     const_iv (SDL_VIDEOEXPOSE),
469     const_iv (SDL_USEREVENT),
470 root 1.167
471     const_iv (SDL_APPINPUTFOCUS),
472     const_iv (SDL_APPMOUSEFOCUS),
473     const_iv (SDL_APPACTIVE),
474    
475 root 1.51 const_iv (SDLK_KP0),
476     const_iv (SDLK_KP1),
477     const_iv (SDLK_KP2),
478     const_iv (SDLK_KP3),
479     const_iv (SDLK_KP4),
480     const_iv (SDLK_KP5),
481     const_iv (SDLK_KP6),
482     const_iv (SDLK_KP7),
483     const_iv (SDLK_KP8),
484     const_iv (SDLK_KP9),
485     const_iv (SDLK_KP_PERIOD),
486     const_iv (SDLK_KP_DIVIDE),
487     const_iv (SDLK_KP_MULTIPLY),
488     const_iv (SDLK_KP_MINUS),
489     const_iv (SDLK_KP_PLUS),
490     const_iv (SDLK_KP_ENTER),
491     const_iv (SDLK_KP_EQUALS),
492     const_iv (SDLK_UP),
493     const_iv (SDLK_DOWN),
494     const_iv (SDLK_RIGHT),
495     const_iv (SDLK_LEFT),
496     const_iv (SDLK_INSERT),
497     const_iv (SDLK_HOME),
498     const_iv (SDLK_END),
499     const_iv (SDLK_PAGEUP),
500     const_iv (SDLK_PAGEDOWN),
501     const_iv (SDLK_F1),
502     const_iv (SDLK_F2),
503     const_iv (SDLK_F3),
504     const_iv (SDLK_F4),
505     const_iv (SDLK_F5),
506     const_iv (SDLK_F6),
507     const_iv (SDLK_F7),
508     const_iv (SDLK_F8),
509     const_iv (SDLK_F9),
510     const_iv (SDLK_F10),
511     const_iv (SDLK_F11),
512     const_iv (SDLK_F12),
513     const_iv (SDLK_F13),
514     const_iv (SDLK_F14),
515     const_iv (SDLK_F15),
516     const_iv (SDLK_NUMLOCK),
517     const_iv (SDLK_CAPSLOCK),
518     const_iv (SDLK_SCROLLOCK),
519     const_iv (SDLK_RSHIFT),
520     const_iv (SDLK_LSHIFT),
521     const_iv (SDLK_RCTRL),
522     const_iv (SDLK_LCTRL),
523     const_iv (SDLK_RALT),
524     const_iv (SDLK_LALT),
525     const_iv (SDLK_RMETA),
526     const_iv (SDLK_LMETA),
527     const_iv (SDLK_LSUPER),
528     const_iv (SDLK_RSUPER),
529     const_iv (SDLK_MODE),
530     const_iv (SDLK_COMPOSE),
531     const_iv (SDLK_HELP),
532     const_iv (SDLK_PRINT),
533     const_iv (SDLK_SYSREQ),
534     const_iv (SDLK_BREAK),
535     const_iv (SDLK_MENU),
536     const_iv (SDLK_POWER),
537     const_iv (SDLK_EURO),
538     const_iv (SDLK_UNDO),
539 root 1.167
540 root 1.51 const_iv (KMOD_NONE),
541 root 1.167 const_iv (KMOD_SHIFT),
542 root 1.51 const_iv (KMOD_LSHIFT),
543     const_iv (KMOD_RSHIFT),
544 root 1.167 const_iv (KMOD_CTRL),
545 root 1.51 const_iv (KMOD_LCTRL),
546     const_iv (KMOD_RCTRL),
547 root 1.167 const_iv (KMOD_ALT),
548 root 1.51 const_iv (KMOD_LALT),
549     const_iv (KMOD_RALT),
550 root 1.167 const_iv (KMOD_META),
551 root 1.51 const_iv (KMOD_LMETA),
552     const_iv (KMOD_RMETA),
553     const_iv (KMOD_NUM),
554     const_iv (KMOD_CAPS),
555     const_iv (KMOD_MODE),
556     # undef const_iv
557     };
558    
559     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
560     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
561 root 1.167
562     assert (SDLK_MODIFIER_MIN == SDLK_NUMLOCK);
563     assert (SDLK_MODIFIER_MAX == SDLK_COMPOSE);
564 root 1.79 }
565 root 1.51
566 root 1.168 void
567     weaken (SV *rv)
568     PROTOTYPE: $
569     CODE:
570     sv_rvweaken (rv);
571    
572 root 1.129 int
573     in_destruct ()
574     CODE:
575     RETVAL = PL_main_cv == Nullcv;
576     OUTPUT:
577     RETVAL
578    
579 root 1.116 NV floor (NV x)
580    
581     NV ceil (NV x)
582    
583 root 1.79 void
584     pango_init ()
585     CODE:
586     {
587 root 1.124 opengl_fontmap = pango_opengl_font_map_new ();
588     pango_opengl_font_map_set_default_substitute ((PangoOpenGLFontMap *)opengl_fontmap, substitute_func, 0, 0);
589     opengl_context = pango_opengl_font_map_create_context ((PangoOpenGLFontMap *)opengl_fontmap);
590 root 1.5 }
591    
592 root 1.51 int
593 root 1.124 SDL_Init (U32 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | PARACHUTE)
594 root 1.51
595     void
596     SDL_Quit ()
597    
598     void
599     SDL_ListModes ()
600     PPCODE:
601     {
602     SDL_Rect **m;
603    
604     SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
605     SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
606     SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
607 root 1.88 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 1);
608 root 1.51
609 root 1.88 SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 15);
610 root 1.115 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 0);
611 root 1.85
612 root 1.51 SDL_GL_SetAttribute (SDL_GL_ACCUM_RED_SIZE, 0);
613     SDL_GL_SetAttribute (SDL_GL_ACCUM_GREEN_SIZE, 0);
614     SDL_GL_SetAttribute (SDL_GL_ACCUM_BLUE_SIZE, 0);
615     SDL_GL_SetAttribute (SDL_GL_ACCUM_ALPHA_SIZE, 0);
616    
617     SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
618 root 1.134 #if SDL_VERSION_ATLEAST(1,2,10)
619 root 1.131 SDL_GL_SetAttribute (SDL_GL_ACCELERATED_VISUAL, 1);
620     SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
621 root 1.134 #endif
622 root 1.51
623 root 1.53 SDL_EnableUNICODE (1);
624     SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
625    
626 root 1.51 m = SDL_ListModes (0, SDL_FULLSCREEN | SDL_OPENGL);
627    
628     if (m && m != (SDL_Rect **)-1)
629     while (*m)
630     {
631     AV *av = newAV ();
632     av_push (av, newSViv ((*m)->w));
633     av_push (av, newSViv ((*m)->h));
634     XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
635    
636     ++m;
637     }
638     }
639    
640 root 1.88 char *
641     SDL_GetError ()
642    
643 root 1.51 int
644     SDL_SetVideoMode (int w, int h, int fullscreen)
645     CODE:
646     RETVAL = !!SDL_SetVideoMode (
647     w, h, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)
648     );
649 root 1.103 if (RETVAL)
650     {
651 root 1.188 av_clear (texture_av);
652    
653 root 1.103 SDL_WM_SetCaption ("Crossfire+ Client " VERSION, "Crossfire+");
654     # define GL_FUNC(ptr,name) gl.name = (ptr)SDL_GL_GetProcAddress ("gl" # name);
655     # include "glfunc.h"
656     # undef GL_FUNC
657 root 1.188
658 root 1.103 }
659 root 1.51 OUTPUT:
660     RETVAL
661    
662 root 1.53 void
663 root 1.54 SDL_GL_SwapBuffers ()
664    
665 root 1.94 char *
666     SDL_GetKeyName (int sym)
667    
668 root 1.54 void
669 root 1.197 poll_events ()
670 root 1.53 PPCODE:
671     {
672     SDL_Event ev;
673    
674 root 1.197 SDL_PumpEvents ();
675     while (SDL_PeepEvents (&ev, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0)
676 root 1.53 {
677     HV *hv = newHV ();
678     hv_store (hv, "type", 4, newSViv (ev.type), 0);
679 root 1.70
680 root 1.53 switch (ev.type)
681     {
682     case SDL_KEYDOWN:
683     case SDL_KEYUP:
684     hv_store (hv, "state", 5, newSViv (ev.key.state), 0);
685     hv_store (hv, "sym", 3, newSViv (ev.key.keysym.sym), 0);
686     hv_store (hv, "mod", 3, newSViv (ev.key.keysym.mod), 0);
687 root 1.167 hv_store (hv, "cmod", 4, newSViv (SDL_GetModState ()), 0); /* current mode */
688 root 1.53 hv_store (hv, "unicode", 7, newSViv (ev.key.keysym.unicode), 0);
689     break;
690    
691     case SDL_ACTIVEEVENT:
692     hv_store (hv, "gain", 4, newSViv (ev.active.gain), 0);
693     hv_store (hv, "state", 5, newSViv (ev.active.state), 0);
694     break;
695    
696     case SDL_MOUSEMOTION:
697 root 1.196 {
698     int state = ev.motion.state;
699     int x = ev.motion.x;
700     int y = ev.motion.y;
701     int xrel = ev.motion.xrel;
702     int yrel = ev.motion.yrel;
703    
704     /* do simplistic event compression */
705     while (SDL_PeepEvents (&ev, 1, SDL_PEEKEVENT, SDL_EVENTMASK (SDL_MOUSEMOTION)) > 0
706     && state == ev.motion.state)
707     {
708     xrel += ev.motion.xrel;
709     yrel += ev.motion.yrel;
710     x = ev.motion.x;
711     y = ev.motion.y;
712     SDL_PeepEvents (&ev, 1, SDL_GETEVENT, SDL_EVENTMASK (SDL_MOUSEMOTION));
713     }
714 root 1.93
715 root 1.196 hv_store (hv, "mod", 3, newSViv (SDL_GetModState ()), 0);
716     hv_store (hv, "state", 5, newSViv (state), 0);
717     hv_store (hv, "x", 1, newSViv (x), 0);
718     hv_store (hv, "y", 1, newSViv (y), 0);
719     hv_store (hv, "xrel", 4, newSViv (xrel), 0);
720     hv_store (hv, "yrel", 4, newSViv (yrel), 0);
721     }
722 root 1.53 break;
723    
724     case SDL_MOUSEBUTTONDOWN:
725     case SDL_MOUSEBUTTONUP:
726 root 1.94 hv_store (hv, "mod", 3, newSViv (SDL_GetModState ()), 0);
727 root 1.93
728 root 1.53 hv_store (hv, "button", 6, newSViv (ev.button.button), 0);
729     hv_store (hv, "state", 5, newSViv (ev.button.state), 0);
730     hv_store (hv, "x", 1, newSViv (ev.button.x), 0);
731     hv_store (hv, "y", 1, newSViv (ev.button.y), 0);
732 root 1.70 break;
733 root 1.72
734     case SDL_USEREVENT:
735     hv_store (hv, "code", 4, newSViv (ev.user.code), 0);
736     hv_store (hv, "data1", 5, newSViv ((IV)ev.user.data1), 0);
737     hv_store (hv, "data2", 5, newSViv ((IV)ev.user.data2), 0);
738     break;
739 root 1.53 }
740    
741 root 1.133 XPUSHs (sv_2mortal (sv_bless (newRV_noinc ((SV *)hv), gv_stashpv ("CFPlus::UI::Event", 1))));
742 root 1.53 }
743     }
744 root 1.52
745     int
746 root 1.73 Mix_OpenAudio (int frequency = 48000, int format = MIX_DEFAULT_FORMAT, int channels = 1, int chunksize = 2048)
747 root 1.56 POSTCALL:
748     Mix_HookMusicFinished (music_finished);
749 root 1.71 Mix_ChannelFinished (channel_finished);
750 root 1.52
751     void
752     Mix_CloseAudio ()
753    
754     int
755     Mix_AllocateChannels (int numchans = -1)
756    
757 root 1.10 void
758     lowdelay (int fd, int val = 1)
759     CODE:
760 root 1.179 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&val, sizeof (val));
761 root 1.10
762 root 1.5 void
763 root 1.157 win32_proxy_info ()
764     PPCODE:
765     {
766     #ifdef _WIN32
767     char buffer[2048];
768     DWORD buflen;
769    
770     EXTEND (SP, 3);
771    
772     buflen = sizeof (buffer);
773     if (InternetQueryOption (0, INTERNET_OPTION_PROXY, (void *)buffer, &buflen))
774     if (((INTERNET_PROXY_INFO *)buffer)->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
775     {
776     PUSHs (newSVpv (((INTERNET_PROXY_INFO *)buffer)->lpszProxy, 0));
777    
778     buflen = sizeof (buffer);
779     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_USERNAME, (void *)buffer, &buflen))
780     {
781     PUSHs (newSVpv (buffer, 0));
782    
783     buflen = sizeof (buffer);
784     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_PASSWORD, (void *)buffer, &buflen))
785     PUSHs (newSVpv (buffer, 0));
786     }
787     }
788     #endif
789     }
790    
791     void
792 root 1.13 add_font (char *file)
793     CODE:
794 root 1.129 FcConfigAppFontAddFile (0, (const FcChar8 *)file);
795 root 1.13
796     void
797 root 1.23 load_image_inline (SV *image_)
798     ALIAS:
799     load_image_file = 1
800     PPCODE:
801     {
802     STRLEN image_len;
803     char *image = (char *)SvPVbyte (image_, image_len);
804     SDL_Surface *surface, *surface2;
805     SDL_PixelFormat fmt;
806     SDL_RWops *rw = ix
807     ? SDL_RWFromFile (image, "r")
808     : SDL_RWFromConstMem (image, image_len);
809    
810     if (!rw)
811 root 1.41 croak ("load_image: %s", SDL_GetError ());
812 root 1.23
813     surface = IMG_Load_RW (rw, 1);
814     if (!surface)
815 root 1.41 croak ("load_image: %s", SDL_GetError ());
816 root 1.23
817     fmt.palette = NULL;
818     fmt.BitsPerPixel = 32;
819     fmt.BytesPerPixel = 4;
820 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
821 root 1.23 fmt.Rmask = 0x000000ff;
822     fmt.Gmask = 0x0000ff00;
823     fmt.Bmask = 0x00ff0000;
824     fmt.Amask = 0xff000000;
825 root 1.49 #else
826     fmt.Rmask = 0xff000000;
827     fmt.Gmask = 0x00ff0000;
828     fmt.Bmask = 0x0000ff00;
829     fmt.Amask = 0x000000ff;
830     #endif
831 root 1.23 fmt.Rloss = 0;
832     fmt.Gloss = 0;
833     fmt.Bloss = 0;
834     fmt.Aloss = 0;
835     fmt.Rshift = 0;
836     fmt.Gshift = 8;
837     fmt.Bshift = 16;
838     fmt.Ashift = 24;
839     fmt.colorkey = 0;
840     fmt.alpha = 0;
841    
842     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
843    
844 root 1.39 assert (surface2->pitch == surface2->w * 4);
845    
846 root 1.129 SDL_LockSurface (surface2);
847     EXTEND (SP, 6);
848 root 1.23 PUSHs (sv_2mortal (newSViv (surface2->w)));
849     PUSHs (sv_2mortal (newSViv (surface2->h)));
850     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
851 root 1.116 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
852 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
853 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
854 root 1.129 SDL_UnlockSurface (surface2);
855 root 1.23
856     SDL_FreeSurface (surface);
857     SDL_FreeSurface (surface2);
858     }
859    
860 root 1.25 void
861 root 1.39 average (int x, int y, uint32_t *data)
862     PPCODE:
863     {
864     uint32_t r = 0, g = 0, b = 0, a = 0;
865    
866     x = y = x * y;
867    
868     while (x--)
869     {
870     uint32_t p = *data++;
871    
872     r += (p ) & 255;
873     g += (p >> 8) & 255;
874     b += (p >> 16) & 255;
875     a += (p >> 24) & 255;
876     }
877    
878     EXTEND (SP, 4);
879 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
880     PUSHs (sv_2mortal (newSViv (g / y)));
881     PUSHs (sv_2mortal (newSViv (b / y)));
882     PUSHs (sv_2mortal (newSViv (a / y)));
883 root 1.39 }
884    
885     void
886 root 1.66 error (char *message)
887     CODE:
888 root 1.86 fprintf (stderr, "ERROR: %s\n", message);
889 root 1.66 #ifdef _WIN32
890 root 1.86 MessageBox (0, message, "Crossfire+ Error", MB_OK | MB_ICONERROR);
891 root 1.66 #endif
892    
893     void
894 root 1.25 fatal (char *message)
895     CODE:
896 root 1.86 fprintf (stderr, "FATAL: %s\n", message);
897 root 1.50 #ifdef _WIN32
898 root 1.86 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR);
899 root 1.25 #endif
900 root 1.112 _exit (1);
901 root 1.111
902     void
903 root 1.158 _exit (int retval = 0)
904 root 1.111 CODE:
905 root 1.161 #ifdef WIN32
906     ExitThread (retval); // unclean, please beam me up
907     #else
908 root 1.112 _exit (retval);
909 root 1.161 #endif
910 root 1.25
911 root 1.193 void
912     debug ()
913     CODE:
914     {
915     #if DEBUG
916     VALGRIND_DO_LEAK_CHECK;
917     #endif
918     }
919    
920 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Font
921 root 1.61
922 root 1.133 CFPlus::Font
923 root 1.70 new_from_file (SV *class, char *path, int id = 0)
924 root 1.61 CODE:
925     {
926     int count;
927 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
928 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
929     FcPatternDestroy (pattern);
930     }
931     OUTPUT:
932     RETVAL
933    
934     void
935 root 1.133 DESTROY (CFPlus::Font self)
936 root 1.61 CODE:
937     pango_font_description_free (self);
938    
939     void
940 root 1.133 make_default (CFPlus::Font self)
941 root 1.61 CODE:
942     default_font = self;
943    
944 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Layout
945 root 1.14
946 root 1.124 void
947 root 1.129 reset_glyph_cache ()
948 root 1.124 CODE:
949     tc_clear ();
950    
951 root 1.133 CFPlus::Layout
952 root 1.128 new (SV *class)
953 root 1.14 CODE:
954     New (0, RETVAL, 1, struct cf_layout);
955 root 1.76
956 root 1.124 RETVAL->pl = pango_layout_new (opengl_context);
957 root 1.76 RETVAL->r = 1.;
958     RETVAL->g = 1.;
959     RETVAL->b = 1.;
960     RETVAL->a = 1.;
961     RETVAL->base_height = MIN_FONT_HEIGHT;
962     RETVAL->font = 0;
963    
964 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
965 root 1.76 layout_update_font (RETVAL);
966 root 1.14 OUTPUT:
967     RETVAL
968    
969     void
970 root 1.133 DESTROY (CFPlus::Layout self)
971 root 1.14 CODE:
972     g_object_unref (self->pl);
973     Safefree (self);
974 root 1.13
975 root 1.8 void
976 root 1.133 set_text (CFPlus::Layout self, SV *text_)
977 root 1.35 CODE:
978     {
979     STRLEN textlen;
980     char *text = SvPVutf8 (text_, textlen);
981    
982     pango_layout_set_text (self->pl, text, textlen);
983     }
984    
985     void
986 root 1.133 set_markup (CFPlus::Layout self, SV *text_)
987 root 1.14 CODE:
988 root 1.5 {
989     STRLEN textlen;
990     char *text = SvPVutf8 (text_, textlen);
991 root 1.14
992     pango_layout_set_markup (self->pl, text, textlen);
993     }
994    
995 root 1.121 void
996 root 1.133 set_shapes (CFPlus::Layout self, ...)
997 root 1.121 CODE:
998     {
999     PangoAttrList *attrs = 0;
1000     const char *text = pango_layout_get_text (self->pl);
1001     const char *pos = text;
1002 root 1.122 int arg = 4;
1003 root 1.121
1004     while (arg < items && (pos = strstr (pos, OBJ_STR)))
1005     {
1006 root 1.122 PangoRectangle inkrect, rect;
1007 root 1.121 PangoAttribute *attr;
1008    
1009 root 1.122 int x = SvIV (ST (arg - 3));
1010     int y = SvIV (ST (arg - 2));
1011 root 1.121 int w = SvIV (ST (arg - 1));
1012 root 1.122 int h = SvIV (ST (arg ));
1013 root 1.121
1014 root 1.122 inkrect.x = 0;
1015     inkrect.y = 0;
1016     inkrect.width = 0;
1017     inkrect.height = 0;
1018    
1019     rect.x = x * PANGO_SCALE;
1020     rect.y = y * PANGO_SCALE;
1021     rect.width = w * PANGO_SCALE;
1022 root 1.121 rect.height = h * PANGO_SCALE;
1023    
1024     if (!attrs)
1025     attrs = pango_layout_get_attributes (self->pl);
1026    
1027 root 1.122 attr = pango_attr_shape_new (&inkrect, &rect);
1028 root 1.121 attr->start_index = pos - text;
1029     attr->end_index = attr->start_index + sizeof (OBJ_STR) - 1;
1030     pango_attr_list_insert (attrs, attr);
1031    
1032 root 1.122 arg += 4;
1033 root 1.121 pos += sizeof (OBJ_STR) - 1;
1034     }
1035    
1036     if (attrs)
1037     pango_layout_set_attributes (self->pl, attrs);
1038     }
1039    
1040     void
1041 root 1.133 get_shapes (CFPlus::Layout self)
1042 root 1.121 PPCODE:
1043     {
1044     PangoLayoutIter *iter = pango_layout_get_iter (self->pl);
1045    
1046     do
1047     {
1048     PangoLayoutRun *run = pango_layout_iter_get_run (iter);
1049    
1050     if (run && shape_attr_p (run))
1051     {
1052     PangoRectangle extents;
1053     pango_layout_iter_get_run_extents (iter, 0, &extents);
1054    
1055 root 1.129 EXTEND (SP, 2);
1056 root 1.121 PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.x))));
1057     PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.y))));
1058     }
1059     }
1060     while (pango_layout_iter_next_run (iter));
1061    
1062     pango_layout_iter_free (iter);
1063     }
1064    
1065     int
1066 root 1.133 has_wrapped (CFPlus::Layout self)
1067 root 1.121 CODE:
1068     {
1069     int lines = 1;
1070     const char *text = pango_layout_get_text (self->pl);
1071    
1072     while (*text)
1073     lines += *text++ == '\n';
1074    
1075     RETVAL = lines < pango_layout_get_line_count (self->pl);
1076     }
1077     OUTPUT:
1078     RETVAL
1079    
1080 root 1.46 SV *
1081 root 1.133 get_text (CFPlus::Layout self)
1082 root 1.46 CODE:
1083 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
1084 root 1.107 sv_utf8_decode (RETVAL);
1085 root 1.46 OUTPUT:
1086     RETVAL
1087    
1088 root 1.14 void
1089 root 1.133 set_foreground (CFPlus::Layout self, float r, float g, float b, float a = 1.)
1090 root 1.76 CODE:
1091     self->r = r;
1092     self->g = g;
1093     self->b = b;
1094     self->a = a;
1095    
1096     void
1097 root 1.133 set_font (CFPlus::Layout self, CFPlus::Font font = 0)
1098 root 1.61 CODE:
1099     if (self->font != font)
1100     {
1101     self->font = font;
1102     layout_update_font (self);
1103     }
1104    
1105     void
1106 root 1.133 set_height (CFPlus::Layout self, int base_height)
1107 root 1.16 CODE:
1108 root 1.61 if (self->base_height != base_height)
1109     {
1110     self->base_height = base_height;
1111     layout_update_font (self);
1112     }
1113 root 1.16
1114     void
1115 root 1.133 set_width (CFPlus::Layout self, int max_width = -1)
1116 root 1.14 CODE:
1117     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
1118    
1119     void
1120 root 1.133 set_indent (CFPlus::Layout self, int indent)
1121 root 1.84 CODE:
1122     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
1123    
1124     void
1125 root 1.133 set_spacing (CFPlus::Layout self, int spacing)
1126 root 1.84 CODE:
1127     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
1128    
1129     void
1130 root 1.133 set_ellipsise (CFPlus::Layout self, int ellipsise)
1131 root 1.84 CODE:
1132     pango_layout_set_ellipsize (self->pl,
1133     ellipsise == 1 ? PANGO_ELLIPSIZE_START
1134     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
1135     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
1136     : PANGO_ELLIPSIZE_NONE
1137     );
1138    
1139     void
1140 root 1.133 set_single_paragraph_mode (CFPlus::Layout self, int spm)
1141 root 1.84 CODE:
1142     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
1143    
1144     void
1145 root 1.133 size (CFPlus::Layout self)
1146 root 1.14 PPCODE:
1147     {
1148     int w, h;
1149    
1150     layout_get_pixel_size (self, &w, &h);
1151    
1152     EXTEND (SP, 2);
1153     PUSHs (sv_2mortal (newSViv (w)));
1154     PUSHs (sv_2mortal (newSViv (h)));
1155     }
1156    
1157 root 1.17 int
1158 root 1.133 descent (CFPlus::Layout self)
1159 root 1.122 CODE:
1160     {
1161     PangoRectangle rect;
1162     PangoLayoutLine *line = pango_layout_get_line (self->pl, 0);
1163     pango_layout_line_get_pixel_extents (line, 0, &rect);
1164     RETVAL = PANGO_DESCENT (rect);
1165     }
1166     OUTPUT:
1167     RETVAL
1168    
1169     int
1170 root 1.133 xy_to_index (CFPlus::Layout self, int x, int y)
1171 root 1.17 CODE:
1172     {
1173     int index, trailing;
1174     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
1175 root 1.165 RETVAL = index + trailing;
1176 root 1.17 }
1177     OUTPUT:
1178     RETVAL
1179    
1180     void
1181 root 1.133 cursor_pos (CFPlus::Layout self, int index)
1182 root 1.17 PPCODE:
1183     {
1184     PangoRectangle strong_pos;
1185     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
1186 root 1.30
1187 root 1.17 EXTEND (SP, 3);
1188     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
1189     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
1190     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
1191     }
1192    
1193 root 1.14 void
1194 root 1.165 index_to_line_x (CFPlus::Layout self, int index, int trailing = 0)
1195     PPCODE:
1196     {
1197     int line, x;
1198    
1199     pango_layout_index_to_line_x (self->pl, index, trailing, &line, &x);
1200     /* pango bug: line is between 1..numlines, not 0..numlines-1 */
1201    
1202     EXTEND (SP, 2);
1203     PUSHs (sv_2mortal (newSViv (line - 1)));
1204     PUSHs (sv_2mortal (newSViv (x / PANGO_SCALE)));
1205     }
1206    
1207     void
1208     line_x_to_index (CFPlus::Layout self, int line, int x)
1209     PPCODE:
1210     {
1211     PangoLayoutLine *lp;
1212     int index, trailing;
1213    
1214     if (line < 0)
1215     XSRETURN_EMPTY;
1216    
1217     if (!(lp = pango_layout_get_line (self->pl, line)))
1218     XSRETURN_EMPTY; /* do better */
1219    
1220 root 1.166 pango_layout_line_x_to_index (lp, x * PANGO_SCALE, &index, &trailing);
1221 root 1.165
1222     EXTEND (SP, 2);
1223     if (GIMME_V == G_SCALAR)
1224     PUSHs (sv_2mortal (newSViv (index + trailing)));
1225     else
1226     {
1227     PUSHs (sv_2mortal (newSViv (index)));
1228     PUSHs (sv_2mortal (newSViv (trailing)));
1229     }
1230     }
1231    
1232     void
1233 root 1.135 render (CFPlus::Layout self, float x, float y, int flags = 0)
1234 root 1.14 PPCODE:
1235 root 1.124 pango_opengl_render_layout_subpixel (
1236     self->pl,
1237     x * PANGO_SCALE, y * PANGO_SCALE,
1238 root 1.135 self->r, self->g, self->b, self->a,
1239     flags
1240 root 1.124 );
1241 root 1.11
1242 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Texture
1243 root 1.11
1244     void
1245 root 1.113 pad2pot (SV *data_, SV *w_, SV *h_)
1246     CODE:
1247     {
1248     int ow = SvIV (w_);
1249     int oh = SvIV (h_);
1250    
1251     if (ow && oh)
1252     {
1253     int nw = minpot (ow);
1254     int nh = minpot (oh);
1255    
1256     if (nw != ow || nh != oh)
1257     {
1258     if (SvOK (data_))
1259     {
1260     STRLEN datalen;
1261     char *data = SvPVbyte (data_, datalen);
1262     int bpp = datalen / (ow * oh);
1263     SV *result_ = sv_2mortal (newSV (nw * nh * bpp));
1264    
1265     SvPOK_only (result_);
1266     SvCUR_set (result_, nw * nh * bpp);
1267    
1268     memset (SvPVX (result_), 0, nw * nh * bpp);
1269     while (oh--)
1270     memcpy (SvPVX (result_) + oh * nw * bpp, data + oh * ow * bpp, ow * bpp);
1271    
1272     sv_setsv (data_, result_);
1273     }
1274    
1275     sv_setiv (w_, nw);
1276     sv_setiv (h_, nh);
1277     }
1278     }
1279     }
1280    
1281     void
1282 root 1.114 draw_quad (SV *self, float x, float y, float w = 0., float h = 0.)
1283 root 1.12 PROTOTYPE: $$$;$$
1284 root 1.76 ALIAS:
1285     draw_quad_alpha = 1
1286     draw_quad_alpha_premultiplied = 2
1287 root 1.11 CODE:
1288     {
1289 root 1.12 HV *hv = (HV *)SvRV (self);
1290 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
1291     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
1292 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
1293    
1294     if (items < 5)
1295     {
1296 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1297     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1298 root 1.12 }
1299    
1300 root 1.76 if (ix)
1301     {
1302     glEnable (GL_BLEND);
1303 root 1.103
1304     if (ix == 2)
1305     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1306     else
1307     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1308 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1309 root 1.103
1310 root 1.86 glEnable (GL_ALPHA_TEST);
1311     glAlphaFunc (GL_GREATER, 0.01f);
1312 root 1.76 }
1313    
1314 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1315 root 1.76
1316 root 1.12 glBegin (GL_QUADS);
1317 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1318     glTexCoord2f (0, t); glVertex2f (x , y + h);
1319     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1320     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1321 root 1.12 glEnd ();
1322 root 1.76
1323     if (ix)
1324 root 1.86 {
1325     glDisable (GL_ALPHA_TEST);
1326     glDisable (GL_BLEND);
1327     }
1328 root 1.11 }
1329 root 1.28
1330 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Map
1331 root 1.28
1332 root 1.133 CFPlus::Map
1333 root 1.164 new (SV *class)
1334 root 1.28 CODE:
1335     New (0, RETVAL, 1, struct map);
1336 root 1.42 RETVAL->x = 0;
1337     RETVAL->y = 0;
1338 root 1.164 RETVAL->w = 0;
1339     RETVAL->h = 0;
1340 root 1.42 RETVAL->ox = 0;
1341     RETVAL->oy = 0;
1342 root 1.174 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1343     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1344 root 1.28 RETVAL->rows = 0;
1345     RETVAL->row = 0;
1346     OUTPUT:
1347     RETVAL
1348    
1349     void
1350 root 1.133 DESTROY (CFPlus::Map self)
1351 root 1.28 CODE:
1352     {
1353 root 1.30 map_clear (self);
1354 root 1.174 Safefree (self->face2tile);
1355 root 1.111 Safefree (self->tex);
1356 root 1.29 Safefree (self);
1357     }
1358    
1359     void
1360 root 1.164 resize (CFPlus::Map self, int map_width, int map_height)
1361     CODE:
1362     self->w = map_width;
1363     self->h = map_height;
1364    
1365     void
1366 root 1.133 clear (CFPlus::Map self)
1367 root 1.30 CODE:
1368     map_clear (self);
1369    
1370     void
1371 root 1.174 set_tileid (CFPlus::Map self, int face, int tile)
1372 root 1.29 CODE:
1373     {
1374 root 1.174 need_facenum (self, face); self->face2tile [face] = tile;
1375     need_texid (self, tile);
1376 root 1.42 }
1377    
1378     void
1379 root 1.176 set_smooth (CFPlus::Map self, int face, int smooth, int level)
1380     CODE:
1381     {
1382     tileid texid;
1383     maptex *tex;
1384    
1385     if (face < 0 || face >= self->faces)
1386     return;
1387    
1388     if (smooth < 0 || smooth >= self->faces)
1389     return;
1390    
1391     texid = self->face2tile [face];
1392    
1393     if (!texid)
1394     return;
1395    
1396     tex = self->tex + texid;
1397     tex->smoothtile = self->face2tile [smooth];
1398     tex->smoothlevel = level;
1399     }
1400    
1401     void
1402 root 1.133 set_texture (CFPlus::Map self, int texid, int name, int w, int h, float s, float t, int r, int g, int b, int a)
1403 root 1.42 CODE:
1404     {
1405 root 1.174 need_texid (self, texid);
1406 root 1.42
1407 root 1.48 {
1408     maptex *tex = self->tex + texid;
1409 root 1.39
1410 root 1.48 tex->name = name;
1411     tex->w = w;
1412     tex->h = h;
1413     tex->s = s;
1414     tex->t = t;
1415     tex->r = r;
1416     tex->g = g;
1417     tex->b = b;
1418     tex->a = a;
1419     }
1420 root 1.95
1421     // somewhat hackish, but for textures that require it, it really
1422     // improves the look, and most others don't suffer.
1423     glBindTexture (GL_TEXTURE_2D, name);
1424 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1425     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1426     // use uglier nearest interpolation because linear suffers
1427     // from transparent color bleeding and ugly wrapping effects.
1428     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1429 root 1.29 }
1430    
1431 root 1.42 int
1432 root 1.133 ox (CFPlus::Map self)
1433 root 1.42 ALIAS:
1434     oy = 1
1435 root 1.101 x = 2
1436     y = 3
1437 root 1.102 w = 4
1438     h = 5
1439 root 1.42 CODE:
1440     switch (ix)
1441     {
1442     case 0: RETVAL = self->ox; break;
1443     case 1: RETVAL = self->oy; break;
1444 root 1.101 case 2: RETVAL = self->x; break;
1445     case 3: RETVAL = self->y; break;
1446 root 1.102 case 4: RETVAL = self->w; break;
1447     case 5: RETVAL = self->h; break;
1448 root 1.42 }
1449     OUTPUT:
1450     RETVAL
1451    
1452 root 1.29 void
1453 root 1.133 scroll (CFPlus::Map self, int dx, int dy)
1454 root 1.43 CODE:
1455     {
1456 root 1.44 if (dx > 0)
1457 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
1458 root 1.44 else if (dx < 0)
1459 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
1460 root 1.44
1461     if (dy > 0)
1462 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
1463 root 1.44 else if (dy < 0)
1464 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
1465 root 1.43
1466 root 1.44 self->ox += dx; self->x += dx;
1467     self->oy += dy; self->y += dy;
1468 root 1.43
1469     while (self->y < 0)
1470     {
1471     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1472    
1473     self->rows += MAP_EXTEND_Y;
1474     self->y += MAP_EXTEND_Y;
1475     }
1476 root 1.44 }
1477 root 1.43
1478 root 1.44 void
1479 root 1.141 map1a_update (CFPlus::Map self, SV *data_, int extmap)
1480 root 1.44 CODE:
1481     {
1482 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1483     uint8_t *data_end = (uint8_t *)SvEND (data_);
1484 root 1.48 mapcell *cell;
1485     int x, y, flags;
1486 root 1.43
1487 root 1.150 while (data < data_end - 1)
1488 root 1.29 {
1489 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1490 root 1.30
1491 root 1.120 x = self->x + ((flags >> 10) & 63);
1492     y = self->y + ((flags >> 4) & 63);
1493 root 1.29
1494 root 1.48 cell = map_get_cell (self, x, y);
1495 root 1.29
1496     if (flags & 15)
1497     {
1498 root 1.142 if (!cell->darkness)
1499 root 1.29 {
1500 root 1.154 memset (cell, 0, sizeof (*cell));
1501 root 1.142 cell->darkness = 256;
1502 root 1.29 }
1503 root 1.45
1504 root 1.142 //TODO: don't trust server data to be in-range(!)
1505    
1506 root 1.141 if (flags & 8)
1507     {
1508     if (extmap)
1509     {
1510     uint8_t ext, cmd;
1511    
1512     do
1513     {
1514     ext = *data++;
1515 root 1.144 cmd = ext & 0x3f;
1516 root 1.141
1517 root 1.147 if (cmd < 4)
1518 root 1.142 cell->darkness = 255 - ext * 64 + 1;
1519 root 1.147 else if (cmd == 5) // health
1520     {
1521     cell->stat_width = 1;
1522     cell->stat_hp = *data++;
1523     }
1524     else if (cmd == 6) // monster width
1525     cell->stat_width = *data++ + 1;
1526 root 1.169 else if (cmd == 0x47)
1527 root 1.153 {
1528 root 1.182 if (*data == 4)
1529     ; // decode player count
1530 root 1.153
1531     data += *data + 1;
1532     }
1533     else if (cmd == 8) // cell flags
1534     cell->flags = *data++;
1535 root 1.144 else if (ext & 0x40) // unknown, multibyte => skip
1536     data += *data + 1;
1537 root 1.147 else
1538     data++;
1539 root 1.141 }
1540 root 1.147 while (ext & 0x80);
1541 root 1.141 }
1542     else
1543 root 1.142 cell->darkness = *data++ + 1;
1544 root 1.141 }
1545 root 1.29
1546     if (flags & 4)
1547     {
1548 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1549     need_facenum (self, face);
1550     cell->tile [0] = self->face2tile [face];
1551 root 1.29 }
1552    
1553     if (flags & 2)
1554     {
1555 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1556     need_facenum (self, face);
1557     cell->tile [1] = self->face2tile [face];
1558 root 1.29 }
1559    
1560     if (flags & 1)
1561     {
1562 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1563     need_facenum (self, face);
1564     cell->tile [2] = self->face2tile [face];
1565 root 1.29 }
1566     }
1567     else
1568 root 1.155 cell->darkness = 0;
1569 root 1.29 }
1570 root 1.28 }
1571    
1572 root 1.40 SV *
1573 root 1.133 mapmap (CFPlus::Map self, int x0, int y0, int w, int h)
1574 root 1.40 CODE:
1575     {
1576 root 1.55 int x1, x;
1577     int y1, y;
1578 root 1.40 int z;
1579     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1580     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1581    
1582     SvPOK_only (map_sv);
1583     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1584    
1585 root 1.55 x0 += self->x; x1 = x0 + w;
1586     y0 += self->y; y1 = y0 + h;
1587 root 1.40
1588     for (y = y0; y < y1; y++)
1589     {
1590     maprow *row = 0 <= y && y < self->rows
1591     ? self->row + y
1592     : 0;
1593    
1594     for (x = x0; x < x1; x++)
1595     {
1596     int r = 32, g = 32, b = 32, a = 192;
1597    
1598     if (row && row->c0 <= x && x < row->c1)
1599     {
1600     mapcell *cell = row->col + (x - row->c0);
1601    
1602     for (z = 0; z <= 0; z++)
1603     {
1604 root 1.174 maptex tex = self->tex [cell->tile [z]];
1605     int a0 = 255 - tex.a;
1606     int a1 = tex.a;
1607    
1608     r = (r * a0 + tex.r * a1) / 255;
1609     g = (g * a0 + tex.g * a1) / 255;
1610     b = (b * a0 + tex.b * a1) / 255;
1611     a = (a * a0 + tex.a * a1) / 255;
1612 root 1.40 }
1613     }
1614    
1615     *map++ = (r )
1616     | (g << 8)
1617     | (b << 16)
1618     | (a << 24);
1619     }
1620     }
1621    
1622     RETVAL = map_sv;
1623     }
1624     OUTPUT:
1625     RETVAL
1626    
1627 root 1.30 void
1628 root 1.171 draw (CFPlus::Map self, int mx, int my, int sw, int sh, int T)
1629 root 1.116 CODE:
1630 root 1.30 {
1631 root 1.176 HV *smooth = (HV *)sv_2mortal ((SV *)newHV ());
1632     uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level
1633 root 1.178 static uint8_t smooth_max[256][256]; // egad, fats and wasteful on memory (64k)
1634 root 1.176 smooth_key skey;
1635 root 1.48 int x, y, z;
1636     int last_name;
1637    
1638 root 1.176 // thats current max. sorry.
1639     if (sw > 255) sw = 255;
1640     if (sh > 255) sh = 255;
1641    
1642     // clear key, in case of extra padding
1643     memset (&skey, 0, sizeof (skey));
1644    
1645 root 1.30 glColor4ub (255, 255, 255, 255);
1646    
1647 root 1.117 glEnable (GL_BLEND);
1648 root 1.30 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1649     glEnable (GL_TEXTURE_2D);
1650     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1651    
1652 root 1.48 glBegin (GL_QUADS);
1653 root 1.30
1654 root 1.48 last_name = 0;
1655 root 1.30
1656 root 1.164 mx += self->x;
1657     my += self->y;
1658    
1659 root 1.176 // first pass: determine smooth_max
1660     // rather ugly, if you ask me
1661     // could also be stored inside mapcell and updated on change
1662     memset (smooth_max, 0, sizeof (smooth_max));
1663    
1664     for (y = 0; y < sh; y++)
1665     if (0 <= y + my && y + my < self->rows)
1666     {
1667     maprow *row = self->row + (y + my);
1668    
1669     for (x = 0; x < sw; x++)
1670     if (row->c0 <= x + mx && x + mx < row->c1)
1671     {
1672     mapcell *cell = row->col + (x + mx - row->c0);
1673    
1674 root 1.177 smooth_max[x + 1][y + 1] =
1675     MAX (self->tex [cell->tile [0]].smoothlevel,
1676     MAX (self->tex [cell->tile [1]].smoothlevel,
1677     self->tex [cell->tile [2]].smoothlevel));
1678 root 1.176 }
1679     }
1680    
1681     for (z = 0; z <= 2; z++)
1682     {
1683 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
1684    
1685 root 1.176 for (y = 0; y < sh; y++)
1686     if (0 <= y + my && y + my < self->rows)
1687     {
1688     maprow *row = self->row + (y + my);
1689    
1690     for (x = 0; x < sw; x++)
1691     if (row->c0 <= x + mx && x + mx < row->c1)
1692     {
1693     mapcell *cell = row->col + (x + mx - row->c0);
1694     tileid tile = cell->tile [z];
1695    
1696     if (tile)
1697     {
1698     maptex tex = self->tex [tile];
1699     int px = (x + 1) * T - tex.w;
1700     int py = (y + 1) * T - tex.h;
1701    
1702     // suppressing texture state switches here
1703     // is only moderately effective, but worth the extra effort
1704     if (last_name != tex.name)
1705     {
1706     if (!tex.name)
1707     tex = self->tex [2]; /* missing, replace by noface */
1708    
1709     glEnd ();
1710     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1711     glBegin (GL_QUADS);
1712     }
1713    
1714     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1715     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1716     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1717     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1718    
1719     if (cell->flags && z == 2)
1720     {
1721     if (cell->flags & 1)
1722     {
1723     maptex tex = self->tex [1];
1724     int px = x * T + T * 2 / 32;
1725     int py = y * T - T * 6 / 32;
1726    
1727     glEnd ();
1728     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1729     glBegin (GL_QUADS);
1730    
1731     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1732     glTexCoord2f (0 , tex.t); glVertex2f (px , py + T);
1733     glTexCoord2f (tex.s, tex.t); glVertex2f (px + T, py + T);
1734     glTexCoord2f (tex.s, 0 ); glVertex2f (px + T, py );
1735     }
1736     }
1737    
1738     // update smooth hash
1739     if (tex.smoothtile)
1740     {
1741     skey.tile = tex.smoothtile;
1742     skey.level = tex.smoothlevel;
1743    
1744     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
1745 root 1.30
1746 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
1747     // shifted +1|+1 so we always stay positive.
1748 root 1.30
1749 root 1.180 // bits is ___n cccc CCCC bbbb
1750     // n do not draw borders&corners
1751     // c draw these corners, but...
1752     // C ... not these
1753     // b draw these borders
1754    
1755     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
1756     // ┃· ·· ·┃ ━━
1757    
1758     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
1759     // ·· ·· ·┏ ┓·
1760    
1761 root 1.176 // full tile
1762     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
1763    
1764     // borders
1765 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
1766     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
1767 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
1768     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
1769    
1770     // corners
1771     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
1772     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
1773     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
1774     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
1775     }
1776     }
1777     }
1778     }
1779 root 1.174
1780 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
1781     // this is basically counting sort
1782 root 1.176 {
1783 root 1.186 int w, b;
1784 root 1.30
1785 root 1.186 for (w = 0; w < 256 / 32; ++w)
1786     {
1787     uint32_t smask = smooth_level [w];
1788     if (smask)
1789     for (b = 0; b < 32; ++b)
1790     if (smask & (((uint32_t)1) << b))
1791 root 1.176 {
1792 root 1.186 int level = (w << 5) | b;
1793     HE *he;
1794 root 1.153
1795 root 1.186 hv_iterinit (smooth);
1796     while ((he = hv_iternext (smooth)))
1797 root 1.153 {
1798 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
1799     IV bits = SvIVX (HeVAL (he));
1800 root 1.176
1801 root 1.186 if (!(bits & 0x1000)
1802     && skey->level == level
1803 root 1.191 && level > smooth_max [skey->x][skey->y])
1804 root 1.174 {
1805 root 1.186 maptex tex = self->tex [skey->tile];
1806     int px = (((int)skey->x) - 1) * T;
1807     int py = (((int)skey->y) - 1) * T;
1808     int border = bits & 15;
1809     int corner = (bits >> 8) & ~(bits >> 4) & 15;
1810     float dx = tex.s * .0625f; // 16 images/row
1811     float dy = tex.t * .5f ; // 2 images/column
1812    
1813     // this time naively avoiding texture state changes
1814     // save gobs of state changes.
1815     if (last_name != tex.name)
1816     {
1817     if (!tex.name)
1818     continue; // smoothing not yet available
1819    
1820     glEnd ();
1821     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1822     glBegin (GL_QUADS);
1823     }
1824    
1825     if (border)
1826     {
1827     float ox = border * dx;
1828    
1829     glTexCoord2f (ox , 0.f ); glVertex2f (px , py );
1830     glTexCoord2f (ox , dy ); glVertex2f (px , py + T);
1831     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py + T);
1832     glTexCoord2f (ox + dx, 0.f ); glVertex2f (px + T, py );
1833     }
1834    
1835     if (corner)
1836     {
1837     float ox = corner * dx;
1838    
1839     glTexCoord2f (ox , dy ); glVertex2f (px , py );
1840     glTexCoord2f (ox , dy * 2.f); glVertex2f (px , py + T);
1841     glTexCoord2f (ox + dx, dy * 2.f); glVertex2f (px + T, py + T);
1842     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py );
1843     }
1844 root 1.174 }
1845 root 1.153 }
1846     }
1847 root 1.186 }
1848 root 1.176 }
1849    
1850 root 1.186 hv_clear (smooth);
1851     }
1852 root 1.30
1853     glEnd ();
1854 root 1.32
1855 root 1.34 glDisable (GL_TEXTURE_2D);
1856 root 1.152 glDisable (GL_BLEND);
1857 root 1.143
1858 root 1.145 // top layer: overlays such as the health bar
1859 root 1.143 for (y = 0; y < sh; y++)
1860 root 1.164 if (0 <= y + my && y + my < self->rows)
1861 root 1.143 {
1862 root 1.164 maprow *row = self->row + (y + my);
1863 root 1.143
1864     for (x = 0; x < sw; x++)
1865 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
1866 root 1.143 {
1867 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
1868 root 1.143
1869 root 1.171 int px = x * T;
1870     int py = y * T;
1871 root 1.143
1872     if (cell->stat_hp)
1873     {
1874 root 1.171 int width = cell->stat_width * T;
1875 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
1876 root 1.143
1877 root 1.152 glColor3ub (0, 0, 0);
1878 root 1.151 glRectf (px + 1, py - thick - 2,
1879     px + width - 1, py);
1880 root 1.147
1881 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
1882 root 1.147 glRectf (px + 2,
1883 root 1.151 py - thick - 1,
1884     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
1885 root 1.143 }
1886     }
1887     }
1888 root 1.116 }
1889    
1890     void
1891 root 1.133 draw_magicmap (CFPlus::Map self, int dx, int dy, int w, int h, unsigned char *data)
1892 root 1.117 CODE:
1893     {
1894     static float color[16][3] = {
1895 root 1.123 { 0.00F, 0.00F, 0.00F },
1896     { 1.00F, 1.00F, 1.00F },
1897     { 0.00F, 0.00F, 0.55F },
1898     { 1.00F, 0.00F, 0.00F },
1899    
1900     { 1.00F, 0.54F, 0.00F },
1901     { 0.11F, 0.56F, 1.00F },
1902     { 0.93F, 0.46F, 0.00F },
1903     { 0.18F, 0.54F, 0.34F },
1904    
1905     { 0.56F, 0.73F, 0.56F },
1906     { 0.80F, 0.80F, 0.80F },
1907     { 0.55F, 0.41F, 0.13F },
1908     { 0.99F, 0.77F, 0.26F },
1909    
1910     { 0.74F, 0.65F, 0.41F },
1911    
1912     { 0.00F, 1.00F, 1.00F },
1913     { 1.00F, 0.00F, 1.00F },
1914     { 1.00F, 1.00F, 0.00F },
1915 root 1.117 };
1916    
1917     int x, y;
1918    
1919     glEnable (GL_TEXTURE_2D);
1920     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1921     glEnable (GL_BLEND);
1922     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1923     glBegin (GL_QUADS);
1924    
1925     for (y = 0; y < h; y++)
1926     for (x = 0; x < w; x++)
1927     {
1928     unsigned char m = data [x + y * w];
1929    
1930 root 1.118 if (m)
1931     {
1932     float *c = color [m & 15];
1933    
1934     float tx1 = m & 0x40 ? 0.5 : 0.;
1935     float tx2 = tx1 + 0.5;
1936    
1937     glColor4f (c[0], c[1], c[2], 0.75);
1938     glTexCoord2f (tx1, 0.); glVertex2i (x , y );
1939     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
1940     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
1941     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
1942     }
1943 root 1.117 }
1944    
1945     glEnd ();
1946     glDisable (GL_BLEND);
1947     glDisable (GL_TEXTURE_2D);
1948     }
1949    
1950     void
1951 root 1.164 fow_texture (CFPlus::Map self, int mx, int my, int sw, int sh)
1952 root 1.116 PPCODE:
1953     {
1954     int x, y;
1955     int sw4 = (sw + 3) & ~3;
1956     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
1957     uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
1958    
1959     memset (darkness, 255, sw4 * sh);
1960     SvPOK_only (darkness_sv);
1961     SvCUR_set (darkness_sv, sw4 * sh);
1962    
1963 root 1.164 mx += self->x;
1964     my += self->y;
1965 root 1.116
1966     for (y = 0; y < sh; y++)
1967 root 1.164 if (0 <= y + my && y + my < self->rows)
1968 root 1.116 {
1969 root 1.164 maprow *row = self->row + (y + my);
1970 root 1.116
1971     for (x = 0; x < sw; x++)
1972 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
1973 root 1.116 {
1974 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
1975 root 1.116
1976 root 1.142 darkness[y * sw4 + x] = cell->darkness
1977 root 1.143 ? 255 - (cell->darkness - 1)
1978 root 1.142 : 255 - FOW_DARKNESS;
1979 root 1.116 }
1980     }
1981 root 1.34
1982 root 1.32 EXTEND (SP, 3);
1983     PUSHs (sv_2mortal (newSViv (sw4)));
1984     PUSHs (sv_2mortal (newSViv (sh)));
1985     PUSHs (darkness_sv);
1986 root 1.30 }
1987    
1988 root 1.42 SV *
1989 root 1.133 get_rect (CFPlus::Map self, int x0, int y0, int w, int h)
1990 root 1.42 CODE:
1991     {
1992     int x, y, x1, y1;
1993     SV *data_sv = newSV (w * h * 7 + 5);
1994     uint8_t *data = (uint8_t *)SvPVX (data_sv);
1995    
1996     *data++ = 0; /* version 0 format */
1997     *data++ = w >> 8; *data++ = w;
1998     *data++ = h >> 8; *data++ = h;
1999    
2000     // we need to do this 'cause we don't keep an absolute coord system for rows
2001 root 1.55 // TODO: treat rows as we treat columns
2002 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2003     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2004    
2005     x0 += self->x - self->ox;
2006     y0 += self->y - self->oy;
2007    
2008     x1 = x0 + w;
2009     y1 = y0 + h;
2010    
2011     for (y = y0; y < y1; y++)
2012     {
2013     maprow *row = 0 <= y && y < self->rows
2014     ? self->row + y
2015     : 0;
2016    
2017     for (x = x0; x < x1; x++)
2018     {
2019     if (row && row->c0 <= x && x < row->c1)
2020     {
2021     mapcell *cell = row->col + (x - row->c0);
2022     uint8_t flags = 0;
2023    
2024 root 1.174 if (cell->tile [0]) flags |= 1;
2025     if (cell->tile [1]) flags |= 2;
2026     if (cell->tile [2]) flags |= 4;
2027 root 1.42
2028     *data++ = flags;
2029    
2030     if (flags & 1)
2031     {
2032 root 1.174 tileid tile = cell->tile [0];
2033     *data++ = tile >> 8;
2034     *data++ = tile;
2035 root 1.42 }
2036    
2037     if (flags & 2)
2038     {
2039 root 1.174 tileid tile = cell->tile [1];
2040     *data++ = tile >> 8;
2041     *data++ = tile;
2042 root 1.42 }
2043    
2044     if (flags & 4)
2045     {
2046 root 1.174 tileid tile = cell->tile [2];
2047     *data++ = tile >> 8;
2048     *data++ = tile;
2049 root 1.42 }
2050     }
2051     else
2052     *data++ = 0;
2053     }
2054     }
2055    
2056     SvPOK_only (data_sv);
2057     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2058     RETVAL = data_sv;
2059     }
2060     OUTPUT:
2061     RETVAL
2062    
2063     void
2064 root 1.133 set_rect (CFPlus::Map self, int x0, int y0, uint8_t *data)
2065 root 1.42 PPCODE:
2066     {
2067     int x, y, z;
2068 root 1.48 int w, h;
2069 root 1.42 int x1, y1;
2070    
2071     if (*data++ != 0)
2072     return; /* version mismatch */
2073    
2074 root 1.48 w = *data++ << 8; w |= *data++;
2075     h = *data++ << 8; h |= *data++;
2076 root 1.42
2077     // we need to do this 'cause we don't keep an absolute coord system for rows
2078 root 1.55 // TODO: treat rows as we treat columns
2079 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2080     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2081    
2082     x0 += self->x - self->ox;
2083     y0 += self->y - self->oy;
2084    
2085     x1 = x0 + w;
2086     y1 = y0 + h;
2087    
2088     for (y = y0; y < y1; y++)
2089     {
2090     maprow *row = map_get_row (self, y);
2091    
2092     for (x = x0; x < x1; x++)
2093     {
2094     uint8_t flags = *data++;
2095    
2096     if (flags)
2097     {
2098     mapcell *cell = row_get_cell (row, x);
2099 root 1.174 tileid tile[3] = { 0, 0, 0 };
2100 root 1.42
2101 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2102     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2103     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2104 root 1.42
2105 root 1.143 if (cell->darkness == 0)
2106 root 1.42 {
2107 root 1.142 cell->darkness = 0;
2108 root 1.42
2109     for (z = 0; z <= 2; z++)
2110     {
2111 root 1.174 tileid t = tile [z];
2112    
2113 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2114 root 1.174 {
2115     XPUSHs (sv_2mortal (newSViv (t)));
2116     need_texid (self, t);
2117     }
2118 root 1.42
2119 root 1.174 cell->tile [z] = t;
2120 root 1.42 }
2121     }
2122     }
2123     }
2124     }
2125     }
2126    
2127 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixChunk
2128 root 1.52
2129 root 1.133 CFPlus::MixChunk
2130 root 1.52 new_from_file (SV *class, char *path)
2131     CODE:
2132     RETVAL = Mix_LoadWAV (path);
2133     OUTPUT:
2134     RETVAL
2135    
2136     void
2137 root 1.133 DESTROY (CFPlus::MixChunk self)
2138 root 1.52 CODE:
2139     Mix_FreeChunk (self);
2140    
2141     int
2142 root 1.133 volume (CFPlus::MixChunk self, int volume = -1)
2143 root 1.52 CODE:
2144     RETVAL = Mix_VolumeChunk (self, volume);
2145     OUTPUT:
2146     RETVAL
2147    
2148     int
2149 root 1.133 play (CFPlus::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
2150 root 1.52 CODE:
2151     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2152     OUTPUT:
2153     RETVAL
2154    
2155 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixMusic
2156 root 1.52
2157     int
2158     volume (int volume = -1)
2159     CODE:
2160     RETVAL = Mix_VolumeMusic (volume);
2161     OUTPUT:
2162     RETVAL
2163    
2164 root 1.194 int
2165     fade_out (int ms)
2166     CODE:
2167     RETVAL = Mix_FadeOutMusic (ms);
2168     OUTPUT:
2169     RETVAL
2170    
2171 root 1.133 CFPlus::MixMusic
2172 root 1.52 new_from_file (SV *class, char *path)
2173     CODE:
2174     RETVAL = Mix_LoadMUS (path);
2175     OUTPUT:
2176     RETVAL
2177    
2178     void
2179 root 1.133 DESTROY (CFPlus::MixMusic self)
2180 root 1.52 CODE:
2181     Mix_FreeMusic (self);
2182    
2183     int
2184 root 1.133 play (CFPlus::MixMusic self, int loops = -1)
2185 root 1.52 CODE:
2186     RETVAL = Mix_PlayMusic (self, loops);
2187     OUTPUT:
2188     RETVAL
2189    
2190 root 1.195 int
2191     fade_in_pos (CFPlus::MixMusic self, int loops, int ms, double position)
2192     CODE:
2193     RETVAL = Mix_FadeInMusicPos (self, loops, ms, position);
2194     OUTPUT:
2195     RETVAL
2196    
2197 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::OpenGL
2198 root 1.54
2199     BOOT:
2200     {
2201 root 1.133 HV *stash = gv_stashpv ("CFPlus::OpenGL", 1);
2202 root 1.54 static const struct {
2203     const char *name;
2204     IV iv;
2205     } *civ, const_iv[] = {
2206     # define const_iv(name) { # name, (IV)name }
2207     const_iv (GL_COLOR_MATERIAL),
2208     const_iv (GL_SMOOTH),
2209     const_iv (GL_FLAT),
2210 root 1.69 const_iv (GL_DITHER),
2211 root 1.54 const_iv (GL_BLEND),
2212 root 1.89 const_iv (GL_CULL_FACE),
2213 root 1.69 const_iv (GL_SCISSOR_TEST),
2214 root 1.89 const_iv (GL_DEPTH_TEST),
2215     const_iv (GL_ALPHA_TEST),
2216     const_iv (GL_NORMALIZE),
2217     const_iv (GL_RESCALE_NORMAL),
2218 root 1.119 const_iv (GL_FRONT),
2219     const_iv (GL_BACK),
2220 root 1.54 const_iv (GL_AND),
2221 root 1.67 const_iv (GL_ONE),
2222     const_iv (GL_ZERO),
2223 root 1.54 const_iv (GL_SRC_ALPHA),
2224 root 1.104 const_iv (GL_DST_ALPHA),
2225 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2226 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2227 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2228 root 1.54 const_iv (GL_RGB),
2229     const_iv (GL_RGBA),
2230 root 1.115 const_iv (GL_RGBA4),
2231     const_iv (GL_RGBA8),
2232     const_iv (GL_RGB5_A1),
2233 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2234 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2235     const_iv (GL_UNSIGNED_INT),
2236 root 1.54 const_iv (GL_ALPHA),
2237 root 1.86 const_iv (GL_INTENSITY),
2238 root 1.76 const_iv (GL_LUMINANCE),
2239 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2240 root 1.54 const_iv (GL_FLOAT),
2241     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2242     const_iv (GL_COMPILE),
2243     const_iv (GL_TEXTURE_1D),
2244     const_iv (GL_TEXTURE_2D),
2245     const_iv (GL_TEXTURE_ENV),
2246     const_iv (GL_TEXTURE_MAG_FILTER),
2247     const_iv (GL_TEXTURE_MIN_FILTER),
2248     const_iv (GL_TEXTURE_ENV_MODE),
2249     const_iv (GL_TEXTURE_WRAP_S),
2250     const_iv (GL_TEXTURE_WRAP_T),
2251 root 1.98 const_iv (GL_REPEAT),
2252 root 1.54 const_iv (GL_CLAMP),
2253 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2254 root 1.54 const_iv (GL_NEAREST),
2255     const_iv (GL_LINEAR),
2256 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2257     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2258     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2259     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2260     const_iv (GL_GENERATE_MIPMAP),
2261 root 1.54 const_iv (GL_MODULATE),
2262 root 1.69 const_iv (GL_DECAL),
2263 root 1.54 const_iv (GL_REPLACE),
2264 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2265 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2266     const_iv (GL_PROJECTION),
2267     const_iv (GL_MODELVIEW),
2268     const_iv (GL_COLOR_LOGIC_OP),
2269 root 1.69 const_iv (GL_SEPARABLE_2D),
2270 root 1.54 const_iv (GL_CONVOLUTION_2D),
2271     const_iv (GL_CONVOLUTION_BORDER_MODE),
2272     const_iv (GL_CONSTANT_BORDER),
2273     const_iv (GL_LINES),
2274 root 1.138 const_iv (GL_LINE_STRIP),
2275 root 1.89 const_iv (GL_LINE_LOOP),
2276 root 1.54 const_iv (GL_QUADS),
2277 root 1.89 const_iv (GL_QUAD_STRIP),
2278     const_iv (GL_TRIANGLES),
2279     const_iv (GL_TRIANGLE_STRIP),
2280     const_iv (GL_TRIANGLE_FAN),
2281 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2282     const_iv (GL_FASTEST),
2283 root 1.89 const_iv (GL_V2F),
2284     const_iv (GL_V3F),
2285     const_iv (GL_T2F_V3F),
2286     const_iv (GL_T2F_N3F_V3F),
2287 root 1.54 # undef const_iv
2288     };
2289    
2290     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2291     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2292 root 1.188
2293     texture_av = newAV ();
2294     AvREAL_off (texture_av);
2295 root 1.54 }
2296    
2297 root 1.97 char *
2298     gl_vendor ()
2299     CODE:
2300     RETVAL = (char *)glGetString (GL_VENDOR);
2301     OUTPUT:
2302     RETVAL
2303    
2304     char *
2305     gl_version ()
2306     CODE:
2307     RETVAL = (char *)glGetString (GL_VERSION);
2308     OUTPUT:
2309     RETVAL
2310    
2311     char *
2312     gl_extensions ()
2313     CODE:
2314     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2315     OUTPUT:
2316     RETVAL
2317    
2318 root 1.54 int glGetError ()
2319    
2320 root 1.114 void glFinish ()
2321    
2322 root 1.54 void glClear (int mask)
2323    
2324     void glClearColor (float r, float g, float b, float a = 1.0)
2325     PROTOTYPE: @
2326    
2327     void glEnable (int cap)
2328    
2329     void glDisable (int cap)
2330    
2331     void glShadeModel (int mode)
2332    
2333     void glHint (int target, int mode)
2334    
2335     void glBlendFunc (int sfactor, int dfactor)
2336    
2337 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
2338     CODE:
2339     gl_BlendFuncSeparate (sa, da, saa, daa);
2340    
2341 root 1.89 void glDepthMask (int flag)
2342    
2343 root 1.54 void glLogicOp (int opcode)
2344    
2345 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
2346    
2347 root 1.54 void glMatrixMode (int mode)
2348    
2349     void glPushMatrix ()
2350    
2351     void glPopMatrix ()
2352    
2353     void glLoadIdentity ()
2354    
2355 root 1.119 void glDrawBuffer (int buffer)
2356    
2357     void glReadBuffer (int buffer)
2358    
2359 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
2360     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
2361    
2362     # near_ and far_ are due to microsofts buggy "c" compiler
2363 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
2364 root 1.54
2365     void glViewport (int x, int y, int width, int height)
2366    
2367 root 1.69 void glScissor (int x, int y, int width, int height)
2368    
2369 root 1.54 void glTranslate (float x, float y, float z = 0.)
2370     CODE:
2371     glTranslatef (x, y, z);
2372    
2373 root 1.62 void glScale (float x, float y, float z = 1.)
2374 root 1.54 CODE:
2375     glScalef (x, y, z);
2376    
2377     void glRotate (float angle, float x, float y, float z)
2378     CODE:
2379     glRotatef (angle, x, y, z);
2380    
2381     void glBegin (int mode)
2382    
2383     void glEnd ()
2384    
2385     void glColor (float r, float g, float b, float a = 1.0)
2386     PROTOTYPE: @
2387 root 1.103 ALIAS:
2388     glColor_premultiply = 1
2389 root 1.54 CODE:
2390 root 1.103 if (ix)
2391     {
2392     r *= a;
2393     g *= a;
2394     b *= a;
2395     }
2396 root 1.90 // microsoft visual "c" rounds instead of truncating...
2397 root 1.130 glColor4f (r, g, b, a);
2398 root 1.54
2399 root 1.89 void glInterleavedArrays (int format, int stride, char *data)
2400    
2401     void glDrawElements (int mode, int count, int type, char *indices)
2402    
2403     # 1.2 void glDrawRangeElements (int mode, int start, int end
2404    
2405 root 1.91 void glRasterPos (float x, float y, float z = 0.)
2406     CODE:
2407     glRasterPos3f (0, 0, z);
2408     glBitmap (0, 0, 0, 0, x, y, 0);
2409    
2410 root 1.54 void glVertex (float x, float y, float z = 0.)
2411     CODE:
2412     glVertex3f (x, y, z);
2413    
2414     void glTexCoord (float s, float t)
2415     CODE:
2416     glTexCoord2f (s, t);
2417    
2418     void glTexEnv (int target, int pname, float param)
2419     CODE:
2420     glTexEnvf (target, pname, param);
2421    
2422     void glTexParameter (int target, int pname, float param)
2423     CODE:
2424     glTexParameterf (target, pname, param);
2425    
2426     void glBindTexture (int target, int name)
2427    
2428     void glConvolutionParameter (int target, int pname, float params)
2429     CODE:
2430 root 1.103 if (gl.ConvolutionParameterf)
2431     gl.ConvolutionParameterf (target, pname, params);
2432 root 1.54
2433     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
2434 root 1.64 CODE:
2435 root 1.103 if (gl.ConvolutionFilter2D)
2436     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
2437 root 1.54
2438 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
2439     CODE:
2440 root 1.103 if (gl.SeparableFilter2D)
2441     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
2442 root 1.69
2443 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
2444    
2445     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
2446    
2447 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
2448 root 1.68
2449     void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
2450    
2451 root 1.54 int glGenTexture ()
2452     CODE:
2453 root 1.192 RETVAL = gen_texture ();
2454 root 1.54 OUTPUT:
2455     RETVAL
2456    
2457     void glDeleteTexture (int name)
2458     CODE:
2459 root 1.192 del_texture (name);
2460    
2461 root 1.54 int glGenList ()
2462     CODE:
2463     RETVAL = glGenLists (1);
2464     OUTPUT:
2465     RETVAL
2466    
2467     void glDeleteList (int list)
2468     CODE:
2469     glDeleteLists (list, 1);
2470    
2471     void glNewList (int list, int mode = GL_COMPILE)
2472    
2473     void glEndList ()
2474    
2475     void glCallList (int list)
2476