ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.331
Committed: Mon Nov 19 00:10:34 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.330: +13 -24 lines
Log Message:
*** empty log message ***

File Contents

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