ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.335
Committed: Mon Nov 19 01:56:11 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.334: +38 -36 lines
Log Message:
*** empty log message ***

File Contents

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