ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.329
Committed: Sun Nov 18 13:07:51 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.328: +20 -23 lines
Log Message:
slight c++ification

File Contents

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