ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.180
Committed: Fri Apr 13 18:11:26 2007 UTC (17 years, 1 month ago) by root
Branch: MAIN
Changes since 1.179: +14 -8 lines
Log Message:
doh, that was a longstanding smoothing bug in cfmaps...

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