ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.261
Committed: Sun Jul 13 12:17:00 2008 UTC (15 years, 10 months ago) by root
Branch: MAIN
Changes since 1.260: +47 -9 lines
Log Message:
support player displacement

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    
1831     pl_tex.name = 0;
1832 root 1.223
1833     rc_t *rc = rc_alloc ();
1834     rc_key_t key;
1835     rc_array_t *arr;
1836 root 1.48
1837 root 1.176 // thats current max. sorry.
1838     if (sw > 255) sw = 255;
1839     if (sh > 255) sh = 255;
1840    
1841     // clear key, in case of extra padding
1842     memset (&skey, 0, sizeof (skey));
1843    
1844 root 1.223 memset (&key, 0, sizeof (key));
1845     key.r = 255;
1846     key.g = 255;
1847     key.b = 255;
1848     key.a = 255;
1849     key.mode = GL_QUADS;
1850     key.format = GL_T2F_V3F;
1851     key.texname = -1;
1852 root 1.30
1853 root 1.164 mx += self->x;
1854     my += self->y;
1855    
1856 root 1.176 // first pass: determine smooth_max
1857     // rather ugly, if you ask me
1858     // could also be stored inside mapcell and updated on change
1859     memset (smooth_max, 0, sizeof (smooth_max));
1860    
1861     for (y = 0; y < sh; y++)
1862     if (0 <= y + my && y + my < self->rows)
1863     {
1864     maprow *row = self->row + (y + my);
1865    
1866     for (x = 0; x < sw; x++)
1867     if (row->c0 <= x + mx && x + mx < row->c1)
1868     {
1869     mapcell *cell = row->col + (x + mx - row->c0);
1870    
1871 root 1.177 smooth_max[x + 1][y + 1] =
1872     MAX (self->tex [cell->tile [0]].smoothlevel,
1873     MAX (self->tex [cell->tile [1]].smoothlevel,
1874     self->tex [cell->tile [2]].smoothlevel));
1875 root 1.176 }
1876     }
1877    
1878 root 1.223 glEnable (GL_BLEND);
1879     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1880     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1881    
1882 root 1.176 for (z = 0; z <= 2; z++)
1883     {
1884 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
1885    
1886 root 1.176 for (y = 0; y < sh; y++)
1887     if (0 <= y + my && y + my < self->rows)
1888     {
1889     maprow *row = self->row + (y + my);
1890    
1891     for (x = 0; x < sw; x++)
1892     if (row->c0 <= x + mx && x + mx < row->c1)
1893     {
1894     mapcell *cell = row->col + (x + mx - row->c0);
1895     tileid tile = cell->tile [z];
1896    
1897     if (tile)
1898     {
1899     maptex tex = self->tex [tile];
1900 root 1.261 int px = (x + 1) * T - tex.w;
1901     int py = (y + 1) * T - tex.h;
1902 root 1.176
1903 root 1.223 if (key.texname != tex.name)
1904 root 1.176 {
1905     if (!tex.name)
1906 root 1.221 tex = self->tex [2]; /* missing, replace by noface */
1907 root 1.176
1908 root 1.223 key.texname = tex.name;
1909     arr = rc_array (rc, &key);
1910 root 1.176 }
1911    
1912 root 1.261 if (expect_false (cell->player == player) && expect_false (z == 2))
1913     {
1914     pl_x = px;
1915     pl_y = py;
1916     pl_tex = tex;
1917     continue;
1918     }
1919 root 1.219
1920 root 1.223 rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
1921     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
1922     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
1923     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
1924 root 1.176
1925 root 1.261 if (expect_false (cell->flags) && expect_false (z == 2))
1926 root 1.176 {
1927 root 1.223 // overlays such as the speech bubble, probably more to come
1928 root 1.176 if (cell->flags & 1)
1929     {
1930     maptex tex = self->tex [1];
1931     int px = x * T + T * 2 / 32;
1932     int py = y * T - T * 6 / 32;
1933    
1934 root 1.223 if (tex.name)
1935     {
1936     if (key.texname != tex.name)
1937     {
1938     key.texname = tex.name;
1939     arr = rc_array (rc, &key);
1940     }
1941    
1942     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
1943     rc_t2f_v3f (arr, 0 , tex.t, px , py + T, 0);
1944     rc_t2f_v3f (arr, tex.s, tex.t, px + T, py + T, 0);
1945     rc_t2f_v3f (arr, tex.s, 0 , px + T, py , 0);
1946     }
1947 root 1.176 }
1948     }
1949    
1950     // update smooth hash
1951     if (tex.smoothtile)
1952     {
1953     skey.tile = tex.smoothtile;
1954     skey.level = tex.smoothlevel;
1955    
1956     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
1957 root 1.30
1958 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
1959     // shifted +1|+1 so we always stay positive.
1960 root 1.30
1961 root 1.180 // bits is ___n cccc CCCC bbbb
1962     // n do not draw borders&corners
1963     // c draw these corners, but...
1964     // C ... not these
1965     // b draw these borders
1966    
1967     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
1968     // ┃· ·· ·┃ ━━
1969    
1970     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
1971     // ·· ·· ·┏ ┓·
1972    
1973 root 1.176 // full tile
1974     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
1975    
1976     // borders
1977 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
1978     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
1979 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
1980     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
1981    
1982     // corners
1983     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
1984     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
1985     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
1986     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
1987     }
1988     }
1989     }
1990     }
1991 root 1.174
1992 root 1.224 rc_draw (rc);
1993     rc_clear (rc);
1994    
1995 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
1996     // this is basically counting sort
1997 root 1.176 {
1998 root 1.186 int w, b;
1999 root 1.30
2000 root 1.226 glEnable (GL_TEXTURE_2D);
2001     glBegin (GL_QUADS);
2002 root 1.186 for (w = 0; w < 256 / 32; ++w)
2003     {
2004     uint32_t smask = smooth_level [w];
2005     if (smask)
2006     for (b = 0; b < 32; ++b)
2007     if (smask & (((uint32_t)1) << b))
2008 root 1.176 {
2009 root 1.186 int level = (w << 5) | b;
2010     HE *he;
2011 root 1.153
2012 root 1.186 hv_iterinit (smooth);
2013     while ((he = hv_iternext (smooth)))
2014 root 1.153 {
2015 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
2016     IV bits = SvIVX (HeVAL (he));
2017 root 1.176
2018 root 1.186 if (!(bits & 0x1000)
2019     && skey->level == level
2020 root 1.191 && level > smooth_max [skey->x][skey->y])
2021 root 1.174 {
2022 root 1.186 maptex tex = self->tex [skey->tile];
2023     int px = (((int)skey->x) - 1) * T;
2024     int py = (((int)skey->y) - 1) * T;
2025     int border = bits & 15;
2026     int corner = (bits >> 8) & ~(bits >> 4) & 15;
2027     float dx = tex.s * .0625f; // 16 images/row
2028     float dy = tex.t * .5f ; // 2 images/column
2029    
2030 root 1.223 if (tex.name)
2031 root 1.186 {
2032 root 1.223 // this time avoiding texture state changes
2033     // save gobs of state changes.
2034     if (key.texname != tex.name)
2035     {
2036 root 1.226 glEnd ();
2037     glBindTexture (GL_TEXTURE_2D, key.texname = tex.name);
2038     glBegin (GL_QUADS);
2039 root 1.223 }
2040    
2041     if (border)
2042     {
2043     float ox = border * dx;
2044    
2045 root 1.226 glTexCoord2f (ox , 0.f ); glVertex2i (px , py );
2046     glTexCoord2f (ox , dy ); glVertex2i (px , py + T);
2047     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py + T);
2048     glTexCoord2f (ox + dx, 0.f ); glVertex2i (px + T, py );
2049 root 1.223 }
2050    
2051     if (corner)
2052     {
2053     float ox = corner * dx;
2054    
2055 root 1.226 glTexCoord2f (ox , dy ); glVertex2i (px , py );
2056     glTexCoord2f (ox , dy * 2.f); glVertex2i (px , py + T);
2057     glTexCoord2f (ox + dx, dy * 2.f); glVertex2i (px + T, py + T);
2058     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py );
2059 root 1.223 }
2060 root 1.186 }
2061 root 1.174 }
2062 root 1.153 }
2063     }
2064 root 1.186 }
2065 root 1.226
2066     glEnd ();
2067     glDisable (GL_TEXTURE_2D);
2068     key.texname = -1;
2069 root 1.176 }
2070    
2071 root 1.186 hv_clear (smooth);
2072     }
2073 root 1.30
2074 root 1.261 if (pl_tex.name)
2075     {
2076     maptex tex = pl_tex;
2077     int px = pl_x + pdx;
2078     int py = pl_y + pdy;
2079    
2080     key.texname = tex.name;
2081     arr = rc_array (rc, &key);
2082    
2083     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2084     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
2085     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
2086     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
2087    
2088     rc_draw (rc);
2089     }
2090    
2091 root 1.152 glDisable (GL_BLEND);
2092 root 1.223 rc_free (rc);
2093 root 1.143
2094 root 1.145 // top layer: overlays such as the health bar
2095 root 1.143 for (y = 0; y < sh; y++)
2096 root 1.164 if (0 <= y + my && y + my < self->rows)
2097 root 1.143 {
2098 root 1.164 maprow *row = self->row + (y + my);
2099 root 1.143
2100     for (x = 0; x < sw; x++)
2101 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2102 root 1.143 {
2103 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2104 root 1.143
2105 root 1.171 int px = x * T;
2106     int py = y * T;
2107 root 1.143
2108     if (cell->stat_hp)
2109     {
2110 root 1.171 int width = cell->stat_width * T;
2111 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
2112 root 1.143
2113 root 1.152 glColor3ub (0, 0, 0);
2114 root 1.151 glRectf (px + 1, py - thick - 2,
2115     px + width - 1, py);
2116 root 1.147
2117 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
2118 root 1.147 glRectf (px + 2,
2119 root 1.151 py - thick - 1,
2120     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
2121 root 1.143 }
2122     }
2123     }
2124 root 1.116 }
2125    
2126     void
2127 root 1.242 draw_magicmap (DC::Map self, int dx, int dy, int w, int h, unsigned char *data)
2128 root 1.117 CODE:
2129     {
2130     static float color[16][3] = {
2131 root 1.123 { 0.00F, 0.00F, 0.00F },
2132     { 1.00F, 1.00F, 1.00F },
2133     { 0.00F, 0.00F, 0.55F },
2134     { 1.00F, 0.00F, 0.00F },
2135    
2136     { 1.00F, 0.54F, 0.00F },
2137     { 0.11F, 0.56F, 1.00F },
2138     { 0.93F, 0.46F, 0.00F },
2139     { 0.18F, 0.54F, 0.34F },
2140    
2141     { 0.56F, 0.73F, 0.56F },
2142     { 0.80F, 0.80F, 0.80F },
2143     { 0.55F, 0.41F, 0.13F },
2144     { 0.99F, 0.77F, 0.26F },
2145    
2146     { 0.74F, 0.65F, 0.41F },
2147    
2148     { 0.00F, 1.00F, 1.00F },
2149     { 1.00F, 0.00F, 1.00F },
2150     { 1.00F, 1.00F, 0.00F },
2151 root 1.117 };
2152    
2153     int x, y;
2154    
2155     glEnable (GL_TEXTURE_2D);
2156     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2157     glEnable (GL_BLEND);
2158     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2159     glBegin (GL_QUADS);
2160    
2161     for (y = 0; y < h; y++)
2162     for (x = 0; x < w; x++)
2163     {
2164     unsigned char m = data [x + y * w];
2165    
2166 root 1.118 if (m)
2167     {
2168     float *c = color [m & 15];
2169    
2170     float tx1 = m & 0x40 ? 0.5 : 0.;
2171     float tx2 = tx1 + 0.5;
2172    
2173     glColor4f (c[0], c[1], c[2], 0.75);
2174     glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2175     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2176     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2177     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2178     }
2179 root 1.117 }
2180    
2181     glEnd ();
2182     glDisable (GL_BLEND);
2183     glDisable (GL_TEXTURE_2D);
2184     }
2185    
2186     void
2187 root 1.242 fow_texture (DC::Map self, int mx, int my, int sw, int sh)
2188 root 1.116 PPCODE:
2189     {
2190     int x, y;
2191 root 1.204 int sw1 = sw + 2;
2192     int sh1 = sh + 2;
2193     int sh3 = sh * 3;
2194     int sw34 = (sw * 3 + 3) & ~3;
2195     uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2196     SV *darkness3_sv = sv_2mortal (newSV (sw34 * sh3));
2197     uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2198    
2199     SvPOK_only (darkness3_sv);
2200     SvCUR_set (darkness3_sv, sw34 * sh3);
2201 root 1.116
2202 root 1.204 mx += self->x - 1;
2203     my += self->y - 1;
2204 root 1.116
2205 root 1.204 memset (darkness1, 255, sw1 * sh1);
2206    
2207     for (y = 0; y < sh1; y++)
2208 root 1.164 if (0 <= y + my && y + my < self->rows)
2209 root 1.116 {
2210 root 1.164 maprow *row = self->row + (y + my);
2211 root 1.116
2212 root 1.204 for (x = 0; x < sw1; x++)
2213 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2214 root 1.116 {
2215 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2216 root 1.116
2217 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2218 root 1.143 ? 255 - (cell->darkness - 1)
2219 root 1.142 : 255 - FOW_DARKNESS;
2220 root 1.116 }
2221     }
2222 root 1.34
2223 root 1.204 for (y = 0; y < sh; ++y)
2224     for (x = 0; x < sw; ++x)
2225     {
2226     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2227     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2228     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2229     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2230     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2231     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2232     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2233     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2234     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2235    
2236     uint8_t r11 = (d11 + d21 + d12) / 3;
2237     uint8_t r21 = d21;
2238     uint8_t r31 = (d21 + d31 + d32) / 3;
2239    
2240     uint8_t r12 = d12;
2241     uint8_t r22 = d22;
2242     uint8_t r32 = d32;
2243    
2244     uint8_t r13 = (d13 + d23 + d12) / 3;
2245     uint8_t r23 = d23;
2246     uint8_t r33 = (d23 + d33 + d32) / 3;
2247    
2248     darkness3 [(y * 3 ) * sw34 + (x * 3 )] = MAX (d22, r11);
2249     darkness3 [(y * 3 ) * sw34 + (x * 3 + 1)] = MAX (d22, r21);
2250     darkness3 [(y * 3 ) * sw34 + (x * 3 + 2)] = MAX (d22, r31);
2251     darkness3 [(y * 3 + 1) * sw34 + (x * 3 )] = MAX (d22, r12);
2252     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 1)] = MAX (d22, r22);
2253     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 2)] = MAX (d22, r32);
2254     darkness3 [(y * 3 + 2) * sw34 + (x * 3 )] = MAX (d22, r13);
2255     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 1)] = MAX (d22, r23);
2256     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 2)] = MAX (d22, r33);
2257     }
2258 root 1.201
2259 root 1.204 free (darkness1);
2260 root 1.201
2261 root 1.32 EXTEND (SP, 3);
2262 root 1.204 PUSHs (sv_2mortal (newSViv (sw34)));
2263     PUSHs (sv_2mortal (newSViv (sh3)));
2264     PUSHs (darkness3_sv);
2265 root 1.30 }
2266    
2267 root 1.42 SV *
2268 root 1.242 get_rect (DC::Map self, int x0, int y0, int w, int h)
2269 root 1.42 CODE:
2270     {
2271     int x, y, x1, y1;
2272     SV *data_sv = newSV (w * h * 7 + 5);
2273     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2274    
2275     *data++ = 0; /* version 0 format */
2276     *data++ = w >> 8; *data++ = w;
2277     *data++ = h >> 8; *data++ = h;
2278    
2279     // we need to do this 'cause we don't keep an absolute coord system for rows
2280 root 1.55 // TODO: treat rows as we treat columns
2281 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2282     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2283    
2284     x0 += self->x - self->ox;
2285     y0 += self->y - self->oy;
2286    
2287     x1 = x0 + w;
2288     y1 = y0 + h;
2289    
2290     for (y = y0; y < y1; y++)
2291     {
2292     maprow *row = 0 <= y && y < self->rows
2293     ? self->row + y
2294     : 0;
2295    
2296     for (x = x0; x < x1; x++)
2297     {
2298     if (row && row->c0 <= x && x < row->c1)
2299     {
2300     mapcell *cell = row->col + (x - row->c0);
2301     uint8_t flags = 0;
2302    
2303 root 1.174 if (cell->tile [0]) flags |= 1;
2304     if (cell->tile [1]) flags |= 2;
2305     if (cell->tile [2]) flags |= 4;
2306 root 1.42
2307     *data++ = flags;
2308    
2309     if (flags & 1)
2310     {
2311 root 1.174 tileid tile = cell->tile [0];
2312     *data++ = tile >> 8;
2313     *data++ = tile;
2314 root 1.42 }
2315    
2316     if (flags & 2)
2317     {
2318 root 1.174 tileid tile = cell->tile [1];
2319     *data++ = tile >> 8;
2320     *data++ = tile;
2321 root 1.42 }
2322    
2323     if (flags & 4)
2324     {
2325 root 1.174 tileid tile = cell->tile [2];
2326     *data++ = tile >> 8;
2327     *data++ = tile;
2328 root 1.42 }
2329     }
2330     else
2331     *data++ = 0;
2332     }
2333     }
2334    
2335 root 1.260 /* if size is w*h + 5 then no data has been found */
2336     if (data - (uint8_t *)SvPVX (data_sv) != w * h + 5)
2337 root 1.259 {
2338     SvPOK_only (data_sv);
2339     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2340     }
2341 root 1.260
2342     RETVAL = data_sv;
2343 root 1.42 }
2344     OUTPUT:
2345     RETVAL
2346    
2347     void
2348 root 1.259 set_rect (DC::Map self, int x0, int y0, SV *data_sv)
2349 root 1.42 PPCODE:
2350     {
2351     int x, y, z;
2352 root 1.48 int w, h;
2353 root 1.42 int x1, y1;
2354 root 1.259 STRLEN len;
2355     uint8_t *data, *end;
2356    
2357     len = SvLEN (data_sv);
2358 root 1.260 SvGROW (data_sv, len + 8); // reserve at least 7+ bytes more
2359 root 1.259 data = SvPVbyte_nolen (data_sv);
2360 root 1.260 end = data + len + 8;
2361 root 1.259
2362     if (len < 5)
2363     XSRETURN_EMPTY;
2364 root 1.42
2365     if (*data++ != 0)
2366 root 1.227 XSRETURN_EMPTY; /* version mismatch */
2367 root 1.42
2368 root 1.48 w = *data++ << 8; w |= *data++;
2369     h = *data++ << 8; h |= *data++;
2370 root 1.42
2371     // we need to do this 'cause we don't keep an absolute coord system for rows
2372 root 1.55 // TODO: treat rows as we treat columns
2373 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2374     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2375    
2376     x0 += self->x - self->ox;
2377     y0 += self->y - self->oy;
2378    
2379     x1 = x0 + w;
2380     y1 = y0 + h;
2381    
2382     for (y = y0; y < y1; y++)
2383     {
2384     maprow *row = map_get_row (self, y);
2385    
2386     for (x = x0; x < x1; x++)
2387     {
2388 root 1.259 uint8_t flags;
2389    
2390     if (data + 7 >= end)
2391     XSRETURN_EMPTY;
2392    
2393     flags = *data++;
2394 root 1.42
2395     if (flags)
2396     {
2397     mapcell *cell = row_get_cell (row, x);
2398 root 1.174 tileid tile[3] = { 0, 0, 0 };
2399 root 1.42
2400 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2401     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2402     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2403 root 1.42
2404 root 1.143 if (cell->darkness == 0)
2405 root 1.42 {
2406 root 1.260 /*cell->darkness = 0;*/
2407     EXTEND (SP, 3);
2408 root 1.42
2409     for (z = 0; z <= 2; z++)
2410     {
2411 root 1.174 tileid t = tile [z];
2412    
2413 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2414 root 1.174 {
2415 root 1.260 PUSHs (sv_2mortal (newSViv (t)));
2416 root 1.174 need_texid (self, t);
2417     }
2418 root 1.42
2419 root 1.174 cell->tile [z] = t;
2420 root 1.42 }
2421     }
2422     }
2423     }
2424     }
2425     }
2426    
2427 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::RW
2428 root 1.205
2429 root 1.242 DC::RW
2430 root 1.211 new (SV *class, SV *data_sv)
2431     CODE:
2432     {
2433     STRLEN datalen;
2434     char *data = SvPVbyte (data_sv, datalen);
2435    
2436 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2437 root 1.211 }
2438     OUTPUT:
2439     RETVAL
2440    
2441 root 1.242 DC::RW
2442 root 1.212 new_from_file (SV *class, const char *path, const char *mode = "rb")
2443     CODE:
2444     RETVAL = SDL_RWFromFile (path, mode);
2445     OUTPUT:
2446     RETVAL
2447    
2448 root 1.218 # fails on win32:
2449 root 1.241 # dc.xs(2268) : error C2059: syntax error : '('
2450 root 1.218 #void
2451 root 1.242 #close (DC::RW self)
2452 root 1.218 # CODE:
2453     # (self->(close)) (self);
2454 root 1.212
2455 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Channel
2456 root 1.212
2457     PROTOTYPES: DISABLE
2458    
2459 root 1.242 DC::Channel
2460 root 1.215 find ()
2461     CODE:
2462     {
2463     RETVAL = Mix_GroupAvailable (-1);
2464    
2465     if (RETVAL < 0)
2466     {
2467     RETVAL = Mix_GroupOldest (-1);
2468    
2469     if (RETVAL < 0)
2470     XSRETURN_UNDEF;
2471    
2472     Mix_HaltChannel (RETVAL);
2473     }
2474    
2475     Mix_UnregisterAllEffects (RETVAL);
2476     Mix_Volume (RETVAL, 128);
2477     }
2478     OUTPUT:
2479     RETVAL
2480    
2481 root 1.213 void
2482 root 1.242 halt (DC::Channel self)
2483 root 1.213 CODE:
2484     Mix_HaltChannel (self);
2485    
2486     void
2487 root 1.242 expire (DC::Channel self, int ticks = -1)
2488 root 1.213 CODE:
2489     Mix_ExpireChannel (self, ticks);
2490    
2491     void
2492 root 1.242 fade_out (DC::Channel self, int ticks = -1)
2493 root 1.213 CODE:
2494     Mix_FadeOutChannel (self, ticks);
2495    
2496 root 1.212 int
2497 root 1.242 volume (DC::Channel self, int volume)
2498 root 1.212 CODE:
2499 root 1.216 RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128));
2500 root 1.212 OUTPUT:
2501     RETVAL
2502    
2503 root 1.213 void
2504 root 1.242 unregister_all_effects (DC::Channel self)
2505 root 1.212 CODE:
2506 root 1.213 Mix_UnregisterAllEffects (self);
2507 root 1.212
2508 root 1.213 void
2509 root 1.242 set_panning (DC::Channel self, int left, int right)
2510 root 1.212 CODE:
2511 root 1.216 left = CLAMP (left , 0, 255);
2512     right = CLAMP (right, 0, 255);
2513 root 1.213 Mix_SetPanning (self, left, right);
2514 root 1.212
2515 root 1.213 void
2516 root 1.242 set_distance (DC::Channel self, int distance)
2517 root 1.212 CODE:
2518 root 1.216 Mix_SetDistance (self, CLAMP (distance, 0, 255));
2519 root 1.212
2520 root 1.213 void
2521 root 1.242 set_position (DC::Channel self, int angle, int distance)
2522 root 1.212 CODE:
2523 root 1.220
2524     void
2525 root 1.242 set_position_r (DC::Channel self, int dx, int dy, int maxdistance)
2526 root 1.220 CODE:
2527     {
2528     int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance));
2529     int angle = 360 + (int)roundf (atan2f (dx, -dy) * 180.f / (float)M_PI);
2530 root 1.216 Mix_SetPosition (self, angle, CLAMP (distance, 0, 255));
2531 root 1.220 }
2532 root 1.212
2533 root 1.213 void
2534 root 1.242 set_reverse_stereo (DC::Channel self, int flip)
2535 root 1.212 CODE:
2536 root 1.213 Mix_SetReverseStereo (self, flip);
2537 root 1.212
2538 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixChunk
2539 root 1.212
2540     PROTOTYPES: DISABLE
2541    
2542 root 1.242 DC::MixChunk
2543     new (SV *class, DC::RW rwops)
2544 root 1.52 CODE:
2545 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2546 root 1.52 OUTPUT:
2547     RETVAL
2548    
2549     void
2550 root 1.242 DESTROY (DC::MixChunk self)
2551 root 1.52 CODE:
2552     Mix_FreeChunk (self);
2553    
2554     int
2555 root 1.242 volume (DC::MixChunk self, int volume = -1)
2556 root 1.52 CODE:
2557 root 1.216 if (items > 1)
2558     volume = CLAMP (volume, 0, 128);
2559 root 1.52 RETVAL = Mix_VolumeChunk (self, volume);
2560     OUTPUT:
2561     RETVAL
2562    
2563 root 1.242 DC::Channel
2564     play (DC::MixChunk self, DC::Channel channel = -1, int loops = 0, int ticks = -1)
2565 root 1.52 CODE:
2566 root 1.215 {
2567 root 1.52 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2568 root 1.215
2569     if (RETVAL < 0)
2570     XSRETURN_UNDEF;
2571    
2572     if (channel < 0)
2573     {
2574     Mix_UnregisterAllEffects (RETVAL);
2575     Mix_Volume (RETVAL, 128);
2576     }
2577     }
2578 root 1.52 OUTPUT:
2579     RETVAL
2580    
2581 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixMusic
2582 root 1.52
2583     int
2584     volume (int volume = -1)
2585 root 1.205 PROTOTYPE: ;$
2586 root 1.52 CODE:
2587 root 1.216 if (items > 0)
2588     volume = CLAMP (volume, 0, 128);
2589 root 1.52 RETVAL = Mix_VolumeMusic (volume);
2590     OUTPUT:
2591     RETVAL
2592    
2593 root 1.213 void
2594 root 1.194 fade_out (int ms)
2595     CODE:
2596 root 1.213 Mix_FadeOutMusic (ms);
2597 root 1.194
2598 root 1.212 void
2599     halt ()
2600     CODE:
2601     Mix_HaltMusic ();
2602    
2603 root 1.242 DC::MixMusic
2604     new (SV *class, DC::RW rwops)
2605 root 1.52 CODE:
2606 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
2607 root 1.52 OUTPUT:
2608     RETVAL
2609    
2610     void
2611 root 1.242 DESTROY (DC::MixMusic self)
2612 root 1.52 CODE:
2613     Mix_FreeMusic (self);
2614    
2615     int
2616 root 1.242 play (DC::MixMusic self, int loops = -1)
2617 root 1.52 CODE:
2618     RETVAL = Mix_PlayMusic (self, loops);
2619     OUTPUT:
2620     RETVAL
2621    
2622 root 1.213 void
2623 root 1.242 fade_in_pos (DC::MixMusic self, int loops, int ms, double position)
2624 root 1.195 CODE:
2625 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
2626 root 1.195
2627 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::OpenGL
2628 root 1.54
2629 root 1.205 PROTOTYPES: ENABLE
2630    
2631 root 1.54 BOOT:
2632     {
2633 root 1.242 HV *stash = gv_stashpv ("DC::OpenGL", 1);
2634 root 1.54 static const struct {
2635     const char *name;
2636     IV iv;
2637     } *civ, const_iv[] = {
2638     # define const_iv(name) { # name, (IV)name }
2639 root 1.199 const_iv (GL_VENDOR),
2640     const_iv (GL_VERSION),
2641     const_iv (GL_EXTENSIONS),
2642 root 1.54 const_iv (GL_COLOR_MATERIAL),
2643     const_iv (GL_SMOOTH),
2644     const_iv (GL_FLAT),
2645 root 1.69 const_iv (GL_DITHER),
2646 root 1.54 const_iv (GL_BLEND),
2647 root 1.89 const_iv (GL_CULL_FACE),
2648 root 1.69 const_iv (GL_SCISSOR_TEST),
2649 root 1.89 const_iv (GL_DEPTH_TEST),
2650     const_iv (GL_ALPHA_TEST),
2651     const_iv (GL_NORMALIZE),
2652     const_iv (GL_RESCALE_NORMAL),
2653 root 1.119 const_iv (GL_FRONT),
2654     const_iv (GL_BACK),
2655 root 1.206 const_iv (GL_AUX0),
2656 root 1.54 const_iv (GL_AND),
2657 root 1.67 const_iv (GL_ONE),
2658     const_iv (GL_ZERO),
2659 root 1.54 const_iv (GL_SRC_ALPHA),
2660 root 1.104 const_iv (GL_DST_ALPHA),
2661 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2662 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2663 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2664 root 1.54 const_iv (GL_RGB),
2665     const_iv (GL_RGBA),
2666 root 1.115 const_iv (GL_RGBA4),
2667     const_iv (GL_RGBA8),
2668     const_iv (GL_RGB5_A1),
2669 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2670 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2671     const_iv (GL_UNSIGNED_INT),
2672 root 1.54 const_iv (GL_ALPHA),
2673 root 1.86 const_iv (GL_INTENSITY),
2674 root 1.76 const_iv (GL_LUMINANCE),
2675 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2676 root 1.54 const_iv (GL_FLOAT),
2677     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2678 root 1.230 const_iv (GL_COMPRESSED_ALPHA_ARB),
2679     const_iv (GL_COMPRESSED_LUMINANCE_ARB),
2680     const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB),
2681     const_iv (GL_COMPRESSED_INTENSITY_ARB),
2682     const_iv (GL_COMPRESSED_RGB_ARB),
2683     const_iv (GL_COMPRESSED_RGBA_ARB),
2684 root 1.54 const_iv (GL_COMPILE),
2685 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
2686     const_iv (GL_PROXY_TEXTURE_2D),
2687 root 1.54 const_iv (GL_TEXTURE_1D),
2688     const_iv (GL_TEXTURE_2D),
2689     const_iv (GL_TEXTURE_ENV),
2690     const_iv (GL_TEXTURE_MAG_FILTER),
2691     const_iv (GL_TEXTURE_MIN_FILTER),
2692     const_iv (GL_TEXTURE_ENV_MODE),
2693     const_iv (GL_TEXTURE_WRAP_S),
2694     const_iv (GL_TEXTURE_WRAP_T),
2695 root 1.98 const_iv (GL_REPEAT),
2696 root 1.54 const_iv (GL_CLAMP),
2697 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2698 root 1.54 const_iv (GL_NEAREST),
2699     const_iv (GL_LINEAR),
2700 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2701     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2702     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2703     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2704     const_iv (GL_GENERATE_MIPMAP),
2705 root 1.54 const_iv (GL_MODULATE),
2706 root 1.69 const_iv (GL_DECAL),
2707 root 1.54 const_iv (GL_REPLACE),
2708 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2709 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2710     const_iv (GL_PROJECTION),
2711     const_iv (GL_MODELVIEW),
2712     const_iv (GL_COLOR_LOGIC_OP),
2713 root 1.69 const_iv (GL_SEPARABLE_2D),
2714 root 1.54 const_iv (GL_CONVOLUTION_2D),
2715     const_iv (GL_CONVOLUTION_BORDER_MODE),
2716     const_iv (GL_CONSTANT_BORDER),
2717 root 1.208 const_iv (GL_POINTS),
2718 root 1.54 const_iv (GL_LINES),
2719 root 1.138 const_iv (GL_LINE_STRIP),
2720 root 1.89 const_iv (GL_LINE_LOOP),
2721 root 1.54 const_iv (GL_QUADS),
2722 root 1.89 const_iv (GL_QUAD_STRIP),
2723     const_iv (GL_TRIANGLES),
2724     const_iv (GL_TRIANGLE_STRIP),
2725     const_iv (GL_TRIANGLE_FAN),
2726 root 1.208 const_iv (GL_POLYGON),
2727 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2728 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
2729     const_iv (GL_LINE_SMOOTH_HINT),
2730     const_iv (GL_POLYGON_SMOOTH_HINT),
2731     const_iv (GL_GENERATE_MIPMAP_HINT),
2732 root 1.232 const_iv (GL_TEXTURE_COMPRESSION_HINT),
2733 root 1.54 const_iv (GL_FASTEST),
2734 root 1.206 const_iv (GL_DONT_CARE),
2735     const_iv (GL_NICEST),
2736 root 1.89 const_iv (GL_V2F),
2737     const_iv (GL_V3F),
2738     const_iv (GL_T2F_V3F),
2739     const_iv (GL_T2F_N3F_V3F),
2740 root 1.54 # undef const_iv
2741     };
2742    
2743     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2744     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2745 root 1.188
2746     texture_av = newAV ();
2747     AvREAL_off (texture_av);
2748 root 1.54 }
2749    
2750 root 1.231 void
2751     disable_GL_EXT_blend_func_separate ()
2752     CODE:
2753     gl.BlendFuncSeparate = 0;
2754     gl.BlendFuncSeparateEXT = 0;
2755    
2756 root 1.97 char *
2757     gl_vendor ()
2758     CODE:
2759     RETVAL = (char *)glGetString (GL_VENDOR);
2760     OUTPUT:
2761     RETVAL
2762    
2763     char *
2764     gl_version ()
2765     CODE:
2766     RETVAL = (char *)glGetString (GL_VERSION);
2767     OUTPUT:
2768     RETVAL
2769    
2770     char *
2771     gl_extensions ()
2772     CODE:
2773     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2774     OUTPUT:
2775     RETVAL
2776    
2777 root 1.201 const char *glGetString (GLenum pname)
2778 root 1.199
2779     GLint glGetInteger (GLenum pname)
2780     CODE:
2781     glGetIntegerv (pname, &RETVAL);
2782     OUTPUT:
2783     RETVAL
2784    
2785     GLdouble glGetDouble (GLenum pname)
2786     CODE:
2787     glGetDoublev (pname, &RETVAL);
2788     OUTPUT:
2789     RETVAL
2790    
2791 root 1.54 int glGetError ()
2792    
2793 root 1.114 void glFinish ()
2794    
2795 root 1.54 void glClear (int mask)
2796    
2797     void glClearColor (float r, float g, float b, float a = 1.0)
2798     PROTOTYPE: @
2799    
2800     void glEnable (int cap)
2801    
2802     void glDisable (int cap)
2803    
2804     void glShadeModel (int mode)
2805    
2806     void glHint (int target, int mode)
2807    
2808     void glBlendFunc (int sfactor, int dfactor)
2809    
2810 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
2811     CODE:
2812     gl_BlendFuncSeparate (sa, da, saa, daa);
2813    
2814 root 1.89 void glDepthMask (int flag)
2815    
2816 root 1.54 void glLogicOp (int opcode)
2817    
2818 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
2819    
2820 root 1.54 void glMatrixMode (int mode)
2821    
2822     void glPushMatrix ()
2823    
2824     void glPopMatrix ()
2825    
2826     void glLoadIdentity ()
2827    
2828 root 1.119 void glDrawBuffer (int buffer)
2829    
2830     void glReadBuffer (int buffer)
2831    
2832 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
2833     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
2834    
2835     # near_ and far_ are due to microsofts buggy "c" compiler
2836 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
2837 root 1.54
2838 root 1.208 PROTOTYPES: DISABLE
2839    
2840 root 1.54 void glViewport (int x, int y, int width, int height)
2841    
2842 root 1.69 void glScissor (int x, int y, int width, int height)
2843    
2844 root 1.54 void glTranslate (float x, float y, float z = 0.)
2845     CODE:
2846     glTranslatef (x, y, z);
2847    
2848 root 1.62 void glScale (float x, float y, float z = 1.)
2849 root 1.54 CODE:
2850     glScalef (x, y, z);
2851    
2852     void glRotate (float angle, float x, float y, float z)
2853     CODE:
2854     glRotatef (angle, x, y, z);
2855    
2856     void glColor (float r, float g, float b, float a = 1.0)
2857 root 1.103 ALIAS:
2858     glColor_premultiply = 1
2859 root 1.54 CODE:
2860 root 1.103 if (ix)
2861     {
2862     r *= a;
2863     g *= a;
2864     b *= a;
2865     }
2866 root 1.90 // microsoft visual "c" rounds instead of truncating...
2867 root 1.130 glColor4f (r, g, b, a);
2868 root 1.54
2869 root 1.91 void glRasterPos (float x, float y, float z = 0.)
2870     CODE:
2871     glRasterPos3f (0, 0, z);
2872     glBitmap (0, 0, 0, 0, x, y, 0);
2873    
2874 root 1.54 void glVertex (float x, float y, float z = 0.)
2875     CODE:
2876     glVertex3f (x, y, z);
2877    
2878     void glTexCoord (float s, float t)
2879     CODE:
2880     glTexCoord2f (s, t);
2881    
2882 root 1.210 void glRect (float x1, float y1, float x2, float y2)
2883     CODE:
2884     glRectf (x1, y1, x2, y2);
2885    
2886 root 1.233 void glRect_lineloop (float x1, float y1, float x2, float y2)
2887     CODE:
2888     glBegin (GL_LINE_LOOP);
2889     glVertex2f (x1, y1);
2890     glVertex2f (x2, y1);
2891     glVertex2f (x2, y2);
2892     glVertex2f (x1, y2);
2893     glEnd ();
2894    
2895 root 1.208 PROTOTYPES: ENABLE
2896    
2897     void glBegin (int mode)
2898    
2899     void glEnd ()
2900    
2901     void glPointSize (GLfloat size)
2902    
2903     void glLineWidth (GLfloat width)
2904    
2905     void glInterleavedArrays (int format, int stride, char *data)
2906    
2907     void glDrawElements (int mode, int count, int type, char *indices)
2908    
2909     # 1.2 void glDrawRangeElements (int mode, int start, int end
2910    
2911 root 1.54 void glTexEnv (int target, int pname, float param)
2912     CODE:
2913     glTexEnvf (target, pname, param);
2914    
2915     void glTexParameter (int target, int pname, float param)
2916     CODE:
2917     glTexParameterf (target, pname, param);
2918    
2919     void glBindTexture (int target, int name)
2920    
2921     void glConvolutionParameter (int target, int pname, float params)
2922     CODE:
2923 root 1.103 if (gl.ConvolutionParameterf)
2924     gl.ConvolutionParameterf (target, pname, params);
2925 root 1.54
2926     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
2927 root 1.64 CODE:
2928 root 1.103 if (gl.ConvolutionFilter2D)
2929     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
2930 root 1.54
2931 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
2932     CODE:
2933 root 1.103 if (gl.SeparableFilter2D)
2934     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
2935 root 1.69
2936 root 1.244 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data = 0)
2937 root 1.54
2938     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
2939    
2940 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
2941 root 1.68
2942 root 1.199 void glPixelZoom (float x, float y)
2943    
2944 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
2945    
2946 root 1.54 int glGenTexture ()
2947     CODE:
2948 root 1.192 RETVAL = gen_texture ();
2949 root 1.54 OUTPUT:
2950     RETVAL
2951    
2952     void glDeleteTexture (int name)
2953     CODE:
2954 root 1.192 del_texture (name);
2955    
2956 root 1.54 int glGenList ()
2957     CODE:
2958     RETVAL = glGenLists (1);
2959     OUTPUT:
2960     RETVAL
2961    
2962     void glDeleteList (int list)
2963     CODE:
2964     glDeleteLists (list, 1);
2965    
2966     void glNewList (int list, int mode = GL_COMPILE)
2967    
2968     void glEndList ()
2969    
2970     void glCallList (int list)
2971    
2972 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::UI::Base
2973 root 1.207
2974     PROTOTYPES: DISABLE
2975    
2976     void
2977 root 1.209 find_widget (SV *self, NV x, NV y)
2978 root 1.207 PPCODE:
2979     {
2980 root 1.209 if (within_widget (self, x, y))
2981     XPUSHs (self);
2982     }
2983    
2984     BOOT:
2985     {
2986 root 1.242 hover_gv = gv_fetchpv ("DC::UI::HOVER", 1, SVt_NV);
2987 root 1.209
2988 root 1.242 draw_x_gv = gv_fetchpv ("DC::UI::Base::draw_x", 1, SVt_NV);
2989     draw_y_gv = gv_fetchpv ("DC::UI::Base::draw_y", 1, SVt_NV);
2990     draw_w_gv = gv_fetchpv ("DC::UI::Base::draw_w", 1, SVt_NV);
2991     draw_h_gv = gv_fetchpv ("DC::UI::Base::draw_h", 1, SVt_NV);
2992 root 1.209 }
2993    
2994     void
2995     draw (SV *self)
2996     CODE:
2997     {
2998     HV *hv;
2999     SV **svp;
3000     NV x, y, w, h;
3001     SV *draw_x_sv = GvSV (draw_x_gv);
3002     SV *draw_y_sv = GvSV (draw_y_gv);
3003     SV *draw_w_sv = GvSV (draw_w_gv);
3004     SV *draw_h_sv = GvSV (draw_h_gv);
3005 root 1.228 double draw_x, draw_y;
3006 root 1.209
3007     if (!SvROK (self))
3008 root 1.242 croak ("DC::Base::draw: %s not a reference", SvPV_nolen (self));
3009 root 1.209
3010     hv = (HV *)SvRV (self);
3011    
3012     if (SvTYPE (hv) != SVt_PVHV)
3013 root 1.242 croak ("DC::Base::draw: %s not a hashref", SvPV_nolen (self));
3014 root 1.209
3015     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
3016     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
3017    
3018     if (!h || !w)
3019     XSRETURN_EMPTY;
3020    
3021     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
3022     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
3023    
3024     draw_x = SvNV (draw_x_sv) + x;
3025     draw_y = SvNV (draw_y_sv) + y;
3026    
3027     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
3028     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
3029     XSRETURN_EMPTY;
3030    
3031     sv_setnv (draw_x_sv, draw_x);
3032     sv_setnv (draw_y_sv, draw_y);
3033    
3034     glPushMatrix ();
3035     glTranslated (x, y, 0);
3036    
3037     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
3038     {
3039     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
3040    
3041     if (svp && SvTRUE (*svp))
3042     {
3043 root 1.228 glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f);
3044 root 1.209 glEnable (GL_BLEND);
3045     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3046     glBegin (GL_QUADS);
3047     glVertex2f (0, 0);
3048     glVertex2f (w, 0);
3049     glVertex2f (w, h);
3050     glVertex2f (0, h);
3051     glEnd ();
3052     glDisable (GL_BLEND);
3053     }
3054     }
3055     #if 0
3056 root 1.234 // draw borders, for debugging
3057     glPushMatrix ();
3058     glColor4f (1., 1., 0., 1.);
3059     glTranslatef (.5, .5, 0.);
3060     glBegin (GL_LINE_LOOP);
3061     glVertex2f (0 , 0);
3062     glVertex2f (w - 1, 0);
3063     glVertex2f (w - 1, h - 1);
3064     glVertex2f (0 , h - 1);
3065     glEnd ();
3066     glPopMatrix ();
3067 root 1.209 #endif
3068     PUSHMARK (SP);
3069     XPUSHs (self);
3070     PUTBACK;
3071     call_method ("_draw", G_VOID | G_DISCARD);
3072     SPAGAIN;
3073    
3074     glPopMatrix ();
3075    
3076     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
3077     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
3078 root 1.207 }
3079