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

File Contents

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