ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.239
Committed: Tue Dec 25 18:58:32 2007 UTC (16 years, 4 months ago) by root
Branch: MAIN
Changes since 1.238: +8 -2 lines
Log Message:
save/restore textures in a safer way, also save/restore glyph cache

File Contents

# User Rev Content
1 root 1.48 #ifdef _WIN32
2 root 1.131 # define WIN32_LEAN_AND_MEAN
3 root 1.170 # define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls
4 root 1.48 # include <malloc.h>
5 root 1.79 # include <windows.h>
6 root 1.157 # include <wininet.h>
7 root 1.75 # pragma warning(disable:4244)
8 root 1.162 # pragma warning(disable:4761)
9 root 1.48 #endif
10    
11 root 1.193 //#define DEBUG 1
12     #if DEBUG
13     # include <valgrind/memcheck.h>
14     #endif
15    
16 root 1.1 #include "EXTERN.h"
17     #include "perl.h"
18     #include "XSUB.h"
19    
20 root 1.131 #ifdef _WIN32
21     # undef pipe
22 root 1.222 // microsoft vs. C
23     # define sqrtf(x) sqrt(x)
24     # define roundf(x) (int)(x)
25     # define atan2f(x,y) atan2(x,y)
26     # define M_PI 3.14159265f
27 root 1.131 #endif
28    
29 root 1.168 #include <assert.h>
30 root 1.80 #include <math.h>
31 root 1.5 #include <string.h>
32 root 1.25 #include <stdio.h>
33 root 1.111 #include <stdlib.h>
34 root 1.5
35 root 1.212 #define USE_RWOPS 1 // for SDL_mixer:LoadMUS_RW
36    
37 root 1.2 #include <SDL.h>
38 root 1.202 #include <SDL_thread.h>
39 root 1.76 #include <SDL_endian.h>
40 root 1.23 #include <SDL_image.h>
41 root 1.52 #include <SDL_mixer.h>
42 root 1.3 #include <SDL_opengl.h>
43 root 1.5
44 root 1.124 #define PANGO_ENABLE_BACKEND
45     #define G_DISABLE_CAST_CHECKS
46    
47 root 1.30 #include <glib/gmacros.h>
48    
49 root 1.5 #include <pango/pango.h>
50    
51 root 1.48 #ifndef _WIN32
52     # include <sys/types.h>
53     # include <sys/socket.h>
54     # include <netinet/in.h>
55     # include <netinet/tcp.h>
56     # include <inttypes.h>
57     #endif
58 root 1.28
59 root 1.162 #define OBJ_STR "\xef\xbf\xbc" /* U+FFFC, object replacement character */
60 root 1.121
61 root 1.29 #define FOW_DARKNESS 32
62    
63     #define MAP_EXTEND_X 32
64     #define MAP_EXTEND_Y 512
65    
66 root 1.63 #define MIN_FONT_HEIGHT 10
67 root 1.58
68 root 1.127 #if 0
69 root 1.124 # define PARACHUTE SDL_INIT_NOPARACHUTE
70     #else
71     # define PARACHUTE 0
72     #endif
73    
74 root 1.188 static AV *texture_av;
75    
76 root 1.103 static struct
77     {
78     #define GL_FUNC(ptr,name) ptr name;
79     #include "glfunc.h"
80     #undef GL_FUNC
81     } gl;
82    
83 root 1.192 static void
84     gl_BlendFuncSeparate (GLenum sa, GLenum da, GLenum saa, GLenum daa)
85 root 1.103 {
86     if (gl.BlendFuncSeparate)
87     gl.BlendFuncSeparate (sa, da, saa, daa);
88     else if (gl.BlendFuncSeparateEXT)
89     gl.BlendFuncSeparateEXT (sa, da, saa, daa);
90     else
91     glBlendFunc (sa, da);
92     }
93 root 1.64
94 root 1.192 static GLuint
95     gen_texture ()
96     {
97     GLuint name;
98    
99     if (AvFILL (texture_av) >= 0)
100     name = (GLuint)(size_t)av_pop (texture_av);
101     else
102     glGenTextures (1, &name);
103    
104     return name;
105     }
106    
107     static void
108     del_texture (GLuint name)
109     {
110     /* make a half-assed attempt at returning the memory used by the texture */
111     /* textures are frequently being reused by cfplus anyway */
112     /*glBindTexture (GL_TEXTURE_2D, name);*/
113     /*glTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, 0, 0, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);*/
114     av_push (texture_av, (SV *)(size_t)name);
115     glDeleteTextures (1, &name);
116     }
117    
118 root 1.124 #include "texcache.c"
119 root 1.223 #include "rendercache.c"
120 root 1.124
121     #include "pango-font.c"
122     #include "pango-fontmap.c"
123     #include "pango-render.c"
124    
125 root 1.212 typedef IV CFPlus__Channel;
126     typedef SDL_RWops *CFPlus__RW;
127 root 1.133 typedef Mix_Chunk *CFPlus__MixChunk;
128     typedef Mix_Music *CFPlus__MixMusic;
129 root 1.52
130 root 1.133 typedef PangoFontDescription *CFPlus__Font;
131 root 1.2
132 root 1.121 static int
133     shape_attr_p (PangoLayoutRun *run)
134     {
135     GSList *attrs = run->item->analysis.extra_attrs;
136    
137     while (attrs)
138     {
139     PangoAttribute *attr = attrs->data;
140    
141     if (attr->klass->type == PANGO_ATTR_SHAPE)
142     return 1;
143    
144     attrs = attrs->next;
145     }
146    
147     return 0;
148     }
149    
150 root 1.14 typedef struct cf_layout {
151 root 1.124 PangoLayout *pl;
152 root 1.76 float r, g, b, a; // default color for rgba mode
153 root 1.14 int base_height;
154 root 1.133 CFPlus__Font font;
155 root 1.225 rc_t *rc;
156 root 1.133 } *CFPlus__Layout;
157 root 1.14
158 root 1.133 static CFPlus__Font default_font;
159 root 1.124 static PangoContext *opengl_context;
160     static PangoFontMap *opengl_fontmap;
161 root 1.61
162 root 1.14 static void
163 root 1.19 substitute_func (FcPattern *pattern, gpointer data)
164     {
165 root 1.108 FcPatternAddBool (pattern, FC_HINTING, 1);
166 root 1.110 #ifdef FC_HINT_STYLE
167 root 1.109 FcPatternAddBool (pattern, FC_HINT_STYLE, FC_HINT_FULL);
168 root 1.110 #endif
169 root 1.82 FcPatternAddBool (pattern, FC_AUTOHINT, 0);
170 root 1.19 }
171    
172     static void
173 root 1.133 layout_update_font (CFPlus__Layout self)
174 root 1.17 {
175 root 1.19 /* use a random scale factor to account for unknown descenders, 0.8 works
176     * reasonably well with bitstream vera
177     */
178 root 1.61 PangoFontDescription *font = self->font ? self->font : default_font;
179 root 1.46
180 root 1.61 pango_font_description_set_absolute_size (font,
181     MAX (MIN_FONT_HEIGHT, self->base_height) * (PANGO_SCALE * 8 / 10));
182 root 1.58
183 root 1.61 pango_layout_set_font_description (self->pl, font);
184 root 1.17 }
185    
186     static void
187 root 1.133 layout_get_pixel_size (CFPlus__Layout self, int *w, int *h)
188 root 1.14 {
189 root 1.139 PangoRectangle rect;
190 root 1.14
191 root 1.139 // get_pixel_* wrongly rounds down
192     pango_layout_get_extents (self->pl, 0, &rect);
193 root 1.76
194 root 1.139 rect.width = (rect.width + PANGO_SCALE - 1) / PANGO_SCALE;
195     rect.height = (rect.height + PANGO_SCALE - 1) / PANGO_SCALE;
196    
197     if (!rect.width) rect.width = 1;
198     if (!rect.height) rect.height = 1;
199    
200     *w = rect.width;
201     *h = rect.height;
202 root 1.14 }
203    
204 root 1.174 typedef uint16_t tileid;
205     typedef uint16_t faceid;
206 root 1.42
207 root 1.28 typedef struct {
208 root 1.228 GLuint name;
209 root 1.30 int w, h;
210     float s, t;
211 root 1.39 uint8_t r, g, b, a;
212 root 1.176 tileid smoothtile;
213     uint8_t smoothlevel;
214 root 1.42 } maptex;
215 root 1.30
216     typedef struct {
217 root 1.153 uint32_t player;
218 root 1.174 tileid tile[3];
219 root 1.142 uint16_t darkness;
220 root 1.176 uint8_t stat_width, stat_hp, flags, smoothmax;
221 root 1.28 } mapcell;
222    
223     typedef struct {
224 root 1.30 int32_t c0, c1;
225 root 1.28 mapcell *col;
226     } maprow;
227    
228     typedef struct map {
229     int x, y, w, h;
230 root 1.42 int ox, oy; /* offset to virtual global coordinate system */
231 root 1.174 int faces; tileid *face2tile; // [faceid]
232     int texs; maptex *tex; // [tileid]
233 root 1.42
234 root 1.48 int32_t rows;
235 root 1.28 maprow *row;
236 root 1.133 } *CFPlus__Map;
237 root 1.28
238 root 1.30 static char *
239     prepend (char *ptr, int sze, int inc)
240     {
241     char *p;
242    
243     New (0, p, sze + inc, char);
244     Zero (p, inc, char);
245     Move (ptr, p + inc, sze, char);
246     Safefree (ptr);
247    
248     return p;
249     }
250    
251     static char *
252     append (char *ptr, int sze, int inc)
253     {
254     Renew (ptr, sze + inc, char);
255     Zero (ptr + sze, inc, char);
256    
257     return ptr;
258     }
259    
260     #define Append(type,ptr,sze,inc) (ptr) = (type *)append ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
261     #define Prepend(type,ptr,sze,inc) (ptr) = (type *)prepend ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
262    
263 root 1.174 static void
264     need_facenum (struct map *self, faceid face)
265     {
266     while (self->faces <= face)
267     {
268     Append (tileid, self->face2tile, self->faces, self->faces);
269     self->faces *= 2;
270     }
271     }
272    
273     static void
274     need_texid (struct map *self, int texid)
275     {
276     while (self->texs <= texid)
277     {
278     Append (maptex, self->tex, self->texs, self->texs);
279     self->texs *= 2;
280     }
281     }
282    
283 root 1.42 static maprow *
284 root 1.133 map_get_row (CFPlus__Map self, int y)
285 root 1.42 {
286     if (0 > y)
287     {
288     int extend = - y + MAP_EXTEND_Y;
289     Prepend (maprow, self->row, self->rows, extend);
290    
291     self->rows += extend;
292     self->y += extend;
293     y += extend;
294     }
295     else if (y >= self->rows)
296     {
297     int extend = y - self->rows + MAP_EXTEND_Y;
298     Append (maprow, self->row, self->rows, extend);
299     self->rows += extend;
300     }
301    
302     return self->row + y;
303     }
304    
305     static mapcell *
306     row_get_cell (maprow *row, int x)
307     {
308     if (!row->col)
309     {
310     Newz (0, row->col, MAP_EXTEND_X, mapcell);
311     row->c0 = x - MAP_EXTEND_X / 4;
312     row->c1 = row->c0 + MAP_EXTEND_X;
313     }
314    
315     if (row->c0 > x)
316     {
317     int extend = row->c0 - x + MAP_EXTEND_X;
318     Prepend (mapcell, row->col, row->c1 - row->c0, extend);
319     row->c0 -= extend;
320     }
321     else if (x >= row->c1)
322     {
323     int extend = x - row->c1 + MAP_EXTEND_X;
324     Append (mapcell, row->col, row->c1 - row->c0, extend);
325     row->c1 += extend;
326     }
327    
328     return row->col + (x - row->c0);
329     }
330    
331     static mapcell *
332 root 1.133 map_get_cell (CFPlus__Map self, int x, int y)
333 root 1.42 {
334     return row_get_cell (map_get_row (self, y), x);
335     }
336    
337 root 1.30 static void
338 root 1.133 map_clear (CFPlus__Map self)
339 root 1.30 {
340     int r;
341    
342     for (r = 0; r < self->rows; r++)
343     Safefree (self->row[r].col);
344    
345     Safefree (self->row);
346    
347     self->x = 0;
348     self->y = 0;
349 root 1.42 self->ox = 0;
350     self->oy = 0;
351 root 1.30 self->row = 0;
352     self->rows = 0;
353     }
354    
355 root 1.29 static void
356 root 1.133 map_blank (CFPlus__Map self, int x0, int y0, int w, int h)
357 root 1.29 {
358     int x, y;
359 root 1.48 maprow *row;
360 root 1.146 mapcell *cell;
361 root 1.29
362     for (y = y0; y < y0 + h; y++)
363 root 1.30 if (y >= 0)
364     {
365     if (y >= self->rows)
366     break;
367    
368 root 1.48 row = self->row + y;
369 root 1.30
370     for (x = x0; x < x0 + w; x++)
371     if (x >= row->c0)
372     {
373     if (x >= row->c1)
374     break;
375 root 1.29
376 root 1.146 cell = row->col + x - row->c0;
377    
378     cell->darkness = 0;
379     cell->stat_hp = 0;
380 root 1.154 cell->flags = 0;
381     cell->player = 0;
382 root 1.30 }
383     }
384 root 1.29 }
385    
386 root 1.176 typedef struct {
387     tileid tile;
388     uint8_t x, y, level;
389     } smooth_key;
390    
391     static void
392     smooth_or_bits (HV *hv, smooth_key *key, IV bits)
393     {
394 root 1.181 SV **sv = hv_fetch (hv, (char *)key, sizeof (*key), 1);
395 root 1.176
396     if (SvIOK (*sv))
397     SvIV_set (*sv, SvIVX (*sv) | bits);
398     else
399     sv_setiv (*sv, bits);
400     }
401    
402 root 1.56 static void
403 root 1.75 music_finished (void)
404 root 1.56 {
405     SDL_UserEvent ev;
406    
407     ev.type = SDL_USEREVENT;
408     ev.code = 0;
409     ev.data1 = 0;
410     ev.data2 = 0;
411    
412 root 1.57 SDL_PushEvent ((SDL_Event *)&ev);
413 root 1.56 }
414    
415 root 1.71 static void
416     channel_finished (int channel)
417     {
418     SDL_UserEvent ev;
419    
420     ev.type = SDL_USEREVENT;
421     ev.code = 1;
422 root 1.74 ev.data1 = (void *)(long)channel;
423 root 1.71 ev.data2 = 0;
424    
425     SDL_PushEvent ((SDL_Event *)&ev);
426     }
427    
428 root 1.113 static unsigned int
429     minpot (unsigned int n)
430     {
431     if (!n)
432     return 0;
433    
434     --n;
435    
436     n |= n >> 1;
437     n |= n >> 2;
438     n |= n >> 4;
439     n |= n >> 8;
440     n |= n >> 16;
441    
442     return n + 1;
443     }
444    
445 root 1.235 static unsigned int
446     popcount (unsigned int n)
447     {
448     n -= (n >> 1) & 0x55555555U;
449     n = ((n >> 2) & 0x33333333U) + (n & 0x33333333U);
450     n = ((n >> 4) + n) & 0x0f0f0f0fU;
451     n *= 0x01010101U;
452    
453     return n >> 24;
454     }
455    
456 root 1.167 /* SDL should provide this, really. */
457     #define SDLK_MODIFIER_MIN 300
458     #define SDLK_MODIFIER_MAX 314
459    
460 root 1.207 /******************************************************************************/
461    
462 root 1.209 static GV *draw_x_gv, *draw_y_gv, *draw_w_gv, *draw_h_gv;
463     static GV *hover_gv;
464    
465 root 1.207 static int
466     within_widget (SV *widget, NV x, NV y)
467     {
468     HV *self;
469     SV **svp;
470     NV wx, ww, wy, wh;
471    
472     if (!SvROK (widget))
473     return 0;
474    
475     self = (HV *)SvRV (widget);
476    
477     if (SvTYPE (self) != SVt_PVHV)
478     return 0;
479    
480     svp = hv_fetch (self, "y", 1, 0); wy = svp ? SvNV (*svp) : 0.;
481     if (y < wy)
482     return 0;
483    
484     svp = hv_fetch (self, "h", 1, 0); wh = svp ? SvNV (*svp) : 0.;
485     if (y >= wy + wh)
486     return 0;
487    
488     svp = hv_fetch (self, "x", 1, 0); wx = svp ? SvNV (*svp) : 0.;
489     if (x < wx)
490     return 0;
491    
492     svp = hv_fetch (self, "w", 1, 0); ww = svp ? SvNV (*svp) : 0.;
493     if (x >= wx + ww)
494     return 0;
495    
496     svp = hv_fetch (self, "can_events", sizeof ("can_events") - 1, 0);
497     if (!svp || !SvTRUE (*svp))
498     return 0;
499    
500     return 1;
501     }
502    
503 root 1.133 MODULE = CFPlus PACKAGE = CFPlus
504 root 1.1
505 root 1.11 PROTOTYPES: ENABLE
506    
507 root 1.5 BOOT:
508     {
509 root 1.133 HV *stash = gv_stashpv ("CFPlus", 1);
510 root 1.51 static const struct {
511     const char *name;
512     IV iv;
513     } *civ, const_iv[] = {
514     # define const_iv(name) { # name, (IV)name }
515 root 1.167 const_iv (SDLK_MODIFIER_MIN),
516     const_iv (SDLK_MODIFIER_MAX),
517    
518 root 1.51 const_iv (SDL_ACTIVEEVENT),
519     const_iv (SDL_KEYDOWN),
520     const_iv (SDL_KEYUP),
521     const_iv (SDL_MOUSEMOTION),
522     const_iv (SDL_MOUSEBUTTONDOWN),
523     const_iv (SDL_MOUSEBUTTONUP),
524     const_iv (SDL_JOYAXISMOTION),
525     const_iv (SDL_JOYBALLMOTION),
526     const_iv (SDL_JOYHATMOTION),
527     const_iv (SDL_JOYBUTTONDOWN),
528     const_iv (SDL_JOYBUTTONUP),
529     const_iv (SDL_QUIT),
530     const_iv (SDL_SYSWMEVENT),
531     const_iv (SDL_EVENT_RESERVEDA),
532     const_iv (SDL_EVENT_RESERVEDB),
533     const_iv (SDL_VIDEORESIZE),
534     const_iv (SDL_VIDEOEXPOSE),
535     const_iv (SDL_USEREVENT),
536 root 1.167
537     const_iv (SDL_APPINPUTFOCUS),
538     const_iv (SDL_APPMOUSEFOCUS),
539     const_iv (SDL_APPACTIVE),
540    
541 root 1.235 const_iv (SDLK_FIRST),
542     const_iv (SDLK_LAST),
543 root 1.51 const_iv (SDLK_KP0),
544     const_iv (SDLK_KP1),
545     const_iv (SDLK_KP2),
546     const_iv (SDLK_KP3),
547     const_iv (SDLK_KP4),
548     const_iv (SDLK_KP5),
549     const_iv (SDLK_KP6),
550     const_iv (SDLK_KP7),
551     const_iv (SDLK_KP8),
552     const_iv (SDLK_KP9),
553     const_iv (SDLK_KP_PERIOD),
554     const_iv (SDLK_KP_DIVIDE),
555     const_iv (SDLK_KP_MULTIPLY),
556     const_iv (SDLK_KP_MINUS),
557     const_iv (SDLK_KP_PLUS),
558     const_iv (SDLK_KP_ENTER),
559     const_iv (SDLK_KP_EQUALS),
560     const_iv (SDLK_UP),
561     const_iv (SDLK_DOWN),
562     const_iv (SDLK_RIGHT),
563     const_iv (SDLK_LEFT),
564     const_iv (SDLK_INSERT),
565     const_iv (SDLK_HOME),
566     const_iv (SDLK_END),
567     const_iv (SDLK_PAGEUP),
568     const_iv (SDLK_PAGEDOWN),
569     const_iv (SDLK_F1),
570     const_iv (SDLK_F2),
571     const_iv (SDLK_F3),
572     const_iv (SDLK_F4),
573     const_iv (SDLK_F5),
574     const_iv (SDLK_F6),
575     const_iv (SDLK_F7),
576     const_iv (SDLK_F8),
577     const_iv (SDLK_F9),
578     const_iv (SDLK_F10),
579     const_iv (SDLK_F11),
580     const_iv (SDLK_F12),
581     const_iv (SDLK_F13),
582     const_iv (SDLK_F14),
583     const_iv (SDLK_F15),
584     const_iv (SDLK_NUMLOCK),
585     const_iv (SDLK_CAPSLOCK),
586     const_iv (SDLK_SCROLLOCK),
587     const_iv (SDLK_RSHIFT),
588     const_iv (SDLK_LSHIFT),
589     const_iv (SDLK_RCTRL),
590     const_iv (SDLK_LCTRL),
591     const_iv (SDLK_RALT),
592     const_iv (SDLK_LALT),
593     const_iv (SDLK_RMETA),
594     const_iv (SDLK_LMETA),
595     const_iv (SDLK_LSUPER),
596     const_iv (SDLK_RSUPER),
597     const_iv (SDLK_MODE),
598     const_iv (SDLK_COMPOSE),
599     const_iv (SDLK_HELP),
600     const_iv (SDLK_PRINT),
601     const_iv (SDLK_SYSREQ),
602     const_iv (SDLK_BREAK),
603     const_iv (SDLK_MENU),
604     const_iv (SDLK_POWER),
605     const_iv (SDLK_EURO),
606     const_iv (SDLK_UNDO),
607 root 1.167
608 root 1.51 const_iv (KMOD_NONE),
609 root 1.167 const_iv (KMOD_SHIFT),
610 root 1.51 const_iv (KMOD_LSHIFT),
611     const_iv (KMOD_RSHIFT),
612 root 1.167 const_iv (KMOD_CTRL),
613 root 1.51 const_iv (KMOD_LCTRL),
614     const_iv (KMOD_RCTRL),
615 root 1.167 const_iv (KMOD_ALT),
616 root 1.51 const_iv (KMOD_LALT),
617     const_iv (KMOD_RALT),
618 root 1.167 const_iv (KMOD_META),
619 root 1.51 const_iv (KMOD_LMETA),
620     const_iv (KMOD_RMETA),
621     const_iv (KMOD_NUM),
622     const_iv (KMOD_CAPS),
623     const_iv (KMOD_MODE),
624 root 1.236
625     const_iv (MIX_DEFAULT_FORMAT),
626 root 1.51 # undef const_iv
627     };
628    
629     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
630     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
631 root 1.167
632     assert (SDLK_MODIFIER_MIN == SDLK_NUMLOCK);
633     assert (SDLK_MODIFIER_MAX == SDLK_COMPOSE);
634 root 1.79 }
635 root 1.51
636 root 1.168 void
637     weaken (SV *rv)
638     PROTOTYPE: $
639     CODE:
640     sv_rvweaken (rv);
641    
642 root 1.129 int
643     in_destruct ()
644     CODE:
645     RETVAL = PL_main_cv == Nullcv;
646     OUTPUT:
647     RETVAL
648    
649 root 1.116 NV floor (NV x)
650    
651     NV ceil (NV x)
652    
653 root 1.235 IV minpot (UV n)
654    
655     IV popcount (UV n)
656    
657 root 1.79 void
658     pango_init ()
659     CODE:
660     {
661 root 1.124 opengl_fontmap = pango_opengl_font_map_new ();
662     pango_opengl_font_map_set_default_substitute ((PangoOpenGLFontMap *)opengl_fontmap, substitute_func, 0, 0);
663     opengl_context = pango_opengl_font_map_create_context ((PangoOpenGLFontMap *)opengl_fontmap);
664 root 1.5 }
665    
666 root 1.200 char *
667     SDL_GetError ()
668    
669 root 1.51 int
670 root 1.124 SDL_Init (U32 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | PARACHUTE)
671 root 1.51
672     void
673     SDL_Quit ()
674    
675     void
676 root 1.200 SDL_ListModes (int rgb, int alpha)
677 root 1.51 PPCODE:
678     {
679     SDL_Rect **m;
680    
681 root 1.200 SDL_GL_SetAttribute (SDL_GL_RED_SIZE , rgb);
682     SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgb);
683     SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE , rgb);
684     SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, alpha);
685 root 1.51
686 root 1.88 SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 15);
687 root 1.200 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE , 0);
688 root 1.85
689 root 1.200 SDL_GL_SetAttribute (SDL_GL_ACCUM_RED_SIZE , 0);
690 root 1.51 SDL_GL_SetAttribute (SDL_GL_ACCUM_GREEN_SIZE, 0);
691 root 1.200 SDL_GL_SetAttribute (SDL_GL_ACCUM_BLUE_SIZE , 0);
692 root 1.51 SDL_GL_SetAttribute (SDL_GL_ACCUM_ALPHA_SIZE, 0);
693    
694     SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
695 root 1.134 #if SDL_VERSION_ATLEAST(1,2,10)
696 root 1.131 SDL_GL_SetAttribute (SDL_GL_ACCELERATED_VISUAL, 1);
697     SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
698 root 1.134 #endif
699 root 1.51
700     m = SDL_ListModes (0, SDL_FULLSCREEN | SDL_OPENGL);
701    
702     if (m && m != (SDL_Rect **)-1)
703     while (*m)
704     {
705 root 1.238 if ((*m)->w >= 800 && (*m)->h >= 600)
706 root 1.200 {
707     AV *av = newAV ();
708     av_push (av, newSViv ((*m)->w));
709     av_push (av, newSViv ((*m)->h));
710     av_push (av, newSViv (rgb));
711     av_push (av, newSViv (alpha));
712     XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
713     }
714 root 1.51
715     ++m;
716     }
717     }
718    
719     int
720 root 1.200 SDL_SetVideoMode (int w, int h, int rgb, int alpha, int fullscreen)
721 root 1.51 CODE:
722 root 1.200 {
723     SDL_EnableUNICODE (1);
724     SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
725    
726     SDL_GL_SetAttribute (SDL_GL_RED_SIZE , rgb);
727     SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgb);
728     SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE , rgb);
729     SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, alpha);
730    
731 root 1.51 RETVAL = !!SDL_SetVideoMode (
732     w, h, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)
733     );
734 root 1.200
735 root 1.103 if (RETVAL)
736     {
737 root 1.188 av_clear (texture_av);
738    
739 root 1.237 SDL_WM_SetCaption ("Deliantra MORPG Client " VERSION, "Deliantra");
740 root 1.200 #define GL_FUNC(ptr,name) gl.name = (ptr)SDL_GL_GetProcAddress ("gl" # name);
741     #include "glfunc.h"
742     #undef GL_FUNC
743 root 1.103 }
744 root 1.200 }
745 root 1.51 OUTPUT:
746     RETVAL
747    
748 root 1.53 void
749 root 1.54 SDL_GL_SwapBuffers ()
750    
751 root 1.94 char *
752     SDL_GetKeyName (int sym)
753    
754 root 1.198 int
755     SDL_GetAppState ()
756    
757 root 1.54 void
758 root 1.197 poll_events ()
759 root 1.53 PPCODE:
760     {
761     SDL_Event ev;
762    
763 root 1.197 SDL_PumpEvents ();
764     while (SDL_PeepEvents (&ev, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0)
765 root 1.53 {
766     HV *hv = newHV ();
767     hv_store (hv, "type", 4, newSViv (ev.type), 0);
768 root 1.70
769 root 1.53 switch (ev.type)
770     {
771     case SDL_KEYDOWN:
772     case SDL_KEYUP:
773     hv_store (hv, "state", 5, newSViv (ev.key.state), 0);
774     hv_store (hv, "sym", 3, newSViv (ev.key.keysym.sym), 0);
775     hv_store (hv, "mod", 3, newSViv (ev.key.keysym.mod), 0);
776 root 1.167 hv_store (hv, "cmod", 4, newSViv (SDL_GetModState ()), 0); /* current mode */
777 root 1.53 hv_store (hv, "unicode", 7, newSViv (ev.key.keysym.unicode), 0);
778     break;
779    
780     case SDL_ACTIVEEVENT:
781     hv_store (hv, "gain", 4, newSViv (ev.active.gain), 0);
782     hv_store (hv, "state", 5, newSViv (ev.active.state), 0);
783     break;
784    
785     case SDL_MOUSEMOTION:
786 root 1.196 {
787     int state = ev.motion.state;
788     int x = ev.motion.x;
789     int y = ev.motion.y;
790     int xrel = ev.motion.xrel;
791     int yrel = ev.motion.yrel;
792    
793     /* do simplistic event compression */
794     while (SDL_PeepEvents (&ev, 1, SDL_PEEKEVENT, SDL_EVENTMASK (SDL_MOUSEMOTION)) > 0
795     && state == ev.motion.state)
796     {
797     xrel += ev.motion.xrel;
798     yrel += ev.motion.yrel;
799     x = ev.motion.x;
800     y = ev.motion.y;
801     SDL_PeepEvents (&ev, 1, SDL_GETEVENT, SDL_EVENTMASK (SDL_MOUSEMOTION));
802     }
803 root 1.93
804 root 1.196 hv_store (hv, "mod", 3, newSViv (SDL_GetModState ()), 0);
805     hv_store (hv, "state", 5, newSViv (state), 0);
806     hv_store (hv, "x", 1, newSViv (x), 0);
807     hv_store (hv, "y", 1, newSViv (y), 0);
808     hv_store (hv, "xrel", 4, newSViv (xrel), 0);
809     hv_store (hv, "yrel", 4, newSViv (yrel), 0);
810     }
811 root 1.53 break;
812    
813     case SDL_MOUSEBUTTONDOWN:
814     case SDL_MOUSEBUTTONUP:
815 root 1.94 hv_store (hv, "mod", 3, newSViv (SDL_GetModState ()), 0);
816 root 1.93
817 root 1.53 hv_store (hv, "button", 6, newSViv (ev.button.button), 0);
818     hv_store (hv, "state", 5, newSViv (ev.button.state), 0);
819     hv_store (hv, "x", 1, newSViv (ev.button.x), 0);
820     hv_store (hv, "y", 1, newSViv (ev.button.y), 0);
821 root 1.70 break;
822 root 1.72
823     case SDL_USEREVENT:
824     hv_store (hv, "code", 4, newSViv (ev.user.code), 0);
825     hv_store (hv, "data1", 5, newSViv ((IV)ev.user.data1), 0);
826     hv_store (hv, "data2", 5, newSViv ((IV)ev.user.data2), 0);
827     break;
828 root 1.53 }
829    
830 root 1.133 XPUSHs (sv_2mortal (sv_bless (newRV_noinc ((SV *)hv), gv_stashpv ("CFPlus::UI::Event", 1))));
831 root 1.53 }
832     }
833 root 1.52
834     int
835 root 1.236 Mix_OpenAudio (int frequency = 44100, int format = MIX_DEFAULT_FORMAT, int channels = 2, int chunksize = 4096)
836 root 1.56 POSTCALL:
837     Mix_HookMusicFinished (music_finished);
838 root 1.71 Mix_ChannelFinished (channel_finished);
839 root 1.52
840     void
841 root 1.236 Mix_QuerySpec ()
842     PPCODE:
843     {
844     int freq, channels;
845     Uint16 format;
846    
847     if (Mix_QuerySpec (&freq, &format, &channels))
848     {
849     EXTEND (SP, 3);
850     PUSHs (sv_2mortal (newSViv (freq)));
851     PUSHs (sv_2mortal (newSViv (format)));
852     PUSHs (sv_2mortal (newSViv (channels)));
853     }
854     }
855    
856     void
857 root 1.52 Mix_CloseAudio ()
858    
859     int
860     Mix_AllocateChannels (int numchans = -1)
861    
862 root 1.214 const char *
863     Mix_GetError ()
864    
865 root 1.10 void
866     lowdelay (int fd, int val = 1)
867     CODE:
868 root 1.179 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&val, sizeof (val));
869 root 1.10
870 root 1.5 void
871 root 1.157 win32_proxy_info ()
872     PPCODE:
873     {
874     #ifdef _WIN32
875     char buffer[2048];
876     DWORD buflen;
877    
878     EXTEND (SP, 3);
879    
880     buflen = sizeof (buffer);
881     if (InternetQueryOption (0, INTERNET_OPTION_PROXY, (void *)buffer, &buflen))
882     if (((INTERNET_PROXY_INFO *)buffer)->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
883     {
884     PUSHs (newSVpv (((INTERNET_PROXY_INFO *)buffer)->lpszProxy, 0));
885    
886     buflen = sizeof (buffer);
887     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_USERNAME, (void *)buffer, &buflen))
888     {
889     PUSHs (newSVpv (buffer, 0));
890    
891     buflen = sizeof (buffer);
892     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_PASSWORD, (void *)buffer, &buflen))
893     PUSHs (newSVpv (buffer, 0));
894     }
895     }
896     #endif
897     }
898    
899     void
900 root 1.13 add_font (char *file)
901     CODE:
902 root 1.129 FcConfigAppFontAddFile (0, (const FcChar8 *)file);
903 root 1.13
904     void
905 root 1.23 load_image_inline (SV *image_)
906     ALIAS:
907     load_image_file = 1
908     PPCODE:
909     {
910     STRLEN image_len;
911     char *image = (char *)SvPVbyte (image_, image_len);
912     SDL_Surface *surface, *surface2;
913     SDL_PixelFormat fmt;
914     SDL_RWops *rw = ix
915 root 1.212 ? SDL_RWFromFile (image, "rb")
916 root 1.23 : SDL_RWFromConstMem (image, image_len);
917    
918     if (!rw)
919 root 1.41 croak ("load_image: %s", SDL_GetError ());
920 root 1.23
921     surface = IMG_Load_RW (rw, 1);
922     if (!surface)
923 root 1.41 croak ("load_image: %s", SDL_GetError ());
924 root 1.23
925     fmt.palette = NULL;
926     fmt.BitsPerPixel = 32;
927     fmt.BytesPerPixel = 4;
928 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
929 root 1.23 fmt.Rmask = 0x000000ff;
930     fmt.Gmask = 0x0000ff00;
931     fmt.Bmask = 0x00ff0000;
932     fmt.Amask = 0xff000000;
933 root 1.49 #else
934     fmt.Rmask = 0xff000000;
935     fmt.Gmask = 0x00ff0000;
936     fmt.Bmask = 0x0000ff00;
937     fmt.Amask = 0x000000ff;
938     #endif
939 root 1.23 fmt.Rloss = 0;
940     fmt.Gloss = 0;
941     fmt.Bloss = 0;
942     fmt.Aloss = 0;
943     fmt.Rshift = 0;
944     fmt.Gshift = 8;
945     fmt.Bshift = 16;
946     fmt.Ashift = 24;
947     fmt.colorkey = 0;
948     fmt.alpha = 0;
949    
950     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
951    
952 root 1.39 assert (surface2->pitch == surface2->w * 4);
953    
954 root 1.129 SDL_LockSurface (surface2);
955     EXTEND (SP, 6);
956 root 1.23 PUSHs (sv_2mortal (newSViv (surface2->w)));
957     PUSHs (sv_2mortal (newSViv (surface2->h)));
958     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
959 root 1.116 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
960 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
961 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
962 root 1.129 SDL_UnlockSurface (surface2);
963 root 1.23
964     SDL_FreeSurface (surface);
965     SDL_FreeSurface (surface2);
966     }
967    
968 root 1.25 void
969 root 1.39 average (int x, int y, uint32_t *data)
970     PPCODE:
971     {
972     uint32_t r = 0, g = 0, b = 0, a = 0;
973    
974     x = y = x * y;
975    
976     while (x--)
977     {
978     uint32_t p = *data++;
979    
980     r += (p ) & 255;
981     g += (p >> 8) & 255;
982     b += (p >> 16) & 255;
983     a += (p >> 24) & 255;
984     }
985    
986     EXTEND (SP, 4);
987 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
988     PUSHs (sv_2mortal (newSViv (g / y)));
989     PUSHs (sv_2mortal (newSViv (b / y)));
990     PUSHs (sv_2mortal (newSViv (a / y)));
991 root 1.39 }
992    
993     void
994 root 1.66 error (char *message)
995     CODE:
996 root 1.86 fprintf (stderr, "ERROR: %s\n", message);
997 root 1.66 #ifdef _WIN32
998 root 1.86 MessageBox (0, message, "Crossfire+ Error", MB_OK | MB_ICONERROR);
999 root 1.66 #endif
1000    
1001     void
1002 root 1.25 fatal (char *message)
1003     CODE:
1004 root 1.86 fprintf (stderr, "FATAL: %s\n", message);
1005 root 1.50 #ifdef _WIN32
1006 root 1.86 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR);
1007 root 1.25 #endif
1008 root 1.112 _exit (1);
1009 root 1.111
1010     void
1011 root 1.158 _exit (int retval = 0)
1012 root 1.111 CODE:
1013 root 1.161 #ifdef WIN32
1014     ExitThread (retval); // unclean, please beam me up
1015     #else
1016 root 1.112 _exit (retval);
1017 root 1.161 #endif
1018 root 1.25
1019 root 1.193 void
1020     debug ()
1021     CODE:
1022     {
1023     #if DEBUG
1024     VALGRIND_DO_LEAK_CHECK;
1025     #endif
1026     }
1027    
1028 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Font
1029 root 1.61
1030 root 1.205 PROTOTYPES: DISABLE
1031    
1032 root 1.133 CFPlus::Font
1033 root 1.70 new_from_file (SV *class, char *path, int id = 0)
1034 root 1.61 CODE:
1035     {
1036     int count;
1037 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
1038 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
1039     FcPatternDestroy (pattern);
1040     }
1041     OUTPUT:
1042     RETVAL
1043    
1044     void
1045 root 1.133 DESTROY (CFPlus::Font self)
1046 root 1.61 CODE:
1047     pango_font_description_free (self);
1048    
1049     void
1050 root 1.133 make_default (CFPlus::Font self)
1051 root 1.205 PROTOTYPE: $
1052 root 1.61 CODE:
1053     default_font = self;
1054    
1055 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Layout
1056 root 1.14
1057 root 1.205 PROTOTYPES: DISABLE
1058    
1059 root 1.124 void
1060 root 1.239 glyph_cache_backup ()
1061 root 1.205 PROTOTYPE:
1062 root 1.124 CODE:
1063 root 1.239 tc_backup ();
1064    
1065     void
1066     glyph_cache_restore ()
1067     PROTOTYPE:
1068     CODE:
1069     tc_restore ();
1070 root 1.124
1071 root 1.133 CFPlus::Layout
1072 root 1.128 new (SV *class)
1073 root 1.14 CODE:
1074     New (0, RETVAL, 1, struct cf_layout);
1075 root 1.76
1076 root 1.124 RETVAL->pl = pango_layout_new (opengl_context);
1077 root 1.76 RETVAL->r = 1.;
1078     RETVAL->g = 1.;
1079     RETVAL->b = 1.;
1080     RETVAL->a = 1.;
1081     RETVAL->base_height = MIN_FONT_HEIGHT;
1082     RETVAL->font = 0;
1083 root 1.225 RETVAL->rc = rc_alloc ();
1084 root 1.76
1085 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
1086 root 1.76 layout_update_font (RETVAL);
1087 root 1.14 OUTPUT:
1088     RETVAL
1089    
1090     void
1091 root 1.133 DESTROY (CFPlus::Layout self)
1092 root 1.14 CODE:
1093     g_object_unref (self->pl);
1094 root 1.225 rc_free (self->rc);
1095 root 1.14 Safefree (self);
1096 root 1.13
1097 root 1.8 void
1098 root 1.133 set_text (CFPlus::Layout self, SV *text_)
1099 root 1.35 CODE:
1100     {
1101     STRLEN textlen;
1102     char *text = SvPVutf8 (text_, textlen);
1103    
1104     pango_layout_set_text (self->pl, text, textlen);
1105     }
1106    
1107     void
1108 root 1.133 set_markup (CFPlus::Layout self, SV *text_)
1109 root 1.14 CODE:
1110 root 1.5 {
1111     STRLEN textlen;
1112     char *text = SvPVutf8 (text_, textlen);
1113 root 1.14
1114     pango_layout_set_markup (self->pl, text, textlen);
1115     }
1116    
1117 root 1.121 void
1118 root 1.133 set_shapes (CFPlus::Layout self, ...)
1119 root 1.121 CODE:
1120     {
1121     PangoAttrList *attrs = 0;
1122     const char *text = pango_layout_get_text (self->pl);
1123     const char *pos = text;
1124 root 1.122 int arg = 4;
1125 root 1.121
1126     while (arg < items && (pos = strstr (pos, OBJ_STR)))
1127     {
1128 root 1.122 PangoRectangle inkrect, rect;
1129 root 1.121 PangoAttribute *attr;
1130    
1131 root 1.122 int x = SvIV (ST (arg - 3));
1132     int y = SvIV (ST (arg - 2));
1133 root 1.121 int w = SvIV (ST (arg - 1));
1134 root 1.122 int h = SvIV (ST (arg ));
1135 root 1.121
1136 root 1.122 inkrect.x = 0;
1137     inkrect.y = 0;
1138     inkrect.width = 0;
1139     inkrect.height = 0;
1140    
1141     rect.x = x * PANGO_SCALE;
1142     rect.y = y * PANGO_SCALE;
1143     rect.width = w * PANGO_SCALE;
1144 root 1.121 rect.height = h * PANGO_SCALE;
1145    
1146     if (!attrs)
1147     attrs = pango_layout_get_attributes (self->pl);
1148    
1149 root 1.122 attr = pango_attr_shape_new (&inkrect, &rect);
1150 root 1.121 attr->start_index = pos - text;
1151     attr->end_index = attr->start_index + sizeof (OBJ_STR) - 1;
1152     pango_attr_list_insert (attrs, attr);
1153    
1154 root 1.122 arg += 4;
1155 root 1.121 pos += sizeof (OBJ_STR) - 1;
1156     }
1157    
1158     if (attrs)
1159     pango_layout_set_attributes (self->pl, attrs);
1160     }
1161    
1162     void
1163 root 1.133 get_shapes (CFPlus::Layout self)
1164 root 1.121 PPCODE:
1165     {
1166     PangoLayoutIter *iter = pango_layout_get_iter (self->pl);
1167    
1168     do
1169     {
1170     PangoLayoutRun *run = pango_layout_iter_get_run (iter);
1171    
1172     if (run && shape_attr_p (run))
1173     {
1174     PangoRectangle extents;
1175     pango_layout_iter_get_run_extents (iter, 0, &extents);
1176    
1177 root 1.129 EXTEND (SP, 2);
1178 root 1.121 PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.x))));
1179     PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.y))));
1180     }
1181     }
1182     while (pango_layout_iter_next_run (iter));
1183    
1184     pango_layout_iter_free (iter);
1185     }
1186    
1187     int
1188 root 1.133 has_wrapped (CFPlus::Layout self)
1189 root 1.121 CODE:
1190     {
1191     int lines = 1;
1192     const char *text = pango_layout_get_text (self->pl);
1193    
1194     while (*text)
1195     lines += *text++ == '\n';
1196    
1197     RETVAL = lines < pango_layout_get_line_count (self->pl);
1198     }
1199     OUTPUT:
1200     RETVAL
1201    
1202 root 1.46 SV *
1203 root 1.133 get_text (CFPlus::Layout self)
1204 root 1.46 CODE:
1205 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
1206 root 1.107 sv_utf8_decode (RETVAL);
1207 root 1.46 OUTPUT:
1208     RETVAL
1209    
1210 root 1.14 void
1211 root 1.133 set_foreground (CFPlus::Layout self, float r, float g, float b, float a = 1.)
1212 root 1.76 CODE:
1213     self->r = r;
1214     self->g = g;
1215     self->b = b;
1216     self->a = a;
1217    
1218     void
1219 root 1.133 set_font (CFPlus::Layout self, CFPlus::Font font = 0)
1220 root 1.61 CODE:
1221     if (self->font != font)
1222     {
1223     self->font = font;
1224     layout_update_font (self);
1225     }
1226    
1227     void
1228 root 1.133 set_height (CFPlus::Layout self, int base_height)
1229 root 1.16 CODE:
1230 root 1.61 if (self->base_height != base_height)
1231     {
1232     self->base_height = base_height;
1233     layout_update_font (self);
1234     }
1235 root 1.16
1236     void
1237 root 1.133 set_width (CFPlus::Layout self, int max_width = -1)
1238 root 1.14 CODE:
1239     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
1240    
1241     void
1242 root 1.133 set_indent (CFPlus::Layout self, int indent)
1243 root 1.84 CODE:
1244     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
1245    
1246     void
1247 root 1.133 set_spacing (CFPlus::Layout self, int spacing)
1248 root 1.84 CODE:
1249     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
1250    
1251     void
1252 root 1.133 set_ellipsise (CFPlus::Layout self, int ellipsise)
1253 root 1.84 CODE:
1254     pango_layout_set_ellipsize (self->pl,
1255     ellipsise == 1 ? PANGO_ELLIPSIZE_START
1256     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
1257     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
1258     : PANGO_ELLIPSIZE_NONE
1259     );
1260    
1261     void
1262 root 1.133 set_single_paragraph_mode (CFPlus::Layout self, int spm)
1263 root 1.84 CODE:
1264     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
1265    
1266     void
1267 root 1.133 size (CFPlus::Layout self)
1268 root 1.14 PPCODE:
1269     {
1270     int w, h;
1271    
1272     layout_get_pixel_size (self, &w, &h);
1273    
1274     EXTEND (SP, 2);
1275     PUSHs (sv_2mortal (newSViv (w)));
1276     PUSHs (sv_2mortal (newSViv (h)));
1277     }
1278    
1279 root 1.17 int
1280 root 1.133 descent (CFPlus::Layout self)
1281 root 1.122 CODE:
1282     {
1283     PangoRectangle rect;
1284     PangoLayoutLine *line = pango_layout_get_line (self->pl, 0);
1285     pango_layout_line_get_pixel_extents (line, 0, &rect);
1286     RETVAL = PANGO_DESCENT (rect);
1287     }
1288     OUTPUT:
1289     RETVAL
1290    
1291     int
1292 root 1.133 xy_to_index (CFPlus::Layout self, int x, int y)
1293 root 1.17 CODE:
1294     {
1295     int index, trailing;
1296     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
1297 root 1.165 RETVAL = index + trailing;
1298 root 1.17 }
1299     OUTPUT:
1300     RETVAL
1301    
1302     void
1303 root 1.133 cursor_pos (CFPlus::Layout self, int index)
1304 root 1.17 PPCODE:
1305     {
1306     PangoRectangle strong_pos;
1307     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
1308 root 1.30
1309 root 1.17 EXTEND (SP, 3);
1310     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
1311     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
1312     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
1313     }
1314    
1315 root 1.14 void
1316 root 1.165 index_to_line_x (CFPlus::Layout self, int index, int trailing = 0)
1317     PPCODE:
1318     {
1319     int line, x;
1320    
1321     pango_layout_index_to_line_x (self->pl, index, trailing, &line, &x);
1322     /* pango bug: line is between 1..numlines, not 0..numlines-1 */
1323    
1324     EXTEND (SP, 2);
1325     PUSHs (sv_2mortal (newSViv (line - 1)));
1326     PUSHs (sv_2mortal (newSViv (x / PANGO_SCALE)));
1327     }
1328    
1329     void
1330     line_x_to_index (CFPlus::Layout self, int line, int x)
1331     PPCODE:
1332     {
1333     PangoLayoutLine *lp;
1334     int index, trailing;
1335    
1336     if (line < 0)
1337     XSRETURN_EMPTY;
1338    
1339     if (!(lp = pango_layout_get_line (self->pl, line)))
1340     XSRETURN_EMPTY; /* do better */
1341    
1342 root 1.166 pango_layout_line_x_to_index (lp, x * PANGO_SCALE, &index, &trailing);
1343 root 1.165
1344     EXTEND (SP, 2);
1345     if (GIMME_V == G_SCALAR)
1346     PUSHs (sv_2mortal (newSViv (index + trailing)));
1347     else
1348     {
1349     PUSHs (sv_2mortal (newSViv (index)));
1350     PUSHs (sv_2mortal (newSViv (trailing)));
1351     }
1352     }
1353    
1354     void
1355 root 1.135 render (CFPlus::Layout self, float x, float y, int flags = 0)
1356 root 1.225 CODE:
1357     rc_clear (self->rc);
1358 root 1.124 pango_opengl_render_layout_subpixel (
1359     self->pl,
1360 root 1.225 self->rc,
1361 root 1.124 x * PANGO_SCALE, y * PANGO_SCALE,
1362 root 1.135 self->r, self->g, self->b, self->a,
1363     flags
1364 root 1.124 );
1365 root 1.225 // we assume that context_change actually clears/frees stuff
1366     // and does not do any recomputation...
1367     pango_layout_context_changed (self->pl);
1368    
1369     void
1370     draw (CFPlus::Layout self)
1371     CODE:
1372     {
1373     glEnable (GL_TEXTURE_2D);
1374     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1375     glEnable (GL_BLEND);
1376     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1377     GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1378     glEnable (GL_ALPHA_TEST);
1379     glAlphaFunc (GL_GREATER, 7.f / 255.f);
1380    
1381     rc_draw (self->rc);
1382    
1383     glDisable (GL_ALPHA_TEST);
1384     glDisable (GL_BLEND);
1385     glDisable (GL_TEXTURE_2D);
1386     }
1387 root 1.11
1388 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Texture
1389 root 1.11
1390 root 1.205 PROTOTYPES: ENABLE
1391    
1392 root 1.11 void
1393 root 1.203 pad (SV *data_, int ow, int oh, int nw, int nh)
1394 root 1.113 CODE:
1395     {
1396 root 1.203 if ((nw != ow || nh != oh) && SvOK (data_))
1397 root 1.113 {
1398 root 1.203 STRLEN datalen;
1399     char *data = SvPVbyte (data_, datalen);
1400     int bpp = datalen / (ow * oh);
1401     SV *result_ = sv_2mortal (newSV (nw * nh * bpp));
1402    
1403     SvPOK_only (result_);
1404     SvCUR_set (result_, nw * nh * bpp);
1405    
1406     memset (SvPVX (result_), 0, nw * nh * bpp);
1407     while (oh--)
1408     memcpy (SvPVX (result_) + oh * nw * bpp, data + oh * ow * bpp, ow * bpp);
1409 root 1.113
1410 root 1.203 sv_setsv (data_, result_);
1411 root 1.113 }
1412     }
1413    
1414     void
1415 root 1.114 draw_quad (SV *self, float x, float y, float w = 0., float h = 0.)
1416 root 1.12 PROTOTYPE: $$$;$$
1417 root 1.76 ALIAS:
1418     draw_quad_alpha = 1
1419     draw_quad_alpha_premultiplied = 2
1420 root 1.11 CODE:
1421     {
1422 root 1.12 HV *hv = (HV *)SvRV (self);
1423 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
1424     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
1425 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
1426    
1427 root 1.219 if (name <= 0)
1428     XSRETURN_EMPTY;
1429    
1430 root 1.12 if (items < 5)
1431     {
1432 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1433     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1434 root 1.12 }
1435    
1436 root 1.76 if (ix)
1437     {
1438     glEnable (GL_BLEND);
1439 root 1.103
1440     if (ix == 2)
1441     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1442     else
1443     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1444 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1445 root 1.103
1446 root 1.86 glEnable (GL_ALPHA_TEST);
1447     glAlphaFunc (GL_GREATER, 0.01f);
1448 root 1.76 }
1449    
1450 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1451 root 1.76
1452 root 1.12 glBegin (GL_QUADS);
1453 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1454     glTexCoord2f (0, t); glVertex2f (x , y + h);
1455     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1456     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1457 root 1.12 glEnd ();
1458 root 1.76
1459     if (ix)
1460 root 1.86 {
1461     glDisable (GL_ALPHA_TEST);
1462     glDisable (GL_BLEND);
1463     }
1464 root 1.11 }
1465 root 1.28
1466 root 1.199 IV texture_valid_2d (GLint internalformat, GLsizei w, GLsizei h, GLenum format, GLenum type)
1467     CODE:
1468     {
1469     GLint width;
1470     glTexImage2D (GL_PROXY_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, 0);
1471     glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
1472     RETVAL = width > 0;
1473     }
1474     OUTPUT:
1475     RETVAL
1476    
1477 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Map
1478 root 1.28
1479 root 1.205 PROTOTYPES: DISABLE
1480    
1481 root 1.133 CFPlus::Map
1482 root 1.164 new (SV *class)
1483 root 1.28 CODE:
1484     New (0, RETVAL, 1, struct map);
1485 root 1.42 RETVAL->x = 0;
1486     RETVAL->y = 0;
1487 root 1.164 RETVAL->w = 0;
1488     RETVAL->h = 0;
1489 root 1.42 RETVAL->ox = 0;
1490     RETVAL->oy = 0;
1491 root 1.174 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1492     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1493 root 1.28 RETVAL->rows = 0;
1494     RETVAL->row = 0;
1495     OUTPUT:
1496     RETVAL
1497    
1498     void
1499 root 1.133 DESTROY (CFPlus::Map self)
1500 root 1.28 CODE:
1501     {
1502 root 1.30 map_clear (self);
1503 root 1.174 Safefree (self->face2tile);
1504 root 1.111 Safefree (self->tex);
1505 root 1.29 Safefree (self);
1506     }
1507    
1508     void
1509 root 1.164 resize (CFPlus::Map self, int map_width, int map_height)
1510     CODE:
1511     self->w = map_width;
1512     self->h = map_height;
1513    
1514     void
1515 root 1.133 clear (CFPlus::Map self)
1516 root 1.30 CODE:
1517     map_clear (self);
1518    
1519     void
1520 root 1.174 set_tileid (CFPlus::Map self, int face, int tile)
1521 root 1.29 CODE:
1522     {
1523 root 1.174 need_facenum (self, face); self->face2tile [face] = tile;
1524     need_texid (self, tile);
1525 root 1.42 }
1526    
1527     void
1528 root 1.176 set_smooth (CFPlus::Map self, int face, int smooth, int level)
1529     CODE:
1530     {
1531     tileid texid;
1532     maptex *tex;
1533    
1534     if (face < 0 || face >= self->faces)
1535     return;
1536    
1537     if (smooth < 0 || smooth >= self->faces)
1538     return;
1539    
1540     texid = self->face2tile [face];
1541    
1542     if (!texid)
1543     return;
1544    
1545     tex = self->tex + texid;
1546     tex->smoothtile = self->face2tile [smooth];
1547     tex->smoothlevel = level;
1548     }
1549    
1550     void
1551 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)
1552 root 1.42 CODE:
1553     {
1554 root 1.174 need_texid (self, texid);
1555 root 1.42
1556 root 1.48 {
1557     maptex *tex = self->tex + texid;
1558 root 1.39
1559 root 1.48 tex->name = name;
1560     tex->w = w;
1561     tex->h = h;
1562     tex->s = s;
1563     tex->t = t;
1564     tex->r = r;
1565     tex->g = g;
1566     tex->b = b;
1567     tex->a = a;
1568     }
1569 root 1.95
1570     // somewhat hackish, but for textures that require it, it really
1571     // improves the look, and most others don't suffer.
1572     glBindTexture (GL_TEXTURE_2D, name);
1573 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1574     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1575     // use uglier nearest interpolation because linear suffers
1576     // from transparent color bleeding and ugly wrapping effects.
1577     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1578 root 1.29 }
1579    
1580 root 1.42 int
1581 root 1.133 ox (CFPlus::Map self)
1582 root 1.42 ALIAS:
1583     oy = 1
1584 root 1.101 x = 2
1585     y = 3
1586 root 1.102 w = 4
1587     h = 5
1588 root 1.42 CODE:
1589     switch (ix)
1590     {
1591     case 0: RETVAL = self->ox; break;
1592     case 1: RETVAL = self->oy; break;
1593 root 1.101 case 2: RETVAL = self->x; break;
1594     case 3: RETVAL = self->y; break;
1595 root 1.102 case 4: RETVAL = self->w; break;
1596     case 5: RETVAL = self->h; break;
1597 root 1.42 }
1598     OUTPUT:
1599     RETVAL
1600    
1601 root 1.29 void
1602 root 1.133 scroll (CFPlus::Map self, int dx, int dy)
1603 root 1.43 CODE:
1604     {
1605 root 1.44 if (dx > 0)
1606 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
1607 root 1.44 else if (dx < 0)
1608 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
1609 root 1.44
1610     if (dy > 0)
1611 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
1612 root 1.44 else if (dy < 0)
1613 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
1614 root 1.43
1615 root 1.44 self->ox += dx; self->x += dx;
1616     self->oy += dy; self->y += dy;
1617 root 1.43
1618     while (self->y < 0)
1619     {
1620     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1621    
1622     self->rows += MAP_EXTEND_Y;
1623     self->y += MAP_EXTEND_Y;
1624     }
1625 root 1.44 }
1626 root 1.43
1627 root 1.221 SV *
1628 root 1.141 map1a_update (CFPlus::Map self, SV *data_, int extmap)
1629 root 1.44 CODE:
1630     {
1631 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1632     uint8_t *data_end = (uint8_t *)SvEND (data_);
1633 root 1.48 mapcell *cell;
1634 root 1.221 int x, y, z, flags;
1635     AV *missing = newAV ();
1636     RETVAL = newRV_noinc ((SV *)missing);
1637 root 1.43
1638 root 1.150 while (data < data_end - 1)
1639 root 1.29 {
1640 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1641 root 1.30
1642 root 1.120 x = self->x + ((flags >> 10) & 63);
1643     y = self->y + ((flags >> 4) & 63);
1644 root 1.29
1645 root 1.48 cell = map_get_cell (self, x, y);
1646 root 1.29
1647     if (flags & 15)
1648     {
1649 root 1.142 if (!cell->darkness)
1650 root 1.29 {
1651 root 1.154 memset (cell, 0, sizeof (*cell));
1652 root 1.142 cell->darkness = 256;
1653 root 1.29 }
1654 root 1.45
1655 root 1.142 //TODO: don't trust server data to be in-range(!)
1656    
1657 root 1.141 if (flags & 8)
1658     {
1659     if (extmap)
1660     {
1661     uint8_t ext, cmd;
1662    
1663     do
1664     {
1665     ext = *data++;
1666 root 1.144 cmd = ext & 0x3f;
1667 root 1.141
1668 root 1.147 if (cmd < 4)
1669 root 1.142 cell->darkness = 255 - ext * 64 + 1;
1670 root 1.147 else if (cmd == 5) // health
1671     {
1672     cell->stat_width = 1;
1673     cell->stat_hp = *data++;
1674     }
1675     else if (cmd == 6) // monster width
1676     cell->stat_width = *data++ + 1;
1677 root 1.169 else if (cmd == 0x47)
1678 root 1.153 {
1679 root 1.182 if (*data == 4)
1680     ; // decode player count
1681 root 1.153
1682     data += *data + 1;
1683     }
1684     else if (cmd == 8) // cell flags
1685     cell->flags = *data++;
1686 root 1.144 else if (ext & 0x40) // unknown, multibyte => skip
1687     data += *data + 1;
1688 root 1.147 else
1689     data++;
1690 root 1.141 }
1691 root 1.147 while (ext & 0x80);
1692 root 1.141 }
1693     else
1694 root 1.142 cell->darkness = *data++ + 1;
1695 root 1.141 }
1696 root 1.29
1697 root 1.221 for (z = 0; z <= 2; ++z)
1698     if (flags & (4 >> z))
1699     {
1700     faceid face = (data [0] << 8) + data [1]; data += 2;
1701     need_facenum (self, face);
1702     cell->tile [z] = self->face2tile [face];
1703 root 1.29
1704 root 1.221 if (cell->tile [z])
1705     {
1706     maptex *tex = self->tex + cell->tile [z];
1707     if (!tex->name)
1708     av_push (missing, newSViv (cell->tile [z]));
1709 root 1.29
1710 root 1.221 if (tex->smoothtile)
1711     {
1712     maptex *smooth = self->tex + tex->smoothtile;
1713     if (!smooth->name)
1714     av_push (missing, newSViv (tex->smoothtile));
1715     }
1716     }
1717     }
1718 root 1.29 }
1719     else
1720 root 1.155 cell->darkness = 0;
1721 root 1.29 }
1722 root 1.28 }
1723 root 1.221 OUTPUT:
1724     RETVAL
1725 root 1.28
1726 root 1.40 SV *
1727 root 1.133 mapmap (CFPlus::Map self, int x0, int y0, int w, int h)
1728 root 1.40 CODE:
1729     {
1730 root 1.55 int x1, x;
1731     int y1, y;
1732 root 1.40 int z;
1733     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1734     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1735    
1736     SvPOK_only (map_sv);
1737     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1738    
1739 root 1.55 x0 += self->x; x1 = x0 + w;
1740     y0 += self->y; y1 = y0 + h;
1741 root 1.40
1742     for (y = y0; y < y1; y++)
1743     {
1744     maprow *row = 0 <= y && y < self->rows
1745     ? self->row + y
1746     : 0;
1747    
1748     for (x = x0; x < x1; x++)
1749     {
1750     int r = 32, g = 32, b = 32, a = 192;
1751    
1752     if (row && row->c0 <= x && x < row->c1)
1753     {
1754     mapcell *cell = row->col + (x - row->c0);
1755    
1756     for (z = 0; z <= 0; z++)
1757     {
1758 root 1.174 maptex tex = self->tex [cell->tile [z]];
1759     int a0 = 255 - tex.a;
1760     int a1 = tex.a;
1761    
1762     r = (r * a0 + tex.r * a1) / 255;
1763     g = (g * a0 + tex.g * a1) / 255;
1764     b = (b * a0 + tex.b * a1) / 255;
1765     a = (a * a0 + tex.a * a1) / 255;
1766 root 1.40 }
1767     }
1768    
1769     *map++ = (r )
1770     | (g << 8)
1771     | (b << 16)
1772     | (a << 24);
1773     }
1774     }
1775    
1776     RETVAL = map_sv;
1777     }
1778     OUTPUT:
1779     RETVAL
1780    
1781 root 1.221 void
1782 root 1.171 draw (CFPlus::Map self, int mx, int my, int sw, int sh, int T)
1783 root 1.116 CODE:
1784 root 1.30 {
1785 root 1.223 int x, y, z;
1786    
1787 root 1.176 HV *smooth = (HV *)sv_2mortal ((SV *)newHV ());
1788     uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level
1789 root 1.226 static uint8_t smooth_max[256][256]; // egad, fast and wasteful on memory (64k)
1790 root 1.176 smooth_key skey;
1791 root 1.223
1792     rc_t *rc = rc_alloc ();
1793     rc_key_t key;
1794     rc_array_t *arr;
1795 root 1.48
1796 root 1.176 // thats current max. sorry.
1797     if (sw > 255) sw = 255;
1798     if (sh > 255) sh = 255;
1799    
1800     // clear key, in case of extra padding
1801     memset (&skey, 0, sizeof (skey));
1802    
1803 root 1.223 memset (&key, 0, sizeof (key));
1804     key.r = 255;
1805     key.g = 255;
1806     key.b = 255;
1807     key.a = 255;
1808     key.mode = GL_QUADS;
1809     key.format = GL_T2F_V3F;
1810     key.texname = -1;
1811 root 1.30
1812 root 1.164 mx += self->x;
1813     my += self->y;
1814    
1815 root 1.176 // first pass: determine smooth_max
1816     // rather ugly, if you ask me
1817     // could also be stored inside mapcell and updated on change
1818     memset (smooth_max, 0, sizeof (smooth_max));
1819    
1820     for (y = 0; y < sh; y++)
1821     if (0 <= y + my && y + my < self->rows)
1822     {
1823     maprow *row = self->row + (y + my);
1824    
1825     for (x = 0; x < sw; x++)
1826     if (row->c0 <= x + mx && x + mx < row->c1)
1827     {
1828     mapcell *cell = row->col + (x + mx - row->c0);
1829    
1830 root 1.177 smooth_max[x + 1][y + 1] =
1831     MAX (self->tex [cell->tile [0]].smoothlevel,
1832     MAX (self->tex [cell->tile [1]].smoothlevel,
1833     self->tex [cell->tile [2]].smoothlevel));
1834 root 1.176 }
1835     }
1836    
1837 root 1.223 glEnable (GL_BLEND);
1838     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1839     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1840    
1841 root 1.176 for (z = 0; z <= 2; z++)
1842     {
1843 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
1844    
1845 root 1.176 for (y = 0; y < sh; y++)
1846     if (0 <= y + my && y + my < self->rows)
1847     {
1848     maprow *row = self->row + (y + my);
1849    
1850     for (x = 0; x < sw; x++)
1851     if (row->c0 <= x + mx && x + mx < row->c1)
1852     {
1853     mapcell *cell = row->col + (x + mx - row->c0);
1854     tileid tile = cell->tile [z];
1855    
1856     if (tile)
1857     {
1858     maptex tex = self->tex [tile];
1859 root 1.219 int px, py;
1860 root 1.176
1861 root 1.223 if (key.texname != tex.name)
1862 root 1.176 {
1863     if (!tex.name)
1864 root 1.221 tex = self->tex [2]; /* missing, replace by noface */
1865 root 1.176
1866 root 1.223 key.texname = tex.name;
1867     arr = rc_array (rc, &key);
1868 root 1.176 }
1869    
1870 root 1.219 px = (x + 1) * T - tex.w;
1871     py = (y + 1) * T - tex.h;
1872    
1873 root 1.223 rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
1874     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
1875     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
1876     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
1877 root 1.176
1878     if (cell->flags && z == 2)
1879     {
1880 root 1.223 // overlays such as the speech bubble, probably more to come
1881 root 1.176 if (cell->flags & 1)
1882     {
1883     maptex tex = self->tex [1];
1884     int px = x * T + T * 2 / 32;
1885     int py = y * T - T * 6 / 32;
1886    
1887 root 1.223 if (tex.name)
1888     {
1889     if (key.texname != tex.name)
1890     {
1891     key.texname = tex.name;
1892     arr = rc_array (rc, &key);
1893     }
1894    
1895     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
1896     rc_t2f_v3f (arr, 0 , tex.t, px , py + T, 0);
1897     rc_t2f_v3f (arr, tex.s, tex.t, px + T, py + T, 0);
1898     rc_t2f_v3f (arr, tex.s, 0 , px + T, py , 0);
1899     }
1900 root 1.176 }
1901     }
1902    
1903     // update smooth hash
1904     if (tex.smoothtile)
1905     {
1906     skey.tile = tex.smoothtile;
1907     skey.level = tex.smoothlevel;
1908    
1909     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
1910 root 1.30
1911 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
1912     // shifted +1|+1 so we always stay positive.
1913 root 1.30
1914 root 1.180 // bits is ___n cccc CCCC bbbb
1915     // n do not draw borders&corners
1916     // c draw these corners, but...
1917     // C ... not these
1918     // b draw these borders
1919    
1920     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
1921     // ┃· ·· ·┃ ━━
1922    
1923     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
1924     // ·· ·· ·┏ ┓·
1925    
1926 root 1.176 // full tile
1927     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
1928    
1929     // borders
1930 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
1931     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
1932 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
1933     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
1934    
1935     // corners
1936     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
1937     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
1938     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
1939     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
1940     }
1941     }
1942     }
1943     }
1944 root 1.174
1945 root 1.224 rc_draw (rc);
1946     rc_clear (rc);
1947    
1948 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
1949     // this is basically counting sort
1950 root 1.176 {
1951 root 1.186 int w, b;
1952 root 1.30
1953 root 1.226 glEnable (GL_TEXTURE_2D);
1954     glBegin (GL_QUADS);
1955 root 1.186 for (w = 0; w < 256 / 32; ++w)
1956     {
1957     uint32_t smask = smooth_level [w];
1958     if (smask)
1959     for (b = 0; b < 32; ++b)
1960     if (smask & (((uint32_t)1) << b))
1961 root 1.176 {
1962 root 1.186 int level = (w << 5) | b;
1963     HE *he;
1964 root 1.153
1965 root 1.186 hv_iterinit (smooth);
1966     while ((he = hv_iternext (smooth)))
1967 root 1.153 {
1968 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
1969     IV bits = SvIVX (HeVAL (he));
1970 root 1.176
1971 root 1.186 if (!(bits & 0x1000)
1972     && skey->level == level
1973 root 1.191 && level > smooth_max [skey->x][skey->y])
1974 root 1.174 {
1975 root 1.186 maptex tex = self->tex [skey->tile];
1976     int px = (((int)skey->x) - 1) * T;
1977     int py = (((int)skey->y) - 1) * T;
1978     int border = bits & 15;
1979     int corner = (bits >> 8) & ~(bits >> 4) & 15;
1980     float dx = tex.s * .0625f; // 16 images/row
1981     float dy = tex.t * .5f ; // 2 images/column
1982    
1983 root 1.223 if (tex.name)
1984 root 1.186 {
1985 root 1.223 // this time avoiding texture state changes
1986     // save gobs of state changes.
1987     if (key.texname != tex.name)
1988     {
1989 root 1.226 glEnd ();
1990     glBindTexture (GL_TEXTURE_2D, key.texname = tex.name);
1991     glBegin (GL_QUADS);
1992 root 1.223 }
1993    
1994     if (border)
1995     {
1996     float ox = border * dx;
1997    
1998 root 1.226 glTexCoord2f (ox , 0.f ); glVertex2i (px , py );
1999     glTexCoord2f (ox , dy ); glVertex2i (px , py + T);
2000     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py + T);
2001     glTexCoord2f (ox + dx, 0.f ); glVertex2i (px + T, py );
2002 root 1.223 }
2003    
2004     if (corner)
2005     {
2006     float ox = corner * dx;
2007    
2008 root 1.226 glTexCoord2f (ox , dy ); glVertex2i (px , py );
2009     glTexCoord2f (ox , dy * 2.f); glVertex2i (px , py + T);
2010     glTexCoord2f (ox + dx, dy * 2.f); glVertex2i (px + T, py + T);
2011     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py );
2012 root 1.223 }
2013 root 1.186 }
2014 root 1.174 }
2015 root 1.153 }
2016     }
2017 root 1.186 }
2018 root 1.226
2019     glEnd ();
2020     glDisable (GL_TEXTURE_2D);
2021     key.texname = -1;
2022 root 1.176 }
2023    
2024 root 1.186 hv_clear (smooth);
2025     }
2026 root 1.30
2027 root 1.152 glDisable (GL_BLEND);
2028 root 1.223 rc_free (rc);
2029 root 1.143
2030 root 1.145 // top layer: overlays such as the health bar
2031 root 1.143 for (y = 0; y < sh; y++)
2032 root 1.164 if (0 <= y + my && y + my < self->rows)
2033 root 1.143 {
2034 root 1.164 maprow *row = self->row + (y + my);
2035 root 1.143
2036     for (x = 0; x < sw; x++)
2037 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2038 root 1.143 {
2039 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2040 root 1.143
2041 root 1.171 int px = x * T;
2042     int py = y * T;
2043 root 1.143
2044     if (cell->stat_hp)
2045     {
2046 root 1.171 int width = cell->stat_width * T;
2047 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
2048 root 1.143
2049 root 1.152 glColor3ub (0, 0, 0);
2050 root 1.151 glRectf (px + 1, py - thick - 2,
2051     px + width - 1, py);
2052 root 1.147
2053 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
2054 root 1.147 glRectf (px + 2,
2055 root 1.151 py - thick - 1,
2056     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
2057 root 1.143 }
2058     }
2059     }
2060 root 1.116 }
2061    
2062     void
2063 root 1.133 draw_magicmap (CFPlus::Map self, int dx, int dy, int w, int h, unsigned char *data)
2064 root 1.117 CODE:
2065     {
2066     static float color[16][3] = {
2067 root 1.123 { 0.00F, 0.00F, 0.00F },
2068     { 1.00F, 1.00F, 1.00F },
2069     { 0.00F, 0.00F, 0.55F },
2070     { 1.00F, 0.00F, 0.00F },
2071    
2072     { 1.00F, 0.54F, 0.00F },
2073     { 0.11F, 0.56F, 1.00F },
2074     { 0.93F, 0.46F, 0.00F },
2075     { 0.18F, 0.54F, 0.34F },
2076    
2077     { 0.56F, 0.73F, 0.56F },
2078     { 0.80F, 0.80F, 0.80F },
2079     { 0.55F, 0.41F, 0.13F },
2080     { 0.99F, 0.77F, 0.26F },
2081    
2082     { 0.74F, 0.65F, 0.41F },
2083    
2084     { 0.00F, 1.00F, 1.00F },
2085     { 1.00F, 0.00F, 1.00F },
2086     { 1.00F, 1.00F, 0.00F },
2087 root 1.117 };
2088    
2089     int x, y;
2090    
2091     glEnable (GL_TEXTURE_2D);
2092     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2093     glEnable (GL_BLEND);
2094     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2095     glBegin (GL_QUADS);
2096    
2097     for (y = 0; y < h; y++)
2098     for (x = 0; x < w; x++)
2099     {
2100     unsigned char m = data [x + y * w];
2101    
2102 root 1.118 if (m)
2103     {
2104     float *c = color [m & 15];
2105    
2106     float tx1 = m & 0x40 ? 0.5 : 0.;
2107     float tx2 = tx1 + 0.5;
2108    
2109     glColor4f (c[0], c[1], c[2], 0.75);
2110     glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2111     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2112     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2113     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2114     }
2115 root 1.117 }
2116    
2117     glEnd ();
2118     glDisable (GL_BLEND);
2119     glDisable (GL_TEXTURE_2D);
2120     }
2121    
2122     void
2123 root 1.204 fow_texture (CFPlus::Map self, int mx, int my, int sw, int sh)
2124 root 1.116 PPCODE:
2125     {
2126     int x, y;
2127 root 1.204 int sw1 = sw + 2;
2128     int sh1 = sh + 2;
2129     int sh3 = sh * 3;
2130     int sw34 = (sw * 3 + 3) & ~3;
2131     uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2132     SV *darkness3_sv = sv_2mortal (newSV (sw34 * sh3));
2133     uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2134    
2135     SvPOK_only (darkness3_sv);
2136     SvCUR_set (darkness3_sv, sw34 * sh3);
2137 root 1.116
2138 root 1.204 mx += self->x - 1;
2139     my += self->y - 1;
2140 root 1.116
2141 root 1.204 memset (darkness1, 255, sw1 * sh1);
2142    
2143     for (y = 0; y < sh1; y++)
2144 root 1.164 if (0 <= y + my && y + my < self->rows)
2145 root 1.116 {
2146 root 1.164 maprow *row = self->row + (y + my);
2147 root 1.116
2148 root 1.204 for (x = 0; x < sw1; x++)
2149 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2150 root 1.116 {
2151 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2152 root 1.116
2153 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2154 root 1.143 ? 255 - (cell->darkness - 1)
2155 root 1.142 : 255 - FOW_DARKNESS;
2156 root 1.116 }
2157     }
2158 root 1.34
2159 root 1.204 for (y = 0; y < sh; ++y)
2160     for (x = 0; x < sw; ++x)
2161     {
2162     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2163     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2164     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2165     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2166     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2167     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2168     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2169     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2170     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2171    
2172     uint8_t r11 = (d11 + d21 + d12) / 3;
2173     uint8_t r21 = d21;
2174     uint8_t r31 = (d21 + d31 + d32) / 3;
2175    
2176     uint8_t r12 = d12;
2177     uint8_t r22 = d22;
2178     uint8_t r32 = d32;
2179    
2180     uint8_t r13 = (d13 + d23 + d12) / 3;
2181     uint8_t r23 = d23;
2182     uint8_t r33 = (d23 + d33 + d32) / 3;
2183    
2184     darkness3 [(y * 3 ) * sw34 + (x * 3 )] = MAX (d22, r11);
2185     darkness3 [(y * 3 ) * sw34 + (x * 3 + 1)] = MAX (d22, r21);
2186     darkness3 [(y * 3 ) * sw34 + (x * 3 + 2)] = MAX (d22, r31);
2187     darkness3 [(y * 3 + 1) * sw34 + (x * 3 )] = MAX (d22, r12);
2188     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 1)] = MAX (d22, r22);
2189     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 2)] = MAX (d22, r32);
2190     darkness3 [(y * 3 + 2) * sw34 + (x * 3 )] = MAX (d22, r13);
2191     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 1)] = MAX (d22, r23);
2192     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 2)] = MAX (d22, r33);
2193     }
2194 root 1.201
2195 root 1.204 free (darkness1);
2196 root 1.201
2197 root 1.32 EXTEND (SP, 3);
2198 root 1.204 PUSHs (sv_2mortal (newSViv (sw34)));
2199     PUSHs (sv_2mortal (newSViv (sh3)));
2200     PUSHs (darkness3_sv);
2201 root 1.30 }
2202    
2203 root 1.42 SV *
2204 root 1.133 get_rect (CFPlus::Map self, int x0, int y0, int w, int h)
2205 root 1.42 CODE:
2206     {
2207     int x, y, x1, y1;
2208     SV *data_sv = newSV (w * h * 7 + 5);
2209     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2210    
2211     *data++ = 0; /* version 0 format */
2212     *data++ = w >> 8; *data++ = w;
2213     *data++ = h >> 8; *data++ = h;
2214    
2215     // we need to do this 'cause we don't keep an absolute coord system for rows
2216 root 1.55 // TODO: treat rows as we treat columns
2217 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2218     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2219    
2220     x0 += self->x - self->ox;
2221     y0 += self->y - self->oy;
2222    
2223     x1 = x0 + w;
2224     y1 = y0 + h;
2225    
2226     for (y = y0; y < y1; y++)
2227     {
2228     maprow *row = 0 <= y && y < self->rows
2229     ? self->row + y
2230     : 0;
2231    
2232     for (x = x0; x < x1; x++)
2233     {
2234     if (row && row->c0 <= x && x < row->c1)
2235     {
2236     mapcell *cell = row->col + (x - row->c0);
2237     uint8_t flags = 0;
2238    
2239 root 1.174 if (cell->tile [0]) flags |= 1;
2240     if (cell->tile [1]) flags |= 2;
2241     if (cell->tile [2]) flags |= 4;
2242 root 1.42
2243     *data++ = flags;
2244    
2245     if (flags & 1)
2246     {
2247 root 1.174 tileid tile = cell->tile [0];
2248     *data++ = tile >> 8;
2249     *data++ = tile;
2250 root 1.42 }
2251    
2252     if (flags & 2)
2253     {
2254 root 1.174 tileid tile = cell->tile [1];
2255     *data++ = tile >> 8;
2256     *data++ = tile;
2257 root 1.42 }
2258    
2259     if (flags & 4)
2260     {
2261 root 1.174 tileid tile = cell->tile [2];
2262     *data++ = tile >> 8;
2263     *data++ = tile;
2264 root 1.42 }
2265     }
2266     else
2267     *data++ = 0;
2268     }
2269     }
2270    
2271     SvPOK_only (data_sv);
2272     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2273     RETVAL = data_sv;
2274     }
2275     OUTPUT:
2276     RETVAL
2277    
2278     void
2279 root 1.133 set_rect (CFPlus::Map self, int x0, int y0, uint8_t *data)
2280 root 1.42 PPCODE:
2281     {
2282     int x, y, z;
2283 root 1.48 int w, h;
2284 root 1.42 int x1, y1;
2285    
2286     if (*data++ != 0)
2287 root 1.227 XSRETURN_EMPTY; /* version mismatch */
2288 root 1.42
2289 root 1.48 w = *data++ << 8; w |= *data++;
2290     h = *data++ << 8; h |= *data++;
2291 root 1.42
2292     // we need to do this 'cause we don't keep an absolute coord system for rows
2293 root 1.55 // TODO: treat rows as we treat columns
2294 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2295     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2296    
2297     x0 += self->x - self->ox;
2298     y0 += self->y - self->oy;
2299    
2300     x1 = x0 + w;
2301     y1 = y0 + h;
2302    
2303     for (y = y0; y < y1; y++)
2304     {
2305     maprow *row = map_get_row (self, y);
2306    
2307     for (x = x0; x < x1; x++)
2308     {
2309     uint8_t flags = *data++;
2310    
2311     if (flags)
2312     {
2313     mapcell *cell = row_get_cell (row, x);
2314 root 1.174 tileid tile[3] = { 0, 0, 0 };
2315 root 1.42
2316 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2317     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2318     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2319 root 1.42
2320 root 1.143 if (cell->darkness == 0)
2321 root 1.42 {
2322 root 1.142 cell->darkness = 0;
2323 root 1.42
2324     for (z = 0; z <= 2; z++)
2325     {
2326 root 1.174 tileid t = tile [z];
2327    
2328 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2329 root 1.174 {
2330     XPUSHs (sv_2mortal (newSViv (t)));
2331     need_texid (self, t);
2332     }
2333 root 1.42
2334 root 1.174 cell->tile [z] = t;
2335 root 1.42 }
2336     }
2337     }
2338     }
2339     }
2340     }
2341    
2342 root 1.212 MODULE = CFPlus PACKAGE = CFPlus::RW
2343 root 1.205
2344 root 1.212 CFPlus::RW
2345 root 1.211 new (SV *class, SV *data_sv)
2346     CODE:
2347     {
2348     STRLEN datalen;
2349     char *data = SvPVbyte (data_sv, datalen);
2350    
2351 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2352 root 1.211 }
2353     OUTPUT:
2354     RETVAL
2355    
2356 root 1.212 CFPlus::RW
2357     new_from_file (SV *class, const char *path, const char *mode = "rb")
2358     CODE:
2359     RETVAL = SDL_RWFromFile (path, mode);
2360     OUTPUT:
2361     RETVAL
2362    
2363 root 1.218 # fails on win32:
2364     # CFPlus.xs(2268) : error C2059: syntax error : '('
2365     #void
2366     #close (CFPlus::RW self)
2367     # CODE:
2368     # (self->(close)) (self);
2369 root 1.212
2370     MODULE = CFPlus PACKAGE = CFPlus::Channel
2371    
2372     PROTOTYPES: DISABLE
2373    
2374 root 1.215 CFPlus::Channel
2375     find ()
2376     CODE:
2377     {
2378     RETVAL = Mix_GroupAvailable (-1);
2379    
2380     if (RETVAL < 0)
2381     {
2382     RETVAL = Mix_GroupOldest (-1);
2383    
2384     if (RETVAL < 0)
2385     XSRETURN_UNDEF;
2386    
2387     Mix_HaltChannel (RETVAL);
2388     }
2389    
2390     Mix_UnregisterAllEffects (RETVAL);
2391     Mix_Volume (RETVAL, 128);
2392     }
2393     OUTPUT:
2394     RETVAL
2395    
2396 root 1.213 void
2397     halt (CFPlus::Channel self)
2398     CODE:
2399     Mix_HaltChannel (self);
2400    
2401     void
2402     expire (CFPlus::Channel self, int ticks = -1)
2403     CODE:
2404     Mix_ExpireChannel (self, ticks);
2405    
2406     void
2407     fade_out (CFPlus::Channel self, int ticks = -1)
2408     CODE:
2409     Mix_FadeOutChannel (self, ticks);
2410    
2411 root 1.212 int
2412     volume (CFPlus::Channel self, int volume)
2413     CODE:
2414 root 1.216 RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128));
2415 root 1.212 OUTPUT:
2416     RETVAL
2417    
2418 root 1.213 void
2419 root 1.212 unregister_all_effects (CFPlus::Channel self)
2420     CODE:
2421 root 1.213 Mix_UnregisterAllEffects (self);
2422 root 1.212
2423 root 1.213 void
2424 root 1.212 set_panning (CFPlus::Channel self, int left, int right)
2425     CODE:
2426 root 1.216 left = CLAMP (left , 0, 255);
2427     right = CLAMP (right, 0, 255);
2428 root 1.213 Mix_SetPanning (self, left, right);
2429 root 1.212
2430 root 1.213 void
2431 root 1.212 set_distance (CFPlus::Channel self, int distance)
2432     CODE:
2433 root 1.216 Mix_SetDistance (self, CLAMP (distance, 0, 255));
2434 root 1.212
2435 root 1.213 void
2436 root 1.212 set_position (CFPlus::Channel self, int angle, int distance)
2437     CODE:
2438 root 1.220
2439     void
2440     set_position_r (CFPlus::Channel self, int dx, int dy, int maxdistance)
2441     CODE:
2442     {
2443     int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance));
2444     int angle = 360 + (int)roundf (atan2f (dx, -dy) * 180.f / (float)M_PI);
2445 root 1.216 Mix_SetPosition (self, angle, CLAMP (distance, 0, 255));
2446 root 1.220 }
2447 root 1.212
2448 root 1.213 void
2449 root 1.212 set_reverse_stereo (CFPlus::Channel self, int flip)
2450     CODE:
2451 root 1.213 Mix_SetReverseStereo (self, flip);
2452 root 1.212
2453     MODULE = CFPlus PACKAGE = CFPlus::MixChunk
2454    
2455     PROTOTYPES: DISABLE
2456    
2457 root 1.211 CFPlus::MixChunk
2458 root 1.212 new (SV *class, CFPlus::RW rwops)
2459 root 1.52 CODE:
2460 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2461 root 1.52 OUTPUT:
2462     RETVAL
2463    
2464     void
2465 root 1.133 DESTROY (CFPlus::MixChunk self)
2466 root 1.52 CODE:
2467     Mix_FreeChunk (self);
2468    
2469     int
2470 root 1.133 volume (CFPlus::MixChunk self, int volume = -1)
2471 root 1.52 CODE:
2472 root 1.216 if (items > 1)
2473     volume = CLAMP (volume, 0, 128);
2474 root 1.52 RETVAL = Mix_VolumeChunk (self, volume);
2475     OUTPUT:
2476     RETVAL
2477    
2478 root 1.212 CFPlus::Channel
2479 root 1.215 play (CFPlus::MixChunk self, CFPlus::Channel channel = -1, int loops = 0, int ticks = -1)
2480 root 1.52 CODE:
2481 root 1.215 {
2482 root 1.52 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2483 root 1.215
2484     if (RETVAL < 0)
2485     XSRETURN_UNDEF;
2486    
2487     if (channel < 0)
2488     {
2489     Mix_UnregisterAllEffects (RETVAL);
2490     Mix_Volume (RETVAL, 128);
2491     }
2492     }
2493 root 1.52 OUTPUT:
2494     RETVAL
2495    
2496 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixMusic
2497 root 1.52
2498     int
2499     volume (int volume = -1)
2500 root 1.205 PROTOTYPE: ;$
2501 root 1.52 CODE:
2502 root 1.216 if (items > 0)
2503     volume = CLAMP (volume, 0, 128);
2504 root 1.52 RETVAL = Mix_VolumeMusic (volume);
2505     OUTPUT:
2506     RETVAL
2507    
2508 root 1.213 void
2509 root 1.194 fade_out (int ms)
2510     CODE:
2511 root 1.213 Mix_FadeOutMusic (ms);
2512 root 1.194
2513 root 1.212 void
2514     halt ()
2515     CODE:
2516     Mix_HaltMusic ();
2517    
2518 root 1.133 CFPlus::MixMusic
2519 root 1.212 new (SV *class, CFPlus::RW rwops)
2520 root 1.52 CODE:
2521 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
2522 root 1.52 OUTPUT:
2523     RETVAL
2524    
2525     void
2526 root 1.133 DESTROY (CFPlus::MixMusic self)
2527 root 1.52 CODE:
2528     Mix_FreeMusic (self);
2529    
2530     int
2531 root 1.133 play (CFPlus::MixMusic self, int loops = -1)
2532 root 1.52 CODE:
2533     RETVAL = Mix_PlayMusic (self, loops);
2534     OUTPUT:
2535     RETVAL
2536    
2537 root 1.213 void
2538 root 1.195 fade_in_pos (CFPlus::MixMusic self, int loops, int ms, double position)
2539     CODE:
2540 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
2541 root 1.195
2542 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::OpenGL
2543 root 1.54
2544 root 1.205 PROTOTYPES: ENABLE
2545    
2546 root 1.54 BOOT:
2547     {
2548 root 1.133 HV *stash = gv_stashpv ("CFPlus::OpenGL", 1);
2549 root 1.54 static const struct {
2550     const char *name;
2551     IV iv;
2552     } *civ, const_iv[] = {
2553     # define const_iv(name) { # name, (IV)name }
2554 root 1.199 const_iv (GL_VENDOR),
2555     const_iv (GL_VERSION),
2556     const_iv (GL_EXTENSIONS),
2557 root 1.54 const_iv (GL_COLOR_MATERIAL),
2558     const_iv (GL_SMOOTH),
2559     const_iv (GL_FLAT),
2560 root 1.69 const_iv (GL_DITHER),
2561 root 1.54 const_iv (GL_BLEND),
2562 root 1.89 const_iv (GL_CULL_FACE),
2563 root 1.69 const_iv (GL_SCISSOR_TEST),
2564 root 1.89 const_iv (GL_DEPTH_TEST),
2565     const_iv (GL_ALPHA_TEST),
2566     const_iv (GL_NORMALIZE),
2567     const_iv (GL_RESCALE_NORMAL),
2568 root 1.119 const_iv (GL_FRONT),
2569     const_iv (GL_BACK),
2570 root 1.206 const_iv (GL_AUX0),
2571 root 1.54 const_iv (GL_AND),
2572 root 1.67 const_iv (GL_ONE),
2573     const_iv (GL_ZERO),
2574 root 1.54 const_iv (GL_SRC_ALPHA),
2575 root 1.104 const_iv (GL_DST_ALPHA),
2576 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2577 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2578 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2579 root 1.54 const_iv (GL_RGB),
2580     const_iv (GL_RGBA),
2581 root 1.115 const_iv (GL_RGBA4),
2582     const_iv (GL_RGBA8),
2583     const_iv (GL_RGB5_A1),
2584 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2585 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2586     const_iv (GL_UNSIGNED_INT),
2587 root 1.54 const_iv (GL_ALPHA),
2588 root 1.86 const_iv (GL_INTENSITY),
2589 root 1.76 const_iv (GL_LUMINANCE),
2590 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2591 root 1.54 const_iv (GL_FLOAT),
2592     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2593 root 1.230 const_iv (GL_COMPRESSED_ALPHA_ARB),
2594     const_iv (GL_COMPRESSED_LUMINANCE_ARB),
2595     const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB),
2596     const_iv (GL_COMPRESSED_INTENSITY_ARB),
2597     const_iv (GL_COMPRESSED_RGB_ARB),
2598     const_iv (GL_COMPRESSED_RGBA_ARB),
2599 root 1.54 const_iv (GL_COMPILE),
2600 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
2601     const_iv (GL_PROXY_TEXTURE_2D),
2602 root 1.54 const_iv (GL_TEXTURE_1D),
2603     const_iv (GL_TEXTURE_2D),
2604     const_iv (GL_TEXTURE_ENV),
2605     const_iv (GL_TEXTURE_MAG_FILTER),
2606     const_iv (GL_TEXTURE_MIN_FILTER),
2607     const_iv (GL_TEXTURE_ENV_MODE),
2608     const_iv (GL_TEXTURE_WRAP_S),
2609     const_iv (GL_TEXTURE_WRAP_T),
2610 root 1.98 const_iv (GL_REPEAT),
2611 root 1.54 const_iv (GL_CLAMP),
2612 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2613 root 1.54 const_iv (GL_NEAREST),
2614     const_iv (GL_LINEAR),
2615 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2616     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2617     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2618     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2619     const_iv (GL_GENERATE_MIPMAP),
2620 root 1.54 const_iv (GL_MODULATE),
2621 root 1.69 const_iv (GL_DECAL),
2622 root 1.54 const_iv (GL_REPLACE),
2623 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2624 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2625     const_iv (GL_PROJECTION),
2626     const_iv (GL_MODELVIEW),
2627     const_iv (GL_COLOR_LOGIC_OP),
2628 root 1.69 const_iv (GL_SEPARABLE_2D),
2629 root 1.54 const_iv (GL_CONVOLUTION_2D),
2630     const_iv (GL_CONVOLUTION_BORDER_MODE),
2631     const_iv (GL_CONSTANT_BORDER),
2632 root 1.208 const_iv (GL_POINTS),
2633 root 1.54 const_iv (GL_LINES),
2634 root 1.138 const_iv (GL_LINE_STRIP),
2635 root 1.89 const_iv (GL_LINE_LOOP),
2636 root 1.54 const_iv (GL_QUADS),
2637 root 1.89 const_iv (GL_QUAD_STRIP),
2638     const_iv (GL_TRIANGLES),
2639     const_iv (GL_TRIANGLE_STRIP),
2640     const_iv (GL_TRIANGLE_FAN),
2641 root 1.208 const_iv (GL_POLYGON),
2642 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2643 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
2644     const_iv (GL_LINE_SMOOTH_HINT),
2645     const_iv (GL_POLYGON_SMOOTH_HINT),
2646     const_iv (GL_GENERATE_MIPMAP_HINT),
2647 root 1.232 const_iv (GL_TEXTURE_COMPRESSION_HINT),
2648 root 1.54 const_iv (GL_FASTEST),
2649 root 1.206 const_iv (GL_DONT_CARE),
2650     const_iv (GL_NICEST),
2651 root 1.89 const_iv (GL_V2F),
2652     const_iv (GL_V3F),
2653     const_iv (GL_T2F_V3F),
2654     const_iv (GL_T2F_N3F_V3F),
2655 root 1.54 # undef const_iv
2656     };
2657    
2658     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2659     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2660 root 1.188
2661     texture_av = newAV ();
2662     AvREAL_off (texture_av);
2663 root 1.54 }
2664    
2665 root 1.231 void
2666     disable_GL_EXT_blend_func_separate ()
2667     CODE:
2668     gl.BlendFuncSeparate = 0;
2669     gl.BlendFuncSeparateEXT = 0;
2670    
2671 root 1.97 char *
2672     gl_vendor ()
2673     CODE:
2674     RETVAL = (char *)glGetString (GL_VENDOR);
2675     OUTPUT:
2676     RETVAL
2677    
2678     char *
2679     gl_version ()
2680     CODE:
2681     RETVAL = (char *)glGetString (GL_VERSION);
2682     OUTPUT:
2683     RETVAL
2684    
2685     char *
2686     gl_extensions ()
2687     CODE:
2688     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2689     OUTPUT:
2690     RETVAL
2691    
2692 root 1.201 const char *glGetString (GLenum pname)
2693 root 1.199
2694     GLint glGetInteger (GLenum pname)
2695     CODE:
2696     glGetIntegerv (pname, &RETVAL);
2697     OUTPUT:
2698     RETVAL
2699    
2700     GLdouble glGetDouble (GLenum pname)
2701     CODE:
2702     glGetDoublev (pname, &RETVAL);
2703     OUTPUT:
2704     RETVAL
2705    
2706 root 1.54 int glGetError ()
2707    
2708 root 1.114 void glFinish ()
2709    
2710 root 1.54 void glClear (int mask)
2711    
2712     void glClearColor (float r, float g, float b, float a = 1.0)
2713     PROTOTYPE: @
2714    
2715     void glEnable (int cap)
2716    
2717     void glDisable (int cap)
2718    
2719     void glShadeModel (int mode)
2720    
2721     void glHint (int target, int mode)
2722    
2723     void glBlendFunc (int sfactor, int dfactor)
2724    
2725 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
2726     CODE:
2727     gl_BlendFuncSeparate (sa, da, saa, daa);
2728    
2729 root 1.89 void glDepthMask (int flag)
2730    
2731 root 1.54 void glLogicOp (int opcode)
2732    
2733 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
2734    
2735 root 1.54 void glMatrixMode (int mode)
2736    
2737     void glPushMatrix ()
2738    
2739     void glPopMatrix ()
2740    
2741     void glLoadIdentity ()
2742    
2743 root 1.119 void glDrawBuffer (int buffer)
2744    
2745     void glReadBuffer (int buffer)
2746    
2747 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
2748     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
2749    
2750     # near_ and far_ are due to microsofts buggy "c" compiler
2751 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
2752 root 1.54
2753 root 1.208 PROTOTYPES: DISABLE
2754    
2755 root 1.54 void glViewport (int x, int y, int width, int height)
2756    
2757 root 1.69 void glScissor (int x, int y, int width, int height)
2758    
2759 root 1.54 void glTranslate (float x, float y, float z = 0.)
2760     CODE:
2761     glTranslatef (x, y, z);
2762    
2763 root 1.62 void glScale (float x, float y, float z = 1.)
2764 root 1.54 CODE:
2765     glScalef (x, y, z);
2766    
2767     void glRotate (float angle, float x, float y, float z)
2768     CODE:
2769     glRotatef (angle, x, y, z);
2770    
2771     void glColor (float r, float g, float b, float a = 1.0)
2772 root 1.103 ALIAS:
2773     glColor_premultiply = 1
2774 root 1.54 CODE:
2775 root 1.103 if (ix)
2776     {
2777     r *= a;
2778     g *= a;
2779     b *= a;
2780     }
2781 root 1.90 // microsoft visual "c" rounds instead of truncating...
2782 root 1.130 glColor4f (r, g, b, a);
2783 root 1.54
2784 root 1.91 void glRasterPos (float x, float y, float z = 0.)
2785     CODE:
2786     glRasterPos3f (0, 0, z);
2787     glBitmap (0, 0, 0, 0, x, y, 0);
2788    
2789 root 1.54 void glVertex (float x, float y, float z = 0.)
2790     CODE:
2791     glVertex3f (x, y, z);
2792    
2793     void glTexCoord (float s, float t)
2794     CODE:
2795     glTexCoord2f (s, t);
2796    
2797 root 1.210 void glRect (float x1, float y1, float x2, float y2)
2798     CODE:
2799     glRectf (x1, y1, x2, y2);
2800    
2801 root 1.233 void glRect_lineloop (float x1, float y1, float x2, float y2)
2802     CODE:
2803     glBegin (GL_LINE_LOOP);
2804     glVertex2f (x1, y1);
2805     glVertex2f (x2, y1);
2806     glVertex2f (x2, y2);
2807     glVertex2f (x1, y2);
2808     glEnd ();
2809    
2810 root 1.208 PROTOTYPES: ENABLE
2811    
2812     void glBegin (int mode)
2813    
2814     void glEnd ()
2815    
2816     void glPointSize (GLfloat size)
2817    
2818     void glLineWidth (GLfloat width)
2819    
2820     void glInterleavedArrays (int format, int stride, char *data)
2821    
2822     void glDrawElements (int mode, int count, int type, char *indices)
2823    
2824     # 1.2 void glDrawRangeElements (int mode, int start, int end
2825    
2826 root 1.54 void glTexEnv (int target, int pname, float param)
2827     CODE:
2828     glTexEnvf (target, pname, param);
2829    
2830     void glTexParameter (int target, int pname, float param)
2831     CODE:
2832     glTexParameterf (target, pname, param);
2833    
2834     void glBindTexture (int target, int name)
2835    
2836     void glConvolutionParameter (int target, int pname, float params)
2837     CODE:
2838 root 1.103 if (gl.ConvolutionParameterf)
2839     gl.ConvolutionParameterf (target, pname, params);
2840 root 1.54
2841     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
2842 root 1.64 CODE:
2843 root 1.103 if (gl.ConvolutionFilter2D)
2844     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
2845 root 1.54
2846 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
2847     CODE:
2848 root 1.103 if (gl.SeparableFilter2D)
2849     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
2850 root 1.69
2851 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
2852    
2853     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
2854    
2855 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
2856 root 1.68
2857 root 1.199 void glPixelZoom (float x, float y)
2858    
2859 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
2860    
2861 root 1.54 int glGenTexture ()
2862     CODE:
2863 root 1.192 RETVAL = gen_texture ();
2864 root 1.54 OUTPUT:
2865     RETVAL
2866    
2867     void glDeleteTexture (int name)
2868     CODE:
2869 root 1.192 del_texture (name);
2870    
2871 root 1.54 int glGenList ()
2872     CODE:
2873     RETVAL = glGenLists (1);
2874     OUTPUT:
2875     RETVAL
2876    
2877     void glDeleteList (int list)
2878     CODE:
2879     glDeleteLists (list, 1);
2880    
2881     void glNewList (int list, int mode = GL_COMPILE)
2882    
2883     void glEndList ()
2884    
2885     void glCallList (int list)
2886    
2887 root 1.207 MODULE = CFPlus PACKAGE = CFPlus::UI::Base
2888    
2889     PROTOTYPES: DISABLE
2890    
2891     void
2892 root 1.209 find_widget (SV *self, NV x, NV y)
2893 root 1.207 PPCODE:
2894     {
2895 root 1.209 if (within_widget (self, x, y))
2896     XPUSHs (self);
2897     }
2898    
2899     BOOT:
2900     {
2901     hover_gv = gv_fetchpv ("CFPlus::UI::HOVER", 1, SVt_NV);
2902    
2903     draw_x_gv = gv_fetchpv ("CFPlus::UI::Base::draw_x", 1, SVt_NV);
2904     draw_y_gv = gv_fetchpv ("CFPlus::UI::Base::draw_y", 1, SVt_NV);
2905     draw_w_gv = gv_fetchpv ("CFPlus::UI::Base::draw_w", 1, SVt_NV);
2906     draw_h_gv = gv_fetchpv ("CFPlus::UI::Base::draw_h", 1, SVt_NV);
2907     }
2908    
2909     void
2910     draw (SV *self)
2911     CODE:
2912     {
2913     HV *hv;
2914     SV **svp;
2915     NV x, y, w, h;
2916     SV *draw_x_sv = GvSV (draw_x_gv);
2917     SV *draw_y_sv = GvSV (draw_y_gv);
2918     SV *draw_w_sv = GvSV (draw_w_gv);
2919     SV *draw_h_sv = GvSV (draw_h_gv);
2920 root 1.228 double draw_x, draw_y;
2921 root 1.209
2922     if (!SvROK (self))
2923     croak ("CFPlus::Base::draw: %s not a reference", SvPV_nolen (self));
2924    
2925     hv = (HV *)SvRV (self);
2926    
2927     if (SvTYPE (hv) != SVt_PVHV)
2928     croak ("CFPlus::Base::draw: %s not a hashref", SvPV_nolen (self));
2929    
2930     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
2931     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
2932    
2933     if (!h || !w)
2934     XSRETURN_EMPTY;
2935    
2936     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
2937     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
2938    
2939     draw_x = SvNV (draw_x_sv) + x;
2940     draw_y = SvNV (draw_y_sv) + y;
2941    
2942     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
2943     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
2944     XSRETURN_EMPTY;
2945    
2946     sv_setnv (draw_x_sv, draw_x);
2947     sv_setnv (draw_y_sv, draw_y);
2948    
2949     glPushMatrix ();
2950     glTranslated (x, y, 0);
2951    
2952     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
2953     {
2954     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
2955    
2956     if (svp && SvTRUE (*svp))
2957     {
2958 root 1.228 glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f);
2959 root 1.209 glEnable (GL_BLEND);
2960     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
2961     glBegin (GL_QUADS);
2962     glVertex2f (0, 0);
2963     glVertex2f (w, 0);
2964     glVertex2f (w, h);
2965     glVertex2f (0, h);
2966     glEnd ();
2967     glDisable (GL_BLEND);
2968     }
2969     }
2970     #if 0
2971 root 1.234 // draw borders, for debugging
2972     glPushMatrix ();
2973     glColor4f (1., 1., 0., 1.);
2974     glTranslatef (.5, .5, 0.);
2975     glBegin (GL_LINE_LOOP);
2976     glVertex2f (0 , 0);
2977     glVertex2f (w - 1, 0);
2978     glVertex2f (w - 1, h - 1);
2979     glVertex2f (0 , h - 1);
2980     glEnd ();
2981     glPopMatrix ();
2982 root 1.209 #endif
2983     PUSHMARK (SP);
2984     XPUSHs (self);
2985     PUTBACK;
2986     call_method ("_draw", G_VOID | G_DISCARD);
2987     SPAGAIN;
2988    
2989     glPopMatrix ();
2990    
2991     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
2992     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
2993 root 1.207 }
2994