ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.264
Committed: Fri Jul 18 22:32:54 2008 UTC (15 years, 9 months ago) by root
Branch: MAIN
Changes since 1.263: +27 -3 lines
Log Message:
*** empty log message ***

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