ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.266
Committed: Sun Jul 20 02:51:40 2008 UTC (15 years, 9 months ago) by root
Branch: MAIN
Changes since 1.265: +9 -4 lines
Log Message:
properly(?) clear cell meta info on map updates

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