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

File Contents

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