ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.330
Committed: Sun Nov 18 15:24:24 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.329: +1 -2 lines
Log Message:
*** empty log message ***

File Contents

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