ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.268
Committed: Sun Jul 20 02:57:43 2008 UTC (15 years, 9 months ago) by root
Branch: MAIN
Changes since 1.267: +2 -0 lines
Log Message:
clear top tile if a palyer is visible, avoids most artifacts but is a hack

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