ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.323
Committed: Sun Nov 18 01:48:39 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.322: +24 -17 lines
Log Message:
c++

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