ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.326
Committed: Sun Nov 18 03:06:13 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.325: +30 -35 lines
Log Message:
clumsy c++ification of rendercache

File Contents

# User Rev Content
1 root 1.48 #ifdef _WIN32
2 root 1.131 # define WIN32_LEAN_AND_MEAN
3 root 1.170 # define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls
4 root 1.48 # include <malloc.h>
5 root 1.79 # include <windows.h>
6 root 1.157 # include <wininet.h>
7 root 1.75 # pragma warning(disable:4244)
8 root 1.162 # pragma warning(disable:4761)
9 root 1.48 #endif
10    
11 root 1.193 //#define DEBUG 1
12     #if DEBUG
13     # include <valgrind/memcheck.h>
14     #endif
15    
16 root 1.1 #include "EXTERN.h"
17     #include "perl.h"
18     #include "XSUB.h"
19    
20 root 1.322 #include "flat_hash_map.hpp"
21    
22 root 1.131 #ifdef _WIN32
23     # undef pipe
24 root 1.222 // microsoft vs. C
25     # define sqrtf(x) sqrt(x)
26     # define atan2f(x,y) atan2(x,y)
27     # define M_PI 3.14159265f
28 root 1.131 #endif
29    
30 root 1.322 #include <cassert>
31     #include <cmath>
32     #include <cstring>
33     #include <cstdio>
34     #include <cstdlib>
35    
36     #include <utility>
37 root 1.324 #include <bitset>
38 root 1.5
39 root 1.212 #define USE_RWOPS 1 // for SDL_mixer:LoadMUS_RW
40    
41 root 1.2 #include <SDL.h>
42 root 1.202 #include <SDL_thread.h>
43 root 1.76 #include <SDL_endian.h>
44 root 1.23 #include <SDL_image.h>
45 root 1.52 #include <SDL_mixer.h>
46 root 1.3 #include <SDL_opengl.h>
47 root 1.5
48 root 1.272 /* work around os x broken headers */
49     #ifdef __MACOSX__
50     typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
51 root 1.298 typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
52     typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
53 root 1.272 #endif
54    
55 root 1.124 #define PANGO_ENABLE_BACKEND
56     #define G_DISABLE_CAST_CHECKS
57    
58 root 1.318 #include <glib.h>
59 root 1.30
60 root 1.5 #include <pango/pango.h>
61    
62 root 1.254 #ifndef PANGO_VERSION_CHECK
63     # define PANGO_VERSION_CHECK(a,b,c) 0
64     #endif
65    
66     #if !PANGO_VERSION_CHECK (1, 15, 2)
67 root 1.255 # define pango_layout_get_line_readonly pango_layout_get_line
68     # define pango_layout_get_lines_readonly pango_layout_get_lines
69     # define pango_layout_iter_get_line_readonly pango_layout_iter_get_line
70     # define pango_layout_iter_get_run_readonly pango_layout_iter_get_run
71 root 1.249 #endif
72    
73 root 1.48 #ifndef _WIN32
74     # include <sys/types.h>
75     # include <sys/socket.h>
76     # include <netinet/in.h>
77     # include <netinet/tcp.h>
78     # include <inttypes.h>
79     #endif
80 root 1.28
81 root 1.261 #if __GNUC__ >= 4
82     # define expect(expr,value) __builtin_expect ((expr),(value))
83     #else
84     # define expect(expr,value) (expr)
85     #endif
86    
87     #define expect_false(expr) expect ((expr) != 0, 0)
88     #define expect_true(expr) expect ((expr) != 0, 1)
89    
90 root 1.162 #define OBJ_STR "\xef\xbf\xbc" /* U+FFFC, object replacement character */
91 root 1.121
92 root 1.296 /* this is used as fow flag as well, so has to have a different value */
93     /* then anything that is computed by incoming darkness */
94     #define FOW_DARKNESS 50
95     #define DARKNESS_ADJUST(n) (n)
96 root 1.29
97     #define MAP_EXTEND_X 32
98     #define MAP_EXTEND_Y 512
99    
100 root 1.63 #define MIN_FONT_HEIGHT 10
101 root 1.58
102 root 1.253 /* mask out modifiers we are not interested in */
103     #define MOD_MASK (KMOD_CTRL | KMOD_SHIFT | KMOD_ALT | KMOD_META)
104    
105 root 1.276 #define KMOD_LRAM 0x10000 // our extension
106    
107 root 1.285 #define TEXID_SPEECH 1
108     #define TEXID_NOFACE 2
109    
110 root 1.306 static char *
111     fast_sv_grow (SV *sv, STRLEN need)
112     {
113     STRLEN len = SvLEN (sv);
114     STRLEN want = SvCUR (sv) + need;
115    
116     if (expect_false (len < want))
117     {
118     do
119     len *= 2;
120     while (len < want);
121    
122     sv_grow (sv, len);
123     }
124    
125     SvCUR_set (sv, want);
126     return SvEND (sv) - need;
127     }
128    
129 root 1.188 static AV *texture_av;
130    
131 root 1.103 static struct
132     {
133     #define GL_FUNC(ptr,name) ptr name;
134     #include "glfunc.h"
135     #undef GL_FUNC
136     } gl;
137    
138 root 1.192 static void
139     gl_BlendFuncSeparate (GLenum sa, GLenum da, GLenum saa, GLenum daa)
140 root 1.103 {
141     if (gl.BlendFuncSeparate)
142     gl.BlendFuncSeparate (sa, da, saa, daa);
143     else if (gl.BlendFuncSeparateEXT)
144     gl.BlendFuncSeparateEXT (sa, da, saa, daa);
145     else
146     glBlendFunc (sa, da);
147     }
148 root 1.64
149 root 1.192 static GLuint
150     gen_texture ()
151     {
152     GLuint name;
153    
154     if (AvFILL (texture_av) >= 0)
155     name = (GLuint)(size_t)av_pop (texture_av);
156     else
157     glGenTextures (1, &name);
158    
159     return name;
160     }
161    
162     static void
163     del_texture (GLuint name)
164     {
165     /* make a half-assed attempt at returning the memory used by the texture */
166     /* textures are frequently being reused by cfplus anyway */
167     /*glBindTexture (GL_TEXTURE_2D, name);*/
168     /*glTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, 0, 0, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);*/
169     av_push (texture_av, (SV *)(size_t)name);
170     glDeleteTextures (1, &name);
171     }
172    
173 root 1.124 #include "texcache.c"
174 root 1.223 #include "rendercache.c"
175 root 1.124
176     #include "pango-font.c"
177     #include "pango-fontmap.c"
178     #include "pango-render.c"
179    
180 root 1.242 typedef IV DC__Channel;
181     typedef SDL_RWops *DC__RW;
182     typedef Mix_Chunk *DC__MixChunk;
183     typedef Mix_Music *DC__MixMusic;
184 root 1.52
185 root 1.242 typedef PangoFontDescription *DC__Font;
186 root 1.2
187 root 1.121 static int
188     shape_attr_p (PangoLayoutRun *run)
189     {
190     GSList *attrs = run->item->analysis.extra_attrs;
191    
192     while (attrs)
193     {
194 root 1.319 PangoAttribute *attr = (PangoAttribute *)attrs->data;
195 root 1.121
196     if (attr->klass->type == PANGO_ATTR_SHAPE)
197     return 1;
198    
199     attrs = attrs->next;
200     }
201    
202     return 0;
203     }
204    
205 root 1.323 struct cf_layout {
206 root 1.124 PangoLayout *pl;
207 root 1.76 float r, g, b, a; // default color for rgba mode
208 root 1.14 int base_height;
209 root 1.242 DC__Font font;
210 root 1.326 rc_t rc;
211 root 1.323 };
212    
213     typedef cf_layout *DC__Layout;
214 root 1.14
215 root 1.242 static DC__Font default_font;
216 root 1.124 static PangoContext *opengl_context;
217     static PangoFontMap *opengl_fontmap;
218 root 1.61
219 root 1.14 static void
220 root 1.19 substitute_func (FcPattern *pattern, gpointer data)
221     {
222 root 1.108 FcPatternAddBool (pattern, FC_HINTING, 1);
223 root 1.110 #ifdef FC_HINT_STYLE
224 root 1.320 FcPatternAddInteger (pattern, FC_HINT_STYLE, FC_HINT_FULL);
225 root 1.110 #endif
226 root 1.82 FcPatternAddBool (pattern, FC_AUTOHINT, 0);
227 root 1.19 }
228    
229     static void
230 root 1.242 layout_update_font (DC__Layout self)
231 root 1.17 {
232 root 1.19 /* use a random scale factor to account for unknown descenders, 0.8 works
233 root 1.258 * reasonably well with dejavu/bistream fonts
234 root 1.19 */
235 root 1.61 PangoFontDescription *font = self->font ? self->font : default_font;
236 root 1.46
237 root 1.61 pango_font_description_set_absolute_size (font,
238     MAX (MIN_FONT_HEIGHT, self->base_height) * (PANGO_SCALE * 8 / 10));
239 root 1.58
240 root 1.61 pango_layout_set_font_description (self->pl, font);
241 root 1.17 }
242    
243     static void
244 root 1.242 layout_get_pixel_size (DC__Layout self, int *w, int *h)
245 root 1.14 {
246 root 1.139 PangoRectangle rect;
247 root 1.14
248 root 1.139 // get_pixel_* wrongly rounds down
249     pango_layout_get_extents (self->pl, 0, &rect);
250 root 1.76
251 root 1.139 rect.width = (rect.width + PANGO_SCALE - 1) / PANGO_SCALE;
252     rect.height = (rect.height + PANGO_SCALE - 1) / PANGO_SCALE;
253    
254     if (!rect.width) rect.width = 1;
255     if (!rect.height) rect.height = 1;
256    
257     *w = rect.width;
258     *h = rect.height;
259 root 1.14 }
260    
261 root 1.174 typedef uint16_t tileid;
262     typedef uint16_t faceid;
263 root 1.42
264 root 1.323 struct maptex
265     {
266 root 1.228 GLuint name;
267 root 1.30 int w, h;
268     float s, t;
269 root 1.39 uint8_t r, g, b, a;
270 root 1.176 tileid smoothtile;
271     uint8_t smoothlevel;
272 root 1.280 uint8_t unused; /* set to zero on use */
273 root 1.323 };
274 root 1.30
275 root 1.323 struct mapcell
276     {
277 root 1.153 uint32_t player;
278 root 1.174 tileid tile[3];
279 root 1.142 uint16_t darkness;
280 root 1.176 uint8_t stat_width, stat_hp, flags, smoothmax;
281 root 1.323 };
282 root 1.28
283 root 1.323 struct maprow
284     {
285 root 1.30 int32_t c0, c1;
286 root 1.28 mapcell *col;
287 root 1.323 };
288 root 1.28
289 root 1.323 struct mapgrid {
290 root 1.28 int x, y, w, h;
291 root 1.42 int ox, oy; /* offset to virtual global coordinate system */
292 root 1.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 root 1.326 RETVAL = new 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    
1384 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
1385 root 1.76 layout_update_font (RETVAL);
1386 root 1.14 OUTPUT:
1387     RETVAL
1388    
1389     void
1390 root 1.242 DESTROY (DC::Layout self)
1391 root 1.14 CODE:
1392     g_object_unref (self->pl);
1393 root 1.326 delete self;
1394 root 1.13
1395 root 1.8 void
1396 root 1.242 set_text (DC::Layout self, SV *text_)
1397 root 1.35 CODE:
1398     {
1399     STRLEN textlen;
1400     char *text = SvPVutf8 (text_, textlen);
1401    
1402     pango_layout_set_text (self->pl, text, textlen);
1403     }
1404    
1405     void
1406 root 1.242 set_markup (DC::Layout self, SV *text_)
1407 root 1.14 CODE:
1408 root 1.5 {
1409     STRLEN textlen;
1410     char *text = SvPVutf8 (text_, textlen);
1411 root 1.14
1412     pango_layout_set_markup (self->pl, text, textlen);
1413     }
1414    
1415 root 1.121 void
1416 root 1.242 set_shapes (DC::Layout self, ...)
1417 root 1.121 CODE:
1418     {
1419     PangoAttrList *attrs = 0;
1420     const char *text = pango_layout_get_text (self->pl);
1421     const char *pos = text;
1422 root 1.122 int arg = 4;
1423 root 1.121
1424     while (arg < items && (pos = strstr (pos, OBJ_STR)))
1425     {
1426 root 1.122 PangoRectangle inkrect, rect;
1427 root 1.121 PangoAttribute *attr;
1428    
1429 root 1.122 int x = SvIV (ST (arg - 3));
1430     int y = SvIV (ST (arg - 2));
1431 root 1.121 int w = SvIV (ST (arg - 1));
1432 root 1.122 int h = SvIV (ST (arg ));
1433 root 1.121
1434 root 1.122 inkrect.x = 0;
1435     inkrect.y = 0;
1436     inkrect.width = 0;
1437     inkrect.height = 0;
1438    
1439     rect.x = x * PANGO_SCALE;
1440     rect.y = y * PANGO_SCALE;
1441     rect.width = w * PANGO_SCALE;
1442 root 1.121 rect.height = h * PANGO_SCALE;
1443    
1444     if (!attrs)
1445     attrs = pango_layout_get_attributes (self->pl);
1446    
1447 root 1.122 attr = pango_attr_shape_new (&inkrect, &rect);
1448 root 1.121 attr->start_index = pos - text;
1449     attr->end_index = attr->start_index + sizeof (OBJ_STR) - 1;
1450     pango_attr_list_insert (attrs, attr);
1451    
1452 root 1.122 arg += 4;
1453 root 1.121 pos += sizeof (OBJ_STR) - 1;
1454     }
1455    
1456     if (attrs)
1457     pango_layout_set_attributes (self->pl, attrs);
1458     }
1459    
1460     void
1461 root 1.242 get_shapes (DC::Layout self)
1462 root 1.121 PPCODE:
1463     {
1464     PangoLayoutIter *iter = pango_layout_get_iter (self->pl);
1465    
1466     do
1467     {
1468 root 1.249 PangoLayoutRun *run = pango_layout_iter_get_run_readonly (iter);
1469 root 1.121
1470     if (run && shape_attr_p (run))
1471     {
1472     PangoRectangle extents;
1473     pango_layout_iter_get_run_extents (iter, 0, &extents);
1474    
1475 root 1.129 EXTEND (SP, 2);
1476 root 1.121 PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.x))));
1477     PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.y))));
1478     }
1479     }
1480     while (pango_layout_iter_next_run (iter));
1481    
1482     pango_layout_iter_free (iter);
1483     }
1484    
1485     int
1486 root 1.242 has_wrapped (DC::Layout self)
1487 root 1.121 CODE:
1488     {
1489     int lines = 1;
1490     const char *text = pango_layout_get_text (self->pl);
1491    
1492     while (*text)
1493     lines += *text++ == '\n';
1494    
1495     RETVAL = lines < pango_layout_get_line_count (self->pl);
1496     }
1497     OUTPUT:
1498     RETVAL
1499    
1500 root 1.46 SV *
1501 root 1.242 get_text (DC::Layout self)
1502 root 1.46 CODE:
1503 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
1504 root 1.107 sv_utf8_decode (RETVAL);
1505 root 1.46 OUTPUT:
1506     RETVAL
1507    
1508 root 1.14 void
1509 root 1.242 set_foreground (DC::Layout self, float r, float g, float b, float a = 1.)
1510 root 1.76 CODE:
1511     self->r = r;
1512     self->g = g;
1513     self->b = b;
1514     self->a = a;
1515    
1516     void
1517 root 1.242 set_font (DC::Layout self, DC::Font font = 0)
1518 root 1.61 CODE:
1519     if (self->font != font)
1520     {
1521     self->font = font;
1522     layout_update_font (self);
1523     }
1524    
1525     void
1526 root 1.242 set_height (DC::Layout self, int base_height)
1527 root 1.16 CODE:
1528 root 1.61 if (self->base_height != base_height)
1529 root 1.317 {
1530 root 1.61 self->base_height = base_height;
1531     layout_update_font (self);
1532     }
1533 root 1.16
1534     void
1535 root 1.242 set_width (DC::Layout self, int max_width = -1)
1536 root 1.14 CODE:
1537     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
1538    
1539     void
1540 root 1.242 set_indent (DC::Layout self, int indent)
1541 root 1.84 CODE:
1542     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
1543    
1544     void
1545 root 1.242 set_spacing (DC::Layout self, int spacing)
1546 root 1.84 CODE:
1547     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
1548    
1549     void
1550 root 1.242 set_ellipsise (DC::Layout self, int ellipsise)
1551 root 1.84 CODE:
1552     pango_layout_set_ellipsize (self->pl,
1553     ellipsise == 1 ? PANGO_ELLIPSIZE_START
1554     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
1555     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
1556     : PANGO_ELLIPSIZE_NONE
1557     );
1558    
1559     void
1560 root 1.242 set_single_paragraph_mode (DC::Layout self, int spm)
1561 root 1.84 CODE:
1562     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
1563    
1564     void
1565 root 1.242 size (DC::Layout self)
1566 root 1.14 PPCODE:
1567     {
1568     int w, h;
1569    
1570     layout_get_pixel_size (self, &w, &h);
1571    
1572     EXTEND (SP, 2);
1573     PUSHs (sv_2mortal (newSViv (w)));
1574     PUSHs (sv_2mortal (newSViv (h)));
1575     }
1576    
1577 root 1.17 int
1578 root 1.242 descent (DC::Layout self)
1579 root 1.122 CODE:
1580     {
1581     PangoRectangle rect;
1582 root 1.249 PangoLayoutLine *line = pango_layout_get_line_readonly (self->pl, 0);
1583 root 1.122 pango_layout_line_get_pixel_extents (line, 0, &rect);
1584     RETVAL = PANGO_DESCENT (rect);
1585     }
1586     OUTPUT:
1587     RETVAL
1588    
1589     int
1590 root 1.242 xy_to_index (DC::Layout self, int x, int y)
1591 root 1.17 CODE:
1592     {
1593     int index, trailing;
1594     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
1595 root 1.165 RETVAL = index + trailing;
1596 root 1.17 }
1597     OUTPUT:
1598     RETVAL
1599    
1600     void
1601 root 1.242 cursor_pos (DC::Layout self, int index)
1602 root 1.17 PPCODE:
1603     {
1604 root 1.251 PangoRectangle pos;
1605 root 1.252 pango_layout_get_cursor_pos (self->pl, index, &pos, 0);
1606 root 1.30
1607 root 1.17 EXTEND (SP, 3);
1608 root 1.251 PUSHs (sv_2mortal (newSViv (pos.x / PANGO_SCALE)));
1609     PUSHs (sv_2mortal (newSViv (pos.y / PANGO_SCALE)));
1610     PUSHs (sv_2mortal (newSViv (pos.height / PANGO_SCALE)));
1611 root 1.17 }
1612    
1613 root 1.14 void
1614 root 1.242 index_to_line_x (DC::Layout self, int index, int trailing = 0)
1615 root 1.165 PPCODE:
1616     {
1617     int line, x;
1618    
1619     pango_layout_index_to_line_x (self->pl, index, trailing, &line, &x);
1620 root 1.254 #if !PANGO_VERSION_CHECK (1, 17, 3)
1621 root 1.165 /* pango bug: line is between 1..numlines, not 0..numlines-1 */
1622 root 1.245 --line;
1623     #endif
1624 root 1.165 EXTEND (SP, 2);
1625 root 1.245 PUSHs (sv_2mortal (newSViv (line)));
1626 root 1.165 PUSHs (sv_2mortal (newSViv (x / PANGO_SCALE)));
1627     }
1628    
1629     void
1630 root 1.242 line_x_to_index (DC::Layout self, int line, int x)
1631 root 1.165 PPCODE:
1632     {
1633     PangoLayoutLine *lp;
1634     int index, trailing;
1635    
1636     if (line < 0)
1637     XSRETURN_EMPTY;
1638    
1639 root 1.249 if (!(lp = pango_layout_get_line_readonly (self->pl, line)))
1640 root 1.165 XSRETURN_EMPTY; /* do better */
1641    
1642 root 1.166 pango_layout_line_x_to_index (lp, x * PANGO_SCALE, &index, &trailing);
1643 root 1.165
1644     EXTEND (SP, 2);
1645     if (GIMME_V == G_SCALAR)
1646     PUSHs (sv_2mortal (newSViv (index + trailing)));
1647     else
1648     {
1649     PUSHs (sv_2mortal (newSViv (index)));
1650     PUSHs (sv_2mortal (newSViv (trailing)));
1651     }
1652     }
1653    
1654     void
1655 root 1.242 render (DC::Layout self, float x, float y, int flags = 0)
1656 root 1.225 CODE:
1657 root 1.326 self->rc.clear ();
1658 root 1.124 pango_opengl_render_layout_subpixel (
1659     self->pl,
1660 root 1.326 &self->rc,
1661 root 1.124 x * PANGO_SCALE, y * PANGO_SCALE,
1662 root 1.135 self->r, self->g, self->b, self->a,
1663     flags
1664 root 1.124 );
1665 root 1.225 // we assume that context_change actually clears/frees stuff
1666     // and does not do any recomputation...
1667     pango_layout_context_changed (self->pl);
1668    
1669     void
1670 root 1.242 draw (DC::Layout self)
1671 root 1.225 CODE:
1672     {
1673     glEnable (GL_TEXTURE_2D);
1674     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1675     glEnable (GL_BLEND);
1676     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1677     GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1678     glEnable (GL_ALPHA_TEST);
1679     glAlphaFunc (GL_GREATER, 7.f / 255.f);
1680    
1681 root 1.326 self->rc.draw ();
1682 root 1.225
1683     glDisable (GL_ALPHA_TEST);
1684     glDisable (GL_BLEND);
1685     glDisable (GL_TEXTURE_2D);
1686     }
1687 root 1.11
1688 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Texture
1689 root 1.11
1690 root 1.205 PROTOTYPES: ENABLE
1691    
1692 root 1.11 void
1693 root 1.203 pad (SV *data_, int ow, int oh, int nw, int nh)
1694 root 1.113 CODE:
1695     {
1696 root 1.203 if ((nw != ow || nh != oh) && SvOK (data_))
1697 root 1.113 {
1698 root 1.203 STRLEN datalen;
1699     char *data = SvPVbyte (data_, datalen);
1700     int bpp = datalen / (ow * oh);
1701     SV *result_ = sv_2mortal (newSV (nw * nh * bpp));
1702    
1703     SvPOK_only (result_);
1704     SvCUR_set (result_, nw * nh * bpp);
1705    
1706     memset (SvPVX (result_), 0, nw * nh * bpp);
1707     while (oh--)
1708     memcpy (SvPVX (result_) + oh * nw * bpp, data + oh * ow * bpp, ow * bpp);
1709 root 1.113
1710 root 1.203 sv_setsv (data_, result_);
1711 root 1.113 }
1712     }
1713    
1714     void
1715 root 1.114 draw_quad (SV *self, float x, float y, float w = 0., float h = 0.)
1716 root 1.12 PROTOTYPE: $$$;$$
1717 root 1.76 ALIAS:
1718     draw_quad_alpha = 1
1719     draw_quad_alpha_premultiplied = 2
1720 root 1.11 CODE:
1721     {
1722 root 1.12 HV *hv = (HV *)SvRV (self);
1723 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
1724     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
1725 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
1726    
1727 root 1.219 if (name <= 0)
1728     XSRETURN_EMPTY;
1729    
1730 root 1.12 if (items < 5)
1731     {
1732 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1733     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1734 root 1.12 }
1735    
1736 root 1.76 if (ix)
1737     {
1738     glEnable (GL_BLEND);
1739 root 1.103
1740     if (ix == 2)
1741     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1742     else
1743     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1744 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1745 root 1.103
1746 root 1.86 glEnable (GL_ALPHA_TEST);
1747     glAlphaFunc (GL_GREATER, 0.01f);
1748 root 1.76 }
1749    
1750 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1751 root 1.76
1752 root 1.12 glBegin (GL_QUADS);
1753 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1754     glTexCoord2f (0, t); glVertex2f (x , y + h);
1755     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1756     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1757 root 1.12 glEnd ();
1758 root 1.76
1759     if (ix)
1760 root 1.86 {
1761     glDisable (GL_ALPHA_TEST);
1762     glDisable (GL_BLEND);
1763     }
1764 root 1.11 }
1765 root 1.28
1766 root 1.293 void
1767 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)
1768 root 1.293 PROTOTYPE: @
1769     CODE:
1770     {
1771     glEnable (GL_BLEND);
1772 root 1.300 glBlendFunc (intensity ? GL_SRC_ALPHA : GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1773 root 1.299 glEnable (GL_TEXTURE_2D);
1774 root 1.294 glBindTexture (GL_TEXTURE_2D, name1);
1775 root 1.293
1776 root 1.294 glColor3f (intensity, intensity, intensity);
1777 root 1.293 glPushMatrix ();
1778     glScalef (1./3, 1./3, 1.);
1779    
1780 root 1.294 if (blend > 0.f)
1781     {
1782 root 1.296 float dx3 = dx * -3.f / w;
1783     float dy3 = dy * -3.f / h;
1784 root 1.294 GLfloat env_color[4] = { 0., 0., 0., blend };
1785    
1786     /* interpolate the two shadow textures */
1787     /* stage 0 == rgb(glcolor) + alpha(t0) */
1788     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1789    
1790     /* stage 1 == rgb(glcolor) + alpha(interpolate t0, t1, texenv) */
1791     gl.ActiveTexture (GL_TEXTURE1);
1792     glEnable (GL_TEXTURE_2D);
1793     glBindTexture (GL_TEXTURE_2D, name2);
1794     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1795    
1796     /* rgb == rgb(glcolor) */
1797     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
1798 root 1.300 glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
1799 root 1.294 glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1800    
1801     /* alpha = interpolate t0, t1 by env_alpha */
1802     glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env_color);
1803    
1804     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);
1805     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
1806     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1807    
1808     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
1809     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
1810    
1811     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_CONSTANT);
1812     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
1813    
1814     glBegin (GL_QUADS);
1815 root 1.296 gl.MultiTexCoord2f (GL_TEXTURE0, 0, 0); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 , dy3 ); glVertex2i (0, 0);
1816     gl.MultiTexCoord2f (GL_TEXTURE0, 0, t); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 , dy3 + t); glVertex2i (0, h);
1817     gl.MultiTexCoord2f (GL_TEXTURE0, s, t); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 + s, dy3 + t); glVertex2i (w, h);
1818     gl.MultiTexCoord2f (GL_TEXTURE0, s, 0); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 + s, dy3 ); glVertex2i (w, 0);
1819 root 1.294 glEnd ();
1820    
1821     glDisable (GL_TEXTURE_2D);
1822     gl.ActiveTexture (GL_TEXTURE0);
1823     }
1824     else
1825     {
1826     /* simple blending of one texture, also opengl <1.3 path */
1827     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1828 root 1.293
1829 root 1.294 glBegin (GL_QUADS);
1830 root 1.296 glTexCoord2f (0, 0); glVertex2f (0, 0);
1831     glTexCoord2f (0, t); glVertex2f (0, h);
1832     glTexCoord2f (s, t); glVertex2f (w, h);
1833     glTexCoord2f (s, 0); glVertex2f (w, 0);
1834 root 1.294 glEnd ();
1835     }
1836 root 1.293
1837 root 1.296 /* draw ?-marks or equivalent, this is very clumsy code :/ */
1838     {
1839     int x, y;
1840     int dx3 = dx * 3;
1841     int dy3 = dy * 3;
1842    
1843     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1844     glBindTexture (GL_TEXTURE_2D, hidden_tex);
1845     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1846     glTranslatef (-1., -1., 0);
1847     glBegin (GL_QUADS);
1848    
1849     for (y = 1; y < h; y += 3)
1850     {
1851     int y1 = y - dy3;
1852     int y1valid = y1 >= 0 && y1 < h;
1853    
1854     for (x = 1; x < w; x += 3)
1855     {
1856     int x1 = x - dx3;
1857     uint8_t h1 = data1 [x + y * w] == DARKNESS_ADJUST (255 - FOW_DARKNESS);
1858     uint8_t h2;
1859    
1860     if (y1valid && x1 >= 0 && x1 < w)
1861     h2 = data2 [x1 + y1 * w] == DARKNESS_ADJUST (255 - FOW_DARKNESS);
1862     else
1863     h2 = 1; /* out of range == invisible */
1864    
1865     if (h1 || h2)
1866     {
1867     float alpha = h1 == h2 ? 1.f : h1 ? 1.f - blend : blend;
1868     glColor4f (1., 1., 1., alpha);
1869    
1870     glTexCoord2f (0, 0.); glVertex2i (x , y );
1871     glTexCoord2f (0, 1.); glVertex2i (x , y + 3);
1872     glTexCoord2f (1, 1.); glVertex2i (x + 3, y + 3);
1873     glTexCoord2f (1, 0.); glVertex2i (x + 3, y );
1874     }
1875     }
1876     }
1877     }
1878    
1879     glEnd ();
1880    
1881 root 1.293 glPopMatrix ();
1882    
1883     glDisable (GL_TEXTURE_2D);
1884     glDisable (GL_BLEND);
1885     }
1886    
1887 root 1.199 IV texture_valid_2d (GLint internalformat, GLsizei w, GLsizei h, GLenum format, GLenum type)
1888     CODE:
1889     {
1890     GLint width;
1891     glTexImage2D (GL_PROXY_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, 0);
1892     glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
1893     RETVAL = width > 0;
1894     }
1895     OUTPUT:
1896     RETVAL
1897    
1898 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Map
1899 root 1.28
1900 root 1.205 PROTOTYPES: DISABLE
1901    
1902 root 1.242 DC::Map
1903 root 1.319 new (SV *klass)
1904 root 1.28 CODE:
1905 root 1.323 New (0, RETVAL, 1, mapgrid);
1906 root 1.42 RETVAL->x = 0;
1907     RETVAL->y = 0;
1908 root 1.164 RETVAL->w = 0;
1909     RETVAL->h = 0;
1910 root 1.42 RETVAL->ox = 0;
1911     RETVAL->oy = 0;
1912 root 1.174 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1913     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1914 root 1.28 RETVAL->rows = 0;
1915     RETVAL->row = 0;
1916     OUTPUT:
1917     RETVAL
1918    
1919     void
1920 root 1.242 DESTROY (DC::Map self)
1921 root 1.28 CODE:
1922     {
1923 root 1.30 map_clear (self);
1924 root 1.174 Safefree (self->face2tile);
1925 root 1.111 Safefree (self->tex);
1926 root 1.29 Safefree (self);
1927     }
1928    
1929     void
1930 root 1.242 resize (DC::Map self, int map_width, int map_height)
1931 root 1.164 CODE:
1932     self->w = map_width;
1933     self->h = map_height;
1934    
1935     void
1936 root 1.242 clear (DC::Map self)
1937 root 1.30 CODE:
1938     map_clear (self);
1939    
1940     void
1941 root 1.242 set_tileid (DC::Map self, int face, int tile)
1942 root 1.29 CODE:
1943     {
1944 root 1.174 need_facenum (self, face); self->face2tile [face] = tile;
1945     need_texid (self, tile);
1946 root 1.42 }
1947    
1948     void
1949 root 1.242 set_smooth (DC::Map self, int face, int smooth, int level)
1950 root 1.176 CODE:
1951     {
1952 root 1.321 tileid texid;
1953 root 1.176 maptex *tex;
1954    
1955     if (face < 0 || face >= self->faces)
1956     return;
1957    
1958     if (smooth < 0 || smooth >= self->faces)
1959     return;
1960    
1961 root 1.321 texid = self->face2tile [face];
1962 root 1.176
1963     if (!texid)
1964     return;
1965    
1966     tex = self->tex + texid;
1967     tex->smoothtile = self->face2tile [smooth];
1968     tex->smoothlevel = level;
1969     }
1970    
1971     void
1972 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)
1973 root 1.42 CODE:
1974     {
1975 root 1.174 need_texid (self, texid);
1976 root 1.42
1977 root 1.48 {
1978     maptex *tex = self->tex + texid;
1979 root 1.39
1980 root 1.48 tex->name = name;
1981     tex->w = w;
1982     tex->h = h;
1983     tex->s = s;
1984     tex->t = t;
1985     tex->r = r;
1986     tex->g = g;
1987     tex->b = b;
1988     tex->a = a;
1989     }
1990 root 1.95
1991     // somewhat hackish, but for textures that require it, it really
1992     // improves the look, and most others don't suffer.
1993     glBindTexture (GL_TEXTURE_2D, name);
1994 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1995     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1996     // use uglier nearest interpolation because linear suffers
1997     // from transparent color bleeding and ugly wrapping effects.
1998     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1999 root 1.29 }
2000    
2001 root 1.280 void
2002     expire_textures (DC::Map self, int texid, int count)
2003     PPCODE:
2004 root 1.321 for (; texid < self->texs && count; ++texid, --count)
2005 root 1.280 {
2006     maptex *tex = self->tex + texid;
2007    
2008     if (tex->name)
2009     {
2010     if (tex->unused)
2011     {
2012     tex->name = 0;
2013 root 1.282 tex->unused = 0;
2014 root 1.280 XPUSHs (sv_2mortal (newSViv (texid)));
2015     }
2016     else
2017     tex->unused = 1;
2018     }
2019     }
2020    
2021 root 1.42 int
2022 root 1.242 ox (DC::Map self)
2023 root 1.42 ALIAS:
2024     oy = 1
2025 root 1.101 x = 2
2026     y = 3
2027 root 1.102 w = 4
2028     h = 5
2029 root 1.42 CODE:
2030     switch (ix)
2031     {
2032     case 0: RETVAL = self->ox; break;
2033     case 1: RETVAL = self->oy; break;
2034 root 1.101 case 2: RETVAL = self->x; break;
2035     case 3: RETVAL = self->y; break;
2036 root 1.102 case 4: RETVAL = self->w; break;
2037     case 5: RETVAL = self->h; break;
2038 root 1.42 }
2039     OUTPUT:
2040     RETVAL
2041    
2042 root 1.29 void
2043 root 1.242 scroll (DC::Map self, int dx, int dy)
2044 root 1.43 CODE:
2045     {
2046 root 1.44 if (dx > 0)
2047 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
2048 root 1.44 else if (dx < 0)
2049 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
2050 root 1.44
2051     if (dy > 0)
2052 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
2053 root 1.44 else if (dy < 0)
2054 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
2055 root 1.43
2056 root 1.44 self->ox += dx; self->x += dx;
2057     self->oy += dy; self->y += dy;
2058 root 1.43
2059     while (self->y < 0)
2060     {
2061     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
2062    
2063     self->rows += MAP_EXTEND_Y;
2064     self->y += MAP_EXTEND_Y;
2065     }
2066 root 1.44 }
2067 root 1.43
2068 root 1.221 SV *
2069 root 1.316 map1a_update (DC::Map self, SV *data_)
2070 root 1.44 CODE:
2071     {
2072 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
2073     uint8_t *data_end = (uint8_t *)SvEND (data_);
2074 root 1.48 mapcell *cell;
2075 root 1.221 int x, y, z, flags;
2076     AV *missing = newAV ();
2077     RETVAL = newRV_noinc ((SV *)missing);
2078 root 1.43
2079 root 1.150 while (data < data_end - 1)
2080 root 1.29 {
2081 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
2082 root 1.30
2083 root 1.120 x = self->x + ((flags >> 10) & 63);
2084     y = self->y + ((flags >> 4) & 63);
2085 root 1.29
2086 root 1.48 cell = map_get_cell (self, x, y);
2087 root 1.29
2088     if (flags & 15)
2089     {
2090 root 1.142 if (!cell->darkness)
2091 root 1.29 {
2092 root 1.154 memset (cell, 0, sizeof (*cell));
2093 root 1.142 cell->darkness = 256;
2094 root 1.29 }
2095 root 1.45
2096 root 1.142 //TODO: don't trust server data to be in-range(!)
2097    
2098 root 1.141 if (flags & 8)
2099     {
2100 root 1.316 uint8_t ext, cmd;
2101    
2102     do
2103 root 1.141 {
2104 root 1.316 ext = *data++;
2105     cmd = ext & 0x7f;
2106 root 1.141
2107 root 1.316 if (cmd < 4)
2108     cell->darkness = 255 - ext * 64 + 1; /* make sure this doesn't collide with FOW_DARKNESS */
2109     else if (cmd == 5) // health
2110     {
2111     cell->stat_width = 1;
2112     cell->stat_hp = *data++;
2113     }
2114     else if (cmd == 6) // monster width
2115     cell->stat_width = *data++ + 1;
2116     else if (cmd == 0x47)
2117 root 1.141 {
2118 root 1.316 if (*data == 1) cell->player = data [1];
2119     else if (*data == 2) cell->player = data [2] + (data [1] << 8);
2120     else if (*data == 3) cell->player = data [3] + (data [2] << 8) + (data [1] << 16);
2121     else if (*data == 4) cell->player = data [4] + (data [3] << 8) + (data [2] << 16) + (data [1] << 24);
2122 root 1.153
2123 root 1.316 data += *data + 1;
2124 root 1.141 }
2125 root 1.316 else if (cmd == 8) // cell flags
2126     cell->flags = *data++;
2127     else if (ext & 0x40) // unknown, multibyte => skip
2128     data += *data + 1;
2129     else
2130     data++;
2131 root 1.141 }
2132 root 1.316 while (ext & 0x80);
2133 root 1.141 }
2134 root 1.29
2135 root 1.221 for (z = 0; z <= 2; ++z)
2136     if (flags & (4 >> z))
2137     {
2138     faceid face = (data [0] << 8) + data [1]; data += 2;
2139     need_facenum (self, face);
2140     cell->tile [z] = self->face2tile [face];
2141 root 1.29
2142 root 1.221 if (cell->tile [z])
2143     {
2144     maptex *tex = self->tex + cell->tile [z];
2145 root 1.280 tex->unused = 0;
2146 root 1.221 if (!tex->name)
2147     av_push (missing, newSViv (cell->tile [z]));
2148 root 1.29
2149 root 1.221 if (tex->smoothtile)
2150     {
2151     maptex *smooth = self->tex + tex->smoothtile;
2152 root 1.280 smooth->unused = 0;
2153 root 1.221 if (!smooth->name)
2154     av_push (missing, newSViv (tex->smoothtile));
2155     }
2156     }
2157     }
2158 root 1.29 }
2159     else
2160 root 1.267 CELL_CLEAR (cell);
2161 root 1.29 }
2162 root 1.28 }
2163 root 1.221 OUTPUT:
2164     RETVAL
2165 root 1.28
2166 root 1.40 SV *
2167 root 1.242 mapmap (DC::Map self, int x0, int y0, int w, int h)
2168 root 1.40 CODE:
2169     {
2170 root 1.55 int x1, x;
2171     int y1, y;
2172 root 1.40 int z;
2173     SV *map_sv = newSV (w * h * sizeof (uint32_t));
2174     uint32_t *map = (uint32_t *)SvPVX (map_sv);
2175    
2176     SvPOK_only (map_sv);
2177     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
2178    
2179 root 1.55 x0 += self->x; x1 = x0 + w;
2180     y0 += self->y; y1 = y0 + h;
2181 root 1.40
2182     for (y = y0; y < y1; y++)
2183     {
2184     maprow *row = 0 <= y && y < self->rows
2185     ? self->row + y
2186     : 0;
2187    
2188     for (x = x0; x < x1; x++)
2189     {
2190 root 1.306 unsigned int r = 32, g = 32, b = 32, a = 192;
2191 root 1.40
2192     if (row && row->c0 <= x && x < row->c1)
2193     {
2194     mapcell *cell = row->col + (x - row->c0);
2195    
2196     for (z = 0; z <= 0; z++)
2197     {
2198 root 1.174 maptex tex = self->tex [cell->tile [z]];
2199     int a0 = 255 - tex.a;
2200     int a1 = tex.a;
2201    
2202 root 1.306 r = div255 (r * a0 + tex.r * a1);
2203     g = div255 (g * a0 + tex.g * a1);
2204     b = div255 (b * a0 + tex.b * a1);
2205     a = div255 (a * a0 + tex.a * a1);
2206 root 1.40 }
2207     }
2208    
2209     *map++ = (r )
2210     | (g << 8)
2211     | (b << 16)
2212     | (a << 24);
2213     }
2214     }
2215    
2216 root 1.321 RETVAL = map_sv;
2217 root 1.40 }
2218     OUTPUT:
2219     RETVAL
2220    
2221 root 1.221 void
2222 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)
2223 root 1.116 CODE:
2224 root 1.30 {
2225 root 1.223 int x, y, z;
2226    
2227 root 1.324 static uint8_t smooth_max[256][256]; // egad, fast and wasteful on memory (64k), also, static!
2228 root 1.261 int pl_x, pl_y;
2229     maptex pl_tex;
2230 root 1.326 rc_t rc;
2231     rc_t rc_ov;
2232 root 1.223 rc_key_t key;
2233 root 1.326 rc_t::array_t *arr;
2234 root 1.48
2235 root 1.262 pl_tex.name = 0;
2236    
2237 pippijn 1.288 // that's current max. sorry.
2238 root 1.176 if (sw > 255) sw = 255;
2239     if (sh > 255) sh = 255;
2240    
2241 root 1.223 memset (&key, 0, sizeof (key));
2242     key.r = 255;
2243     key.g = 255;
2244     key.b = 255;
2245     key.a = 255;
2246     key.mode = GL_QUADS;
2247     key.format = GL_T2F_V3F;
2248 root 1.30
2249 root 1.164 mx += self->x;
2250     my += self->y;
2251    
2252 root 1.176 // first pass: determine smooth_max
2253     // rather ugly, if you ask me
2254     // could also be stored inside mapcell and updated on change
2255 root 1.324 memset (smooth_max, 0, sizeof (smooth_max[0]) * (sh + 1));
2256 root 1.176
2257     for (y = 0; y < sh; y++)
2258     if (0 <= y + my && y + my < self->rows)
2259     {
2260     maprow *row = self->row + (y + my);
2261    
2262     for (x = 0; x < sw; x++)
2263     if (row->c0 <= x + mx && x + mx < row->c1)
2264     {
2265     mapcell *cell = row->col + (x + mx - row->c0);
2266    
2267 root 1.177 smooth_max[x + 1][y + 1] =
2268     MAX (self->tex [cell->tile [0]].smoothlevel,
2269     MAX (self->tex [cell->tile [1]].smoothlevel,
2270     self->tex [cell->tile [2]].smoothlevel));
2271 root 1.176 }
2272     }
2273    
2274 root 1.223 glEnable (GL_BLEND);
2275     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2276     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2277    
2278 root 1.176 for (z = 0; z <= 2; z++)
2279     {
2280 root 1.325 std::bitset<256> smooth_level; // one bit for every possible smooth level
2281 root 1.324 smooth_key skey;
2282 root 1.322 smooth_hash smooth;
2283 root 1.283 key.texname = -1;
2284 root 1.186
2285 root 1.176 for (y = 0; y < sh; y++)
2286     if (0 <= y + my && y + my < self->rows)
2287     {
2288     maprow *row = self->row + (y + my);
2289    
2290     for (x = 0; x < sw; x++)
2291     if (row->c0 <= x + mx && x + mx < row->c1)
2292     {
2293     mapcell *cell = row->col + (x + mx - row->c0);
2294     tileid tile = cell->tile [z];
2295    
2296     if (tile)
2297     {
2298     maptex tex = self->tex [tile];
2299 root 1.285 int px, py;
2300 root 1.176
2301 root 1.223 if (key.texname != tex.name)
2302 root 1.176 {
2303 root 1.280 self->tex [tile].unused = 0;
2304    
2305 root 1.176 if (!tex.name)
2306 root 1.285 tex = self->tex [TEXID_NOFACE]; /* missing, replace by noface */
2307 root 1.176
2308 root 1.223 key.texname = tex.name;
2309 root 1.326 arr = &rc.array (key);
2310 root 1.176 }
2311    
2312 root 1.306 px = (x + 1) * Th - tex.w;
2313     py = (y + 1) * Tw - tex.h;
2314 root 1.285
2315 root 1.261 if (expect_false (cell->player == player) && expect_false (z == 2))
2316     {
2317     pl_x = px;
2318     pl_y = py;
2319     pl_tex = tex;
2320     continue;
2321     }
2322 root 1.219
2323 root 1.326 arr->t2f_v3f (0 , 0 , px , py , 0);
2324     arr->t2f_v3f (0 , tex.t, px , py + tex.h, 0);
2325     arr->t2f_v3f (tex.s, tex.t, px + tex.w, py + tex.h, 0);
2326     arr->t2f_v3f (tex.s, 0 , px + tex.w, py , 0);
2327 root 1.176
2328     // update smooth hash
2329     if (tex.smoothtile)
2330     {
2331     skey.tile = tex.smoothtile;
2332     skey.level = tex.smoothlevel;
2333    
2334 root 1.325 smooth_level[tex.smoothlevel] = 1;
2335 root 1.30
2336 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
2337     // shifted +1|+1 so we always stay positive.
2338 root 1.30
2339 root 1.180 // bits is ___n cccc CCCC bbbb
2340     // n do not draw borders&corners
2341     // c draw these corners, but...
2342     // C ... not these
2343     // b draw these borders
2344    
2345     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
2346     // ┃· ·· ·┃ ━━
2347    
2348     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
2349     // ·· ·· ·┏ ┓·
2350    
2351 root 1.176 // full tile
2352 root 1.322 skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, skey, 0x1000);
2353 root 1.176
2354     // borders
2355 root 1.322 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, skey, 0x0091);
2356     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, skey, 0x0032);
2357     skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, skey, 0x0064);
2358     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, skey, 0x00c8);
2359 root 1.176
2360     // corners
2361 root 1.322 skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, skey, 0x0100);
2362     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, skey, 0x0200);
2363     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, skey, 0x0400);
2364     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, skey, 0x0800);
2365 root 1.176 }
2366     }
2367 root 1.285
2368 root 1.296 if (expect_false (z == 2) && expect_false (cell->flags))
2369 root 1.285 {
2370 root 1.296 // overlays such as the speech bubble, probably more to come
2371     if (cell->flags & 1)
2372 root 1.285 {
2373 root 1.296 rc_key_t key_ov = key;
2374 root 1.326 maptex tex = self->tex[TEXID_SPEECH];
2375 root 1.306 int px = x * Tw + Tw * 2 / 32;
2376     int py = y * Th - Th * 6 / 32;
2377 root 1.296
2378     key_ov.texname = tex.name;
2379 root 1.326 rc_t::array_t &arr = rc_ov.array (key_ov);
2380 root 1.296
2381 root 1.326 arr.t2f_v3f (0 , 0 , px , py , 0);
2382     arr.t2f_v3f (0 , tex.t, px , py + Th, 0);
2383     arr.t2f_v3f (tex.s, tex.t, px + Tw, py + Th, 0);
2384     arr.t2f_v3f (tex.s, 0 , px + Tw, py , 0);
2385 root 1.285 }
2386     }
2387 root 1.176 }
2388     }
2389 root 1.174
2390 root 1.326 rc.draw ();
2391     rc.clear ();
2392 root 1.224
2393 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
2394     // this is basically counting sort
2395 root 1.176 {
2396 root 1.186 int w, b;
2397 root 1.30
2398 root 1.226 glEnable (GL_TEXTURE_2D);
2399     glBegin (GL_QUADS);
2400 root 1.325 for (int level = 0; level < smooth_level.size (); ++level)
2401     if (smooth_level[level])
2402     for (auto &&it = smooth.begin (); it != smooth.end (); ++it)
2403     {
2404     smooth_key &skey = it->first;
2405     IV bits = it->second;
2406    
2407     if (!(bits & 0x1000)
2408     && skey.level == level
2409     && level > smooth_max [skey.x][skey.y])
2410 root 1.176 {
2411 root 1.325 maptex tex = self->tex [skey.tile];
2412     int px = (((int)skey.x) - 1) * Tw;
2413     int py = (((int)skey.y) - 1) * Th;
2414     int border = bits & 15;
2415     int corner = (bits >> 8) & ~(bits >> 4) & 15;
2416     float dx = tex.s * .0625f; // 16 images/row
2417     float dy = tex.t * .5f ; // 2 images/column
2418 root 1.153
2419 root 1.325 if (tex.name)
2420 root 1.153 {
2421 root 1.325 // this time avoiding texture state changes
2422     // save gobs of state changes.
2423     if (key.texname != tex.name)
2424     {
2425     self->tex [skey.tile].unused = 0;
2426    
2427     glEnd ();
2428     glBindTexture (GL_TEXTURE_2D, key.texname = tex.name);
2429     glBegin (GL_QUADS);
2430     }
2431    
2432     if (border)
2433     {
2434     float ox = border * dx;
2435    
2436     glTexCoord2f (ox , 0.f ); glVertex2i (px , py );
2437     glTexCoord2f (ox , dy ); glVertex2i (px , py + Th);
2438     glTexCoord2f (ox + dx, dy ); glVertex2i (px + Tw, py + Th);
2439     glTexCoord2f (ox + dx, 0.f ); glVertex2i (px + Tw, py );
2440     }
2441 root 1.176
2442 root 1.325 if (corner)
2443 root 1.174 {
2444 root 1.325 float ox = corner * dx;
2445    
2446     glTexCoord2f (ox , dy ); glVertex2i (px , py );
2447     glTexCoord2f (ox , dy * 2.f); glVertex2i (px , py + Th);
2448     glTexCoord2f (ox + dx, dy * 2.f); glVertex2i (px + Tw, py + Th);
2449     glTexCoord2f (ox + dx, dy ); glVertex2i (px + Tw, py );
2450 root 1.174 }
2451 root 1.153 }
2452     }
2453 root 1.325 }
2454 root 1.226
2455     glEnd ();
2456     glDisable (GL_TEXTURE_2D);
2457     key.texname = -1;
2458 root 1.176 }
2459 root 1.186 }
2460 root 1.30
2461 root 1.261 if (pl_tex.name)
2462     {
2463     maptex tex = pl_tex;
2464 root 1.266 int px = pl_x + sdx;
2465     int py = pl_y + sdy;
2466 root 1.261
2467     key.texname = tex.name;
2468 root 1.326 rc_t::array_t &arr = rc.array (key);
2469 root 1.261
2470 root 1.326 arr.t2f_v3f (0 , 0 , px , py , 0);
2471     arr.t2f_v3f (0 , tex.t, px , py + tex.h, 0);
2472     arr.t2f_v3f (tex.s, tex.t, px + tex.w, py + tex.h, 0);
2473     arr.t2f_v3f (tex.s, 0 , px + tex.w, py , 0);
2474 root 1.261
2475 root 1.326 rc.draw ();
2476 root 1.261 }
2477    
2478 root 1.326 rc_ov.draw ();
2479     rc_ov.clear ();
2480 root 1.285
2481 root 1.152 glDisable (GL_BLEND);
2482 root 1.143
2483 root 1.145 // top layer: overlays such as the health bar
2484 root 1.143 for (y = 0; y < sh; y++)
2485 root 1.164 if (0 <= y + my && y + my < self->rows)
2486 root 1.143 {
2487 root 1.164 maprow *row = self->row + (y + my);
2488 root 1.143
2489     for (x = 0; x < sw; x++)
2490 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2491 root 1.143 {
2492 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2493 root 1.143
2494 root 1.306 int px = x * Tw;
2495     int py = y * Th;
2496 root 1.143
2497 root 1.279 if (expect_false (cell->player == player))
2498     {
2499     px += sdx;
2500     py += sdy;
2501     }
2502    
2503 root 1.143 if (cell->stat_hp)
2504     {
2505 root 1.306 int width = cell->stat_width * Tw;
2506     int thick = (sh * Th / 32 + 27) / 28 + 1 + cell->stat_width;
2507 root 1.143
2508 root 1.152 glColor3ub (0, 0, 0);
2509 root 1.151 glRectf (px + 1, py - thick - 2,
2510     px + width - 1, py);
2511 root 1.147
2512 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
2513 root 1.147 glRectf (px + 2,
2514 root 1.151 py - thick - 1,
2515     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
2516 root 1.143 }
2517     }
2518     }
2519 root 1.116 }
2520    
2521     void
2522 root 1.295 draw_magicmap (DC::Map self, int w, int h, unsigned char *data)
2523 root 1.117 CODE:
2524     {
2525     static float color[16][3] = {
2526 root 1.295 { 0.00f, 0.00f, 0.00f },
2527     { 1.00f, 1.00f, 1.00f },
2528     { 0.00f, 0.00f, 0.55f },
2529     { 1.00f, 0.00f, 0.00f },
2530    
2531     { 1.00f, 0.54f, 0.00f },
2532     { 0.11f, 0.56f, 1.00f },
2533     { 0.93f, 0.46f, 0.00f },
2534     { 0.18f, 0.54f, 0.34f },
2535    
2536     { 0.56f, 0.73f, 0.56f },
2537     { 0.80f, 0.80f, 0.80f },
2538     { 0.55f, 0.41f, 0.13f },
2539     { 0.99f, 0.77f, 0.26f },
2540    
2541     { 0.74f, 0.65f, 0.41f },
2542    
2543     { 0.00f, 1.00f, 1.00f },
2544     { 1.00f, 0.00f, 1.00f },
2545     { 1.00f, 1.00f, 0.00f },
2546 root 1.117 };
2547    
2548     int x, y;
2549    
2550     glEnable (GL_TEXTURE_2D);
2551 root 1.290 /* GL_REPLACE would be correct, as we don't need to modulate alpha,
2552     * but the nvidia driver (185.18.14) mishandles alpha textures
2553 root 1.296 * and takes the colour from god knows where instead of using
2554 root 1.290 * Cp. MODULATE results in the same colour, but slightly different
2555     * alpha, but atcually gives us the correct colour with nvidia.
2556     */
2557     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2558 root 1.117 glEnable (GL_BLEND);
2559     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2560     glBegin (GL_QUADS);
2561    
2562     for (y = 0; y < h; y++)
2563     for (x = 0; x < w; x++)
2564     {
2565     unsigned char m = data [x + y * w];
2566    
2567 root 1.118 if (m)
2568     {
2569     float *c = color [m & 15];
2570    
2571 root 1.295 float tx1 = m & 0x40 ? 0.5f : 0.f;
2572     float tx2 = tx1 + 0.5f;
2573 root 1.118
2574 root 1.290 glColor4f (c[0], c[1], c[2], 1);
2575 root 1.118 glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2576     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2577     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2578     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2579     }
2580 root 1.117 }
2581    
2582     glEnd ();
2583     glDisable (GL_BLEND);
2584     glDisable (GL_TEXTURE_2D);
2585     }
2586    
2587     void
2588 root 1.242 fow_texture (DC::Map self, int mx, int my, int sw, int sh)
2589 root 1.116 PPCODE:
2590     {
2591     int x, y;
2592 root 1.296 int sw1 = sw + 2;
2593     int sh1 = sh + 2;
2594     int sh3 = sh * 3;
2595     int sw3 = sw * 3;
2596     SV *darkness3_sv = sv_2mortal (newSV (sw3 * sh3));
2597 root 1.204 uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2598 root 1.307 uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2599     memset (darkness1, 0, sw1*sh1);
2600 root 1.204
2601     SvPOK_only (darkness3_sv);
2602 root 1.296 SvCUR_set (darkness3_sv, sw3 * sh3);
2603 root 1.116
2604 root 1.204 mx += self->x - 1;
2605     my += self->y - 1;
2606 root 1.116
2607 root 1.204 for (y = 0; y < sh1; y++)
2608 root 1.164 if (0 <= y + my && y + my < self->rows)
2609 root 1.116 {
2610 root 1.164 maprow *row = self->row + (y + my);
2611 root 1.116
2612 root 1.204 for (x = 0; x < sw1; x++)
2613 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2614 root 1.116 {
2615 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2616 root 1.116
2617 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2618 root 1.294 ? DARKNESS_ADJUST (255 - (cell->darkness - 1))
2619     : DARKNESS_ADJUST (255 - FOW_DARKNESS);
2620 root 1.116 }
2621     }
2622 root 1.34
2623 root 1.204 for (y = 0; y < sh; ++y)
2624     for (x = 0; x < sw; ++x)
2625     {
2626     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2627     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2628     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2629     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2630     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2631     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2632     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2633     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2634     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2635    
2636     uint8_t r11 = (d11 + d21 + d12) / 3;
2637     uint8_t r21 = d21;
2638     uint8_t r31 = (d21 + d31 + d32) / 3;
2639    
2640     uint8_t r12 = d12;
2641     uint8_t r22 = d22;
2642     uint8_t r32 = d32;
2643    
2644     uint8_t r13 = (d13 + d23 + d12) / 3;
2645     uint8_t r23 = d23;
2646     uint8_t r33 = (d23 + d33 + d32) / 3;
2647    
2648 root 1.296 darkness3 [(y * 3 ) * sw3 + (x * 3 )] = MAX (d22, r11);
2649     darkness3 [(y * 3 ) * sw3 + (x * 3 + 1)] = MAX (d22, r21);
2650     darkness3 [(y * 3 ) * sw3 + (x * 3 + 2)] = MAX (d22, r31);
2651     darkness3 [(y * 3 + 1) * sw3 + (x * 3 )] = MAX (d22, r12);
2652     darkness3 [(y * 3 + 1) * sw3 + (x * 3 + 1)] = MAX (d22, r22); /* this MUST be == d22 */
2653     darkness3 [(y * 3 + 1) * sw3 + (x * 3 + 2)] = MAX (d22, r32);
2654     darkness3 [(y * 3 + 2) * sw3 + (x * 3 )] = MAX (d22, r13);
2655     darkness3 [(y * 3 + 2) * sw3 + (x * 3 + 1)] = MAX (d22, r23);
2656     darkness3 [(y * 3 + 2) * sw3 + (x * 3 + 2)] = MAX (d22, r33);
2657 root 1.204 }
2658 root 1.201
2659 root 1.204 free (darkness1);
2660 root 1.201
2661 root 1.32 EXTEND (SP, 3);
2662 root 1.296 PUSHs (sv_2mortal (newSViv (sw3)));
2663 root 1.204 PUSHs (sv_2mortal (newSViv (sh3)));
2664     PUSHs (darkness3_sv);
2665 root 1.30 }
2666    
2667 root 1.42 SV *
2668 root 1.242 get_rect (DC::Map self, int x0, int y0, int w, int h)
2669 root 1.42 CODE:
2670     {
2671     int x, y, x1, y1;
2672     SV *data_sv = newSV (w * h * 7 + 5);
2673     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2674    
2675     *data++ = 0; /* version 0 format */
2676     *data++ = w >> 8; *data++ = w;
2677     *data++ = h >> 8; *data++ = h;
2678    
2679     // we need to do this 'cause we don't keep an absolute coord system for rows
2680 root 1.55 // TODO: treat rows as we treat columns
2681 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2682     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2683    
2684     x0 += self->x - self->ox;
2685     y0 += self->y - self->oy;
2686    
2687     x1 = x0 + w;
2688     y1 = y0 + h;
2689    
2690     for (y = y0; y < y1; y++)
2691     {
2692     maprow *row = 0 <= y && y < self->rows
2693     ? self->row + y
2694     : 0;
2695    
2696     for (x = x0; x < x1; x++)
2697     {
2698     if (row && row->c0 <= x && x < row->c1)
2699     {
2700     mapcell *cell = row->col + (x - row->c0);
2701     uint8_t flags = 0;
2702    
2703 root 1.174 if (cell->tile [0]) flags |= 1;
2704     if (cell->tile [1]) flags |= 2;
2705     if (cell->tile [2]) flags |= 4;
2706 root 1.42
2707     *data++ = flags;
2708    
2709     if (flags & 1)
2710     {
2711 root 1.174 tileid tile = cell->tile [0];
2712     *data++ = tile >> 8;
2713     *data++ = tile;
2714 root 1.42 }
2715    
2716     if (flags & 2)
2717     {
2718 root 1.174 tileid tile = cell->tile [1];
2719     *data++ = tile >> 8;
2720     *data++ = tile;
2721 root 1.42 }
2722    
2723     if (flags & 4)
2724     {
2725 root 1.174 tileid tile = cell->tile [2];
2726     *data++ = tile >> 8;
2727     *data++ = tile;
2728 root 1.42 }
2729     }
2730     else
2731     *data++ = 0;
2732     }
2733     }
2734    
2735 root 1.321 /* if size is w*h + 5 then no data has been found */
2736 root 1.260 if (data - (uint8_t *)SvPVX (data_sv) != w * h + 5)
2737 root 1.259 {
2738     SvPOK_only (data_sv);
2739     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2740     }
2741 root 1.260
2742 root 1.321 RETVAL = data_sv;
2743 root 1.42 }
2744     OUTPUT:
2745     RETVAL
2746    
2747     void
2748 root 1.259 set_rect (DC::Map self, int x0, int y0, SV *data_sv)
2749 root 1.42 PPCODE:
2750     {
2751     int x, y, z;
2752 root 1.48 int w, h;
2753 root 1.42 int x1, y1;
2754 root 1.259 STRLEN len;
2755     uint8_t *data, *end;
2756    
2757     len = SvLEN (data_sv);
2758 root 1.260 SvGROW (data_sv, len + 8); // reserve at least 7+ bytes more
2759 root 1.319 data = (uint8_t *)SvPVbyte_nolen (data_sv);
2760 root 1.260 end = data + len + 8;
2761 root 1.259
2762     if (len < 5)
2763     XSRETURN_EMPTY;
2764 root 1.42
2765     if (*data++ != 0)
2766 root 1.227 XSRETURN_EMPTY; /* version mismatch */
2767 root 1.42
2768 root 1.48 w = *data++ << 8; w |= *data++;
2769     h = *data++ << 8; h |= *data++;
2770 root 1.42
2771     // we need to do this 'cause we don't keep an absolute coord system for rows
2772 root 1.55 // TODO: treat rows as we treat columns
2773 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2774     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2775    
2776     x0 += self->x - self->ox;
2777     y0 += self->y - self->oy;
2778    
2779     x1 = x0 + w;
2780     y1 = y0 + h;
2781    
2782     for (y = y0; y < y1; y++)
2783     {
2784     maprow *row = map_get_row (self, y);
2785    
2786     for (x = x0; x < x1; x++)
2787     {
2788 root 1.259 uint8_t flags;
2789    
2790     if (data + 7 >= end)
2791     XSRETURN_EMPTY;
2792    
2793     flags = *data++;
2794 root 1.42
2795     if (flags)
2796     {
2797     mapcell *cell = row_get_cell (row, x);
2798 root 1.174 tileid tile[3] = { 0, 0, 0 };
2799 root 1.42
2800 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2801     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2802     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2803 root 1.42
2804 root 1.143 if (cell->darkness == 0)
2805 root 1.42 {
2806 root 1.260 /*cell->darkness = 0;*/
2807     EXTEND (SP, 3);
2808 root 1.42
2809     for (z = 0; z <= 2; z++)
2810     {
2811 root 1.174 tileid t = tile [z];
2812    
2813 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2814 root 1.174 {
2815 root 1.260 PUSHs (sv_2mortal (newSViv (t)));
2816 root 1.174 need_texid (self, t);
2817     }
2818 root 1.42
2819 root 1.174 cell->tile [z] = t;
2820 root 1.42 }
2821     }
2822     }
2823     }
2824     }
2825     }
2826    
2827 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::RW
2828 root 1.205
2829 root 1.242 DC::RW
2830 root 1.319 new (SV *klass, SV *data_sv)
2831 root 1.211 CODE:
2832     {
2833     STRLEN datalen;
2834     char *data = SvPVbyte (data_sv, datalen);
2835    
2836 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2837 root 1.211 }
2838     OUTPUT:
2839     RETVAL
2840    
2841 root 1.242 DC::RW
2842 root 1.319 new_from_file (SV *klass, const char *path, const char *mode = "rb")
2843 root 1.212 CODE:
2844     RETVAL = SDL_RWFromFile (path, mode);
2845     OUTPUT:
2846     RETVAL
2847    
2848 root 1.218 # fails on win32:
2849 root 1.241 # dc.xs(2268) : error C2059: syntax error : '('
2850 root 1.218 #void
2851 root 1.242 #close (DC::RW self)
2852 root 1.218 # CODE:
2853     # (self->(close)) (self);
2854 root 1.212
2855 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Channel
2856 root 1.212
2857     PROTOTYPES: DISABLE
2858    
2859 root 1.242 DC::Channel
2860 root 1.215 find ()
2861     CODE:
2862     {
2863     RETVAL = Mix_GroupAvailable (-1);
2864    
2865     if (RETVAL < 0)
2866     {
2867     RETVAL = Mix_GroupOldest (-1);
2868    
2869     if (RETVAL < 0)
2870 root 1.302 {
2871     // happens sometimes, maybe it just stopped playing(?)
2872     RETVAL = Mix_GroupAvailable (-1);
2873 root 1.215
2874 root 1.302 if (RETVAL < 0)
2875     XSRETURN_UNDEF;
2876     }
2877     else
2878     Mix_HaltChannel (RETVAL);
2879 root 1.215 }
2880    
2881     Mix_UnregisterAllEffects (RETVAL);
2882     Mix_Volume (RETVAL, 128);
2883     }
2884     OUTPUT:
2885     RETVAL
2886    
2887 root 1.213 void
2888 root 1.242 halt (DC::Channel self)
2889 root 1.213 CODE:
2890     Mix_HaltChannel (self);
2891    
2892     void
2893 root 1.242 expire (DC::Channel self, int ticks = -1)
2894 root 1.213 CODE:
2895     Mix_ExpireChannel (self, ticks);
2896    
2897     void
2898 root 1.242 fade_out (DC::Channel self, int ticks = -1)
2899 root 1.213 CODE:
2900     Mix_FadeOutChannel (self, ticks);
2901    
2902 root 1.212 int
2903 root 1.242 volume (DC::Channel self, int volume)
2904 root 1.212 CODE:
2905 root 1.216 RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128));
2906 root 1.212 OUTPUT:
2907     RETVAL
2908    
2909 root 1.213 void
2910 root 1.242 unregister_all_effects (DC::Channel self)
2911 root 1.212 CODE:
2912 root 1.213 Mix_UnregisterAllEffects (self);
2913 root 1.212
2914 root 1.213 void
2915 root 1.242 set_panning (DC::Channel self, int left, int right)
2916 root 1.212 CODE:
2917 root 1.216 left = CLAMP (left , 0, 255);
2918     right = CLAMP (right, 0, 255);
2919 root 1.213 Mix_SetPanning (self, left, right);
2920 root 1.212
2921 root 1.213 void
2922 root 1.242 set_distance (DC::Channel self, int distance)
2923 root 1.212 CODE:
2924 root 1.216 Mix_SetDistance (self, CLAMP (distance, 0, 255));
2925 root 1.212
2926 root 1.213 void
2927 root 1.242 set_position (DC::Channel self, int angle, int distance)
2928 root 1.212 CODE:
2929 root 1.220
2930     void
2931 root 1.242 set_position_r (DC::Channel self, int dx, int dy, int maxdistance)
2932 root 1.220 CODE:
2933     {
2934     int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance));
2935 root 1.295 int angle = atan2f (dx, -dy) * 180.f / (float)M_PI + 360.f;
2936 root 1.216 Mix_SetPosition (self, angle, CLAMP (distance, 0, 255));
2937 root 1.220 }
2938 root 1.212
2939 root 1.213 void
2940 root 1.242 set_reverse_stereo (DC::Channel self, int flip)
2941 root 1.212 CODE:
2942 root 1.213 Mix_SetReverseStereo (self, flip);
2943 root 1.212
2944 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixChunk
2945 root 1.212
2946     PROTOTYPES: DISABLE
2947    
2948 root 1.301 void
2949     decoders ()
2950     PPCODE:
2951     #if SDL_MIXER_MAJOR_VERSION > 1 || SDL_MIXER_MINOR_VERSION > 2 || SDL_MIXER_PATCHLEVEL >= 10
2952     int i, num = Mix_GetNumChunkDecoders ();
2953     EXTEND (SP, num);
2954     for (i = 0; i < num; ++i)
2955     PUSHs (sv_2mortal (newSVpv (Mix_GetChunkDecoder (i), 0)));
2956     #else
2957     XPUSHs (sv_2mortal (newSVpv ("(sdl mixer too old)", 0)));
2958     #endif
2959    
2960 root 1.242 DC::MixChunk
2961 root 1.319 new (SV *klass, DC::RW rwops)
2962 root 1.52 CODE:
2963 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2964 root 1.52 OUTPUT:
2965     RETVAL
2966    
2967     void
2968 root 1.242 DESTROY (DC::MixChunk self)
2969 root 1.52 CODE:
2970     Mix_FreeChunk (self);
2971    
2972     int
2973 root 1.242 volume (DC::MixChunk self, int volume = -1)
2974 root 1.52 CODE:
2975 root 1.216 if (items > 1)
2976     volume = CLAMP (volume, 0, 128);
2977 root 1.52 RETVAL = Mix_VolumeChunk (self, volume);
2978     OUTPUT:
2979     RETVAL
2980    
2981 root 1.242 DC::Channel
2982     play (DC::MixChunk self, DC::Channel channel = -1, int loops = 0, int ticks = -1)
2983 root 1.52 CODE:
2984 root 1.215 {
2985 root 1.52 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2986 root 1.215
2987     if (RETVAL < 0)
2988     XSRETURN_UNDEF;
2989    
2990     if (channel < 0)
2991     {
2992     Mix_UnregisterAllEffects (RETVAL);
2993     Mix_Volume (RETVAL, 128);
2994     }
2995     }
2996 root 1.52 OUTPUT:
2997     RETVAL
2998    
2999 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixMusic
3000 root 1.52
3001 root 1.301 void
3002     decoders ()
3003     PPCODE:
3004     #if SDL_MIXER_MAJOR_VERSION > 1 || SDL_MIXER_MINOR_VERSION > 2 || SDL_MIXER_PATCHLEVEL >= 10
3005     int i, num = Mix_GetNumMusicDecoders ();
3006     EXTEND (SP, num);
3007     for (i = 0; i < num; ++i)
3008     PUSHs (sv_2mortal (newSVpv (Mix_GetMusicDecoder (i), 0)));
3009     #else
3010     XPUSHs (sv_2mortal (newSVpv ("(sdl mixer too old)", 0)));
3011     #endif
3012    
3013 root 1.52 int
3014     volume (int volume = -1)
3015 root 1.205 PROTOTYPE: ;$
3016 root 1.52 CODE:
3017 root 1.216 if (items > 0)
3018     volume = CLAMP (volume, 0, 128);
3019 root 1.52 RETVAL = Mix_VolumeMusic (volume);
3020     OUTPUT:
3021     RETVAL
3022    
3023 root 1.213 void
3024 root 1.194 fade_out (int ms)
3025     CODE:
3026 root 1.213 Mix_FadeOutMusic (ms);
3027 root 1.194
3028 root 1.212 void
3029     halt ()
3030     CODE:
3031     Mix_HaltMusic ();
3032    
3033 root 1.301 int
3034     playing ()
3035     CODE:
3036     RETVAL = Mix_PlayingMusic ();
3037     OUTPUT:
3038     RETVAL
3039    
3040 root 1.242 DC::MixMusic
3041 root 1.319 new (SV *klass, DC::RW rwops)
3042 root 1.52 CODE:
3043 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
3044 root 1.52 OUTPUT:
3045     RETVAL
3046    
3047     void
3048 root 1.242 DESTROY (DC::MixMusic self)
3049 root 1.52 CODE:
3050     Mix_FreeMusic (self);
3051    
3052     int
3053 root 1.242 play (DC::MixMusic self, int loops = -1)
3054 root 1.52 CODE:
3055     RETVAL = Mix_PlayMusic (self, loops);
3056     OUTPUT:
3057     RETVAL
3058    
3059 root 1.213 void
3060 root 1.242 fade_in_pos (DC::MixMusic self, int loops, int ms, double position)
3061 root 1.195 CODE:
3062 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
3063 root 1.195
3064 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::OpenGL
3065 root 1.54
3066 root 1.205 PROTOTYPES: ENABLE
3067    
3068 root 1.54 BOOT:
3069     {
3070 root 1.242 HV *stash = gv_stashpv ("DC::OpenGL", 1);
3071 root 1.54 static const struct {
3072     const char *name;
3073     IV iv;
3074     } *civ, const_iv[] = {
3075     # define const_iv(name) { # name, (IV)name }
3076 root 1.199 const_iv (GL_VENDOR),
3077     const_iv (GL_VERSION),
3078     const_iv (GL_EXTENSIONS),
3079 root 1.293 const_iv (GL_MAX_TEXTURE_UNITS),
3080 root 1.54 const_iv (GL_COLOR_MATERIAL),
3081     const_iv (GL_SMOOTH),
3082     const_iv (GL_FLAT),
3083 root 1.69 const_iv (GL_DITHER),
3084 root 1.54 const_iv (GL_BLEND),
3085 root 1.89 const_iv (GL_CULL_FACE),
3086 root 1.69 const_iv (GL_SCISSOR_TEST),
3087 root 1.89 const_iv (GL_DEPTH_TEST),
3088     const_iv (GL_ALPHA_TEST),
3089     const_iv (GL_NORMALIZE),
3090     const_iv (GL_RESCALE_NORMAL),
3091 root 1.119 const_iv (GL_FRONT),
3092     const_iv (GL_BACK),
3093 root 1.206 const_iv (GL_AUX0),
3094 root 1.54 const_iv (GL_AND),
3095 root 1.67 const_iv (GL_ONE),
3096     const_iv (GL_ZERO),
3097 root 1.54 const_iv (GL_SRC_ALPHA),
3098 root 1.104 const_iv (GL_DST_ALPHA),
3099 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
3100 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
3101 root 1.293 const_iv (GL_SRC_COLOR),
3102     const_iv (GL_DST_COLOR),
3103     const_iv (GL_ONE_MINUS_SRC_COLOR),
3104     const_iv (GL_ONE_MINUS_DST_COLOR),
3105 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
3106 root 1.54 const_iv (GL_RGB),
3107     const_iv (GL_RGBA),
3108 root 1.115 const_iv (GL_RGBA4),
3109     const_iv (GL_RGBA8),
3110     const_iv (GL_RGB5_A1),
3111 root 1.54 const_iv (GL_UNSIGNED_BYTE),
3112 root 1.89 const_iv (GL_UNSIGNED_SHORT),
3113     const_iv (GL_UNSIGNED_INT),
3114 root 1.54 const_iv (GL_ALPHA),
3115 root 1.86 const_iv (GL_INTENSITY),
3116 root 1.76 const_iv (GL_LUMINANCE),
3117 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
3118 root 1.54 const_iv (GL_FLOAT),
3119     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
3120 root 1.230 const_iv (GL_COMPRESSED_ALPHA_ARB),
3121     const_iv (GL_COMPRESSED_LUMINANCE_ARB),
3122     const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB),
3123     const_iv (GL_COMPRESSED_INTENSITY_ARB),
3124     const_iv (GL_COMPRESSED_RGB_ARB),
3125     const_iv (GL_COMPRESSED_RGBA_ARB),
3126 root 1.54 const_iv (GL_COMPILE),
3127 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
3128     const_iv (GL_PROXY_TEXTURE_2D),
3129 root 1.54 const_iv (GL_TEXTURE_1D),
3130     const_iv (GL_TEXTURE_2D),
3131     const_iv (GL_TEXTURE_ENV),
3132     const_iv (GL_TEXTURE_MAG_FILTER),
3133     const_iv (GL_TEXTURE_MIN_FILTER),
3134     const_iv (GL_TEXTURE_ENV_MODE),
3135     const_iv (GL_TEXTURE_WRAP_S),
3136     const_iv (GL_TEXTURE_WRAP_T),
3137 root 1.98 const_iv (GL_REPEAT),
3138 root 1.54 const_iv (GL_CLAMP),
3139 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
3140 root 1.54 const_iv (GL_NEAREST),
3141     const_iv (GL_LINEAR),
3142 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
3143     const_iv (GL_LINEAR_MIPMAP_NEAREST),
3144     const_iv (GL_NEAREST_MIPMAP_LINEAR),
3145     const_iv (GL_LINEAR_MIPMAP_LINEAR),
3146     const_iv (GL_GENERATE_MIPMAP),
3147 root 1.54 const_iv (GL_MODULATE),
3148 root 1.69 const_iv (GL_DECAL),
3149 root 1.54 const_iv (GL_REPLACE),
3150 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
3151 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
3152     const_iv (GL_PROJECTION),
3153     const_iv (GL_MODELVIEW),
3154     const_iv (GL_COLOR_LOGIC_OP),
3155 root 1.69 const_iv (GL_SEPARABLE_2D),
3156 root 1.54 const_iv (GL_CONVOLUTION_2D),
3157     const_iv (GL_CONVOLUTION_BORDER_MODE),
3158     const_iv (GL_CONSTANT_BORDER),
3159 root 1.208 const_iv (GL_POINTS),
3160 root 1.54 const_iv (GL_LINES),
3161 root 1.138 const_iv (GL_LINE_STRIP),
3162 root 1.89 const_iv (GL_LINE_LOOP),
3163 root 1.54 const_iv (GL_QUADS),
3164 root 1.89 const_iv (GL_QUAD_STRIP),
3165     const_iv (GL_TRIANGLES),
3166     const_iv (GL_TRIANGLE_STRIP),
3167     const_iv (GL_TRIANGLE_FAN),
3168 root 1.208 const_iv (GL_POLYGON),
3169 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
3170 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
3171     const_iv (GL_LINE_SMOOTH_HINT),
3172     const_iv (GL_POLYGON_SMOOTH_HINT),
3173     const_iv (GL_GENERATE_MIPMAP_HINT),
3174 root 1.232 const_iv (GL_TEXTURE_COMPRESSION_HINT),
3175 root 1.54 const_iv (GL_FASTEST),
3176 root 1.206 const_iv (GL_DONT_CARE),
3177     const_iv (GL_NICEST),
3178 root 1.89 const_iv (GL_V2F),
3179     const_iv (GL_V3F),
3180     const_iv (GL_T2F_V3F),
3181     const_iv (GL_T2F_N3F_V3F),
3182 root 1.291 const_iv (GL_FUNC_ADD),
3183     const_iv (GL_FUNC_SUBTRACT),
3184     const_iv (GL_FUNC_REVERSE_SUBTRACT),
3185 root 1.54 # undef const_iv
3186     };
3187    
3188 root 1.308 for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ > const_iv; civ--)
3189     newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
3190 root 1.188
3191     texture_av = newAV ();
3192     AvREAL_off (texture_av);
3193 root 1.54 }
3194    
3195 root 1.231 void
3196     disable_GL_EXT_blend_func_separate ()
3197     CODE:
3198     gl.BlendFuncSeparate = 0;
3199     gl.BlendFuncSeparateEXT = 0;
3200    
3201 root 1.291 void
3202     apple_nvidia_bug (int enable)
3203    
3204 root 1.319 const char *
3205 root 1.97 gl_vendor ()
3206     CODE:
3207 root 1.319 RETVAL = (const char *)glGetString (GL_VENDOR);
3208 root 1.97 OUTPUT:
3209     RETVAL
3210    
3211 root 1.319 const char *
3212 root 1.97 gl_version ()
3213     CODE:
3214 root 1.319 RETVAL = (const char *)glGetString (GL_VERSION);
3215 root 1.97 OUTPUT:
3216     RETVAL
3217    
3218 root 1.319 const char *
3219 root 1.97 gl_extensions ()
3220     CODE:
3221 root 1.319 RETVAL = (const char *)glGetString (GL_EXTENSIONS);
3222 root 1.97 OUTPUT:
3223     RETVAL
3224    
3225 root 1.201 const char *glGetString (GLenum pname)
3226 root 1.319 CODE:
3227     RETVAL = (const char *)glGetString (pname);
3228     OUTPUT:
3229     RETVAL
3230 root 1.199
3231     GLint glGetInteger (GLenum pname)
3232     CODE:
3233     glGetIntegerv (pname, &RETVAL);
3234     OUTPUT:
3235     RETVAL
3236    
3237     GLdouble glGetDouble (GLenum pname)
3238     CODE:
3239     glGetDoublev (pname, &RETVAL);
3240     OUTPUT:
3241     RETVAL
3242    
3243 root 1.54 int glGetError ()
3244    
3245 root 1.114 void glFinish ()
3246    
3247 root 1.304 void glFlush ()
3248    
3249 root 1.54 void glClear (int mask)
3250    
3251     void glClearColor (float r, float g, float b, float a = 1.0)
3252     PROTOTYPE: @
3253    
3254     void glEnable (int cap)
3255    
3256     void glDisable (int cap)
3257    
3258     void glShadeModel (int mode)
3259    
3260     void glHint (int target, int mode)
3261    
3262     void glBlendFunc (int sfactor, int dfactor)
3263    
3264 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
3265     CODE:
3266     gl_BlendFuncSeparate (sa, da, saa, daa);
3267    
3268 root 1.292 # void glBlendEquation (int se)
3269 root 1.291
3270 root 1.89 void glDepthMask (int flag)
3271    
3272 root 1.54 void glLogicOp (int opcode)
3273    
3274 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
3275    
3276 root 1.54 void glMatrixMode (int mode)
3277    
3278     void glPushMatrix ()
3279    
3280     void glPopMatrix ()
3281    
3282     void glLoadIdentity ()
3283    
3284 root 1.119 void glDrawBuffer (int buffer)
3285    
3286     void glReadBuffer (int buffer)
3287    
3288 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
3289     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
3290    
3291     # near_ and far_ are due to microsofts buggy "c" compiler
3292 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
3293 root 1.54
3294 root 1.208 PROTOTYPES: DISABLE
3295    
3296 root 1.54 void glViewport (int x, int y, int width, int height)
3297    
3298 root 1.69 void glScissor (int x, int y, int width, int height)
3299    
3300 root 1.54 void glTranslate (float x, float y, float z = 0.)
3301     CODE:
3302     glTranslatef (x, y, z);
3303    
3304 root 1.62 void glScale (float x, float y, float z = 1.)
3305 root 1.54 CODE:
3306     glScalef (x, y, z);
3307    
3308     void glRotate (float angle, float x, float y, float z)
3309     CODE:
3310     glRotatef (angle, x, y, z);
3311    
3312     void glColor (float r, float g, float b, float a = 1.0)
3313 root 1.278 PROTOTYPE: @
3314 root 1.103 ALIAS:
3315     glColor_premultiply = 1
3316 root 1.54 CODE:
3317 root 1.103 if (ix)
3318     {
3319     r *= a;
3320     g *= a;
3321     b *= a;
3322     }
3323 root 1.90 // microsoft visual "c" rounds instead of truncating...
3324 root 1.130 glColor4f (r, g, b, a);
3325 root 1.54
3326 root 1.91 void glRasterPos (float x, float y, float z = 0.)
3327     CODE:
3328     glRasterPos3f (0, 0, z);
3329     glBitmap (0, 0, 0, 0, x, y, 0);
3330    
3331 root 1.54 void glVertex (float x, float y, float z = 0.)
3332     CODE:
3333     glVertex3f (x, y, z);
3334    
3335     void glTexCoord (float s, float t)
3336     CODE:
3337     glTexCoord2f (s, t);
3338    
3339 root 1.210 void glRect (float x1, float y1, float x2, float y2)
3340     CODE:
3341     glRectf (x1, y1, x2, y2);
3342    
3343 root 1.233 void glRect_lineloop (float x1, float y1, float x2, float y2)
3344     CODE:
3345     glBegin (GL_LINE_LOOP);
3346     glVertex2f (x1, y1);
3347     glVertex2f (x2, y1);
3348     glVertex2f (x2, y2);
3349     glVertex2f (x1, y2);
3350     glEnd ();
3351    
3352 root 1.208 PROTOTYPES: ENABLE
3353    
3354     void glBegin (int mode)
3355    
3356     void glEnd ()
3357    
3358     void glPointSize (GLfloat size)
3359    
3360     void glLineWidth (GLfloat width)
3361    
3362     void glInterleavedArrays (int format, int stride, char *data)
3363    
3364     void glDrawElements (int mode, int count, int type, char *indices)
3365    
3366     # 1.2 void glDrawRangeElements (int mode, int start, int end
3367    
3368 root 1.54 void glTexEnv (int target, int pname, float param)
3369     CODE:
3370     glTexEnvf (target, pname, param);
3371    
3372     void glTexParameter (int target, int pname, float param)
3373     CODE:
3374     glTexParameterf (target, pname, param);
3375    
3376     void glBindTexture (int target, int name)
3377    
3378     void glConvolutionParameter (int target, int pname, float params)
3379     CODE:
3380 root 1.103 if (gl.ConvolutionParameterf)
3381     gl.ConvolutionParameterf (target, pname, params);
3382 root 1.54
3383     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
3384 root 1.64 CODE:
3385 root 1.103 if (gl.ConvolutionFilter2D)
3386     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
3387 root 1.54
3388 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
3389     CODE:
3390 root 1.103 if (gl.SeparableFilter2D)
3391     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
3392 root 1.69
3393 root 1.244 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data = 0)
3394 root 1.54
3395     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
3396    
3397 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
3398 root 1.68
3399 root 1.199 void glPixelZoom (float x, float y)
3400    
3401 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
3402    
3403 root 1.54 int glGenTexture ()
3404     CODE:
3405 root 1.192 RETVAL = gen_texture ();
3406 root 1.54 OUTPUT:
3407     RETVAL
3408    
3409     void glDeleteTexture (int name)
3410     CODE:
3411 root 1.192 del_texture (name);
3412    
3413 root 1.54 int glGenList ()
3414     CODE:
3415     RETVAL = glGenLists (1);
3416     OUTPUT:
3417     RETVAL
3418    
3419     void glDeleteList (int list)
3420     CODE:
3421     glDeleteLists (list, 1);
3422    
3423     void glNewList (int list, int mode = GL_COMPILE)
3424    
3425     void glEndList ()
3426    
3427     void glCallList (int list)
3428    
3429 root 1.296 void c_init ()
3430     CODE:
3431     glPixelStorei (GL_PACK_ALIGNMENT , 1);
3432     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
3433    
3434 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::UI::Base
3435 root 1.207
3436     PROTOTYPES: DISABLE
3437    
3438     void
3439 root 1.209 find_widget (SV *self, NV x, NV y)
3440 root 1.207 PPCODE:
3441     {
3442 root 1.321 if (within_widget (self, x, y))
3443 root 1.209 XPUSHs (self);
3444     }
3445    
3446     BOOT:
3447     {
3448 root 1.242 hover_gv = gv_fetchpv ("DC::UI::HOVER", 1, SVt_NV);
3449 root 1.209
3450 root 1.242 draw_x_gv = gv_fetchpv ("DC::UI::Base::draw_x", 1, SVt_NV);
3451     draw_y_gv = gv_fetchpv ("DC::UI::Base::draw_y", 1, SVt_NV);
3452     draw_w_gv = gv_fetchpv ("DC::UI::Base::draw_w", 1, SVt_NV);
3453     draw_h_gv = gv_fetchpv ("DC::UI::Base::draw_h", 1, SVt_NV);
3454 root 1.209 }
3455    
3456     void
3457     draw (SV *self)
3458     CODE:
3459     {
3460 root 1.321 HV *hv;
3461     SV **svp;
3462 root 1.209 NV x, y, w, h;
3463     SV *draw_x_sv = GvSV (draw_x_gv);
3464     SV *draw_y_sv = GvSV (draw_y_gv);
3465     SV *draw_w_sv = GvSV (draw_w_gv);
3466     SV *draw_h_sv = GvSV (draw_h_gv);
3467 root 1.228 double draw_x, draw_y;
3468 root 1.209
3469     if (!SvROK (self))
3470 root 1.242 croak ("DC::Base::draw: %s not a reference", SvPV_nolen (self));
3471 root 1.209
3472     hv = (HV *)SvRV (self);
3473    
3474     if (SvTYPE (hv) != SVt_PVHV)
3475 root 1.242 croak ("DC::Base::draw: %s not a hashref", SvPV_nolen (self));
3476 root 1.209
3477     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
3478     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
3479    
3480     if (!h || !w)
3481     XSRETURN_EMPTY;
3482    
3483     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
3484     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
3485    
3486     draw_x = SvNV (draw_x_sv) + x;
3487     draw_y = SvNV (draw_y_sv) + y;
3488    
3489     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
3490     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
3491     XSRETURN_EMPTY;
3492    
3493     sv_setnv (draw_x_sv, draw_x);
3494     sv_setnv (draw_y_sv, draw_y);
3495    
3496     glPushMatrix ();
3497     glTranslated (x, y, 0);
3498    
3499     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
3500     {
3501     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
3502    
3503     if (svp && SvTRUE (*svp))
3504     {
3505 root 1.228 glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f);
3506 root 1.209 glEnable (GL_BLEND);
3507     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3508     glBegin (GL_QUADS);
3509     glVertex2f (0, 0);
3510     glVertex2f (w, 0);
3511     glVertex2f (w, h);
3512     glVertex2f (0, h);
3513     glEnd ();
3514     glDisable (GL_BLEND);
3515     }
3516     }
3517     #if 0
3518 root 1.234 // draw borders, for debugging
3519     glPushMatrix ();
3520     glColor4f (1., 1., 0., 1.);
3521     glTranslatef (.5, .5, 0.);
3522     glBegin (GL_LINE_LOOP);
3523     glVertex2f (0 , 0);
3524     glVertex2f (w - 1, 0);
3525     glVertex2f (w - 1, h - 1);
3526     glVertex2f (0 , h - 1);
3527     glEnd ();
3528     glPopMatrix ();
3529 root 1.209 #endif
3530     PUSHMARK (SP);
3531     XPUSHs (self);
3532     PUTBACK;
3533     call_method ("_draw", G_VOID | G_DISCARD);
3534     SPAGAIN;
3535    
3536     glPopMatrix ();
3537    
3538     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
3539     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
3540 root 1.207 }
3541