ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.262
Committed: Wed Jul 16 20:12:27 2008 UTC (15 years, 9 months ago) by root
Branch: MAIN
Changes since 1.261: +2 -3 lines
Log Message:
c89

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