ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.269
Committed: Sun Jul 20 03:46:02 2008 UTC (15 years, 9 months ago) by root
Branch: MAIN
Changes since 1.268: +4 -2 lines
Log Message:
enlarge fow texture when displacing

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