ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.196
Committed: Sun Jul 15 21:02:20 2007 UTC (16 years, 10 months ago) by root
Branch: MAIN
Changes since 1.195: +24 -6 lines
Log Message:
implement very simplistic mouse motion event compression,
fixing a longstanding mysterious problem.

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.53 SDL_PollEvent ()
670     PPCODE:
671     {
672     SDL_Event ev;
673    
674     while (SDL_PollEvent (&ev))
675     {
676     HV *hv = newHV ();
677     hv_store (hv, "type", 4, newSViv (ev.type), 0);
678 root 1.70
679 root 1.53 switch (ev.type)
680     {
681     case SDL_KEYDOWN:
682     case SDL_KEYUP:
683     hv_store (hv, "state", 5, newSViv (ev.key.state), 0);
684     hv_store (hv, "sym", 3, newSViv (ev.key.keysym.sym), 0);
685     hv_store (hv, "mod", 3, newSViv (ev.key.keysym.mod), 0);
686 root 1.167 hv_store (hv, "cmod", 4, newSViv (SDL_GetModState ()), 0); /* current mode */
687 root 1.53 hv_store (hv, "unicode", 7, newSViv (ev.key.keysym.unicode), 0);
688     break;
689    
690     case SDL_ACTIVEEVENT:
691     hv_store (hv, "gain", 4, newSViv (ev.active.gain), 0);
692     hv_store (hv, "state", 5, newSViv (ev.active.state), 0);
693     break;
694    
695     case SDL_MOUSEMOTION:
696 root 1.196 {
697     int state = ev.motion.state;
698     int x = ev.motion.x;
699     int y = ev.motion.y;
700     int xrel = ev.motion.xrel;
701     int yrel = ev.motion.yrel;
702    
703     /* do simplistic event compression */
704     while (SDL_PeepEvents (&ev, 1, SDL_PEEKEVENT, SDL_EVENTMASK (SDL_MOUSEMOTION)) > 0
705     && state == ev.motion.state)
706     {
707     xrel += ev.motion.xrel;
708     yrel += ev.motion.yrel;
709     x = ev.motion.x;
710     y = ev.motion.y;
711     SDL_PeepEvents (&ev, 1, SDL_GETEVENT, SDL_EVENTMASK (SDL_MOUSEMOTION));
712     }
713 root 1.93
714 root 1.196 hv_store (hv, "mod", 3, newSViv (SDL_GetModState ()), 0);
715     hv_store (hv, "state", 5, newSViv (state), 0);
716     hv_store (hv, "x", 1, newSViv (x), 0);
717     hv_store (hv, "y", 1, newSViv (y), 0);
718     hv_store (hv, "xrel", 4, newSViv (xrel), 0);
719     hv_store (hv, "yrel", 4, newSViv (yrel), 0);
720     }
721 root 1.53 break;
722    
723     case SDL_MOUSEBUTTONDOWN:
724     case SDL_MOUSEBUTTONUP:
725 root 1.94 hv_store (hv, "mod", 3, newSViv (SDL_GetModState ()), 0);
726 root 1.93
727 root 1.53 hv_store (hv, "button", 6, newSViv (ev.button.button), 0);
728     hv_store (hv, "state", 5, newSViv (ev.button.state), 0);
729     hv_store (hv, "x", 1, newSViv (ev.button.x), 0);
730     hv_store (hv, "y", 1, newSViv (ev.button.y), 0);
731 root 1.70 break;
732 root 1.72
733     case SDL_USEREVENT:
734     hv_store (hv, "code", 4, newSViv (ev.user.code), 0);
735     hv_store (hv, "data1", 5, newSViv ((IV)ev.user.data1), 0);
736     hv_store (hv, "data2", 5, newSViv ((IV)ev.user.data2), 0);
737     break;
738 root 1.53 }
739    
740 root 1.133 XPUSHs (sv_2mortal (sv_bless (newRV_noinc ((SV *)hv), gv_stashpv ("CFPlus::UI::Event", 1))));
741 root 1.53 }
742     }
743 root 1.52
744     int
745 root 1.73 Mix_OpenAudio (int frequency = 48000, int format = MIX_DEFAULT_FORMAT, int channels = 1, int chunksize = 2048)
746 root 1.56 POSTCALL:
747     Mix_HookMusicFinished (music_finished);
748 root 1.71 Mix_ChannelFinished (channel_finished);
749 root 1.52
750     void
751     Mix_CloseAudio ()
752    
753     int
754     Mix_AllocateChannels (int numchans = -1)
755    
756 root 1.10 void
757     lowdelay (int fd, int val = 1)
758     CODE:
759 root 1.179 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&val, sizeof (val));
760 root 1.10
761 root 1.5 void
762 root 1.157 win32_proxy_info ()
763     PPCODE:
764     {
765     #ifdef _WIN32
766     char buffer[2048];
767     DWORD buflen;
768    
769     EXTEND (SP, 3);
770    
771     buflen = sizeof (buffer);
772     if (InternetQueryOption (0, INTERNET_OPTION_PROXY, (void *)buffer, &buflen))
773     if (((INTERNET_PROXY_INFO *)buffer)->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
774     {
775     PUSHs (newSVpv (((INTERNET_PROXY_INFO *)buffer)->lpszProxy, 0));
776    
777     buflen = sizeof (buffer);
778     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_USERNAME, (void *)buffer, &buflen))
779     {
780     PUSHs (newSVpv (buffer, 0));
781    
782     buflen = sizeof (buffer);
783     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_PASSWORD, (void *)buffer, &buflen))
784     PUSHs (newSVpv (buffer, 0));
785     }
786     }
787     #endif
788     }
789    
790     void
791 root 1.13 add_font (char *file)
792     CODE:
793 root 1.129 FcConfigAppFontAddFile (0, (const FcChar8 *)file);
794 root 1.13
795     void
796 root 1.23 load_image_inline (SV *image_)
797     ALIAS:
798     load_image_file = 1
799     PPCODE:
800     {
801     STRLEN image_len;
802     char *image = (char *)SvPVbyte (image_, image_len);
803     SDL_Surface *surface, *surface2;
804     SDL_PixelFormat fmt;
805     SDL_RWops *rw = ix
806     ? SDL_RWFromFile (image, "r")
807     : SDL_RWFromConstMem (image, image_len);
808    
809     if (!rw)
810 root 1.41 croak ("load_image: %s", SDL_GetError ());
811 root 1.23
812     surface = IMG_Load_RW (rw, 1);
813     if (!surface)
814 root 1.41 croak ("load_image: %s", SDL_GetError ());
815 root 1.23
816     fmt.palette = NULL;
817     fmt.BitsPerPixel = 32;
818     fmt.BytesPerPixel = 4;
819 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
820 root 1.23 fmt.Rmask = 0x000000ff;
821     fmt.Gmask = 0x0000ff00;
822     fmt.Bmask = 0x00ff0000;
823     fmt.Amask = 0xff000000;
824 root 1.49 #else
825     fmt.Rmask = 0xff000000;
826     fmt.Gmask = 0x00ff0000;
827     fmt.Bmask = 0x0000ff00;
828     fmt.Amask = 0x000000ff;
829     #endif
830 root 1.23 fmt.Rloss = 0;
831     fmt.Gloss = 0;
832     fmt.Bloss = 0;
833     fmt.Aloss = 0;
834     fmt.Rshift = 0;
835     fmt.Gshift = 8;
836     fmt.Bshift = 16;
837     fmt.Ashift = 24;
838     fmt.colorkey = 0;
839     fmt.alpha = 0;
840    
841     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
842    
843 root 1.39 assert (surface2->pitch == surface2->w * 4);
844    
845 root 1.129 SDL_LockSurface (surface2);
846     EXTEND (SP, 6);
847 root 1.23 PUSHs (sv_2mortal (newSViv (surface2->w)));
848     PUSHs (sv_2mortal (newSViv (surface2->h)));
849     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
850 root 1.116 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
851 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
852 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
853 root 1.129 SDL_UnlockSurface (surface2);
854 root 1.23
855     SDL_FreeSurface (surface);
856     SDL_FreeSurface (surface2);
857     }
858    
859 root 1.25 void
860 root 1.39 average (int x, int y, uint32_t *data)
861     PPCODE:
862     {
863     uint32_t r = 0, g = 0, b = 0, a = 0;
864    
865     x = y = x * y;
866    
867     while (x--)
868     {
869     uint32_t p = *data++;
870    
871     r += (p ) & 255;
872     g += (p >> 8) & 255;
873     b += (p >> 16) & 255;
874     a += (p >> 24) & 255;
875     }
876    
877     EXTEND (SP, 4);
878 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
879     PUSHs (sv_2mortal (newSViv (g / y)));
880     PUSHs (sv_2mortal (newSViv (b / y)));
881     PUSHs (sv_2mortal (newSViv (a / y)));
882 root 1.39 }
883    
884     void
885 root 1.66 error (char *message)
886     CODE:
887 root 1.86 fprintf (stderr, "ERROR: %s\n", message);
888 root 1.66 #ifdef _WIN32
889 root 1.86 MessageBox (0, message, "Crossfire+ Error", MB_OK | MB_ICONERROR);
890 root 1.66 #endif
891    
892     void
893 root 1.25 fatal (char *message)
894     CODE:
895 root 1.86 fprintf (stderr, "FATAL: %s\n", message);
896 root 1.50 #ifdef _WIN32
897 root 1.86 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR);
898 root 1.25 #endif
899 root 1.112 _exit (1);
900 root 1.111
901     void
902 root 1.158 _exit (int retval = 0)
903 root 1.111 CODE:
904 root 1.161 #ifdef WIN32
905     ExitThread (retval); // unclean, please beam me up
906     #else
907 root 1.112 _exit (retval);
908 root 1.161 #endif
909 root 1.25
910 root 1.193 void
911     debug ()
912     CODE:
913     {
914     #if DEBUG
915     VALGRIND_DO_LEAK_CHECK;
916     #endif
917     }
918    
919 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Font
920 root 1.61
921 root 1.133 CFPlus::Font
922 root 1.70 new_from_file (SV *class, char *path, int id = 0)
923 root 1.61 CODE:
924     {
925     int count;
926 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
927 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
928     FcPatternDestroy (pattern);
929     }
930     OUTPUT:
931     RETVAL
932    
933     void
934 root 1.133 DESTROY (CFPlus::Font self)
935 root 1.61 CODE:
936     pango_font_description_free (self);
937    
938     void
939 root 1.133 make_default (CFPlus::Font self)
940 root 1.61 CODE:
941     default_font = self;
942    
943 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Layout
944 root 1.14
945 root 1.124 void
946 root 1.129 reset_glyph_cache ()
947 root 1.124 CODE:
948     tc_clear ();
949    
950 root 1.133 CFPlus::Layout
951 root 1.128 new (SV *class)
952 root 1.14 CODE:
953     New (0, RETVAL, 1, struct cf_layout);
954 root 1.76
955 root 1.124 RETVAL->pl = pango_layout_new (opengl_context);
956 root 1.76 RETVAL->r = 1.;
957     RETVAL->g = 1.;
958     RETVAL->b = 1.;
959     RETVAL->a = 1.;
960     RETVAL->base_height = MIN_FONT_HEIGHT;
961     RETVAL->font = 0;
962    
963 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
964 root 1.76 layout_update_font (RETVAL);
965 root 1.14 OUTPUT:
966     RETVAL
967    
968     void
969 root 1.133 DESTROY (CFPlus::Layout self)
970 root 1.14 CODE:
971     g_object_unref (self->pl);
972     Safefree (self);
973 root 1.13
974 root 1.8 void
975 root 1.133 set_text (CFPlus::Layout self, SV *text_)
976 root 1.35 CODE:
977     {
978     STRLEN textlen;
979     char *text = SvPVutf8 (text_, textlen);
980    
981     pango_layout_set_text (self->pl, text, textlen);
982     }
983    
984     void
985 root 1.133 set_markup (CFPlus::Layout self, SV *text_)
986 root 1.14 CODE:
987 root 1.5 {
988     STRLEN textlen;
989     char *text = SvPVutf8 (text_, textlen);
990 root 1.14
991     pango_layout_set_markup (self->pl, text, textlen);
992     }
993    
994 root 1.121 void
995 root 1.133 set_shapes (CFPlus::Layout self, ...)
996 root 1.121 CODE:
997     {
998     PangoAttrList *attrs = 0;
999     const char *text = pango_layout_get_text (self->pl);
1000     const char *pos = text;
1001 root 1.122 int arg = 4;
1002 root 1.121
1003     while (arg < items && (pos = strstr (pos, OBJ_STR)))
1004     {
1005 root 1.122 PangoRectangle inkrect, rect;
1006 root 1.121 PangoAttribute *attr;
1007    
1008 root 1.122 int x = SvIV (ST (arg - 3));
1009     int y = SvIV (ST (arg - 2));
1010 root 1.121 int w = SvIV (ST (arg - 1));
1011 root 1.122 int h = SvIV (ST (arg ));
1012 root 1.121
1013 root 1.122 inkrect.x = 0;
1014     inkrect.y = 0;
1015     inkrect.width = 0;
1016     inkrect.height = 0;
1017    
1018     rect.x = x * PANGO_SCALE;
1019     rect.y = y * PANGO_SCALE;
1020     rect.width = w * PANGO_SCALE;
1021 root 1.121 rect.height = h * PANGO_SCALE;
1022    
1023     if (!attrs)
1024     attrs = pango_layout_get_attributes (self->pl);
1025    
1026 root 1.122 attr = pango_attr_shape_new (&inkrect, &rect);
1027 root 1.121 attr->start_index = pos - text;
1028     attr->end_index = attr->start_index + sizeof (OBJ_STR) - 1;
1029     pango_attr_list_insert (attrs, attr);
1030    
1031 root 1.122 arg += 4;
1032 root 1.121 pos += sizeof (OBJ_STR) - 1;
1033     }
1034    
1035     if (attrs)
1036     pango_layout_set_attributes (self->pl, attrs);
1037     }
1038    
1039     void
1040 root 1.133 get_shapes (CFPlus::Layout self)
1041 root 1.121 PPCODE:
1042     {
1043     PangoLayoutIter *iter = pango_layout_get_iter (self->pl);
1044    
1045     do
1046     {
1047     PangoLayoutRun *run = pango_layout_iter_get_run (iter);
1048    
1049     if (run && shape_attr_p (run))
1050     {
1051     PangoRectangle extents;
1052     pango_layout_iter_get_run_extents (iter, 0, &extents);
1053    
1054 root 1.129 EXTEND (SP, 2);
1055 root 1.121 PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.x))));
1056     PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.y))));
1057     }
1058     }
1059     while (pango_layout_iter_next_run (iter));
1060    
1061     pango_layout_iter_free (iter);
1062     }
1063    
1064     int
1065 root 1.133 has_wrapped (CFPlus::Layout self)
1066 root 1.121 CODE:
1067     {
1068     int lines = 1;
1069     const char *text = pango_layout_get_text (self->pl);
1070    
1071     while (*text)
1072     lines += *text++ == '\n';
1073    
1074     RETVAL = lines < pango_layout_get_line_count (self->pl);
1075     }
1076     OUTPUT:
1077     RETVAL
1078    
1079 root 1.46 SV *
1080 root 1.133 get_text (CFPlus::Layout self)
1081 root 1.46 CODE:
1082 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
1083 root 1.107 sv_utf8_decode (RETVAL);
1084 root 1.46 OUTPUT:
1085     RETVAL
1086    
1087 root 1.14 void
1088 root 1.133 set_foreground (CFPlus::Layout self, float r, float g, float b, float a = 1.)
1089 root 1.76 CODE:
1090     self->r = r;
1091     self->g = g;
1092     self->b = b;
1093     self->a = a;
1094    
1095     void
1096 root 1.133 set_font (CFPlus::Layout self, CFPlus::Font font = 0)
1097 root 1.61 CODE:
1098     if (self->font != font)
1099     {
1100     self->font = font;
1101     layout_update_font (self);
1102     }
1103    
1104     void
1105 root 1.133 set_height (CFPlus::Layout self, int base_height)
1106 root 1.16 CODE:
1107 root 1.61 if (self->base_height != base_height)
1108     {
1109     self->base_height = base_height;
1110     layout_update_font (self);
1111     }
1112 root 1.16
1113     void
1114 root 1.133 set_width (CFPlus::Layout self, int max_width = -1)
1115 root 1.14 CODE:
1116     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
1117    
1118     void
1119 root 1.133 set_indent (CFPlus::Layout self, int indent)
1120 root 1.84 CODE:
1121     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
1122    
1123     void
1124 root 1.133 set_spacing (CFPlus::Layout self, int spacing)
1125 root 1.84 CODE:
1126     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
1127    
1128     void
1129 root 1.133 set_ellipsise (CFPlus::Layout self, int ellipsise)
1130 root 1.84 CODE:
1131     pango_layout_set_ellipsize (self->pl,
1132     ellipsise == 1 ? PANGO_ELLIPSIZE_START
1133     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
1134     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
1135     : PANGO_ELLIPSIZE_NONE
1136     );
1137    
1138     void
1139 root 1.133 set_single_paragraph_mode (CFPlus::Layout self, int spm)
1140 root 1.84 CODE:
1141     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
1142    
1143     void
1144 root 1.133 size (CFPlus::Layout self)
1145 root 1.14 PPCODE:
1146     {
1147     int w, h;
1148    
1149     layout_get_pixel_size (self, &w, &h);
1150    
1151     EXTEND (SP, 2);
1152     PUSHs (sv_2mortal (newSViv (w)));
1153     PUSHs (sv_2mortal (newSViv (h)));
1154     }
1155    
1156 root 1.17 int
1157 root 1.133 descent (CFPlus::Layout self)
1158 root 1.122 CODE:
1159     {
1160     PangoRectangle rect;
1161     PangoLayoutLine *line = pango_layout_get_line (self->pl, 0);
1162     pango_layout_line_get_pixel_extents (line, 0, &rect);
1163     RETVAL = PANGO_DESCENT (rect);
1164     }
1165     OUTPUT:
1166     RETVAL
1167    
1168     int
1169 root 1.133 xy_to_index (CFPlus::Layout self, int x, int y)
1170 root 1.17 CODE:
1171     {
1172     int index, trailing;
1173     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
1174 root 1.165 RETVAL = index + trailing;
1175 root 1.17 }
1176     OUTPUT:
1177     RETVAL
1178    
1179     void
1180 root 1.133 cursor_pos (CFPlus::Layout self, int index)
1181 root 1.17 PPCODE:
1182     {
1183     PangoRectangle strong_pos;
1184     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
1185 root 1.30
1186 root 1.17 EXTEND (SP, 3);
1187     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
1188     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
1189     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
1190     }
1191    
1192 root 1.14 void
1193 root 1.165 index_to_line_x (CFPlus::Layout self, int index, int trailing = 0)
1194     PPCODE:
1195     {
1196     int line, x;
1197    
1198     pango_layout_index_to_line_x (self->pl, index, trailing, &line, &x);
1199     /* pango bug: line is between 1..numlines, not 0..numlines-1 */
1200    
1201     EXTEND (SP, 2);
1202     PUSHs (sv_2mortal (newSViv (line - 1)));
1203     PUSHs (sv_2mortal (newSViv (x / PANGO_SCALE)));
1204     }
1205    
1206     void
1207     line_x_to_index (CFPlus::Layout self, int line, int x)
1208     PPCODE:
1209     {
1210     PangoLayoutLine *lp;
1211     int index, trailing;
1212    
1213     if (line < 0)
1214     XSRETURN_EMPTY;
1215    
1216     if (!(lp = pango_layout_get_line (self->pl, line)))
1217     XSRETURN_EMPTY; /* do better */
1218    
1219 root 1.166 pango_layout_line_x_to_index (lp, x * PANGO_SCALE, &index, &trailing);
1220 root 1.165
1221     EXTEND (SP, 2);
1222     if (GIMME_V == G_SCALAR)
1223     PUSHs (sv_2mortal (newSViv (index + trailing)));
1224     else
1225     {
1226     PUSHs (sv_2mortal (newSViv (index)));
1227     PUSHs (sv_2mortal (newSViv (trailing)));
1228     }
1229     }
1230    
1231     void
1232 root 1.135 render (CFPlus::Layout self, float x, float y, int flags = 0)
1233 root 1.14 PPCODE:
1234 root 1.124 pango_opengl_render_layout_subpixel (
1235     self->pl,
1236     x * PANGO_SCALE, y * PANGO_SCALE,
1237 root 1.135 self->r, self->g, self->b, self->a,
1238     flags
1239 root 1.124 );
1240 root 1.11
1241 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Texture
1242 root 1.11
1243     void
1244 root 1.113 pad2pot (SV *data_, SV *w_, SV *h_)
1245     CODE:
1246     {
1247     int ow = SvIV (w_);
1248     int oh = SvIV (h_);
1249    
1250     if (ow && oh)
1251     {
1252     int nw = minpot (ow);
1253     int nh = minpot (oh);
1254    
1255     if (nw != ow || nh != oh)
1256     {
1257     if (SvOK (data_))
1258     {
1259     STRLEN datalen;
1260     char *data = SvPVbyte (data_, datalen);
1261     int bpp = datalen / (ow * oh);
1262     SV *result_ = sv_2mortal (newSV (nw * nh * bpp));
1263    
1264     SvPOK_only (result_);
1265     SvCUR_set (result_, nw * nh * bpp);
1266    
1267     memset (SvPVX (result_), 0, nw * nh * bpp);
1268     while (oh--)
1269     memcpy (SvPVX (result_) + oh * nw * bpp, data + oh * ow * bpp, ow * bpp);
1270    
1271     sv_setsv (data_, result_);
1272     }
1273    
1274     sv_setiv (w_, nw);
1275     sv_setiv (h_, nh);
1276     }
1277     }
1278     }
1279    
1280     void
1281 root 1.114 draw_quad (SV *self, float x, float y, float w = 0., float h = 0.)
1282 root 1.12 PROTOTYPE: $$$;$$
1283 root 1.76 ALIAS:
1284     draw_quad_alpha = 1
1285     draw_quad_alpha_premultiplied = 2
1286 root 1.11 CODE:
1287     {
1288 root 1.12 HV *hv = (HV *)SvRV (self);
1289 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
1290     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
1291 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
1292    
1293     if (items < 5)
1294     {
1295 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1296     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1297 root 1.12 }
1298    
1299 root 1.76 if (ix)
1300     {
1301     glEnable (GL_BLEND);
1302 root 1.103
1303     if (ix == 2)
1304     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1305     else
1306     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1307 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1308 root 1.103
1309 root 1.86 glEnable (GL_ALPHA_TEST);
1310     glAlphaFunc (GL_GREATER, 0.01f);
1311 root 1.76 }
1312    
1313 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1314 root 1.76
1315 root 1.12 glBegin (GL_QUADS);
1316 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1317     glTexCoord2f (0, t); glVertex2f (x , y + h);
1318     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1319     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1320 root 1.12 glEnd ();
1321 root 1.76
1322     if (ix)
1323 root 1.86 {
1324     glDisable (GL_ALPHA_TEST);
1325     glDisable (GL_BLEND);
1326     }
1327 root 1.11 }
1328 root 1.28
1329 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Map
1330 root 1.28
1331 root 1.133 CFPlus::Map
1332 root 1.164 new (SV *class)
1333 root 1.28 CODE:
1334     New (0, RETVAL, 1, struct map);
1335 root 1.42 RETVAL->x = 0;
1336     RETVAL->y = 0;
1337 root 1.164 RETVAL->w = 0;
1338     RETVAL->h = 0;
1339 root 1.42 RETVAL->ox = 0;
1340     RETVAL->oy = 0;
1341 root 1.174 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1342     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1343 root 1.28 RETVAL->rows = 0;
1344     RETVAL->row = 0;
1345     OUTPUT:
1346     RETVAL
1347    
1348     void
1349 root 1.133 DESTROY (CFPlus::Map self)
1350 root 1.28 CODE:
1351     {
1352 root 1.30 map_clear (self);
1353 root 1.174 Safefree (self->face2tile);
1354 root 1.111 Safefree (self->tex);
1355 root 1.29 Safefree (self);
1356     }
1357    
1358     void
1359 root 1.164 resize (CFPlus::Map self, int map_width, int map_height)
1360     CODE:
1361     self->w = map_width;
1362     self->h = map_height;
1363    
1364     void
1365 root 1.133 clear (CFPlus::Map self)
1366 root 1.30 CODE:
1367     map_clear (self);
1368    
1369     void
1370 root 1.174 set_tileid (CFPlus::Map self, int face, int tile)
1371 root 1.29 CODE:
1372     {
1373 root 1.174 need_facenum (self, face); self->face2tile [face] = tile;
1374     need_texid (self, tile);
1375 root 1.42 }
1376    
1377     void
1378 root 1.176 set_smooth (CFPlus::Map self, int face, int smooth, int level)
1379     CODE:
1380     {
1381     tileid texid;
1382     maptex *tex;
1383    
1384     if (face < 0 || face >= self->faces)
1385     return;
1386    
1387     if (smooth < 0 || smooth >= self->faces)
1388     return;
1389    
1390     texid = self->face2tile [face];
1391    
1392     if (!texid)
1393     return;
1394    
1395     tex = self->tex + texid;
1396     tex->smoothtile = self->face2tile [smooth];
1397     tex->smoothlevel = level;
1398     }
1399    
1400     void
1401 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)
1402 root 1.42 CODE:
1403     {
1404 root 1.174 need_texid (self, texid);
1405 root 1.42
1406 root 1.48 {
1407     maptex *tex = self->tex + texid;
1408 root 1.39
1409 root 1.48 tex->name = name;
1410     tex->w = w;
1411     tex->h = h;
1412     tex->s = s;
1413     tex->t = t;
1414     tex->r = r;
1415     tex->g = g;
1416     tex->b = b;
1417     tex->a = a;
1418     }
1419 root 1.95
1420     // somewhat hackish, but for textures that require it, it really
1421     // improves the look, and most others don't suffer.
1422     glBindTexture (GL_TEXTURE_2D, name);
1423 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1424     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1425     // use uglier nearest interpolation because linear suffers
1426     // from transparent color bleeding and ugly wrapping effects.
1427     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1428 root 1.29 }
1429    
1430 root 1.42 int
1431 root 1.133 ox (CFPlus::Map self)
1432 root 1.42 ALIAS:
1433     oy = 1
1434 root 1.101 x = 2
1435     y = 3
1436 root 1.102 w = 4
1437     h = 5
1438 root 1.42 CODE:
1439     switch (ix)
1440     {
1441     case 0: RETVAL = self->ox; break;
1442     case 1: RETVAL = self->oy; break;
1443 root 1.101 case 2: RETVAL = self->x; break;
1444     case 3: RETVAL = self->y; break;
1445 root 1.102 case 4: RETVAL = self->w; break;
1446     case 5: RETVAL = self->h; break;
1447 root 1.42 }
1448     OUTPUT:
1449     RETVAL
1450    
1451 root 1.29 void
1452 root 1.133 scroll (CFPlus::Map self, int dx, int dy)
1453 root 1.43 CODE:
1454     {
1455 root 1.44 if (dx > 0)
1456 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
1457 root 1.44 else if (dx < 0)
1458 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
1459 root 1.44
1460     if (dy > 0)
1461 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
1462 root 1.44 else if (dy < 0)
1463 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
1464 root 1.43
1465 root 1.44 self->ox += dx; self->x += dx;
1466     self->oy += dy; self->y += dy;
1467 root 1.43
1468     while (self->y < 0)
1469     {
1470     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1471    
1472     self->rows += MAP_EXTEND_Y;
1473     self->y += MAP_EXTEND_Y;
1474     }
1475 root 1.44 }
1476 root 1.43
1477 root 1.44 void
1478 root 1.141 map1a_update (CFPlus::Map self, SV *data_, int extmap)
1479 root 1.44 CODE:
1480     {
1481 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1482     uint8_t *data_end = (uint8_t *)SvEND (data_);
1483 root 1.48 mapcell *cell;
1484     int x, y, flags;
1485 root 1.43
1486 root 1.150 while (data < data_end - 1)
1487 root 1.29 {
1488 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1489 root 1.30
1490 root 1.120 x = self->x + ((flags >> 10) & 63);
1491     y = self->y + ((flags >> 4) & 63);
1492 root 1.29
1493 root 1.48 cell = map_get_cell (self, x, y);
1494 root 1.29
1495     if (flags & 15)
1496     {
1497 root 1.142 if (!cell->darkness)
1498 root 1.29 {
1499 root 1.154 memset (cell, 0, sizeof (*cell));
1500 root 1.142 cell->darkness = 256;
1501 root 1.29 }
1502 root 1.45
1503 root 1.142 //TODO: don't trust server data to be in-range(!)
1504    
1505 root 1.141 if (flags & 8)
1506     {
1507     if (extmap)
1508     {
1509     uint8_t ext, cmd;
1510    
1511     do
1512     {
1513     ext = *data++;
1514 root 1.144 cmd = ext & 0x3f;
1515 root 1.141
1516 root 1.147 if (cmd < 4)
1517 root 1.142 cell->darkness = 255 - ext * 64 + 1;
1518 root 1.147 else if (cmd == 5) // health
1519     {
1520     cell->stat_width = 1;
1521     cell->stat_hp = *data++;
1522     }
1523     else if (cmd == 6) // monster width
1524     cell->stat_width = *data++ + 1;
1525 root 1.169 else if (cmd == 0x47)
1526 root 1.153 {
1527 root 1.182 if (*data == 4)
1528     ; // decode player count
1529 root 1.153
1530     data += *data + 1;
1531     }
1532     else if (cmd == 8) // cell flags
1533     cell->flags = *data++;
1534 root 1.144 else if (ext & 0x40) // unknown, multibyte => skip
1535     data += *data + 1;
1536 root 1.147 else
1537     data++;
1538 root 1.141 }
1539 root 1.147 while (ext & 0x80);
1540 root 1.141 }
1541     else
1542 root 1.142 cell->darkness = *data++ + 1;
1543 root 1.141 }
1544 root 1.29
1545     if (flags & 4)
1546     {
1547 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1548     need_facenum (self, face);
1549     cell->tile [0] = self->face2tile [face];
1550 root 1.29 }
1551    
1552     if (flags & 2)
1553     {
1554 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1555     need_facenum (self, face);
1556     cell->tile [1] = self->face2tile [face];
1557 root 1.29 }
1558    
1559     if (flags & 1)
1560     {
1561 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1562     need_facenum (self, face);
1563     cell->tile [2] = self->face2tile [face];
1564 root 1.29 }
1565     }
1566     else
1567 root 1.155 cell->darkness = 0;
1568 root 1.29 }
1569 root 1.28 }
1570    
1571 root 1.40 SV *
1572 root 1.133 mapmap (CFPlus::Map self, int x0, int y0, int w, int h)
1573 root 1.40 CODE:
1574     {
1575 root 1.55 int x1, x;
1576     int y1, y;
1577 root 1.40 int z;
1578     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1579     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1580    
1581     SvPOK_only (map_sv);
1582     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1583    
1584 root 1.55 x0 += self->x; x1 = x0 + w;
1585     y0 += self->y; y1 = y0 + h;
1586 root 1.40
1587     for (y = y0; y < y1; y++)
1588     {
1589     maprow *row = 0 <= y && y < self->rows
1590     ? self->row + y
1591     : 0;
1592    
1593     for (x = x0; x < x1; x++)
1594     {
1595     int r = 32, g = 32, b = 32, a = 192;
1596    
1597     if (row && row->c0 <= x && x < row->c1)
1598     {
1599     mapcell *cell = row->col + (x - row->c0);
1600    
1601     for (z = 0; z <= 0; z++)
1602     {
1603 root 1.174 maptex tex = self->tex [cell->tile [z]];
1604     int a0 = 255 - tex.a;
1605     int a1 = tex.a;
1606    
1607     r = (r * a0 + tex.r * a1) / 255;
1608     g = (g * a0 + tex.g * a1) / 255;
1609     b = (b * a0 + tex.b * a1) / 255;
1610     a = (a * a0 + tex.a * a1) / 255;
1611 root 1.40 }
1612     }
1613    
1614     *map++ = (r )
1615     | (g << 8)
1616     | (b << 16)
1617     | (a << 24);
1618     }
1619     }
1620    
1621     RETVAL = map_sv;
1622     }
1623     OUTPUT:
1624     RETVAL
1625    
1626 root 1.30 void
1627 root 1.171 draw (CFPlus::Map self, int mx, int my, int sw, int sh, int T)
1628 root 1.116 CODE:
1629 root 1.30 {
1630 root 1.176 HV *smooth = (HV *)sv_2mortal ((SV *)newHV ());
1631     uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level
1632 root 1.178 static uint8_t smooth_max[256][256]; // egad, fats and wasteful on memory (64k)
1633 root 1.176 smooth_key skey;
1634 root 1.48 int x, y, z;
1635     int last_name;
1636    
1637 root 1.176 // thats current max. sorry.
1638     if (sw > 255) sw = 255;
1639     if (sh > 255) sh = 255;
1640    
1641     // clear key, in case of extra padding
1642     memset (&skey, 0, sizeof (skey));
1643    
1644 root 1.30 glColor4ub (255, 255, 255, 255);
1645    
1646 root 1.117 glEnable (GL_BLEND);
1647 root 1.30 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1648     glEnable (GL_TEXTURE_2D);
1649     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1650    
1651 root 1.48 glBegin (GL_QUADS);
1652 root 1.30
1653 root 1.48 last_name = 0;
1654 root 1.30
1655 root 1.164 mx += self->x;
1656     my += self->y;
1657    
1658 root 1.176 // first pass: determine smooth_max
1659     // rather ugly, if you ask me
1660     // could also be stored inside mapcell and updated on change
1661     memset (smooth_max, 0, sizeof (smooth_max));
1662    
1663     for (y = 0; y < sh; y++)
1664     if (0 <= y + my && y + my < self->rows)
1665     {
1666     maprow *row = self->row + (y + my);
1667    
1668     for (x = 0; x < sw; x++)
1669     if (row->c0 <= x + mx && x + mx < row->c1)
1670     {
1671     mapcell *cell = row->col + (x + mx - row->c0);
1672    
1673 root 1.177 smooth_max[x + 1][y + 1] =
1674     MAX (self->tex [cell->tile [0]].smoothlevel,
1675     MAX (self->tex [cell->tile [1]].smoothlevel,
1676     self->tex [cell->tile [2]].smoothlevel));
1677 root 1.176 }
1678     }
1679    
1680     for (z = 0; z <= 2; z++)
1681     {
1682 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
1683    
1684 root 1.176 for (y = 0; y < sh; y++)
1685     if (0 <= y + my && y + my < self->rows)
1686     {
1687     maprow *row = self->row + (y + my);
1688    
1689     for (x = 0; x < sw; x++)
1690     if (row->c0 <= x + mx && x + mx < row->c1)
1691     {
1692     mapcell *cell = row->col + (x + mx - row->c0);
1693     tileid tile = cell->tile [z];
1694    
1695     if (tile)
1696     {
1697     maptex tex = self->tex [tile];
1698     int px = (x + 1) * T - tex.w;
1699     int py = (y + 1) * T - tex.h;
1700    
1701     // suppressing texture state switches here
1702     // is only moderately effective, but worth the extra effort
1703     if (last_name != tex.name)
1704     {
1705     if (!tex.name)
1706     tex = self->tex [2]; /* missing, replace by noface */
1707    
1708     glEnd ();
1709     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1710     glBegin (GL_QUADS);
1711     }
1712    
1713     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1714     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1715     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1716     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1717    
1718     if (cell->flags && z == 2)
1719     {
1720     if (cell->flags & 1)
1721     {
1722     maptex tex = self->tex [1];
1723     int px = x * T + T * 2 / 32;
1724     int py = y * T - T * 6 / 32;
1725    
1726     glEnd ();
1727     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1728     glBegin (GL_QUADS);
1729    
1730     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1731     glTexCoord2f (0 , tex.t); glVertex2f (px , py + T);
1732     glTexCoord2f (tex.s, tex.t); glVertex2f (px + T, py + T);
1733     glTexCoord2f (tex.s, 0 ); glVertex2f (px + T, py );
1734     }
1735     }
1736    
1737     // update smooth hash
1738     if (tex.smoothtile)
1739     {
1740     skey.tile = tex.smoothtile;
1741     skey.level = tex.smoothlevel;
1742    
1743     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
1744 root 1.30
1745 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
1746     // shifted +1|+1 so we always stay positive.
1747 root 1.30
1748 root 1.180 // bits is ___n cccc CCCC bbbb
1749     // n do not draw borders&corners
1750     // c draw these corners, but...
1751     // C ... not these
1752     // b draw these borders
1753    
1754     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
1755     // ┃· ·· ·┃ ━━
1756    
1757     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
1758     // ·· ·· ·┏ ┓·
1759    
1760 root 1.176 // full tile
1761     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
1762    
1763     // borders
1764 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
1765     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
1766 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
1767     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
1768    
1769     // corners
1770     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
1771     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
1772     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
1773     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
1774     }
1775     }
1776     }
1777     }
1778 root 1.174
1779 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
1780     // this is basically counting sort
1781 root 1.176 {
1782 root 1.186 int w, b;
1783 root 1.30
1784 root 1.186 for (w = 0; w < 256 / 32; ++w)
1785     {
1786     uint32_t smask = smooth_level [w];
1787     if (smask)
1788     for (b = 0; b < 32; ++b)
1789     if (smask & (((uint32_t)1) << b))
1790 root 1.176 {
1791 root 1.186 int level = (w << 5) | b;
1792     HE *he;
1793 root 1.153
1794 root 1.186 hv_iterinit (smooth);
1795     while ((he = hv_iternext (smooth)))
1796 root 1.153 {
1797 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
1798     IV bits = SvIVX (HeVAL (he));
1799 root 1.176
1800 root 1.186 if (!(bits & 0x1000)
1801     && skey->level == level
1802 root 1.191 && level > smooth_max [skey->x][skey->y])
1803 root 1.174 {
1804 root 1.186 maptex tex = self->tex [skey->tile];
1805     int px = (((int)skey->x) - 1) * T;
1806     int py = (((int)skey->y) - 1) * T;
1807     int border = bits & 15;
1808     int corner = (bits >> 8) & ~(bits >> 4) & 15;
1809     float dx = tex.s * .0625f; // 16 images/row
1810     float dy = tex.t * .5f ; // 2 images/column
1811    
1812     // this time naively avoiding texture state changes
1813     // save gobs of state changes.
1814     if (last_name != tex.name)
1815     {
1816     if (!tex.name)
1817     continue; // smoothing not yet available
1818    
1819     glEnd ();
1820     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1821     glBegin (GL_QUADS);
1822     }
1823    
1824     if (border)
1825     {
1826     float ox = border * dx;
1827    
1828     glTexCoord2f (ox , 0.f ); glVertex2f (px , py );
1829     glTexCoord2f (ox , dy ); glVertex2f (px , py + T);
1830     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py + T);
1831     glTexCoord2f (ox + dx, 0.f ); glVertex2f (px + T, py );
1832     }
1833    
1834     if (corner)
1835     {
1836     float ox = corner * dx;
1837    
1838     glTexCoord2f (ox , dy ); glVertex2f (px , py );
1839     glTexCoord2f (ox , dy * 2.f); glVertex2f (px , py + T);
1840     glTexCoord2f (ox + dx, dy * 2.f); glVertex2f (px + T, py + T);
1841     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py );
1842     }
1843 root 1.174 }
1844 root 1.153 }
1845     }
1846 root 1.186 }
1847 root 1.176 }
1848    
1849 root 1.186 hv_clear (smooth);
1850     }
1851 root 1.30
1852     glEnd ();
1853 root 1.32
1854 root 1.34 glDisable (GL_TEXTURE_2D);
1855 root 1.152 glDisable (GL_BLEND);
1856 root 1.143
1857 root 1.145 // top layer: overlays such as the health bar
1858 root 1.143 for (y = 0; y < sh; y++)
1859 root 1.164 if (0 <= y + my && y + my < self->rows)
1860 root 1.143 {
1861 root 1.164 maprow *row = self->row + (y + my);
1862 root 1.143
1863     for (x = 0; x < sw; x++)
1864 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
1865 root 1.143 {
1866 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
1867 root 1.143
1868 root 1.171 int px = x * T;
1869     int py = y * T;
1870 root 1.143
1871     if (cell->stat_hp)
1872     {
1873 root 1.171 int width = cell->stat_width * T;
1874 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
1875 root 1.143
1876 root 1.152 glColor3ub (0, 0, 0);
1877 root 1.151 glRectf (px + 1, py - thick - 2,
1878     px + width - 1, py);
1879 root 1.147
1880 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
1881 root 1.147 glRectf (px + 2,
1882 root 1.151 py - thick - 1,
1883     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
1884 root 1.143 }
1885     }
1886     }
1887 root 1.116 }
1888    
1889     void
1890 root 1.133 draw_magicmap (CFPlus::Map self, int dx, int dy, int w, int h, unsigned char *data)
1891 root 1.117 CODE:
1892     {
1893     static float color[16][3] = {
1894 root 1.123 { 0.00F, 0.00F, 0.00F },
1895     { 1.00F, 1.00F, 1.00F },
1896     { 0.00F, 0.00F, 0.55F },
1897     { 1.00F, 0.00F, 0.00F },
1898    
1899     { 1.00F, 0.54F, 0.00F },
1900     { 0.11F, 0.56F, 1.00F },
1901     { 0.93F, 0.46F, 0.00F },
1902     { 0.18F, 0.54F, 0.34F },
1903    
1904     { 0.56F, 0.73F, 0.56F },
1905     { 0.80F, 0.80F, 0.80F },
1906     { 0.55F, 0.41F, 0.13F },
1907     { 0.99F, 0.77F, 0.26F },
1908    
1909     { 0.74F, 0.65F, 0.41F },
1910    
1911     { 0.00F, 1.00F, 1.00F },
1912     { 1.00F, 0.00F, 1.00F },
1913     { 1.00F, 1.00F, 0.00F },
1914 root 1.117 };
1915    
1916     int x, y;
1917    
1918     glEnable (GL_TEXTURE_2D);
1919     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1920     glEnable (GL_BLEND);
1921     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1922     glBegin (GL_QUADS);
1923    
1924     for (y = 0; y < h; y++)
1925     for (x = 0; x < w; x++)
1926     {
1927     unsigned char m = data [x + y * w];
1928    
1929 root 1.118 if (m)
1930     {
1931     float *c = color [m & 15];
1932    
1933     float tx1 = m & 0x40 ? 0.5 : 0.;
1934     float tx2 = tx1 + 0.5;
1935    
1936     glColor4f (c[0], c[1], c[2], 0.75);
1937     glTexCoord2f (tx1, 0.); glVertex2i (x , y );
1938     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
1939     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
1940     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
1941     }
1942 root 1.117 }
1943    
1944     glEnd ();
1945     glDisable (GL_BLEND);
1946     glDisable (GL_TEXTURE_2D);
1947     }
1948    
1949     void
1950 root 1.164 fow_texture (CFPlus::Map self, int mx, int my, int sw, int sh)
1951 root 1.116 PPCODE:
1952     {
1953     int x, y;
1954     int sw4 = (sw + 3) & ~3;
1955     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
1956     uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
1957    
1958     memset (darkness, 255, sw4 * sh);
1959     SvPOK_only (darkness_sv);
1960     SvCUR_set (darkness_sv, sw4 * sh);
1961    
1962 root 1.164 mx += self->x;
1963     my += self->y;
1964 root 1.116
1965     for (y = 0; y < sh; y++)
1966 root 1.164 if (0 <= y + my && y + my < self->rows)
1967 root 1.116 {
1968 root 1.164 maprow *row = self->row + (y + my);
1969 root 1.116
1970     for (x = 0; x < sw; x++)
1971 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
1972 root 1.116 {
1973 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
1974 root 1.116
1975 root 1.142 darkness[y * sw4 + x] = cell->darkness
1976 root 1.143 ? 255 - (cell->darkness - 1)
1977 root 1.142 : 255 - FOW_DARKNESS;
1978 root 1.116 }
1979     }
1980 root 1.34
1981 root 1.32 EXTEND (SP, 3);
1982     PUSHs (sv_2mortal (newSViv (sw4)));
1983     PUSHs (sv_2mortal (newSViv (sh)));
1984     PUSHs (darkness_sv);
1985 root 1.30 }
1986    
1987 root 1.42 SV *
1988 root 1.133 get_rect (CFPlus::Map self, int x0, int y0, int w, int h)
1989 root 1.42 CODE:
1990     {
1991     int x, y, x1, y1;
1992     SV *data_sv = newSV (w * h * 7 + 5);
1993     uint8_t *data = (uint8_t *)SvPVX (data_sv);
1994    
1995     *data++ = 0; /* version 0 format */
1996     *data++ = w >> 8; *data++ = w;
1997     *data++ = h >> 8; *data++ = h;
1998    
1999     // we need to do this 'cause we don't keep an absolute coord system for rows
2000 root 1.55 // TODO: treat rows as we treat columns
2001 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2002     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2003    
2004     x0 += self->x - self->ox;
2005     y0 += self->y - self->oy;
2006    
2007     x1 = x0 + w;
2008     y1 = y0 + h;
2009    
2010     for (y = y0; y < y1; y++)
2011     {
2012     maprow *row = 0 <= y && y < self->rows
2013     ? self->row + y
2014     : 0;
2015    
2016     for (x = x0; x < x1; x++)
2017     {
2018     if (row && row->c0 <= x && x < row->c1)
2019     {
2020     mapcell *cell = row->col + (x - row->c0);
2021     uint8_t flags = 0;
2022    
2023 root 1.174 if (cell->tile [0]) flags |= 1;
2024     if (cell->tile [1]) flags |= 2;
2025     if (cell->tile [2]) flags |= 4;
2026 root 1.42
2027     *data++ = flags;
2028    
2029     if (flags & 1)
2030     {
2031 root 1.174 tileid tile = cell->tile [0];
2032     *data++ = tile >> 8;
2033     *data++ = tile;
2034 root 1.42 }
2035    
2036     if (flags & 2)
2037     {
2038 root 1.174 tileid tile = cell->tile [1];
2039     *data++ = tile >> 8;
2040     *data++ = tile;
2041 root 1.42 }
2042    
2043     if (flags & 4)
2044     {
2045 root 1.174 tileid tile = cell->tile [2];
2046     *data++ = tile >> 8;
2047     *data++ = tile;
2048 root 1.42 }
2049     }
2050     else
2051     *data++ = 0;
2052     }
2053     }
2054    
2055     SvPOK_only (data_sv);
2056     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2057     RETVAL = data_sv;
2058     }
2059     OUTPUT:
2060     RETVAL
2061    
2062     void
2063 root 1.133 set_rect (CFPlus::Map self, int x0, int y0, uint8_t *data)
2064 root 1.42 PPCODE:
2065     {
2066     int x, y, z;
2067 root 1.48 int w, h;
2068 root 1.42 int x1, y1;
2069    
2070     if (*data++ != 0)
2071     return; /* version mismatch */
2072    
2073 root 1.48 w = *data++ << 8; w |= *data++;
2074     h = *data++ << 8; h |= *data++;
2075 root 1.42
2076     // we need to do this 'cause we don't keep an absolute coord system for rows
2077 root 1.55 // TODO: treat rows as we treat columns
2078 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2079     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2080    
2081     x0 += self->x - self->ox;
2082     y0 += self->y - self->oy;
2083    
2084     x1 = x0 + w;
2085     y1 = y0 + h;
2086    
2087     for (y = y0; y < y1; y++)
2088     {
2089     maprow *row = map_get_row (self, y);
2090    
2091     for (x = x0; x < x1; x++)
2092     {
2093     uint8_t flags = *data++;
2094    
2095     if (flags)
2096     {
2097     mapcell *cell = row_get_cell (row, x);
2098 root 1.174 tileid tile[3] = { 0, 0, 0 };
2099 root 1.42
2100 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2101     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2102     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2103 root 1.42
2104 root 1.143 if (cell->darkness == 0)
2105 root 1.42 {
2106 root 1.142 cell->darkness = 0;
2107 root 1.42
2108     for (z = 0; z <= 2; z++)
2109     {
2110 root 1.174 tileid t = tile [z];
2111    
2112 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2113 root 1.174 {
2114     XPUSHs (sv_2mortal (newSViv (t)));
2115     need_texid (self, t);
2116     }
2117 root 1.42
2118 root 1.174 cell->tile [z] = t;
2119 root 1.42 }
2120     }
2121     }
2122     }
2123     }
2124     }
2125    
2126 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixChunk
2127 root 1.52
2128 root 1.133 CFPlus::MixChunk
2129 root 1.52 new_from_file (SV *class, char *path)
2130     CODE:
2131     RETVAL = Mix_LoadWAV (path);
2132     OUTPUT:
2133     RETVAL
2134    
2135     void
2136 root 1.133 DESTROY (CFPlus::MixChunk self)
2137 root 1.52 CODE:
2138     Mix_FreeChunk (self);
2139    
2140     int
2141 root 1.133 volume (CFPlus::MixChunk self, int volume = -1)
2142 root 1.52 CODE:
2143     RETVAL = Mix_VolumeChunk (self, volume);
2144     OUTPUT:
2145     RETVAL
2146    
2147     int
2148 root 1.133 play (CFPlus::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
2149 root 1.52 CODE:
2150     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2151     OUTPUT:
2152     RETVAL
2153    
2154 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixMusic
2155 root 1.52
2156     int
2157     volume (int volume = -1)
2158     CODE:
2159     RETVAL = Mix_VolumeMusic (volume);
2160     OUTPUT:
2161     RETVAL
2162    
2163 root 1.194 int
2164     fade_out (int ms)
2165     CODE:
2166     RETVAL = Mix_FadeOutMusic (ms);
2167     OUTPUT:
2168     RETVAL
2169    
2170 root 1.133 CFPlus::MixMusic
2171 root 1.52 new_from_file (SV *class, char *path)
2172     CODE:
2173     RETVAL = Mix_LoadMUS (path);
2174     OUTPUT:
2175     RETVAL
2176    
2177     void
2178 root 1.133 DESTROY (CFPlus::MixMusic self)
2179 root 1.52 CODE:
2180     Mix_FreeMusic (self);
2181    
2182     int
2183 root 1.133 play (CFPlus::MixMusic self, int loops = -1)
2184 root 1.52 CODE:
2185     RETVAL = Mix_PlayMusic (self, loops);
2186     OUTPUT:
2187     RETVAL
2188    
2189 root 1.195 int
2190     fade_in_pos (CFPlus::MixMusic self, int loops, int ms, double position)
2191     CODE:
2192     RETVAL = Mix_FadeInMusicPos (self, loops, ms, position);
2193     OUTPUT:
2194     RETVAL
2195    
2196 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::OpenGL
2197 root 1.54
2198     BOOT:
2199     {
2200 root 1.133 HV *stash = gv_stashpv ("CFPlus::OpenGL", 1);
2201 root 1.54 static const struct {
2202     const char *name;
2203     IV iv;
2204     } *civ, const_iv[] = {
2205     # define const_iv(name) { # name, (IV)name }
2206     const_iv (GL_COLOR_MATERIAL),
2207     const_iv (GL_SMOOTH),
2208     const_iv (GL_FLAT),
2209 root 1.69 const_iv (GL_DITHER),
2210 root 1.54 const_iv (GL_BLEND),
2211 root 1.89 const_iv (GL_CULL_FACE),
2212 root 1.69 const_iv (GL_SCISSOR_TEST),
2213 root 1.89 const_iv (GL_DEPTH_TEST),
2214     const_iv (GL_ALPHA_TEST),
2215     const_iv (GL_NORMALIZE),
2216     const_iv (GL_RESCALE_NORMAL),
2217 root 1.119 const_iv (GL_FRONT),
2218     const_iv (GL_BACK),
2219 root 1.54 const_iv (GL_AND),
2220 root 1.67 const_iv (GL_ONE),
2221     const_iv (GL_ZERO),
2222 root 1.54 const_iv (GL_SRC_ALPHA),
2223 root 1.104 const_iv (GL_DST_ALPHA),
2224 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2225 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2226 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2227 root 1.54 const_iv (GL_RGB),
2228     const_iv (GL_RGBA),
2229 root 1.115 const_iv (GL_RGBA4),
2230     const_iv (GL_RGBA8),
2231     const_iv (GL_RGB5_A1),
2232 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2233 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2234     const_iv (GL_UNSIGNED_INT),
2235 root 1.54 const_iv (GL_ALPHA),
2236 root 1.86 const_iv (GL_INTENSITY),
2237 root 1.76 const_iv (GL_LUMINANCE),
2238 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2239 root 1.54 const_iv (GL_FLOAT),
2240     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2241     const_iv (GL_COMPILE),
2242     const_iv (GL_TEXTURE_1D),
2243     const_iv (GL_TEXTURE_2D),
2244     const_iv (GL_TEXTURE_ENV),
2245     const_iv (GL_TEXTURE_MAG_FILTER),
2246     const_iv (GL_TEXTURE_MIN_FILTER),
2247     const_iv (GL_TEXTURE_ENV_MODE),
2248     const_iv (GL_TEXTURE_WRAP_S),
2249     const_iv (GL_TEXTURE_WRAP_T),
2250 root 1.98 const_iv (GL_REPEAT),
2251 root 1.54 const_iv (GL_CLAMP),
2252 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2253 root 1.54 const_iv (GL_NEAREST),
2254     const_iv (GL_LINEAR),
2255 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2256     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2257     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2258     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2259     const_iv (GL_GENERATE_MIPMAP),
2260 root 1.54 const_iv (GL_MODULATE),
2261 root 1.69 const_iv (GL_DECAL),
2262 root 1.54 const_iv (GL_REPLACE),
2263 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2264 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2265     const_iv (GL_PROJECTION),
2266     const_iv (GL_MODELVIEW),
2267     const_iv (GL_COLOR_LOGIC_OP),
2268 root 1.69 const_iv (GL_SEPARABLE_2D),
2269 root 1.54 const_iv (GL_CONVOLUTION_2D),
2270     const_iv (GL_CONVOLUTION_BORDER_MODE),
2271     const_iv (GL_CONSTANT_BORDER),
2272     const_iv (GL_LINES),
2273 root 1.138 const_iv (GL_LINE_STRIP),
2274 root 1.89 const_iv (GL_LINE_LOOP),
2275 root 1.54 const_iv (GL_QUADS),
2276 root 1.89 const_iv (GL_QUAD_STRIP),
2277     const_iv (GL_TRIANGLES),
2278     const_iv (GL_TRIANGLE_STRIP),
2279     const_iv (GL_TRIANGLE_FAN),
2280 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2281     const_iv (GL_FASTEST),
2282 root 1.89 const_iv (GL_V2F),
2283     const_iv (GL_V3F),
2284     const_iv (GL_T2F_V3F),
2285     const_iv (GL_T2F_N3F_V3F),
2286 root 1.54 # undef const_iv
2287     };
2288    
2289     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2290     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2291 root 1.188
2292     texture_av = newAV ();
2293     AvREAL_off (texture_av);
2294 root 1.54 }
2295    
2296 root 1.97 char *
2297     gl_vendor ()
2298     CODE:
2299     RETVAL = (char *)glGetString (GL_VENDOR);
2300     OUTPUT:
2301     RETVAL
2302    
2303     char *
2304     gl_version ()
2305     CODE:
2306     RETVAL = (char *)glGetString (GL_VERSION);
2307     OUTPUT:
2308     RETVAL
2309    
2310     char *
2311     gl_extensions ()
2312     CODE:
2313     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2314     OUTPUT:
2315     RETVAL
2316    
2317 root 1.54 int glGetError ()
2318    
2319 root 1.114 void glFinish ()
2320    
2321 root 1.54 void glClear (int mask)
2322    
2323     void glClearColor (float r, float g, float b, float a = 1.0)
2324     PROTOTYPE: @
2325    
2326     void glEnable (int cap)
2327    
2328     void glDisable (int cap)
2329    
2330     void glShadeModel (int mode)
2331    
2332     void glHint (int target, int mode)
2333    
2334     void glBlendFunc (int sfactor, int dfactor)
2335    
2336 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
2337     CODE:
2338     gl_BlendFuncSeparate (sa, da, saa, daa);
2339    
2340 root 1.89 void glDepthMask (int flag)
2341    
2342 root 1.54 void glLogicOp (int opcode)
2343    
2344 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
2345    
2346 root 1.54 void glMatrixMode (int mode)
2347    
2348     void glPushMatrix ()
2349    
2350     void glPopMatrix ()
2351    
2352     void glLoadIdentity ()
2353    
2354 root 1.119 void glDrawBuffer (int buffer)
2355    
2356     void glReadBuffer (int buffer)
2357    
2358 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
2359     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
2360    
2361     # near_ and far_ are due to microsofts buggy "c" compiler
2362 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
2363 root 1.54
2364     void glViewport (int x, int y, int width, int height)
2365    
2366 root 1.69 void glScissor (int x, int y, int width, int height)
2367    
2368 root 1.54 void glTranslate (float x, float y, float z = 0.)
2369     CODE:
2370     glTranslatef (x, y, z);
2371    
2372 root 1.62 void glScale (float x, float y, float z = 1.)
2373 root 1.54 CODE:
2374     glScalef (x, y, z);
2375    
2376     void glRotate (float angle, float x, float y, float z)
2377     CODE:
2378     glRotatef (angle, x, y, z);
2379    
2380     void glBegin (int mode)
2381    
2382     void glEnd ()
2383    
2384     void glColor (float r, float g, float b, float a = 1.0)
2385     PROTOTYPE: @
2386 root 1.103 ALIAS:
2387     glColor_premultiply = 1
2388 root 1.54 CODE:
2389 root 1.103 if (ix)
2390     {
2391     r *= a;
2392     g *= a;
2393     b *= a;
2394     }
2395 root 1.90 // microsoft visual "c" rounds instead of truncating...
2396 root 1.130 glColor4f (r, g, b, a);
2397 root 1.54
2398 root 1.89 void glInterleavedArrays (int format, int stride, char *data)
2399    
2400     void glDrawElements (int mode, int count, int type, char *indices)
2401    
2402     # 1.2 void glDrawRangeElements (int mode, int start, int end
2403    
2404 root 1.91 void glRasterPos (float x, float y, float z = 0.)
2405     CODE:
2406     glRasterPos3f (0, 0, z);
2407     glBitmap (0, 0, 0, 0, x, y, 0);
2408    
2409 root 1.54 void glVertex (float x, float y, float z = 0.)
2410     CODE:
2411     glVertex3f (x, y, z);
2412    
2413     void glTexCoord (float s, float t)
2414     CODE:
2415     glTexCoord2f (s, t);
2416    
2417     void glTexEnv (int target, int pname, float param)
2418     CODE:
2419     glTexEnvf (target, pname, param);
2420    
2421     void glTexParameter (int target, int pname, float param)
2422     CODE:
2423     glTexParameterf (target, pname, param);
2424    
2425     void glBindTexture (int target, int name)
2426    
2427     void glConvolutionParameter (int target, int pname, float params)
2428     CODE:
2429 root 1.103 if (gl.ConvolutionParameterf)
2430     gl.ConvolutionParameterf (target, pname, params);
2431 root 1.54
2432     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
2433 root 1.64 CODE:
2434 root 1.103 if (gl.ConvolutionFilter2D)
2435     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
2436 root 1.54
2437 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
2438     CODE:
2439 root 1.103 if (gl.SeparableFilter2D)
2440     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
2441 root 1.69
2442 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
2443    
2444     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
2445    
2446 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
2447 root 1.68
2448     void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
2449    
2450 root 1.54 int glGenTexture ()
2451     CODE:
2452 root 1.192 RETVAL = gen_texture ();
2453 root 1.54 OUTPUT:
2454     RETVAL
2455    
2456     void glDeleteTexture (int name)
2457     CODE:
2458 root 1.192 del_texture (name);
2459    
2460 root 1.54 int glGenList ()
2461     CODE:
2462     RETVAL = glGenLists (1);
2463     OUTPUT:
2464     RETVAL
2465    
2466     void glDeleteList (int list)
2467     CODE:
2468     glDeleteLists (list, 1);
2469    
2470     void glNewList (int list, int mode = GL_COMPILE)
2471    
2472     void glEndList ()
2473    
2474     void glCallList (int list)
2475