ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.235
Committed: Tue Aug 28 01:23:47 2007 UTC (16 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-0_99
Changes since 1.234: +17 -2 lines
Log Message:
- generalise keyboard handling a bit into a default
  keymapping + macro functions (such as "!completer shout").
- default keymappings ahve a lower priority, so its possible to
  (in theory) override them. a UI for this has not yet been created.
- re-enable NPOT texture usage, if available.

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