ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.225
Committed: Sat Aug 11 12:07:54 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.224: +28 -1 lines
Log Message:
use rendercache to speed up text reendering and hopefully also save memory

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