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

File Contents

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