ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.185
Committed: Sat Apr 21 09:21:03 2007 UTC (17 years ago) by root
Branch: MAIN
Changes since 1.184: +61 -62 lines
Log Message:
try to do smoothing globally, not per-layer

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