ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.222
Committed: Sat Aug 11 06:34:26 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.221: +5 -0 lines
Log Message:
port to windows, i.e. far away from C

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