ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.325
Committed: Sun Nov 18 02:04:48 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.324: +48 -59 lines
Log Message:
use std::bitset instead of out own. nicer code, but smells like deoptimisation

File Contents

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