ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.324
Committed: Sun Nov 18 01:58:53 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.323: +5 -7 lines
Log Message:
only clear needed parts of smooth_max

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