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