ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.177
Committed: Tue Apr 10 10:13:10 2007 UTC (17 years, 1 month ago) by root
Branch: MAIN
Changes since 1.176: +4 -6 lines
Log Message:
*** empty log message ***

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 root 1.177 smooth_max[x + 1][y + 1] =
1614     MAX (self->tex [cell->tile [0]].smoothlevel,
1615     MAX (self->tex [cell->tile [1]].smoothlevel,
1616     self->tex [cell->tile [2]].smoothlevel));
1617 root 1.176 }
1618     }
1619    
1620     for (z = 0; z <= 2; z++)
1621     {
1622     memset (smooth_level, 0, sizeof (smooth_level));
1623    
1624     for (y = 0; y < sh; y++)
1625     if (0 <= y + my && y + my < self->rows)
1626     {
1627     maprow *row = self->row + (y + my);
1628    
1629     for (x = 0; x < sw; x++)
1630     if (row->c0 <= x + mx && x + mx < row->c1)
1631     {
1632     mapcell *cell = row->col + (x + mx - row->c0);
1633     tileid tile = cell->tile [z];
1634    
1635     if (tile)
1636     {
1637     maptex tex = self->tex [tile];
1638     int px = (x + 1) * T - tex.w;
1639     int py = (y + 1) * T - tex.h;
1640    
1641     // suppressing texture state switches here
1642     // is only moderately effective, but worth the extra effort
1643     if (last_name != tex.name)
1644     {
1645     if (!tex.name)
1646     tex = self->tex [2]; /* missing, replace by noface */
1647    
1648     glEnd ();
1649     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1650     glBegin (GL_QUADS);
1651     }
1652    
1653     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1654     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1655     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1656     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1657    
1658     if (cell->flags && z == 2)
1659     {
1660     if (cell->flags & 1)
1661     {
1662     maptex tex = self->tex [1];
1663     int px = x * T + T * 2 / 32;
1664     int py = y * T - T * 6 / 32;
1665    
1666     glEnd ();
1667     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1668     glBegin (GL_QUADS);
1669    
1670     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1671     glTexCoord2f (0 , tex.t); glVertex2f (px , py + T);
1672     glTexCoord2f (tex.s, tex.t); glVertex2f (px + T, py + T);
1673     glTexCoord2f (tex.s, 0 ); glVertex2f (px + T, py );
1674     }
1675     }
1676    
1677     // update smooth hash
1678     if (tex.smoothtile)
1679     {
1680     skey.tile = tex.smoothtile;
1681     skey.level = tex.smoothlevel;
1682    
1683     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
1684 root 1.30
1685 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
1686     // shifted +1|+1 so we always stay positive.
1687 root 1.30
1688 root 1.176 // full tile
1689     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
1690    
1691     // borders
1692     skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0031);
1693     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0092);
1694     skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
1695     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
1696    
1697     // corners
1698     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
1699     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
1700     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
1701     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
1702     }
1703     }
1704     }
1705     }
1706 root 1.174
1707 root 1.176 // go through all smoothlevels, lowest to highest, then draw
1708     // this is basically counting sort
1709     {
1710     int w, b;
1711 root 1.30
1712 root 1.176 for (w = 0; w < 256 / 32; ++w)
1713     {
1714     uint32_t smask = smooth_level [w];
1715     if (smask)
1716     for (b = 0; b < 32; ++b)
1717     if (smask & (((uint32_t)1) << b))
1718     {
1719     int level = (w << 5) | b;
1720     HE *he;
1721 root 1.153
1722 root 1.176 hv_iterinit (smooth);
1723     while ((he = hv_iternext (smooth)))
1724 root 1.153 {
1725 root 1.176 smooth_key *skey = (smooth_key *)HeKEY (he);
1726     IV bits = SvIVX (HeVAL (he));
1727    
1728     // bits is ___n cccc CCCC bbbb
1729     // n do not draw borders&corners
1730     // c draw these corners, but...
1731     // C ... not these
1732     // b draw these borders
1733    
1734     if (!(bits & 0x1000)
1735     && skey->level == level
1736     && level >= smooth_max [skey->x][skey->y])
1737 root 1.174 {
1738 root 1.176 maptex tex = self->tex [skey->tile];
1739     int px = (((int)skey->x) - 1) * T;
1740     int py = (((int)skey->y) - 1) * T;
1741     int border = bits & 15;
1742     int corner = (bits >> 8) & ~(bits >> 4) & 15;
1743     float dx = tex.s * .0625f; // 16 images/row
1744     float dy = tex.t * .5f ; // 2 images/column
1745    
1746     // this time naively avoiding texture state changes
1747     // save gobs of state changes.
1748     if (last_name != tex.name)
1749     {
1750     if (!tex.name)
1751     continue; // smoothing not yet available
1752    
1753     glEnd ();
1754     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1755     glBegin (GL_QUADS);
1756     }
1757    
1758     if (border)
1759     {
1760     float ox = border * dx;
1761    
1762     glTexCoord2f (ox , 0.f ); glVertex2f (px , py );
1763     glTexCoord2f (ox , dy ); glVertex2f (px , py + T);
1764     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py + T);
1765     glTexCoord2f (ox + dx, 0.f ); glVertex2f (px + T, py );
1766     }
1767    
1768     if (corner)
1769     {
1770     float ox = corner * dx;
1771    
1772     glTexCoord2f (ox , dy ); glVertex2f (px , py );
1773     glTexCoord2f (ox , dy * 2.f); glVertex2f (px , py + T);
1774     glTexCoord2f (ox + dx, dy * 2.f); glVertex2f (px + T, py + T);
1775     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py );
1776     }
1777 root 1.174 }
1778 root 1.153 }
1779     }
1780 root 1.176 }
1781     }
1782    
1783     hv_clear (smooth);
1784     }
1785 root 1.30
1786     glEnd ();
1787 root 1.32
1788 root 1.34 glDisable (GL_TEXTURE_2D);
1789 root 1.152 glDisable (GL_BLEND);
1790 root 1.143
1791 root 1.145 // top layer: overlays such as the health bar
1792 root 1.143 for (y = 0; y < sh; y++)
1793 root 1.164 if (0 <= y + my && y + my < self->rows)
1794 root 1.143 {
1795 root 1.164 maprow *row = self->row + (y + my);
1796 root 1.143
1797     for (x = 0; x < sw; x++)
1798 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
1799 root 1.143 {
1800 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
1801 root 1.143
1802 root 1.171 int px = x * T;
1803     int py = y * T;
1804 root 1.143
1805     if (cell->stat_hp)
1806     {
1807 root 1.171 int width = cell->stat_width * T;
1808 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
1809 root 1.143
1810 root 1.152 glColor3ub (0, 0, 0);
1811 root 1.151 glRectf (px + 1, py - thick - 2,
1812     px + width - 1, py);
1813 root 1.147
1814 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
1815 root 1.147 glRectf (px + 2,
1816 root 1.151 py - thick - 1,
1817     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
1818 root 1.143 }
1819     }
1820     }
1821 root 1.116 }
1822    
1823     void
1824 root 1.133 draw_magicmap (CFPlus::Map self, int dx, int dy, int w, int h, unsigned char *data)
1825 root 1.117 CODE:
1826     {
1827     static float color[16][3] = {
1828 root 1.123 { 0.00F, 0.00F, 0.00F },
1829     { 1.00F, 1.00F, 1.00F },
1830     { 0.00F, 0.00F, 0.55F },
1831     { 1.00F, 0.00F, 0.00F },
1832    
1833     { 1.00F, 0.54F, 0.00F },
1834     { 0.11F, 0.56F, 1.00F },
1835     { 0.93F, 0.46F, 0.00F },
1836     { 0.18F, 0.54F, 0.34F },
1837    
1838     { 0.56F, 0.73F, 0.56F },
1839     { 0.80F, 0.80F, 0.80F },
1840     { 0.55F, 0.41F, 0.13F },
1841     { 0.99F, 0.77F, 0.26F },
1842    
1843     { 0.74F, 0.65F, 0.41F },
1844    
1845     { 0.00F, 1.00F, 1.00F },
1846     { 1.00F, 0.00F, 1.00F },
1847     { 1.00F, 1.00F, 0.00F },
1848 root 1.117 };
1849    
1850     int x, y;
1851    
1852     glEnable (GL_TEXTURE_2D);
1853     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1854     glEnable (GL_BLEND);
1855     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1856     glBegin (GL_QUADS);
1857    
1858     for (y = 0; y < h; y++)
1859     for (x = 0; x < w; x++)
1860     {
1861     unsigned char m = data [x + y * w];
1862    
1863 root 1.118 if (m)
1864     {
1865     float *c = color [m & 15];
1866    
1867     float tx1 = m & 0x40 ? 0.5 : 0.;
1868     float tx2 = tx1 + 0.5;
1869    
1870     glColor4f (c[0], c[1], c[2], 0.75);
1871     glTexCoord2f (tx1, 0.); glVertex2i (x , y );
1872     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
1873     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
1874     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
1875     }
1876 root 1.117 }
1877    
1878     glEnd ();
1879     glDisable (GL_BLEND);
1880     glDisable (GL_TEXTURE_2D);
1881     }
1882    
1883     void
1884 root 1.164 fow_texture (CFPlus::Map self, int mx, int my, int sw, int sh)
1885 root 1.116 PPCODE:
1886     {
1887     int x, y;
1888     int sw4 = (sw + 3) & ~3;
1889     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
1890     uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
1891    
1892     memset (darkness, 255, sw4 * sh);
1893     SvPOK_only (darkness_sv);
1894     SvCUR_set (darkness_sv, sw4 * sh);
1895    
1896 root 1.164 mx += self->x;
1897     my += self->y;
1898 root 1.116
1899     for (y = 0; y < sh; y++)
1900 root 1.164 if (0 <= y + my && y + my < self->rows)
1901 root 1.116 {
1902 root 1.164 maprow *row = self->row + (y + my);
1903 root 1.116
1904     for (x = 0; x < sw; x++)
1905 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
1906 root 1.116 {
1907 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
1908 root 1.116
1909 root 1.142 darkness[y * sw4 + x] = cell->darkness
1910 root 1.143 ? 255 - (cell->darkness - 1)
1911 root 1.142 : 255 - FOW_DARKNESS;
1912 root 1.116 }
1913     }
1914 root 1.34
1915 root 1.32 EXTEND (SP, 3);
1916     PUSHs (sv_2mortal (newSViv (sw4)));
1917     PUSHs (sv_2mortal (newSViv (sh)));
1918     PUSHs (darkness_sv);
1919 root 1.30 }
1920    
1921 root 1.42 SV *
1922 root 1.133 get_rect (CFPlus::Map self, int x0, int y0, int w, int h)
1923 root 1.42 CODE:
1924     {
1925     int x, y, x1, y1;
1926     SV *data_sv = newSV (w * h * 7 + 5);
1927     uint8_t *data = (uint8_t *)SvPVX (data_sv);
1928    
1929     *data++ = 0; /* version 0 format */
1930     *data++ = w >> 8; *data++ = w;
1931     *data++ = h >> 8; *data++ = h;
1932    
1933     // we need to do this 'cause we don't keep an absolute coord system for rows
1934 root 1.55 // TODO: treat rows as we treat columns
1935 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1936     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1937    
1938     x0 += self->x - self->ox;
1939     y0 += self->y - self->oy;
1940    
1941     x1 = x0 + w;
1942     y1 = y0 + h;
1943    
1944     for (y = y0; y < y1; y++)
1945     {
1946     maprow *row = 0 <= y && y < self->rows
1947     ? self->row + y
1948     : 0;
1949    
1950     for (x = x0; x < x1; x++)
1951     {
1952     if (row && row->c0 <= x && x < row->c1)
1953     {
1954     mapcell *cell = row->col + (x - row->c0);
1955     uint8_t flags = 0;
1956    
1957 root 1.174 if (cell->tile [0]) flags |= 1;
1958     if (cell->tile [1]) flags |= 2;
1959     if (cell->tile [2]) flags |= 4;
1960 root 1.42
1961     *data++ = flags;
1962    
1963     if (flags & 1)
1964     {
1965 root 1.174 tileid tile = cell->tile [0];
1966     *data++ = tile >> 8;
1967     *data++ = tile;
1968 root 1.42 }
1969    
1970     if (flags & 2)
1971     {
1972 root 1.174 tileid tile = cell->tile [1];
1973     *data++ = tile >> 8;
1974     *data++ = tile;
1975 root 1.42 }
1976    
1977     if (flags & 4)
1978     {
1979 root 1.174 tileid tile = cell->tile [2];
1980     *data++ = tile >> 8;
1981     *data++ = tile;
1982 root 1.42 }
1983     }
1984     else
1985     *data++ = 0;
1986     }
1987     }
1988    
1989     SvPOK_only (data_sv);
1990     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
1991     RETVAL = data_sv;
1992     }
1993     OUTPUT:
1994     RETVAL
1995    
1996     void
1997 root 1.133 set_rect (CFPlus::Map self, int x0, int y0, uint8_t *data)
1998 root 1.42 PPCODE:
1999     {
2000     int x, y, z;
2001 root 1.48 int w, h;
2002 root 1.42 int x1, y1;
2003    
2004     if (*data++ != 0)
2005     return; /* version mismatch */
2006    
2007 root 1.48 w = *data++ << 8; w |= *data++;
2008     h = *data++ << 8; h |= *data++;
2009 root 1.42
2010     // we need to do this 'cause we don't keep an absolute coord system for rows
2011 root 1.55 // TODO: treat rows as we treat columns
2012 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2013     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2014    
2015     x0 += self->x - self->ox;
2016     y0 += self->y - self->oy;
2017    
2018     x1 = x0 + w;
2019     y1 = y0 + h;
2020    
2021     for (y = y0; y < y1; y++)
2022     {
2023     maprow *row = map_get_row (self, y);
2024    
2025     for (x = x0; x < x1; x++)
2026     {
2027     uint8_t flags = *data++;
2028    
2029     if (flags)
2030     {
2031     mapcell *cell = row_get_cell (row, x);
2032 root 1.174 tileid tile[3] = { 0, 0, 0 };
2033 root 1.42
2034 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2035     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2036     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2037 root 1.42
2038 root 1.143 if (cell->darkness == 0)
2039 root 1.42 {
2040 root 1.142 cell->darkness = 0;
2041 root 1.42
2042     for (z = 0; z <= 2; z++)
2043     {
2044 root 1.174 tileid t = tile [z];
2045    
2046 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2047 root 1.174 {
2048     XPUSHs (sv_2mortal (newSViv (t)));
2049     need_texid (self, t);
2050     }
2051 root 1.42
2052 root 1.174 cell->tile [z] = t;
2053 root 1.42 }
2054     }
2055     }
2056     }
2057     }
2058     }
2059    
2060 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixChunk
2061 root 1.52
2062 root 1.133 CFPlus::MixChunk
2063 root 1.52 new_from_file (SV *class, char *path)
2064     CODE:
2065     RETVAL = Mix_LoadWAV (path);
2066     OUTPUT:
2067     RETVAL
2068    
2069     void
2070 root 1.133 DESTROY (CFPlus::MixChunk self)
2071 root 1.52 CODE:
2072     Mix_FreeChunk (self);
2073    
2074     int
2075 root 1.133 volume (CFPlus::MixChunk self, int volume = -1)
2076 root 1.52 CODE:
2077     RETVAL = Mix_VolumeChunk (self, volume);
2078     OUTPUT:
2079     RETVAL
2080    
2081     int
2082 root 1.133 play (CFPlus::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
2083 root 1.52 CODE:
2084     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2085     OUTPUT:
2086     RETVAL
2087    
2088 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixMusic
2089 root 1.52
2090     int
2091     volume (int volume = -1)
2092     CODE:
2093     RETVAL = Mix_VolumeMusic (volume);
2094     OUTPUT:
2095     RETVAL
2096    
2097 root 1.133 CFPlus::MixMusic
2098 root 1.52 new_from_file (SV *class, char *path)
2099     CODE:
2100     RETVAL = Mix_LoadMUS (path);
2101     OUTPUT:
2102     RETVAL
2103    
2104     void
2105 root 1.133 DESTROY (CFPlus::MixMusic self)
2106 root 1.52 CODE:
2107     Mix_FreeMusic (self);
2108    
2109     int
2110 root 1.133 play (CFPlus::MixMusic self, int loops = -1)
2111 root 1.52 CODE:
2112     RETVAL = Mix_PlayMusic (self, loops);
2113     OUTPUT:
2114     RETVAL
2115    
2116 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::OpenGL
2117 root 1.54
2118     BOOT:
2119     {
2120 root 1.133 HV *stash = gv_stashpv ("CFPlus::OpenGL", 1);
2121 root 1.54 static const struct {
2122     const char *name;
2123     IV iv;
2124     } *civ, const_iv[] = {
2125     # define const_iv(name) { # name, (IV)name }
2126     const_iv (GL_COLOR_MATERIAL),
2127     const_iv (GL_SMOOTH),
2128     const_iv (GL_FLAT),
2129 root 1.69 const_iv (GL_DITHER),
2130 root 1.54 const_iv (GL_BLEND),
2131 root 1.89 const_iv (GL_CULL_FACE),
2132 root 1.69 const_iv (GL_SCISSOR_TEST),
2133 root 1.89 const_iv (GL_DEPTH_TEST),
2134     const_iv (GL_ALPHA_TEST),
2135     const_iv (GL_NORMALIZE),
2136     const_iv (GL_RESCALE_NORMAL),
2137 root 1.119 const_iv (GL_FRONT),
2138     const_iv (GL_BACK),
2139 root 1.54 const_iv (GL_AND),
2140 root 1.67 const_iv (GL_ONE),
2141     const_iv (GL_ZERO),
2142 root 1.54 const_iv (GL_SRC_ALPHA),
2143 root 1.104 const_iv (GL_DST_ALPHA),
2144 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2145 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2146 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2147 root 1.54 const_iv (GL_RGB),
2148     const_iv (GL_RGBA),
2149 root 1.115 const_iv (GL_RGBA4),
2150     const_iv (GL_RGBA8),
2151     const_iv (GL_RGB5_A1),
2152 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2153 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2154     const_iv (GL_UNSIGNED_INT),
2155 root 1.54 const_iv (GL_ALPHA),
2156 root 1.86 const_iv (GL_INTENSITY),
2157 root 1.76 const_iv (GL_LUMINANCE),
2158 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2159 root 1.54 const_iv (GL_FLOAT),
2160     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2161     const_iv (GL_COMPILE),
2162     const_iv (GL_TEXTURE_1D),
2163     const_iv (GL_TEXTURE_2D),
2164     const_iv (GL_TEXTURE_ENV),
2165     const_iv (GL_TEXTURE_MAG_FILTER),
2166     const_iv (GL_TEXTURE_MIN_FILTER),
2167     const_iv (GL_TEXTURE_ENV_MODE),
2168     const_iv (GL_TEXTURE_WRAP_S),
2169     const_iv (GL_TEXTURE_WRAP_T),
2170 root 1.98 const_iv (GL_REPEAT),
2171 root 1.54 const_iv (GL_CLAMP),
2172 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2173 root 1.54 const_iv (GL_NEAREST),
2174     const_iv (GL_LINEAR),
2175 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2176     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2177     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2178     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2179     const_iv (GL_GENERATE_MIPMAP),
2180 root 1.54 const_iv (GL_MODULATE),
2181 root 1.69 const_iv (GL_DECAL),
2182 root 1.54 const_iv (GL_REPLACE),
2183 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2184 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2185     const_iv (GL_PROJECTION),
2186     const_iv (GL_MODELVIEW),
2187     const_iv (GL_COLOR_LOGIC_OP),
2188 root 1.69 const_iv (GL_SEPARABLE_2D),
2189 root 1.54 const_iv (GL_CONVOLUTION_2D),
2190     const_iv (GL_CONVOLUTION_BORDER_MODE),
2191     const_iv (GL_CONSTANT_BORDER),
2192     const_iv (GL_LINES),
2193 root 1.138 const_iv (GL_LINE_STRIP),
2194 root 1.89 const_iv (GL_LINE_LOOP),
2195 root 1.54 const_iv (GL_QUADS),
2196 root 1.89 const_iv (GL_QUAD_STRIP),
2197     const_iv (GL_TRIANGLES),
2198     const_iv (GL_TRIANGLE_STRIP),
2199     const_iv (GL_TRIANGLE_FAN),
2200 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2201     const_iv (GL_FASTEST),
2202 root 1.89 const_iv (GL_V2F),
2203     const_iv (GL_V3F),
2204     const_iv (GL_T2F_V3F),
2205     const_iv (GL_T2F_N3F_V3F),
2206 root 1.54 # undef const_iv
2207     };
2208    
2209     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2210     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2211     }
2212    
2213 root 1.97 char *
2214     gl_vendor ()
2215     CODE:
2216     RETVAL = (char *)glGetString (GL_VENDOR);
2217     OUTPUT:
2218     RETVAL
2219    
2220     char *
2221     gl_version ()
2222     CODE:
2223     RETVAL = (char *)glGetString (GL_VERSION);
2224     OUTPUT:
2225     RETVAL
2226    
2227     char *
2228     gl_extensions ()
2229     CODE:
2230     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2231     OUTPUT:
2232     RETVAL
2233    
2234 root 1.54 int glGetError ()
2235    
2236 root 1.114 void glFinish ()
2237    
2238 root 1.54 void glClear (int mask)
2239    
2240     void glClearColor (float r, float g, float b, float a = 1.0)
2241     PROTOTYPE: @
2242    
2243     void glEnable (int cap)
2244    
2245     void glDisable (int cap)
2246    
2247     void glShadeModel (int mode)
2248    
2249     void glHint (int target, int mode)
2250    
2251     void glBlendFunc (int sfactor, int dfactor)
2252    
2253 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
2254     CODE:
2255     gl_BlendFuncSeparate (sa, da, saa, daa);
2256    
2257 root 1.89 void glDepthMask (int flag)
2258    
2259 root 1.54 void glLogicOp (int opcode)
2260    
2261 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
2262    
2263 root 1.54 void glMatrixMode (int mode)
2264    
2265     void glPushMatrix ()
2266    
2267     void glPopMatrix ()
2268    
2269     void glLoadIdentity ()
2270    
2271 root 1.119 void glDrawBuffer (int buffer)
2272    
2273     void glReadBuffer (int buffer)
2274    
2275 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
2276     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
2277    
2278     # near_ and far_ are due to microsofts buggy "c" compiler
2279 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
2280 root 1.54
2281     void glViewport (int x, int y, int width, int height)
2282    
2283 root 1.69 void glScissor (int x, int y, int width, int height)
2284    
2285 root 1.54 void glTranslate (float x, float y, float z = 0.)
2286     CODE:
2287     glTranslatef (x, y, z);
2288    
2289 root 1.62 void glScale (float x, float y, float z = 1.)
2290 root 1.54 CODE:
2291     glScalef (x, y, z);
2292    
2293     void glRotate (float angle, float x, float y, float z)
2294     CODE:
2295     glRotatef (angle, x, y, z);
2296    
2297     void glBegin (int mode)
2298    
2299     void glEnd ()
2300    
2301     void glColor (float r, float g, float b, float a = 1.0)
2302     PROTOTYPE: @
2303 root 1.103 ALIAS:
2304     glColor_premultiply = 1
2305 root 1.54 CODE:
2306 root 1.103 if (ix)
2307     {
2308     r *= a;
2309     g *= a;
2310     b *= a;
2311     }
2312 root 1.90 // microsoft visual "c" rounds instead of truncating...
2313 root 1.130 glColor4f (r, g, b, a);
2314 root 1.54
2315 root 1.89 void glInterleavedArrays (int format, int stride, char *data)
2316    
2317     void glDrawElements (int mode, int count, int type, char *indices)
2318    
2319     # 1.2 void glDrawRangeElements (int mode, int start, int end
2320    
2321 root 1.91 void glRasterPos (float x, float y, float z = 0.)
2322     CODE:
2323     glRasterPos3f (0, 0, z);
2324     glBitmap (0, 0, 0, 0, x, y, 0);
2325    
2326 root 1.54 void glVertex (float x, float y, float z = 0.)
2327     CODE:
2328     glVertex3f (x, y, z);
2329    
2330     void glTexCoord (float s, float t)
2331     CODE:
2332     glTexCoord2f (s, t);
2333    
2334     void glTexEnv (int target, int pname, float param)
2335     CODE:
2336     glTexEnvf (target, pname, param);
2337    
2338     void glTexParameter (int target, int pname, float param)
2339     CODE:
2340     glTexParameterf (target, pname, param);
2341    
2342     void glBindTexture (int target, int name)
2343    
2344     void glConvolutionParameter (int target, int pname, float params)
2345     CODE:
2346 root 1.103 if (gl.ConvolutionParameterf)
2347     gl.ConvolutionParameterf (target, pname, params);
2348 root 1.54
2349     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
2350 root 1.64 CODE:
2351 root 1.103 if (gl.ConvolutionFilter2D)
2352     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
2353 root 1.54
2354 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
2355     CODE:
2356 root 1.103 if (gl.SeparableFilter2D)
2357     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
2358 root 1.69
2359 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
2360    
2361     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
2362    
2363 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
2364 root 1.68
2365     void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
2366    
2367 root 1.54 int glGenTexture ()
2368     CODE:
2369     {
2370     GLuint name;
2371     glGenTextures (1, &name);
2372     RETVAL = name;
2373     }
2374     OUTPUT:
2375     RETVAL
2376    
2377     void glDeleteTexture (int name)
2378     CODE:
2379     {
2380     GLuint name_ = name;
2381     glDeleteTextures (1, &name_);
2382     }
2383    
2384     int glGenList ()
2385     CODE:
2386     RETVAL = glGenLists (1);
2387     OUTPUT:
2388     RETVAL
2389    
2390     void glDeleteList (int list)
2391     CODE:
2392     glDeleteLists (list, 1);
2393    
2394     void glNewList (int list, int mode = GL_COMPILE)
2395    
2396     void glEndList ()
2397    
2398     void glCallList (int list)
2399