ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.176
Committed: Tue Apr 10 09:39:48 2007 UTC (17 years, 1 month ago) by root
Branch: MAIN
Changes since 1.175: +232 -45 lines
Log Message:
- first stab at implementing smoothing.
- this works only on 2.x servers but takes no additional bandwidth over the
  additional faces (i.e. the map command is not getting larger,
  unlike the 1.x protocol).
- it is also simpler to implement on the client side (the current implementation
  tries to favour simplicity over efficiency and is a bit ugly, but does work).
- impact on speed is ignored - smoothing should be disabled when fast&ugly,
  because it increases drawing demands a lot.

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