ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.332
Committed: Mon Nov 19 00:56:08 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.331: +6 -0 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 root 1.332 UV ld32 (UV n)
872     CODE:
873     RETVAL = ecb_ld32 (n);
874     OUTPUT:
875     RETVAL
876    
877 root 1.235 IV popcount (UV n)
878 root 1.331 CODE:
879     RETVAL = ecb_popcount32 (n);
880     OUTPUT:
881     RETVAL
882 root 1.235
883 root 1.295 NV distance (NV dx, NV dy)
884     CODE:
885     RETVAL = pow (dx * dx + dy * dy, 0.5);
886     OUTPUT:
887     RETVAL
888    
889 root 1.79 void
890     pango_init ()
891     CODE:
892     {
893 root 1.124 opengl_fontmap = pango_opengl_font_map_new ();
894     pango_opengl_font_map_set_default_substitute ((PangoOpenGLFontMap *)opengl_fontmap, substitute_func, 0, 0);
895     opengl_context = pango_opengl_font_map_create_context ((PangoOpenGLFontMap *)opengl_fontmap);
896 root 1.257 /*pango_context_set_font_description (opengl_context, default_font);*/
897 root 1.254 #if PANGO_VERSION_CHECK (1, 15, 2)
898 root 1.249 pango_context_set_language (opengl_context, pango_language_from_string ("en"));
899 root 1.250 /*pango_context_set_base_dir (opengl_context, PANGO_DIRECTION_WEAK_LTR);*/
900 root 1.249 #endif
901 root 1.5 }
902    
903 root 1.263 char *SDL_GetError ()
904    
905 root 1.314 void SDL_main_hack (SV *real_main)
906     PROTOTYPE: &
907 root 1.272
908 root 1.263 int SDL_Init (U32 flags)
909    
910     int SDL_InitSubSystem (U32 flags)
911 root 1.200
912 root 1.263 void SDL_QuitSubSystem (U32 flags)
913 root 1.51
914 root 1.263 void SDL_Quit ()
915 root 1.51
916 root 1.264 int SDL_GL_SetAttribute (int attr, int value)
917 root 1.319 C_ARGS: (SDL_GLattr)attr, value
918 root 1.264
919     int SDL_GL_GetAttribute (int attr)
920     CODE:
921 root 1.319 if (SDL_GL_GetAttribute ((SDL_GLattr)attr, &RETVAL))
922 root 1.264 XSRETURN_UNDEF;
923     OUTPUT:
924     RETVAL
925    
926 root 1.51 void
927 root 1.200 SDL_ListModes (int rgb, int alpha)
928 root 1.51 PPCODE:
929     {
930     SDL_Rect **m;
931    
932 root 1.200 SDL_GL_SetAttribute (SDL_GL_RED_SIZE , rgb);
933     SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgb);
934     SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE , rgb);
935     SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, alpha);
936 root 1.51
937 root 1.88 SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 15);
938 root 1.200 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE , 0);
939 root 1.85
940 root 1.200 SDL_GL_SetAttribute (SDL_GL_ACCUM_RED_SIZE , 0);
941 root 1.51 SDL_GL_SetAttribute (SDL_GL_ACCUM_GREEN_SIZE, 0);
942 root 1.200 SDL_GL_SetAttribute (SDL_GL_ACCUM_BLUE_SIZE , 0);
943 root 1.51 SDL_GL_SetAttribute (SDL_GL_ACCUM_ALPHA_SIZE, 0);
944    
945     SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
946 root 1.131 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
947 root 1.51
948     m = SDL_ListModes (0, SDL_FULLSCREEN | SDL_OPENGL);
949    
950     if (m && m != (SDL_Rect **)-1)
951     while (*m)
952     {
953 root 1.265 if ((*m)->w >= 400 && (*m)->h >= 300)
954     {
955     AV *av = newAV ();
956     av_push (av, newSViv ((*m)->w));
957     av_push (av, newSViv ((*m)->h));
958     av_push (av, newSViv (rgb));
959     av_push (av, newSViv (alpha));
960     XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
961     }
962 root 1.51
963     ++m;
964     }
965     }
966    
967     int
968 root 1.200 SDL_SetVideoMode (int w, int h, int rgb, int alpha, int fullscreen)
969 root 1.51 CODE:
970 root 1.200 {
971     SDL_EnableUNICODE (1);
972     SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
973    
974     SDL_GL_SetAttribute (SDL_GL_RED_SIZE , rgb);
975     SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgb);
976     SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE , rgb);
977     SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, alpha);
978    
979 root 1.51 RETVAL = !!SDL_SetVideoMode (
980     w, h, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)
981     );
982 root 1.200
983 root 1.103 if (RETVAL)
984     {
985 root 1.188 av_clear (texture_av);
986 root 1.200 #define GL_FUNC(ptr,name) gl.name = (ptr)SDL_GL_GetProcAddress ("gl" # name);
987     #include "glfunc.h"
988     #undef GL_FUNC
989 root 1.299 if (!gl.ActiveTexture ) gl.ActiveTexture = gl.ActiveTextureARB;
990     if (!gl.MultiTexCoord2f) gl.MultiTexCoord2f = gl.MultiTexCoord2fARB;
991 root 1.103 }
992 root 1.200 }
993 root 1.51 OUTPUT:
994     RETVAL
995    
996 root 1.53 void
997 root 1.313 SDL_WM_SetCaption (const char *title, const char *icon)
998    
999     void
1000 root 1.54 SDL_GL_SwapBuffers ()
1001    
1002 root 1.94 char *
1003     SDL_GetKeyName (int sym)
1004 root 1.319 C_ARGS: (SDLKey)sym
1005 root 1.94
1006 root 1.198 int
1007     SDL_GetAppState ()
1008    
1009 root 1.256 int
1010     SDL_GetModState ()
1011    
1012 root 1.311 int
1013     SDL_WaitEvent ()
1014     C_ARGS: 0
1015    
1016     void
1017     SDL_PumpEvents ()
1018    
1019 root 1.54 void
1020 root 1.311 peep_events ()
1021 root 1.53 PPCODE:
1022     {
1023     SDL_Event ev;
1024    
1025 root 1.197 SDL_PumpEvents ();
1026     while (SDL_PeepEvents (&ev, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0)
1027 root 1.53 {
1028     HV *hv = newHV ();
1029     hv_store (hv, "type", 4, newSViv (ev.type), 0);
1030 root 1.70
1031 root 1.53 switch (ev.type)
1032     {
1033     case SDL_KEYDOWN:
1034     case SDL_KEYUP:
1035     hv_store (hv, "state", 5, newSViv (ev.key.state), 0);
1036     hv_store (hv, "sym", 3, newSViv (ev.key.keysym.sym), 0);
1037 root 1.276 hv_store (hv, "mod", 3, newSViv (mod_munge (ev.key.keysym.mod)), 0);
1038     hv_store (hv, "cmod", 4, newSViv (mod_munge (SDL_GetModState ())), 0); /* current mode */
1039 root 1.53 hv_store (hv, "unicode", 7, newSViv (ev.key.keysym.unicode), 0);
1040     break;
1041    
1042     case SDL_ACTIVEEVENT:
1043     hv_store (hv, "gain", 4, newSViv (ev.active.gain), 0);
1044     hv_store (hv, "state", 5, newSViv (ev.active.state), 0);
1045     break;
1046    
1047     case SDL_MOUSEMOTION:
1048 root 1.196 {
1049     int state = ev.motion.state;
1050     int x = ev.motion.x;
1051     int y = ev.motion.y;
1052     int xrel = ev.motion.xrel;
1053     int yrel = ev.motion.yrel;
1054    
1055     /* do simplistic event compression */
1056     while (SDL_PeepEvents (&ev, 1, SDL_PEEKEVENT, SDL_EVENTMASK (SDL_MOUSEMOTION)) > 0
1057     && state == ev.motion.state)
1058     {
1059     xrel += ev.motion.xrel;
1060     yrel += ev.motion.yrel;
1061     x = ev.motion.x;
1062     y = ev.motion.y;
1063     SDL_PeepEvents (&ev, 1, SDL_GETEVENT, SDL_EVENTMASK (SDL_MOUSEMOTION));
1064     }
1065 root 1.93
1066 root 1.276 hv_store (hv, "mod", 3, newSViv (mod_munge (SDL_GetModState ())), 0);
1067 root 1.196 hv_store (hv, "state", 5, newSViv (state), 0);
1068     hv_store (hv, "x", 1, newSViv (x), 0);
1069     hv_store (hv, "y", 1, newSViv (y), 0);
1070     hv_store (hv, "xrel", 4, newSViv (xrel), 0);
1071     hv_store (hv, "yrel", 4, newSViv (yrel), 0);
1072     }
1073 root 1.53 break;
1074    
1075     case SDL_MOUSEBUTTONDOWN:
1076     case SDL_MOUSEBUTTONUP:
1077 root 1.253 hv_store (hv, "mod", 3, newSViv (SDL_GetModState () & MOD_MASK), 0);
1078 root 1.93
1079 root 1.53 hv_store (hv, "button", 6, newSViv (ev.button.button), 0);
1080     hv_store (hv, "state", 5, newSViv (ev.button.state), 0);
1081     hv_store (hv, "x", 1, newSViv (ev.button.x), 0);
1082     hv_store (hv, "y", 1, newSViv (ev.button.y), 0);
1083 root 1.70 break;
1084 root 1.72
1085     case SDL_USEREVENT:
1086     hv_store (hv, "code", 4, newSViv (ev.user.code), 0);
1087     hv_store (hv, "data1", 5, newSViv ((IV)ev.user.data1), 0);
1088     hv_store (hv, "data2", 5, newSViv ((IV)ev.user.data2), 0);
1089     break;
1090 root 1.53 }
1091    
1092 root 1.242 XPUSHs (sv_2mortal (sv_bless (newRV_noinc ((SV *)hv), gv_stashpv ("DC::UI::Event", 1))));
1093 root 1.53 }
1094     }
1095 root 1.52
1096 root 1.303 char *
1097     SDL_AudioDriverName ()
1098     CODE:
1099     {
1100     char buf [256];
1101     if (!SDL_AudioDriverName (buf, sizeof (buf)))
1102     XSRETURN_UNDEF;
1103    
1104     RETVAL = buf;
1105     }
1106     OUTPUT:
1107     RETVAL
1108    
1109 root 1.52 int
1110 root 1.236 Mix_OpenAudio (int frequency = 44100, int format = MIX_DEFAULT_FORMAT, int channels = 2, int chunksize = 4096)
1111 root 1.321 POSTCALL:
1112 root 1.56 Mix_HookMusicFinished (music_finished);
1113 root 1.71 Mix_ChannelFinished (channel_finished);
1114 root 1.52
1115     void
1116 root 1.236 Mix_QuerySpec ()
1117     PPCODE:
1118     {
1119     int freq, channels;
1120     Uint16 format;
1121    
1122     if (Mix_QuerySpec (&freq, &format, &channels))
1123     {
1124     EXTEND (SP, 3);
1125     PUSHs (sv_2mortal (newSViv (freq)));
1126     PUSHs (sv_2mortal (newSViv (format)));
1127     PUSHs (sv_2mortal (newSViv (channels)));
1128     }
1129     }
1130    
1131     void
1132 root 1.52 Mix_CloseAudio ()
1133    
1134     int
1135     Mix_AllocateChannels (int numchans = -1)
1136    
1137 root 1.214 const char *
1138     Mix_GetError ()
1139    
1140 root 1.10 void
1141     lowdelay (int fd, int val = 1)
1142     CODE:
1143 root 1.179 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&val, sizeof (val));
1144 root 1.10
1145 root 1.5 void
1146 root 1.157 win32_proxy_info ()
1147     PPCODE:
1148     {
1149     #ifdef _WIN32
1150     char buffer[2048];
1151     DWORD buflen;
1152    
1153     EXTEND (SP, 3);
1154    
1155     buflen = sizeof (buffer);
1156     if (InternetQueryOption (0, INTERNET_OPTION_PROXY, (void *)buffer, &buflen))
1157     if (((INTERNET_PROXY_INFO *)buffer)->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
1158     {
1159     PUSHs (newSVpv (((INTERNET_PROXY_INFO *)buffer)->lpszProxy, 0));
1160    
1161     buflen = sizeof (buffer);
1162     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_USERNAME, (void *)buffer, &buflen))
1163     {
1164     PUSHs (newSVpv (buffer, 0));
1165    
1166     buflen = sizeof (buffer);
1167     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_PASSWORD, (void *)buffer, &buflen))
1168     PUSHs (newSVpv (buffer, 0));
1169     }
1170     }
1171     #endif
1172     }
1173    
1174 root 1.257 int
1175 root 1.13 add_font (char *file)
1176     CODE:
1177 root 1.257 RETVAL = FcConfigAppFontAddFile (0, (const FcChar8 *)file);
1178     OUTPUT:
1179     RETVAL
1180 root 1.13
1181     void
1182 root 1.305 IMG_Init (int flags = IMG_INIT_JPG | IMG_INIT_PNG)
1183    
1184 root 1.312 # MIX_INIT_MP3 gives smpeg + libstdc++ + libgcc_s
1185 root 1.305 void
1186 root 1.312 Mix_Init (int flags = MIX_INIT_MOD | MIX_INIT_OGG)
1187 root 1.309
1188     void
1189 root 1.23 load_image_inline (SV *image_)
1190     ALIAS:
1191     load_image_file = 1
1192     PPCODE:
1193     {
1194     STRLEN image_len;
1195     char *image = (char *)SvPVbyte (image_, image_len);
1196     SDL_Surface *surface, *surface2;
1197     SDL_PixelFormat fmt;
1198     SDL_RWops *rw = ix
1199 root 1.212 ? SDL_RWFromFile (image, "rb")
1200 root 1.23 : SDL_RWFromConstMem (image, image_len);
1201    
1202     if (!rw)
1203 root 1.41 croak ("load_image: %s", SDL_GetError ());
1204 root 1.23
1205     surface = IMG_Load_RW (rw, 1);
1206     if (!surface)
1207 root 1.41 croak ("load_image: %s", SDL_GetError ());
1208 root 1.23
1209     fmt.palette = NULL;
1210     fmt.BitsPerPixel = 32;
1211     fmt.BytesPerPixel = 4;
1212 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1213 root 1.23 fmt.Rmask = 0x000000ff;
1214     fmt.Gmask = 0x0000ff00;
1215     fmt.Bmask = 0x00ff0000;
1216     fmt.Amask = 0xff000000;
1217 root 1.49 #else
1218     fmt.Rmask = 0xff000000;
1219     fmt.Gmask = 0x00ff0000;
1220     fmt.Bmask = 0x0000ff00;
1221     fmt.Amask = 0x000000ff;
1222     #endif
1223 root 1.23 fmt.Rloss = 0;
1224     fmt.Gloss = 0;
1225     fmt.Bloss = 0;
1226     fmt.Aloss = 0;
1227     fmt.Rshift = 0;
1228     fmt.Gshift = 8;
1229     fmt.Bshift = 16;
1230     fmt.Ashift = 24;
1231     fmt.colorkey = 0;
1232     fmt.alpha = 0;
1233    
1234     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
1235    
1236 root 1.39 assert (surface2->pitch == surface2->w * 4);
1237    
1238 root 1.129 SDL_LockSurface (surface2);
1239     EXTEND (SP, 6);
1240 root 1.23 PUSHs (sv_2mortal (newSViv (surface2->w)));
1241     PUSHs (sv_2mortal (newSViv (surface2->h)));
1242 root 1.319 PUSHs (sv_2mortal (newSVpvn ((const char *)surface2->pixels, surface2->h * surface2->pitch)));
1243 root 1.116 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
1244 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
1245 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
1246 root 1.129 SDL_UnlockSurface (surface2);
1247 root 1.23
1248     SDL_FreeSurface (surface);
1249     SDL_FreeSurface (surface2);
1250     }
1251    
1252 root 1.25 void
1253 root 1.39 average (int x, int y, uint32_t *data)
1254     PPCODE:
1255     {
1256     uint32_t r = 0, g = 0, b = 0, a = 0;
1257    
1258     x = y = x * y;
1259    
1260     while (x--)
1261     {
1262     uint32_t p = *data++;
1263    
1264     r += (p ) & 255;
1265     g += (p >> 8) & 255;
1266     b += (p >> 16) & 255;
1267     a += (p >> 24) & 255;
1268     }
1269    
1270     EXTEND (SP, 4);
1271 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
1272     PUSHs (sv_2mortal (newSViv (g / y)));
1273     PUSHs (sv_2mortal (newSViv (b / y)));
1274     PUSHs (sv_2mortal (newSViv (a / y)));
1275 root 1.39 }
1276    
1277     void
1278 root 1.66 error (char *message)
1279     CODE:
1280 root 1.86 fprintf (stderr, "ERROR: %s\n", message);
1281 root 1.66 #ifdef _WIN32
1282 root 1.240 MessageBox (0, message, "Deliantra Client Error", MB_OK | MB_ICONERROR);
1283 root 1.66 #endif
1284    
1285     void
1286 root 1.25 fatal (char *message)
1287     CODE:
1288 root 1.86 fprintf (stderr, "FATAL: %s\n", message);
1289 root 1.50 #ifdef _WIN32
1290 root 1.240 MessageBox (0, message, "Deliantra Client Fatal Error", MB_OK | MB_ICONERROR);
1291 root 1.25 #endif
1292 root 1.112 _exit (1);
1293 root 1.111
1294     void
1295 root 1.158 _exit (int retval = 0)
1296 root 1.111 CODE:
1297 root 1.161 #ifdef WIN32
1298     ExitThread (retval); // unclean, please beam me up
1299     #else
1300 root 1.112 _exit (retval);
1301 root 1.161 #endif
1302 root 1.25
1303 root 1.193 void
1304     debug ()
1305     CODE:
1306     {
1307     #if DEBUG
1308     VALGRIND_DO_LEAK_CHECK;
1309     #endif
1310     }
1311    
1312 root 1.280 int
1313     SvREFCNT (SV *sv)
1314     CODE:
1315     RETVAL = SvREFCNT (sv);
1316     OUTPUT:
1317     RETVAL
1318    
1319 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Font
1320 root 1.61
1321 root 1.205 PROTOTYPES: DISABLE
1322    
1323 root 1.242 DC::Font
1324 root 1.319 new_from_file (SV *klass, char *path, int id = 0)
1325 root 1.61 CODE:
1326     {
1327     int count;
1328 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
1329 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
1330     FcPatternDestroy (pattern);
1331     }
1332     OUTPUT:
1333     RETVAL
1334    
1335     void
1336 root 1.242 DESTROY (DC::Font self)
1337 root 1.61 CODE:
1338     pango_font_description_free (self);
1339    
1340     void
1341 root 1.242 make_default (DC::Font self)
1342 root 1.205 PROTOTYPE: $
1343 root 1.61 CODE:
1344     default_font = self;
1345    
1346 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Layout
1347 root 1.14
1348 root 1.205 PROTOTYPES: DISABLE
1349    
1350 root 1.124 void
1351 root 1.239 glyph_cache_backup ()
1352 root 1.205 PROTOTYPE:
1353 root 1.124 CODE:
1354 root 1.239 tc_backup ();
1355    
1356     void
1357     glyph_cache_restore ()
1358     PROTOTYPE:
1359     CODE:
1360     tc_restore ();
1361 root 1.124
1362 root 1.242 DC::Layout
1363 root 1.319 new (SV *klass)
1364 root 1.14 CODE:
1365 root 1.326 RETVAL = new cf_layout;
1366 root 1.76
1367 root 1.124 RETVAL->pl = pango_layout_new (opengl_context);
1368 root 1.76 RETVAL->r = 1.;
1369     RETVAL->g = 1.;
1370     RETVAL->b = 1.;
1371     RETVAL->a = 1.;
1372     RETVAL->base_height = MIN_FONT_HEIGHT;
1373     RETVAL->font = 0;
1374    
1375 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
1376 root 1.76 layout_update_font (RETVAL);
1377 root 1.14 OUTPUT:
1378     RETVAL
1379    
1380     void
1381 root 1.242 DESTROY (DC::Layout self)
1382 root 1.14 CODE:
1383     g_object_unref (self->pl);
1384 root 1.326 delete self;
1385 root 1.13
1386 root 1.8 void
1387 root 1.242 set_text (DC::Layout self, SV *text_)
1388 root 1.35 CODE:
1389     {
1390     STRLEN textlen;
1391     char *text = SvPVutf8 (text_, textlen);
1392    
1393     pango_layout_set_text (self->pl, text, textlen);
1394     }
1395    
1396     void
1397 root 1.242 set_markup (DC::Layout self, SV *text_)
1398 root 1.14 CODE:
1399 root 1.5 {
1400     STRLEN textlen;
1401     char *text = SvPVutf8 (text_, textlen);
1402 root 1.14
1403     pango_layout_set_markup (self->pl, text, textlen);
1404     }
1405    
1406 root 1.121 void
1407 root 1.242 set_shapes (DC::Layout self, ...)
1408 root 1.121 CODE:
1409     {
1410     PangoAttrList *attrs = 0;
1411     const char *text = pango_layout_get_text (self->pl);
1412     const char *pos = text;
1413 root 1.122 int arg = 4;
1414 root 1.121
1415     while (arg < items && (pos = strstr (pos, OBJ_STR)))
1416     {
1417 root 1.122 PangoRectangle inkrect, rect;
1418 root 1.121 PangoAttribute *attr;
1419    
1420 root 1.122 int x = SvIV (ST (arg - 3));
1421     int y = SvIV (ST (arg - 2));
1422 root 1.121 int w = SvIV (ST (arg - 1));
1423 root 1.122 int h = SvIV (ST (arg ));
1424 root 1.121
1425 root 1.122 inkrect.x = 0;
1426     inkrect.y = 0;
1427     inkrect.width = 0;
1428     inkrect.height = 0;
1429    
1430     rect.x = x * PANGO_SCALE;
1431     rect.y = y * PANGO_SCALE;
1432     rect.width = w * PANGO_SCALE;
1433 root 1.121 rect.height = h * PANGO_SCALE;
1434    
1435     if (!attrs)
1436     attrs = pango_layout_get_attributes (self->pl);
1437    
1438 root 1.122 attr = pango_attr_shape_new (&inkrect, &rect);
1439 root 1.121 attr->start_index = pos - text;
1440     attr->end_index = attr->start_index + sizeof (OBJ_STR) - 1;
1441     pango_attr_list_insert (attrs, attr);
1442    
1443 root 1.122 arg += 4;
1444 root 1.121 pos += sizeof (OBJ_STR) - 1;
1445     }
1446    
1447     if (attrs)
1448     pango_layout_set_attributes (self->pl, attrs);
1449     }
1450    
1451     void
1452 root 1.242 get_shapes (DC::Layout self)
1453 root 1.121 PPCODE:
1454     {
1455     PangoLayoutIter *iter = pango_layout_get_iter (self->pl);
1456    
1457     do
1458     {
1459 root 1.249 PangoLayoutRun *run = pango_layout_iter_get_run_readonly (iter);
1460 root 1.121
1461     if (run && shape_attr_p (run))
1462     {
1463     PangoRectangle extents;
1464     pango_layout_iter_get_run_extents (iter, 0, &extents);
1465    
1466 root 1.129 EXTEND (SP, 2);
1467 root 1.121 PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.x))));
1468     PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.y))));
1469     }
1470     }
1471     while (pango_layout_iter_next_run (iter));
1472    
1473     pango_layout_iter_free (iter);
1474     }
1475    
1476     int
1477 root 1.242 has_wrapped (DC::Layout self)
1478 root 1.121 CODE:
1479     {
1480     int lines = 1;
1481     const char *text = pango_layout_get_text (self->pl);
1482    
1483     while (*text)
1484     lines += *text++ == '\n';
1485    
1486     RETVAL = lines < pango_layout_get_line_count (self->pl);
1487     }
1488     OUTPUT:
1489     RETVAL
1490    
1491 root 1.46 SV *
1492 root 1.242 get_text (DC::Layout self)
1493 root 1.46 CODE:
1494 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
1495 root 1.107 sv_utf8_decode (RETVAL);
1496 root 1.46 OUTPUT:
1497     RETVAL
1498    
1499 root 1.14 void
1500 root 1.242 set_foreground (DC::Layout self, float r, float g, float b, float a = 1.)
1501 root 1.76 CODE:
1502     self->r = r;
1503     self->g = g;
1504     self->b = b;
1505     self->a = a;
1506    
1507     void
1508 root 1.242 set_font (DC::Layout self, DC::Font font = 0)
1509 root 1.61 CODE:
1510     if (self->font != font)
1511     {
1512     self->font = font;
1513     layout_update_font (self);
1514     }
1515    
1516     void
1517 root 1.242 set_height (DC::Layout self, int base_height)
1518 root 1.16 CODE:
1519 root 1.61 if (self->base_height != base_height)
1520 root 1.317 {
1521 root 1.61 self->base_height = base_height;
1522     layout_update_font (self);
1523     }
1524 root 1.16
1525     void
1526 root 1.242 set_width (DC::Layout self, int max_width = -1)
1527 root 1.14 CODE:
1528     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
1529    
1530     void
1531 root 1.242 set_indent (DC::Layout self, int indent)
1532 root 1.84 CODE:
1533     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
1534    
1535     void
1536 root 1.242 set_spacing (DC::Layout self, int spacing)
1537 root 1.84 CODE:
1538     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
1539    
1540     void
1541 root 1.242 set_ellipsise (DC::Layout self, int ellipsise)
1542 root 1.84 CODE:
1543     pango_layout_set_ellipsize (self->pl,
1544     ellipsise == 1 ? PANGO_ELLIPSIZE_START
1545     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
1546     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
1547     : PANGO_ELLIPSIZE_NONE
1548     );
1549    
1550     void
1551 root 1.242 set_single_paragraph_mode (DC::Layout self, int spm)
1552 root 1.84 CODE:
1553     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
1554    
1555     void
1556 root 1.242 size (DC::Layout self)
1557 root 1.14 PPCODE:
1558     {
1559     int w, h;
1560    
1561     layout_get_pixel_size (self, &w, &h);
1562    
1563     EXTEND (SP, 2);
1564     PUSHs (sv_2mortal (newSViv (w)));
1565     PUSHs (sv_2mortal (newSViv (h)));
1566     }
1567    
1568 root 1.17 int
1569 root 1.242 descent (DC::Layout self)
1570 root 1.122 CODE:
1571     {
1572     PangoRectangle rect;
1573 root 1.249 PangoLayoutLine *line = pango_layout_get_line_readonly (self->pl, 0);
1574 root 1.122 pango_layout_line_get_pixel_extents (line, 0, &rect);
1575     RETVAL = PANGO_DESCENT (rect);
1576     }
1577     OUTPUT:
1578     RETVAL
1579    
1580     int
1581 root 1.242 xy_to_index (DC::Layout self, int x, int y)
1582 root 1.17 CODE:
1583     {
1584     int index, trailing;
1585     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
1586 root 1.165 RETVAL = index + trailing;
1587 root 1.17 }
1588     OUTPUT:
1589     RETVAL
1590    
1591     void
1592 root 1.242 cursor_pos (DC::Layout self, int index)
1593 root 1.17 PPCODE:
1594     {
1595 root 1.251 PangoRectangle pos;
1596 root 1.252 pango_layout_get_cursor_pos (self->pl, index, &pos, 0);
1597 root 1.30
1598 root 1.17 EXTEND (SP, 3);
1599 root 1.251 PUSHs (sv_2mortal (newSViv (pos.x / PANGO_SCALE)));
1600     PUSHs (sv_2mortal (newSViv (pos.y / PANGO_SCALE)));
1601     PUSHs (sv_2mortal (newSViv (pos.height / PANGO_SCALE)));
1602 root 1.17 }
1603    
1604 root 1.14 void
1605 root 1.242 index_to_line_x (DC::Layout self, int index, int trailing = 0)
1606 root 1.165 PPCODE:
1607     {
1608     int line, x;
1609    
1610     pango_layout_index_to_line_x (self->pl, index, trailing, &line, &x);
1611 root 1.254 #if !PANGO_VERSION_CHECK (1, 17, 3)
1612 root 1.165 /* pango bug: line is between 1..numlines, not 0..numlines-1 */
1613 root 1.245 --line;
1614     #endif
1615 root 1.165 EXTEND (SP, 2);
1616 root 1.245 PUSHs (sv_2mortal (newSViv (line)));
1617 root 1.165 PUSHs (sv_2mortal (newSViv (x / PANGO_SCALE)));
1618     }
1619    
1620     void
1621 root 1.242 line_x_to_index (DC::Layout self, int line, int x)
1622 root 1.165 PPCODE:
1623     {
1624     PangoLayoutLine *lp;
1625     int index, trailing;
1626    
1627     if (line < 0)
1628     XSRETURN_EMPTY;
1629    
1630 root 1.249 if (!(lp = pango_layout_get_line_readonly (self->pl, line)))
1631 root 1.165 XSRETURN_EMPTY; /* do better */
1632    
1633 root 1.166 pango_layout_line_x_to_index (lp, x * PANGO_SCALE, &index, &trailing);
1634 root 1.165
1635     EXTEND (SP, 2);
1636     if (GIMME_V == G_SCALAR)
1637     PUSHs (sv_2mortal (newSViv (index + trailing)));
1638     else
1639     {
1640     PUSHs (sv_2mortal (newSViv (index)));
1641     PUSHs (sv_2mortal (newSViv (trailing)));
1642     }
1643     }
1644    
1645     void
1646 root 1.242 render (DC::Layout self, float x, float y, int flags = 0)
1647 root 1.225 CODE:
1648 root 1.326 self->rc.clear ();
1649 root 1.124 pango_opengl_render_layout_subpixel (
1650     self->pl,
1651 root 1.326 &self->rc,
1652 root 1.124 x * PANGO_SCALE, y * PANGO_SCALE,
1653 root 1.135 self->r, self->g, self->b, self->a,
1654     flags
1655 root 1.124 );
1656 root 1.225 // we assume that context_change actually clears/frees stuff
1657     // and does not do any recomputation...
1658     pango_layout_context_changed (self->pl);
1659    
1660     void
1661 root 1.242 draw (DC::Layout self)
1662 root 1.225 CODE:
1663     {
1664     glEnable (GL_TEXTURE_2D);
1665     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1666     glEnable (GL_BLEND);
1667     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1668     GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1669     glEnable (GL_ALPHA_TEST);
1670     glAlphaFunc (GL_GREATER, 7.f / 255.f);
1671    
1672 root 1.326 self->rc.draw ();
1673 root 1.225
1674     glDisable (GL_ALPHA_TEST);
1675     glDisable (GL_BLEND);
1676     glDisable (GL_TEXTURE_2D);
1677     }
1678 root 1.11
1679 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Texture
1680 root 1.11
1681 root 1.205 PROTOTYPES: ENABLE
1682    
1683 root 1.11 void
1684 root 1.203 pad (SV *data_, int ow, int oh, int nw, int nh)
1685 root 1.113 CODE:
1686     {
1687 root 1.203 if ((nw != ow || nh != oh) && SvOK (data_))
1688 root 1.113 {
1689 root 1.203 STRLEN datalen;
1690     char *data = SvPVbyte (data_, datalen);
1691     int bpp = datalen / (ow * oh);
1692     SV *result_ = sv_2mortal (newSV (nw * nh * bpp));
1693    
1694     SvPOK_only (result_);
1695     SvCUR_set (result_, nw * nh * bpp);
1696    
1697     memset (SvPVX (result_), 0, nw * nh * bpp);
1698     while (oh--)
1699     memcpy (SvPVX (result_) + oh * nw * bpp, data + oh * ow * bpp, ow * bpp);
1700 root 1.113
1701 root 1.203 sv_setsv (data_, result_);
1702 root 1.113 }
1703     }
1704    
1705     void
1706 root 1.114 draw_quad (SV *self, float x, float y, float w = 0., float h = 0.)
1707 root 1.12 PROTOTYPE: $$$;$$
1708 root 1.76 ALIAS:
1709     draw_quad_alpha = 1
1710     draw_quad_alpha_premultiplied = 2
1711 root 1.11 CODE:
1712     {
1713 root 1.12 HV *hv = (HV *)SvRV (self);
1714 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
1715     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
1716 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
1717    
1718 root 1.219 if (name <= 0)
1719     XSRETURN_EMPTY;
1720    
1721 root 1.12 if (items < 5)
1722     {
1723 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1724     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1725 root 1.12 }
1726    
1727 root 1.76 if (ix)
1728     {
1729     glEnable (GL_BLEND);
1730 root 1.103
1731     if (ix == 2)
1732     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1733     else
1734     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1735 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1736 root 1.103
1737 root 1.86 glEnable (GL_ALPHA_TEST);
1738     glAlphaFunc (GL_GREATER, 0.01f);
1739 root 1.76 }
1740    
1741 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1742 root 1.76
1743 root 1.12 glBegin (GL_QUADS);
1744 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1745     glTexCoord2f (0, t); glVertex2f (x , y + h);
1746     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1747     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1748 root 1.12 glEnd ();
1749 root 1.76
1750     if (ix)
1751 root 1.86 {
1752     glDisable (GL_ALPHA_TEST);
1753     glDisable (GL_BLEND);
1754     }
1755 root 1.11 }
1756 root 1.28
1757 root 1.293 void
1758 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)
1759 root 1.293 PROTOTYPE: @
1760     CODE:
1761     {
1762     glEnable (GL_BLEND);
1763 root 1.300 glBlendFunc (intensity ? GL_SRC_ALPHA : GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1764 root 1.299 glEnable (GL_TEXTURE_2D);
1765 root 1.294 glBindTexture (GL_TEXTURE_2D, name1);
1766 root 1.293
1767 root 1.294 glColor3f (intensity, intensity, intensity);
1768 root 1.293 glPushMatrix ();
1769     glScalef (1./3, 1./3, 1.);
1770    
1771 root 1.294 if (blend > 0.f)
1772     {
1773 root 1.296 float dx3 = dx * -3.f / w;
1774     float dy3 = dy * -3.f / h;
1775 root 1.294 GLfloat env_color[4] = { 0., 0., 0., blend };
1776    
1777     /* interpolate the two shadow textures */
1778     /* stage 0 == rgb(glcolor) + alpha(t0) */
1779     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1780    
1781     /* stage 1 == rgb(glcolor) + alpha(interpolate t0, t1, texenv) */
1782     gl.ActiveTexture (GL_TEXTURE1);
1783     glEnable (GL_TEXTURE_2D);
1784     glBindTexture (GL_TEXTURE_2D, name2);
1785     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1786    
1787     /* rgb == rgb(glcolor) */
1788     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
1789 root 1.300 glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
1790 root 1.294 glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1791    
1792     /* alpha = interpolate t0, t1 by env_alpha */
1793     glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env_color);
1794    
1795     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);
1796     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
1797     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1798    
1799     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
1800     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
1801    
1802     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_CONSTANT);
1803     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
1804    
1805     glBegin (GL_QUADS);
1806 root 1.296 gl.MultiTexCoord2f (GL_TEXTURE0, 0, 0); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 , dy3 ); glVertex2i (0, 0);
1807     gl.MultiTexCoord2f (GL_TEXTURE0, 0, t); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 , dy3 + t); glVertex2i (0, h);
1808     gl.MultiTexCoord2f (GL_TEXTURE0, s, t); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 + s, dy3 + t); glVertex2i (w, h);
1809     gl.MultiTexCoord2f (GL_TEXTURE0, s, 0); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 + s, dy3 ); glVertex2i (w, 0);
1810 root 1.294 glEnd ();
1811    
1812     glDisable (GL_TEXTURE_2D);
1813     gl.ActiveTexture (GL_TEXTURE0);
1814     }
1815     else
1816     {
1817     /* simple blending of one texture, also opengl <1.3 path */
1818     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1819 root 1.293
1820 root 1.294 glBegin (GL_QUADS);
1821 root 1.296 glTexCoord2f (0, 0); glVertex2f (0, 0);
1822     glTexCoord2f (0, t); glVertex2f (0, h);
1823     glTexCoord2f (s, t); glVertex2f (w, h);
1824     glTexCoord2f (s, 0); glVertex2f (w, 0);
1825 root 1.294 glEnd ();
1826     }
1827 root 1.293
1828 root 1.296 /* draw ?-marks or equivalent, this is very clumsy code :/ */
1829     {
1830     int x, y;
1831     int dx3 = dx * 3;
1832     int dy3 = dy * 3;
1833    
1834     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1835     glBindTexture (GL_TEXTURE_2D, hidden_tex);
1836     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1837     glTranslatef (-1., -1., 0);
1838     glBegin (GL_QUADS);
1839    
1840     for (y = 1; y < h; y += 3)
1841     {
1842     int y1 = y - dy3;
1843     int y1valid = y1 >= 0 && y1 < h;
1844    
1845     for (x = 1; x < w; x += 3)
1846     {
1847     int x1 = x - dx3;
1848     uint8_t h1 = data1 [x + y * w] == DARKNESS_ADJUST (255 - FOW_DARKNESS);
1849     uint8_t h2;
1850    
1851     if (y1valid && x1 >= 0 && x1 < w)
1852     h2 = data2 [x1 + y1 * w] == DARKNESS_ADJUST (255 - FOW_DARKNESS);
1853     else
1854     h2 = 1; /* out of range == invisible */
1855    
1856     if (h1 || h2)
1857     {
1858     float alpha = h1 == h2 ? 1.f : h1 ? 1.f - blend : blend;
1859     glColor4f (1., 1., 1., alpha);
1860    
1861     glTexCoord2f (0, 0.); glVertex2i (x , y );
1862     glTexCoord2f (0, 1.); glVertex2i (x , y + 3);
1863     glTexCoord2f (1, 1.); glVertex2i (x + 3, y + 3);
1864     glTexCoord2f (1, 0.); glVertex2i (x + 3, y );
1865     }
1866     }
1867     }
1868     }
1869    
1870     glEnd ();
1871    
1872 root 1.293 glPopMatrix ();
1873    
1874     glDisable (GL_TEXTURE_2D);
1875     glDisable (GL_BLEND);
1876     }
1877    
1878 root 1.199 IV texture_valid_2d (GLint internalformat, GLsizei w, GLsizei h, GLenum format, GLenum type)
1879     CODE:
1880     {
1881     GLint width;
1882     glTexImage2D (GL_PROXY_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, 0);
1883     glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
1884     RETVAL = width > 0;
1885     }
1886     OUTPUT:
1887     RETVAL
1888    
1889 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Map
1890 root 1.28
1891 root 1.205 PROTOTYPES: DISABLE
1892    
1893 root 1.242 DC::Map
1894 root 1.319 new (SV *klass)
1895 root 1.28 CODE:
1896 root 1.328 New (0, RETVAL, 1, mapgrid);
1897 root 1.42 RETVAL->x = 0;
1898     RETVAL->y = 0;
1899 root 1.164 RETVAL->w = 0;
1900     RETVAL->h = 0;
1901 root 1.42 RETVAL->ox = 0;
1902     RETVAL->oy = 0;
1903 root 1.328 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1904     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1905 root 1.28 RETVAL->rows = 0;
1906     RETVAL->row = 0;
1907     OUTPUT:
1908     RETVAL
1909    
1910     void
1911 root 1.242 DESTROY (DC::Map self)
1912 root 1.28 CODE:
1913     {
1914 root 1.328 map_clear (self);
1915     Safefree (self->face2tile);
1916     Safefree (self->tex);
1917     Safefree (self);
1918 root 1.29 }
1919    
1920     void
1921 root 1.242 resize (DC::Map self, int map_width, int map_height)
1922 root 1.164 CODE:
1923     self->w = map_width;
1924     self->h = map_height;
1925    
1926     void
1927 root 1.242 clear (DC::Map self)
1928 root 1.30 CODE:
1929 root 1.328 map_clear (self);
1930 root 1.30
1931     void
1932 root 1.242 set_tileid (DC::Map self, int face, int tile)
1933 root 1.29 CODE:
1934     {
1935 root 1.328 need_facenum (self, face); self->face2tile [face] = tile;
1936     need_texid (self, tile);
1937 root 1.42 }
1938    
1939     void
1940 root 1.242 set_smooth (DC::Map self, int face, int smooth, int level)
1941 root 1.176 CODE:
1942     {
1943 root 1.328 tileid texid;
1944     maptex *tex;
1945    
1946     if (face < 0 || face >= self->faces)
1947 root 1.176 return;
1948    
1949 root 1.328 if (smooth < 0 || smooth >= self->faces)
1950 root 1.176 return;
1951    
1952 root 1.328 texid = self->face2tile [face];
1953 root 1.176
1954     if (!texid)
1955     return;
1956    
1957 root 1.328 tex = self->tex + texid;
1958     tex->smoothtile = self->face2tile [smooth];
1959     tex->smoothlevel = level;
1960 root 1.176 }
1961    
1962     void
1963 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)
1964 root 1.42 CODE:
1965     {
1966 root 1.328 need_texid (self, texid);
1967 root 1.42
1968 root 1.48 {
1969 root 1.328 maptex *tex = self->tex + texid;
1970 root 1.39
1971 root 1.328 tex->name = name;
1972     tex->w = w;
1973     tex->h = h;
1974     tex->s = s;
1975     tex->t = t;
1976     tex->r = r;
1977     tex->g = g;
1978     tex->b = b;
1979     tex->a = a;
1980 root 1.48 }
1981 root 1.95
1982     // somewhat hackish, but for textures that require it, it really
1983     // improves the look, and most others don't suffer.
1984     glBindTexture (GL_TEXTURE_2D, name);
1985 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1986     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1987     // use uglier nearest interpolation because linear suffers
1988     // from transparent color bleeding and ugly wrapping effects.
1989     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1990 root 1.29 }
1991    
1992 root 1.280 void
1993     expire_textures (DC::Map self, int texid, int count)
1994     PPCODE:
1995 root 1.328 for (; texid < self->texs && count; ++texid, --count)
1996 root 1.280 {
1997 root 1.328 maptex *tex = self->tex + texid;
1998 root 1.280
1999 root 1.328 if (tex->name)
2000 root 1.280 {
2001 root 1.328 if (tex->unused)
2002 root 1.280 {
2003 root 1.328 tex->name = 0;
2004     tex->unused = 0;
2005 root 1.280 XPUSHs (sv_2mortal (newSViv (texid)));
2006     }
2007     else
2008 root 1.328 tex->unused = 1;
2009 root 1.280 }
2010     }
2011    
2012 root 1.42 int
2013 root 1.242 ox (DC::Map self)
2014 root 1.42 ALIAS:
2015     oy = 1
2016 root 1.101 x = 2
2017     y = 3
2018 root 1.102 w = 4
2019     h = 5
2020 root 1.42 CODE:
2021     switch (ix)
2022     {
2023     case 0: RETVAL = self->ox; break;
2024     case 1: RETVAL = self->oy; break;
2025 root 1.101 case 2: RETVAL = self->x; break;
2026     case 3: RETVAL = self->y; break;
2027 root 1.102 case 4: RETVAL = self->w; break;
2028     case 5: RETVAL = self->h; break;
2029 root 1.42 }
2030     OUTPUT:
2031     RETVAL
2032    
2033 root 1.29 void
2034 root 1.242 scroll (DC::Map self, int dx, int dy)
2035 root 1.43 CODE:
2036     {
2037 root 1.44 if (dx > 0)
2038 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
2039 root 1.44 else if (dx < 0)
2040 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
2041 root 1.44
2042     if (dy > 0)
2043 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
2044 root 1.44 else if (dy < 0)
2045 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
2046 root 1.43
2047 root 1.44 self->ox += dx; self->x += dx;
2048     self->oy += dy; self->y += dy;
2049 root 1.43
2050     while (self->y < 0)
2051     {
2052 root 1.329 prepend (self->row, self->rows, MAP_EXTEND_Y);
2053 root 1.43
2054     self->rows += MAP_EXTEND_Y;
2055     self->y += MAP_EXTEND_Y;
2056     }
2057 root 1.44 }
2058 root 1.43
2059 root 1.221 SV *
2060 root 1.316 map1a_update (DC::Map self, SV *data_)
2061 root 1.44 CODE:
2062     {
2063 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
2064     uint8_t *data_end = (uint8_t *)SvEND (data_);
2065 root 1.48 mapcell *cell;
2066 root 1.221 int x, y, z, flags;
2067     AV *missing = newAV ();
2068     RETVAL = newRV_noinc ((SV *)missing);
2069 root 1.43
2070 root 1.150 while (data < data_end - 1)
2071 root 1.29 {
2072 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
2073 root 1.30
2074 root 1.120 x = self->x + ((flags >> 10) & 63);
2075     y = self->y + ((flags >> 4) & 63);
2076 root 1.29
2077 root 1.48 cell = map_get_cell (self, x, y);
2078 root 1.29
2079     if (flags & 15)
2080     {
2081 root 1.142 if (!cell->darkness)
2082 root 1.29 {
2083 root 1.154 memset (cell, 0, sizeof (*cell));
2084 root 1.142 cell->darkness = 256;
2085 root 1.29 }
2086 root 1.45
2087 root 1.142 //TODO: don't trust server data to be in-range(!)
2088    
2089 root 1.141 if (flags & 8)
2090     {
2091 root 1.316 uint8_t ext, cmd;
2092    
2093     do
2094 root 1.141 {
2095 root 1.316 ext = *data++;
2096     cmd = ext & 0x7f;
2097 root 1.141
2098 root 1.316 if (cmd < 4)
2099     cell->darkness = 255 - ext * 64 + 1; /* make sure this doesn't collide with FOW_DARKNESS */
2100     else if (cmd == 5) // health
2101     {
2102     cell->stat_width = 1;
2103     cell->stat_hp = *data++;
2104     }
2105     else if (cmd == 6) // monster width
2106     cell->stat_width = *data++ + 1;
2107     else if (cmd == 0x47)
2108 root 1.141 {
2109 root 1.316 if (*data == 1) cell->player = data [1];
2110     else if (*data == 2) cell->player = data [2] + (data [1] << 8);
2111     else if (*data == 3) cell->player = data [3] + (data [2] << 8) + (data [1] << 16);
2112     else if (*data == 4) cell->player = data [4] + (data [3] << 8) + (data [2] << 16) + (data [1] << 24);
2113 root 1.153
2114 root 1.316 data += *data + 1;
2115 root 1.141 }
2116 root 1.316 else if (cmd == 8) // cell flags
2117     cell->flags = *data++;
2118     else if (ext & 0x40) // unknown, multibyte => skip
2119     data += *data + 1;
2120     else
2121     data++;
2122 root 1.141 }
2123 root 1.316 while (ext & 0x80);
2124 root 1.141 }
2125 root 1.29
2126 root 1.221 for (z = 0; z <= 2; ++z)
2127     if (flags & (4 >> z))
2128     {
2129 root 1.328 faceid face = (data [0] << 8) + data [1]; data += 2;
2130     need_facenum (self, face);
2131     cell->tile [z] = self->face2tile [face];
2132 root 1.29
2133 root 1.328 if (cell->tile [z])
2134 root 1.221 {
2135 root 1.328 maptex *tex = self->tex + cell->tile [z];
2136     tex->unused = 0;
2137     if (!tex->name)
2138 root 1.221 av_push (missing, newSViv (cell->tile [z]));
2139 root 1.29
2140 root 1.328 if (tex->smoothtile)
2141 root 1.221 {
2142 root 1.328 maptex *smooth = self->tex + tex->smoothtile;
2143     smooth->unused = 0;
2144     if (!smooth->name)
2145     av_push (missing, newSViv (tex->smoothtile));
2146 root 1.221 }
2147     }
2148     }
2149 root 1.29 }
2150     else
2151 root 1.267 CELL_CLEAR (cell);
2152 root 1.29 }
2153 root 1.28 }
2154 root 1.221 OUTPUT:
2155     RETVAL
2156 root 1.28
2157 root 1.40 SV *
2158 root 1.242 mapmap (DC::Map self, int x0, int y0, int w, int h)
2159 root 1.40 CODE:
2160     {
2161 root 1.55 int x1, x;
2162     int y1, y;
2163 root 1.40 int z;
2164     SV *map_sv = newSV (w * h * sizeof (uint32_t));
2165     uint32_t *map = (uint32_t *)SvPVX (map_sv);
2166    
2167     SvPOK_only (map_sv);
2168     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
2169    
2170 root 1.55 x0 += self->x; x1 = x0 + w;
2171     y0 += self->y; y1 = y0 + h;
2172 root 1.40
2173     for (y = y0; y < y1; y++)
2174     {
2175     maprow *row = 0 <= y && y < self->rows
2176     ? self->row + y
2177     : 0;
2178    
2179     for (x = x0; x < x1; x++)
2180     {
2181 root 1.306 unsigned int r = 32, g = 32, b = 32, a = 192;
2182 root 1.40
2183     if (row && row->c0 <= x && x < row->c1)
2184     {
2185     mapcell *cell = row->col + (x - row->c0);
2186    
2187     for (z = 0; z <= 0; z++)
2188     {
2189 root 1.174 maptex tex = self->tex [cell->tile [z]];
2190     int a0 = 255 - tex.a;
2191     int a1 = tex.a;
2192    
2193 root 1.306 r = div255 (r * a0 + tex.r * a1);
2194     g = div255 (g * a0 + tex.g * a1);
2195     b = div255 (b * a0 + tex.b * a1);
2196     a = div255 (a * a0 + tex.a * a1);
2197 root 1.40 }
2198     }
2199    
2200     *map++ = (r )
2201     | (g << 8)
2202     | (b << 16)
2203     | (a << 24);
2204     }
2205     }
2206    
2207 root 1.321 RETVAL = map_sv;
2208 root 1.40 }
2209     OUTPUT:
2210     RETVAL
2211    
2212 root 1.221 void
2213 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)
2214 root 1.116 CODE:
2215 root 1.30 {
2216 root 1.223 int x, y, z;
2217    
2218 root 1.324 static uint8_t smooth_max[256][256]; // egad, fast and wasteful on memory (64k), also, static!
2219 root 1.261 int pl_x, pl_y;
2220     maptex pl_tex;
2221 root 1.326 rc_t rc;
2222     rc_t rc_ov;
2223 root 1.223 rc_key_t key;
2224 root 1.326 rc_t::array_t *arr;
2225 root 1.48
2226 root 1.262 pl_tex.name = 0;
2227    
2228 pippijn 1.288 // that's current max. sorry.
2229 root 1.176 if (sw > 255) sw = 255;
2230     if (sh > 255) sh = 255;
2231    
2232 root 1.223 memset (&key, 0, sizeof (key));
2233     key.r = 255;
2234     key.g = 255;
2235     key.b = 255;
2236     key.a = 255;
2237     key.mode = GL_QUADS;
2238     key.format = GL_T2F_V3F;
2239 root 1.30
2240 root 1.164 mx += self->x;
2241     my += self->y;
2242    
2243 root 1.176 // first pass: determine smooth_max
2244     // rather ugly, if you ask me
2245     // could also be stored inside mapcell and updated on change
2246 root 1.324 memset (smooth_max, 0, sizeof (smooth_max[0]) * (sh + 1));
2247 root 1.176
2248     for (y = 0; y < sh; y++)
2249     if (0 <= y + my && y + my < self->rows)
2250     {
2251     maprow *row = self->row + (y + my);
2252    
2253     for (x = 0; x < sw; x++)
2254     if (row->c0 <= x + mx && x + mx < row->c1)
2255     {
2256     mapcell *cell = row->col + (x + mx - row->c0);
2257    
2258 root 1.177 smooth_max[x + 1][y + 1] =
2259     MAX (self->tex [cell->tile [0]].smoothlevel,
2260     MAX (self->tex [cell->tile [1]].smoothlevel,
2261     self->tex [cell->tile [2]].smoothlevel));
2262 root 1.176 }
2263     }
2264    
2265 root 1.223 glEnable (GL_BLEND);
2266     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2267     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2268    
2269 root 1.176 for (z = 0; z <= 2; z++)
2270     {
2271 root 1.325 std::bitset<256> smooth_level; // one bit for every possible smooth level
2272 root 1.324 smooth_key skey;
2273 root 1.322 smooth_hash smooth;
2274 root 1.283 key.texname = -1;
2275 root 1.186
2276 root 1.176 for (y = 0; y < sh; y++)
2277     if (0 <= y + my && y + my < self->rows)
2278     {
2279     maprow *row = self->row + (y + my);
2280    
2281     for (x = 0; x < sw; x++)
2282     if (row->c0 <= x + mx && x + mx < row->c1)
2283     {
2284     mapcell *cell = row->col + (x + mx - row->c0);
2285     tileid tile = cell->tile [z];
2286    
2287     if (tile)
2288     {
2289     maptex tex = self->tex [tile];
2290 root 1.285 int px, py;
2291 root 1.176
2292 root 1.223 if (key.texname != tex.name)
2293 root 1.176 {
2294 root 1.280 self->tex [tile].unused = 0;
2295    
2296 root 1.176 if (!tex.name)
2297 root 1.285 tex = self->tex [TEXID_NOFACE]; /* missing, replace by noface */
2298 root 1.176
2299 root 1.223 key.texname = tex.name;
2300 root 1.326 arr = &rc.array (key);
2301 root 1.176 }
2302    
2303 root 1.306 px = (x + 1) * Th - tex.w;
2304     py = (y + 1) * Tw - tex.h;
2305 root 1.285
2306 root 1.331 if (ecb_expect_false (cell->player == player) && ecb_expect_false (z == 2))
2307 root 1.261 {
2308     pl_x = px;
2309     pl_y = py;
2310     pl_tex = tex;
2311     continue;
2312     }
2313 root 1.219
2314 root 1.326 arr->t2f_v3f (0 , 0 , px , py , 0);
2315     arr->t2f_v3f (0 , tex.t, px , py + tex.h, 0);
2316     arr->t2f_v3f (tex.s, tex.t, px + tex.w, py + tex.h, 0);
2317     arr->t2f_v3f (tex.s, 0 , px + tex.w, py , 0);
2318 root 1.176
2319     // update smooth hash
2320     if (tex.smoothtile)
2321     {
2322     skey.tile = tex.smoothtile;
2323     skey.level = tex.smoothlevel;
2324    
2325 root 1.325 smooth_level[tex.smoothlevel] = 1;
2326 root 1.30
2327 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
2328     // shifted +1|+1 so we always stay positive.
2329 root 1.30
2330 root 1.180 // bits is ___n cccc CCCC bbbb
2331     // n do not draw borders&corners
2332     // c draw these corners, but...
2333     // C ... not these
2334     // b draw these borders
2335    
2336     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
2337     // ┃· ·· ·┃ ━━
2338    
2339     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
2340     // ·· ·· ·┏ ┓·
2341    
2342 root 1.176 // full tile
2343 root 1.322 skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, skey, 0x1000);
2344 root 1.176
2345     // borders
2346 root 1.322 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, skey, 0x0091);
2347     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, skey, 0x0032);
2348     skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, skey, 0x0064);
2349     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, skey, 0x00c8);
2350 root 1.176
2351     // corners
2352 root 1.322 skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, skey, 0x0100);
2353     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, skey, 0x0200);
2354     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, skey, 0x0400);
2355     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, skey, 0x0800);
2356 root 1.176 }
2357     }
2358 root 1.285
2359 root 1.331 if (ecb_expect_false (z == 2) && ecb_expect_false (cell->flags))
2360 root 1.285 {
2361 root 1.296 // overlays such as the speech bubble, probably more to come
2362     if (cell->flags & 1)
2363 root 1.285 {
2364 root 1.296 rc_key_t key_ov = key;
2365 root 1.326 maptex tex = self->tex[TEXID_SPEECH];
2366 root 1.306 int px = x * Tw + Tw * 2 / 32;
2367     int py = y * Th - Th * 6 / 32;
2368 root 1.296
2369     key_ov.texname = tex.name;
2370 root 1.326 rc_t::array_t &arr = rc_ov.array (key_ov);
2371 root 1.296
2372 root 1.326 arr.t2f_v3f (0 , 0 , px , py , 0);
2373     arr.t2f_v3f (0 , tex.t, px , py + Th, 0);
2374     arr.t2f_v3f (tex.s, tex.t, px + Tw, py + Th, 0);
2375     arr.t2f_v3f (tex.s, 0 , px + Tw, py , 0);
2376 root 1.285 }
2377     }
2378 root 1.176 }
2379     }
2380 root 1.174
2381 root 1.326 rc.draw ();
2382     rc.clear ();
2383 root 1.224
2384 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
2385     // this is basically counting sort
2386 root 1.176 {
2387 root 1.186 int w, b;
2388 root 1.30
2389 root 1.226 glEnable (GL_TEXTURE_2D);
2390     glBegin (GL_QUADS);
2391 root 1.325 for (int level = 0; level < smooth_level.size (); ++level)
2392     if (smooth_level[level])
2393     for (auto &&it = smooth.begin (); it != smooth.end (); ++it)
2394     {
2395     smooth_key &skey = it->first;
2396     IV bits = it->second;
2397    
2398     if (!(bits & 0x1000)
2399     && skey.level == level
2400     && level > smooth_max [skey.x][skey.y])
2401 root 1.176 {
2402 root 1.325 maptex tex = self->tex [skey.tile];
2403     int px = (((int)skey.x) - 1) * Tw;
2404     int py = (((int)skey.y) - 1) * Th;
2405     int border = bits & 15;
2406     int corner = (bits >> 8) & ~(bits >> 4) & 15;
2407     float dx = tex.s * .0625f; // 16 images/row
2408     float dy = tex.t * .5f ; // 2 images/column
2409 root 1.153
2410 root 1.325 if (tex.name)
2411 root 1.153 {
2412 root 1.325 // this time avoiding texture state changes
2413     // save gobs of state changes.
2414     if (key.texname != tex.name)
2415     {
2416     self->tex [skey.tile].unused = 0;
2417    
2418     glEnd ();
2419     glBindTexture (GL_TEXTURE_2D, key.texname = tex.name);
2420     glBegin (GL_QUADS);
2421     }
2422    
2423     if (border)
2424     {
2425     float ox = border * dx;
2426    
2427     glTexCoord2f (ox , 0.f ); glVertex2i (px , py );
2428     glTexCoord2f (ox , dy ); glVertex2i (px , py + Th);
2429     glTexCoord2f (ox + dx, dy ); glVertex2i (px + Tw, py + Th);
2430     glTexCoord2f (ox + dx, 0.f ); glVertex2i (px + Tw, py );
2431     }
2432 root 1.176
2433 root 1.325 if (corner)
2434 root 1.174 {
2435 root 1.325 float ox = corner * dx;
2436    
2437     glTexCoord2f (ox , dy ); glVertex2i (px , py );
2438     glTexCoord2f (ox , dy * 2.f); glVertex2i (px , py + Th);
2439     glTexCoord2f (ox + dx, dy * 2.f); glVertex2i (px + Tw, py + Th);
2440     glTexCoord2f (ox + dx, dy ); glVertex2i (px + Tw, py );
2441 root 1.174 }
2442 root 1.153 }
2443     }
2444 root 1.325 }
2445 root 1.226
2446     glEnd ();
2447     glDisable (GL_TEXTURE_2D);
2448     key.texname = -1;
2449 root 1.176 }
2450 root 1.186 }
2451 root 1.30
2452 root 1.261 if (pl_tex.name)
2453     {
2454     maptex tex = pl_tex;
2455 root 1.266 int px = pl_x + sdx;
2456     int py = pl_y + sdy;
2457 root 1.261
2458     key.texname = tex.name;
2459 root 1.326 rc_t::array_t &arr = rc.array (key);
2460 root 1.261
2461 root 1.326 arr.t2f_v3f (0 , 0 , px , py , 0);
2462     arr.t2f_v3f (0 , tex.t, px , py + tex.h, 0);
2463     arr.t2f_v3f (tex.s, tex.t, px + tex.w, py + tex.h, 0);
2464     arr.t2f_v3f (tex.s, 0 , px + tex.w, py , 0);
2465 root 1.261
2466 root 1.326 rc.draw ();
2467 root 1.261 }
2468    
2469 root 1.326 rc_ov.draw ();
2470     rc_ov.clear ();
2471 root 1.285
2472 root 1.152 glDisable (GL_BLEND);
2473 root 1.143
2474 root 1.145 // top layer: overlays such as the health bar
2475 root 1.143 for (y = 0; y < sh; y++)
2476 root 1.164 if (0 <= y + my && y + my < self->rows)
2477 root 1.143 {
2478 root 1.164 maprow *row = self->row + (y + my);
2479 root 1.143
2480     for (x = 0; x < sw; x++)
2481 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2482 root 1.143 {
2483 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2484 root 1.143
2485 root 1.306 int px = x * Tw;
2486     int py = y * Th;
2487 root 1.143
2488 root 1.331 if (ecb_expect_false (cell->player == player))
2489 root 1.279 {
2490     px += sdx;
2491     py += sdy;
2492     }
2493    
2494 root 1.143 if (cell->stat_hp)
2495     {
2496 root 1.306 int width = cell->stat_width * Tw;
2497     int thick = (sh * Th / 32 + 27) / 28 + 1 + cell->stat_width;
2498 root 1.143
2499 root 1.152 glColor3ub (0, 0, 0);
2500 root 1.151 glRectf (px + 1, py - thick - 2,
2501     px + width - 1, py);
2502 root 1.147
2503 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
2504 root 1.147 glRectf (px + 2,
2505 root 1.151 py - thick - 1,
2506     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
2507 root 1.143 }
2508     }
2509     }
2510 root 1.116 }
2511    
2512     void
2513 root 1.295 draw_magicmap (DC::Map self, int w, int h, unsigned char *data)
2514 root 1.117 CODE:
2515     {
2516     static float color[16][3] = {
2517 root 1.295 { 0.00f, 0.00f, 0.00f },
2518     { 1.00f, 1.00f, 1.00f },
2519     { 0.00f, 0.00f, 0.55f },
2520     { 1.00f, 0.00f, 0.00f },
2521    
2522     { 1.00f, 0.54f, 0.00f },
2523     { 0.11f, 0.56f, 1.00f },
2524     { 0.93f, 0.46f, 0.00f },
2525     { 0.18f, 0.54f, 0.34f },
2526    
2527     { 0.56f, 0.73f, 0.56f },
2528     { 0.80f, 0.80f, 0.80f },
2529     { 0.55f, 0.41f, 0.13f },
2530     { 0.99f, 0.77f, 0.26f },
2531    
2532     { 0.74f, 0.65f, 0.41f },
2533    
2534     { 0.00f, 1.00f, 1.00f },
2535     { 1.00f, 0.00f, 1.00f },
2536     { 1.00f, 1.00f, 0.00f },
2537 root 1.117 };
2538    
2539     int x, y;
2540    
2541     glEnable (GL_TEXTURE_2D);
2542 root 1.290 /* GL_REPLACE would be correct, as we don't need to modulate alpha,
2543     * but the nvidia driver (185.18.14) mishandles alpha textures
2544 root 1.296 * and takes the colour from god knows where instead of using
2545 root 1.290 * Cp. MODULATE results in the same colour, but slightly different
2546     * alpha, but atcually gives us the correct colour with nvidia.
2547     */
2548     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2549 root 1.117 glEnable (GL_BLEND);
2550     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2551     glBegin (GL_QUADS);
2552    
2553     for (y = 0; y < h; y++)
2554     for (x = 0; x < w; x++)
2555     {
2556     unsigned char m = data [x + y * w];
2557    
2558 root 1.118 if (m)
2559     {
2560     float *c = color [m & 15];
2561    
2562 root 1.295 float tx1 = m & 0x40 ? 0.5f : 0.f;
2563     float tx2 = tx1 + 0.5f;
2564 root 1.118
2565 root 1.290 glColor4f (c[0], c[1], c[2], 1);
2566 root 1.118 glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2567     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2568     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2569     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2570     }
2571 root 1.117 }
2572    
2573     glEnd ();
2574     glDisable (GL_BLEND);
2575     glDisable (GL_TEXTURE_2D);
2576     }
2577    
2578     void
2579 root 1.242 fow_texture (DC::Map self, int mx, int my, int sw, int sh)
2580 root 1.116 PPCODE:
2581     {
2582     int x, y;
2583 root 1.296 int sw1 = sw + 2;
2584     int sh1 = sh + 2;
2585     int sh3 = sh * 3;
2586     int sw3 = sw * 3;
2587     SV *darkness3_sv = sv_2mortal (newSV (sw3 * sh3));
2588 root 1.204 uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2589 root 1.307 uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2590     memset (darkness1, 0, sw1*sh1);
2591 root 1.204
2592     SvPOK_only (darkness3_sv);
2593 root 1.296 SvCUR_set (darkness3_sv, sw3 * sh3);
2594 root 1.116
2595 root 1.204 mx += self->x - 1;
2596     my += self->y - 1;
2597 root 1.116
2598 root 1.204 for (y = 0; y < sh1; y++)
2599 root 1.164 if (0 <= y + my && y + my < self->rows)
2600 root 1.116 {
2601 root 1.164 maprow *row = self->row + (y + my);
2602 root 1.116
2603 root 1.204 for (x = 0; x < sw1; x++)
2604 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2605 root 1.116 {
2606 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2607 root 1.116
2608 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2609 root 1.294 ? DARKNESS_ADJUST (255 - (cell->darkness - 1))
2610     : DARKNESS_ADJUST (255 - FOW_DARKNESS);
2611 root 1.116 }
2612     }
2613 root 1.34
2614 root 1.204 for (y = 0; y < sh; ++y)
2615     for (x = 0; x < sw; ++x)
2616     {
2617     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2618     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2619     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2620     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2621     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2622     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2623     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2624     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2625     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2626    
2627     uint8_t r11 = (d11 + d21 + d12) / 3;
2628     uint8_t r21 = d21;
2629     uint8_t r31 = (d21 + d31 + d32) / 3;
2630    
2631     uint8_t r12 = d12;
2632     uint8_t r22 = d22;
2633     uint8_t r32 = d32;
2634    
2635     uint8_t r13 = (d13 + d23 + d12) / 3;
2636     uint8_t r23 = d23;
2637     uint8_t r33 = (d23 + d33 + d32) / 3;
2638    
2639 root 1.296 darkness3 [(y * 3 ) * sw3 + (x * 3 )] = MAX (d22, r11);
2640     darkness3 [(y * 3 ) * sw3 + (x * 3 + 1)] = MAX (d22, r21);
2641     darkness3 [(y * 3 ) * sw3 + (x * 3 + 2)] = MAX (d22, r31);
2642     darkness3 [(y * 3 + 1) * sw3 + (x * 3 )] = MAX (d22, r12);
2643     darkness3 [(y * 3 + 1) * sw3 + (x * 3 + 1)] = MAX (d22, r22); /* this MUST be == d22 */
2644     darkness3 [(y * 3 + 1) * sw3 + (x * 3 + 2)] = MAX (d22, r32);
2645     darkness3 [(y * 3 + 2) * sw3 + (x * 3 )] = MAX (d22, r13);
2646     darkness3 [(y * 3 + 2) * sw3 + (x * 3 + 1)] = MAX (d22, r23);
2647     darkness3 [(y * 3 + 2) * sw3 + (x * 3 + 2)] = MAX (d22, r33);
2648 root 1.204 }
2649 root 1.201
2650 root 1.204 free (darkness1);
2651 root 1.201
2652 root 1.32 EXTEND (SP, 3);
2653 root 1.296 PUSHs (sv_2mortal (newSViv (sw3)));
2654 root 1.204 PUSHs (sv_2mortal (newSViv (sh3)));
2655     PUSHs (darkness3_sv);
2656 root 1.30 }
2657    
2658 root 1.42 SV *
2659 root 1.242 get_rect (DC::Map self, int x0, int y0, int w, int h)
2660 root 1.42 CODE:
2661     {
2662     int x, y, x1, y1;
2663     SV *data_sv = newSV (w * h * 7 + 5);
2664     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2665    
2666     *data++ = 0; /* version 0 format */
2667     *data++ = w >> 8; *data++ = w;
2668     *data++ = h >> 8; *data++ = h;
2669    
2670     // we need to do this 'cause we don't keep an absolute coord system for rows
2671 root 1.55 // TODO: treat rows as we treat columns
2672 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2673     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2674    
2675     x0 += self->x - self->ox;
2676     y0 += self->y - self->oy;
2677    
2678     x1 = x0 + w;
2679     y1 = y0 + h;
2680    
2681     for (y = y0; y < y1; y++)
2682     {
2683     maprow *row = 0 <= y && y < self->rows
2684     ? self->row + y
2685     : 0;
2686    
2687     for (x = x0; x < x1; x++)
2688     {
2689     if (row && row->c0 <= x && x < row->c1)
2690     {
2691     mapcell *cell = row->col + (x - row->c0);
2692     uint8_t flags = 0;
2693    
2694 root 1.174 if (cell->tile [0]) flags |= 1;
2695     if (cell->tile [1]) flags |= 2;
2696     if (cell->tile [2]) flags |= 4;
2697 root 1.42
2698     *data++ = flags;
2699    
2700     if (flags & 1)
2701     {
2702 root 1.174 tileid tile = cell->tile [0];
2703     *data++ = tile >> 8;
2704     *data++ = tile;
2705 root 1.42 }
2706    
2707     if (flags & 2)
2708     {
2709 root 1.174 tileid tile = cell->tile [1];
2710     *data++ = tile >> 8;
2711     *data++ = tile;
2712 root 1.42 }
2713    
2714     if (flags & 4)
2715     {
2716 root 1.174 tileid tile = cell->tile [2];
2717     *data++ = tile >> 8;
2718     *data++ = tile;
2719 root 1.42 }
2720     }
2721     else
2722     *data++ = 0;
2723     }
2724     }
2725    
2726 root 1.321 /* if size is w*h + 5 then no data has been found */
2727 root 1.260 if (data - (uint8_t *)SvPVX (data_sv) != w * h + 5)
2728 root 1.259 {
2729     SvPOK_only (data_sv);
2730     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2731     }
2732 root 1.260
2733 root 1.321 RETVAL = data_sv;
2734 root 1.42 }
2735     OUTPUT:
2736     RETVAL
2737    
2738     void
2739 root 1.259 set_rect (DC::Map self, int x0, int y0, SV *data_sv)
2740 root 1.42 PPCODE:
2741     {
2742     int x, y, z;
2743 root 1.48 int w, h;
2744 root 1.42 int x1, y1;
2745 root 1.259 STRLEN len;
2746     uint8_t *data, *end;
2747    
2748     len = SvLEN (data_sv);
2749 root 1.260 SvGROW (data_sv, len + 8); // reserve at least 7+ bytes more
2750 root 1.319 data = (uint8_t *)SvPVbyte_nolen (data_sv);
2751 root 1.260 end = data + len + 8;
2752 root 1.259
2753     if (len < 5)
2754     XSRETURN_EMPTY;
2755 root 1.42
2756     if (*data++ != 0)
2757 root 1.227 XSRETURN_EMPTY; /* version mismatch */
2758 root 1.42
2759 root 1.48 w = *data++ << 8; w |= *data++;
2760     h = *data++ << 8; h |= *data++;
2761 root 1.42
2762     // we need to do this 'cause we don't keep an absolute coord system for rows
2763 root 1.55 // TODO: treat rows as we treat columns
2764 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2765     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2766    
2767     x0 += self->x - self->ox;
2768     y0 += self->y - self->oy;
2769    
2770     x1 = x0 + w;
2771     y1 = y0 + h;
2772    
2773     for (y = y0; y < y1; y++)
2774     {
2775     maprow *row = map_get_row (self, y);
2776    
2777     for (x = x0; x < x1; x++)
2778     {
2779 root 1.259 uint8_t flags;
2780    
2781     if (data + 7 >= end)
2782     XSRETURN_EMPTY;
2783    
2784     flags = *data++;
2785 root 1.42
2786     if (flags)
2787     {
2788     mapcell *cell = row_get_cell (row, x);
2789 root 1.174 tileid tile[3] = { 0, 0, 0 };
2790 root 1.42
2791 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2792     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2793     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2794 root 1.42
2795 root 1.143 if (cell->darkness == 0)
2796 root 1.42 {
2797 root 1.260 /*cell->darkness = 0;*/
2798     EXTEND (SP, 3);
2799 root 1.42
2800     for (z = 0; z <= 2; z++)
2801     {
2802 root 1.174 tileid t = tile [z];
2803    
2804 root 1.328 if (t >= self->texs || (t && !self->tex [t].name))
2805 root 1.174 {
2806 root 1.260 PUSHs (sv_2mortal (newSViv (t)));
2807 root 1.328 need_texid (self, t);
2808 root 1.174 }
2809 root 1.42
2810 root 1.328 cell->tile [z] = t;
2811 root 1.42 }
2812     }
2813     }
2814     }
2815     }
2816     }
2817    
2818 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::RW
2819 root 1.205
2820 root 1.242 DC::RW
2821 root 1.319 new (SV *klass, SV *data_sv)
2822 root 1.211 CODE:
2823     {
2824     STRLEN datalen;
2825     char *data = SvPVbyte (data_sv, datalen);
2826    
2827 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2828 root 1.211 }
2829     OUTPUT:
2830     RETVAL
2831    
2832 root 1.242 DC::RW
2833 root 1.319 new_from_file (SV *klass, const char *path, const char *mode = "rb")
2834 root 1.212 CODE:
2835     RETVAL = SDL_RWFromFile (path, mode);
2836     OUTPUT:
2837     RETVAL
2838    
2839 root 1.218 # fails on win32:
2840 root 1.241 # dc.xs(2268) : error C2059: syntax error : '('
2841 root 1.218 #void
2842 root 1.242 #close (DC::RW self)
2843 root 1.218 # CODE:
2844     # (self->(close)) (self);
2845 root 1.212
2846 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Channel
2847 root 1.212
2848     PROTOTYPES: DISABLE
2849    
2850 root 1.242 DC::Channel
2851 root 1.215 find ()
2852     CODE:
2853     {
2854     RETVAL = Mix_GroupAvailable (-1);
2855    
2856     if (RETVAL < 0)
2857     {
2858     RETVAL = Mix_GroupOldest (-1);
2859    
2860     if (RETVAL < 0)
2861 root 1.302 {
2862     // happens sometimes, maybe it just stopped playing(?)
2863     RETVAL = Mix_GroupAvailable (-1);
2864 root 1.215
2865 root 1.302 if (RETVAL < 0)
2866     XSRETURN_UNDEF;
2867     }
2868     else
2869     Mix_HaltChannel (RETVAL);
2870 root 1.215 }
2871    
2872     Mix_UnregisterAllEffects (RETVAL);
2873     Mix_Volume (RETVAL, 128);
2874     }
2875     OUTPUT:
2876     RETVAL
2877    
2878 root 1.213 void
2879 root 1.242 halt (DC::Channel self)
2880 root 1.213 CODE:
2881     Mix_HaltChannel (self);
2882    
2883     void
2884 root 1.242 expire (DC::Channel self, int ticks = -1)
2885 root 1.213 CODE:
2886     Mix_ExpireChannel (self, ticks);
2887    
2888     void
2889 root 1.242 fade_out (DC::Channel self, int ticks = -1)
2890 root 1.213 CODE:
2891     Mix_FadeOutChannel (self, ticks);
2892    
2893 root 1.212 int
2894 root 1.242 volume (DC::Channel self, int volume)
2895 root 1.212 CODE:
2896 root 1.216 RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128));
2897 root 1.212 OUTPUT:
2898     RETVAL
2899    
2900 root 1.213 void
2901 root 1.242 unregister_all_effects (DC::Channel self)
2902 root 1.212 CODE:
2903 root 1.213 Mix_UnregisterAllEffects (self);
2904 root 1.212
2905 root 1.213 void
2906 root 1.242 set_panning (DC::Channel self, int left, int right)
2907 root 1.212 CODE:
2908 root 1.216 left = CLAMP (left , 0, 255);
2909     right = CLAMP (right, 0, 255);
2910 root 1.213 Mix_SetPanning (self, left, right);
2911 root 1.212
2912 root 1.213 void
2913 root 1.242 set_distance (DC::Channel self, int distance)
2914 root 1.212 CODE:
2915 root 1.216 Mix_SetDistance (self, CLAMP (distance, 0, 255));
2916 root 1.212
2917 root 1.213 void
2918 root 1.242 set_position (DC::Channel self, int angle, int distance)
2919 root 1.212 CODE:
2920 root 1.220
2921     void
2922 root 1.242 set_position_r (DC::Channel self, int dx, int dy, int maxdistance)
2923 root 1.220 CODE:
2924     {
2925     int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance));
2926 root 1.295 int angle = atan2f (dx, -dy) * 180.f / (float)M_PI + 360.f;
2927 root 1.216 Mix_SetPosition (self, angle, CLAMP (distance, 0, 255));
2928 root 1.220 }
2929 root 1.212
2930 root 1.213 void
2931 root 1.242 set_reverse_stereo (DC::Channel self, int flip)
2932 root 1.212 CODE:
2933 root 1.213 Mix_SetReverseStereo (self, flip);
2934 root 1.212
2935 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixChunk
2936 root 1.212
2937     PROTOTYPES: DISABLE
2938    
2939 root 1.301 void
2940     decoders ()
2941     PPCODE:
2942     #if SDL_MIXER_MAJOR_VERSION > 1 || SDL_MIXER_MINOR_VERSION > 2 || SDL_MIXER_PATCHLEVEL >= 10
2943     int i, num = Mix_GetNumChunkDecoders ();
2944     EXTEND (SP, num);
2945     for (i = 0; i < num; ++i)
2946     PUSHs (sv_2mortal (newSVpv (Mix_GetChunkDecoder (i), 0)));
2947     #else
2948     XPUSHs (sv_2mortal (newSVpv ("(sdl mixer too old)", 0)));
2949     #endif
2950    
2951 root 1.242 DC::MixChunk
2952 root 1.319 new (SV *klass, DC::RW rwops)
2953 root 1.52 CODE:
2954 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2955 root 1.52 OUTPUT:
2956     RETVAL
2957    
2958     void
2959 root 1.242 DESTROY (DC::MixChunk self)
2960 root 1.52 CODE:
2961     Mix_FreeChunk (self);
2962    
2963     int
2964 root 1.242 volume (DC::MixChunk self, int volume = -1)
2965 root 1.52 CODE:
2966 root 1.216 if (items > 1)
2967     volume = CLAMP (volume, 0, 128);
2968 root 1.52 RETVAL = Mix_VolumeChunk (self, volume);
2969     OUTPUT:
2970     RETVAL
2971    
2972 root 1.242 DC::Channel
2973     play (DC::MixChunk self, DC::Channel channel = -1, int loops = 0, int ticks = -1)
2974 root 1.52 CODE:
2975 root 1.215 {
2976 root 1.52 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2977 root 1.215
2978     if (RETVAL < 0)
2979     XSRETURN_UNDEF;
2980    
2981     if (channel < 0)
2982     {
2983     Mix_UnregisterAllEffects (RETVAL);
2984     Mix_Volume (RETVAL, 128);
2985     }
2986     }
2987 root 1.52 OUTPUT:
2988     RETVAL
2989    
2990 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixMusic
2991 root 1.52
2992 root 1.301 void
2993     decoders ()
2994     PPCODE:
2995     #if SDL_MIXER_MAJOR_VERSION > 1 || SDL_MIXER_MINOR_VERSION > 2 || SDL_MIXER_PATCHLEVEL >= 10
2996     int i, num = Mix_GetNumMusicDecoders ();
2997     EXTEND (SP, num);
2998     for (i = 0; i < num; ++i)
2999     PUSHs (sv_2mortal (newSVpv (Mix_GetMusicDecoder (i), 0)));
3000     #else
3001     XPUSHs (sv_2mortal (newSVpv ("(sdl mixer too old)", 0)));
3002     #endif
3003    
3004 root 1.52 int
3005     volume (int volume = -1)
3006 root 1.205 PROTOTYPE: ;$
3007 root 1.52 CODE:
3008 root 1.216 if (items > 0)
3009     volume = CLAMP (volume, 0, 128);
3010 root 1.52 RETVAL = Mix_VolumeMusic (volume);
3011     OUTPUT:
3012     RETVAL
3013    
3014 root 1.213 void
3015 root 1.194 fade_out (int ms)
3016     CODE:
3017 root 1.213 Mix_FadeOutMusic (ms);
3018 root 1.194
3019 root 1.212 void
3020     halt ()
3021     CODE:
3022     Mix_HaltMusic ();
3023    
3024 root 1.301 int
3025     playing ()
3026     CODE:
3027     RETVAL = Mix_PlayingMusic ();
3028     OUTPUT:
3029     RETVAL
3030    
3031 root 1.242 DC::MixMusic
3032 root 1.319 new (SV *klass, DC::RW rwops)
3033 root 1.52 CODE:
3034 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
3035 root 1.52 OUTPUT:
3036     RETVAL
3037    
3038     void
3039 root 1.242 DESTROY (DC::MixMusic self)
3040 root 1.52 CODE:
3041     Mix_FreeMusic (self);
3042    
3043     int
3044 root 1.242 play (DC::MixMusic self, int loops = -1)
3045 root 1.52 CODE:
3046     RETVAL = Mix_PlayMusic (self, loops);
3047     OUTPUT:
3048     RETVAL
3049    
3050 root 1.213 void
3051 root 1.242 fade_in_pos (DC::MixMusic self, int loops, int ms, double position)
3052 root 1.195 CODE:
3053 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
3054 root 1.195
3055 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::OpenGL
3056 root 1.54
3057 root 1.205 PROTOTYPES: ENABLE
3058    
3059 root 1.54 BOOT:
3060     {
3061 root 1.242 HV *stash = gv_stashpv ("DC::OpenGL", 1);
3062 root 1.54 static const struct {
3063     const char *name;
3064     IV iv;
3065     } *civ, const_iv[] = {
3066     # define const_iv(name) { # name, (IV)name }
3067 root 1.199 const_iv (GL_VENDOR),
3068     const_iv (GL_VERSION),
3069     const_iv (GL_EXTENSIONS),
3070 root 1.293 const_iv (GL_MAX_TEXTURE_UNITS),
3071 root 1.54 const_iv (GL_COLOR_MATERIAL),
3072     const_iv (GL_SMOOTH),
3073     const_iv (GL_FLAT),
3074 root 1.69 const_iv (GL_DITHER),
3075 root 1.54 const_iv (GL_BLEND),
3076 root 1.89 const_iv (GL_CULL_FACE),
3077 root 1.69 const_iv (GL_SCISSOR_TEST),
3078 root 1.89 const_iv (GL_DEPTH_TEST),
3079     const_iv (GL_ALPHA_TEST),
3080     const_iv (GL_NORMALIZE),
3081     const_iv (GL_RESCALE_NORMAL),
3082 root 1.119 const_iv (GL_FRONT),
3083     const_iv (GL_BACK),
3084 root 1.206 const_iv (GL_AUX0),
3085 root 1.54 const_iv (GL_AND),
3086 root 1.67 const_iv (GL_ONE),
3087     const_iv (GL_ZERO),
3088 root 1.54 const_iv (GL_SRC_ALPHA),
3089 root 1.104 const_iv (GL_DST_ALPHA),
3090 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
3091 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
3092 root 1.293 const_iv (GL_SRC_COLOR),
3093     const_iv (GL_DST_COLOR),
3094     const_iv (GL_ONE_MINUS_SRC_COLOR),
3095     const_iv (GL_ONE_MINUS_DST_COLOR),
3096 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
3097 root 1.54 const_iv (GL_RGB),
3098     const_iv (GL_RGBA),
3099 root 1.115 const_iv (GL_RGBA4),
3100     const_iv (GL_RGBA8),
3101     const_iv (GL_RGB5_A1),
3102 root 1.54 const_iv (GL_UNSIGNED_BYTE),
3103 root 1.89 const_iv (GL_UNSIGNED_SHORT),
3104     const_iv (GL_UNSIGNED_INT),
3105 root 1.54 const_iv (GL_ALPHA),
3106 root 1.86 const_iv (GL_INTENSITY),
3107 root 1.76 const_iv (GL_LUMINANCE),
3108 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
3109 root 1.54 const_iv (GL_FLOAT),
3110     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
3111 root 1.230 const_iv (GL_COMPRESSED_ALPHA_ARB),
3112     const_iv (GL_COMPRESSED_LUMINANCE_ARB),
3113     const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB),
3114     const_iv (GL_COMPRESSED_INTENSITY_ARB),
3115     const_iv (GL_COMPRESSED_RGB_ARB),
3116     const_iv (GL_COMPRESSED_RGBA_ARB),
3117 root 1.54 const_iv (GL_COMPILE),
3118 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
3119     const_iv (GL_PROXY_TEXTURE_2D),
3120 root 1.54 const_iv (GL_TEXTURE_1D),
3121     const_iv (GL_TEXTURE_2D),
3122     const_iv (GL_TEXTURE_ENV),
3123     const_iv (GL_TEXTURE_MAG_FILTER),
3124     const_iv (GL_TEXTURE_MIN_FILTER),
3125     const_iv (GL_TEXTURE_ENV_MODE),
3126     const_iv (GL_TEXTURE_WRAP_S),
3127     const_iv (GL_TEXTURE_WRAP_T),
3128 root 1.98 const_iv (GL_REPEAT),
3129 root 1.54 const_iv (GL_CLAMP),
3130 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
3131 root 1.54 const_iv (GL_NEAREST),
3132     const_iv (GL_LINEAR),
3133 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
3134     const_iv (GL_LINEAR_MIPMAP_NEAREST),
3135     const_iv (GL_NEAREST_MIPMAP_LINEAR),
3136     const_iv (GL_LINEAR_MIPMAP_LINEAR),
3137     const_iv (GL_GENERATE_MIPMAP),
3138 root 1.54 const_iv (GL_MODULATE),
3139 root 1.69 const_iv (GL_DECAL),
3140 root 1.54 const_iv (GL_REPLACE),
3141 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
3142 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
3143     const_iv (GL_PROJECTION),
3144     const_iv (GL_MODELVIEW),
3145     const_iv (GL_COLOR_LOGIC_OP),
3146 root 1.69 const_iv (GL_SEPARABLE_2D),
3147 root 1.54 const_iv (GL_CONVOLUTION_2D),
3148     const_iv (GL_CONVOLUTION_BORDER_MODE),
3149     const_iv (GL_CONSTANT_BORDER),
3150 root 1.208 const_iv (GL_POINTS),
3151 root 1.54 const_iv (GL_LINES),
3152 root 1.138 const_iv (GL_LINE_STRIP),
3153 root 1.89 const_iv (GL_LINE_LOOP),
3154 root 1.54 const_iv (GL_QUADS),
3155 root 1.89 const_iv (GL_QUAD_STRIP),
3156     const_iv (GL_TRIANGLES),
3157     const_iv (GL_TRIANGLE_STRIP),
3158     const_iv (GL_TRIANGLE_FAN),
3159 root 1.208 const_iv (GL_POLYGON),
3160 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
3161 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
3162     const_iv (GL_LINE_SMOOTH_HINT),
3163     const_iv (GL_POLYGON_SMOOTH_HINT),
3164     const_iv (GL_GENERATE_MIPMAP_HINT),
3165 root 1.232 const_iv (GL_TEXTURE_COMPRESSION_HINT),
3166 root 1.54 const_iv (GL_FASTEST),
3167 root 1.206 const_iv (GL_DONT_CARE),
3168     const_iv (GL_NICEST),
3169 root 1.89 const_iv (GL_V2F),
3170     const_iv (GL_V3F),
3171     const_iv (GL_T2F_V3F),
3172     const_iv (GL_T2F_N3F_V3F),
3173 root 1.291 const_iv (GL_FUNC_ADD),
3174     const_iv (GL_FUNC_SUBTRACT),
3175     const_iv (GL_FUNC_REVERSE_SUBTRACT),
3176 root 1.54 # undef const_iv
3177     };
3178    
3179 root 1.308 for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ > const_iv; civ--)
3180     newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
3181 root 1.188
3182     texture_av = newAV ();
3183     AvREAL_off (texture_av);
3184 root 1.54 }
3185    
3186 root 1.231 void
3187     disable_GL_EXT_blend_func_separate ()
3188     CODE:
3189     gl.BlendFuncSeparate = 0;
3190     gl.BlendFuncSeparateEXT = 0;
3191    
3192 root 1.291 void
3193     apple_nvidia_bug (int enable)
3194    
3195 root 1.319 const char *
3196 root 1.97 gl_vendor ()
3197     CODE:
3198 root 1.319 RETVAL = (const char *)glGetString (GL_VENDOR);
3199 root 1.97 OUTPUT:
3200     RETVAL
3201    
3202 root 1.319 const char *
3203 root 1.97 gl_version ()
3204     CODE:
3205 root 1.319 RETVAL = (const char *)glGetString (GL_VERSION);
3206 root 1.97 OUTPUT:
3207     RETVAL
3208    
3209 root 1.319 const char *
3210 root 1.97 gl_extensions ()
3211     CODE:
3212 root 1.319 RETVAL = (const char *)glGetString (GL_EXTENSIONS);
3213 root 1.97 OUTPUT:
3214     RETVAL
3215    
3216 root 1.201 const char *glGetString (GLenum pname)
3217 root 1.319 CODE:
3218     RETVAL = (const char *)glGetString (pname);
3219     OUTPUT:
3220     RETVAL
3221 root 1.199
3222     GLint glGetInteger (GLenum pname)
3223     CODE:
3224     glGetIntegerv (pname, &RETVAL);
3225     OUTPUT:
3226     RETVAL
3227    
3228     GLdouble glGetDouble (GLenum pname)
3229     CODE:
3230     glGetDoublev (pname, &RETVAL);
3231     OUTPUT:
3232     RETVAL
3233    
3234 root 1.54 int glGetError ()
3235    
3236 root 1.114 void glFinish ()
3237    
3238 root 1.304 void glFlush ()
3239    
3240 root 1.54 void glClear (int mask)
3241    
3242     void glClearColor (float r, float g, float b, float a = 1.0)
3243     PROTOTYPE: @
3244    
3245     void glEnable (int cap)
3246    
3247     void glDisable (int cap)
3248    
3249     void glShadeModel (int mode)
3250    
3251     void glHint (int target, int mode)
3252    
3253     void glBlendFunc (int sfactor, int dfactor)
3254    
3255 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
3256     CODE:
3257     gl_BlendFuncSeparate (sa, da, saa, daa);
3258    
3259 root 1.292 # void glBlendEquation (int se)
3260 root 1.291
3261 root 1.89 void glDepthMask (int flag)
3262    
3263 root 1.54 void glLogicOp (int opcode)
3264    
3265 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
3266    
3267 root 1.54 void glMatrixMode (int mode)
3268    
3269     void glPushMatrix ()
3270    
3271     void glPopMatrix ()
3272    
3273     void glLoadIdentity ()
3274    
3275 root 1.119 void glDrawBuffer (int buffer)
3276    
3277     void glReadBuffer (int buffer)
3278    
3279 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
3280     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
3281    
3282     # near_ and far_ are due to microsofts buggy "c" compiler
3283 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
3284 root 1.54
3285 root 1.208 PROTOTYPES: DISABLE
3286    
3287 root 1.54 void glViewport (int x, int y, int width, int height)
3288    
3289 root 1.69 void glScissor (int x, int y, int width, int height)
3290    
3291 root 1.54 void glTranslate (float x, float y, float z = 0.)
3292     CODE:
3293     glTranslatef (x, y, z);
3294    
3295 root 1.62 void glScale (float x, float y, float z = 1.)
3296 root 1.54 CODE:
3297     glScalef (x, y, z);
3298    
3299     void glRotate (float angle, float x, float y, float z)
3300     CODE:
3301     glRotatef (angle, x, y, z);
3302    
3303     void glColor (float r, float g, float b, float a = 1.0)
3304 root 1.278 PROTOTYPE: @
3305 root 1.103 ALIAS:
3306     glColor_premultiply = 1
3307 root 1.54 CODE:
3308 root 1.103 if (ix)
3309     {
3310     r *= a;
3311     g *= a;
3312     b *= a;
3313     }
3314 root 1.90 // microsoft visual "c" rounds instead of truncating...
3315 root 1.130 glColor4f (r, g, b, a);
3316 root 1.54
3317 root 1.91 void glRasterPos (float x, float y, float z = 0.)
3318     CODE:
3319     glRasterPos3f (0, 0, z);
3320     glBitmap (0, 0, 0, 0, x, y, 0);
3321    
3322 root 1.54 void glVertex (float x, float y, float z = 0.)
3323     CODE:
3324     glVertex3f (x, y, z);
3325    
3326     void glTexCoord (float s, float t)
3327     CODE:
3328     glTexCoord2f (s, t);
3329    
3330 root 1.210 void glRect (float x1, float y1, float x2, float y2)
3331     CODE:
3332     glRectf (x1, y1, x2, y2);
3333    
3334 root 1.233 void glRect_lineloop (float x1, float y1, float x2, float y2)
3335     CODE:
3336     glBegin (GL_LINE_LOOP);
3337     glVertex2f (x1, y1);
3338     glVertex2f (x2, y1);
3339     glVertex2f (x2, y2);
3340     glVertex2f (x1, y2);
3341     glEnd ();
3342    
3343 root 1.208 PROTOTYPES: ENABLE
3344    
3345     void glBegin (int mode)
3346    
3347     void glEnd ()
3348    
3349     void glPointSize (GLfloat size)
3350    
3351     void glLineWidth (GLfloat width)
3352    
3353     void glInterleavedArrays (int format, int stride, char *data)
3354    
3355     void glDrawElements (int mode, int count, int type, char *indices)
3356    
3357     # 1.2 void glDrawRangeElements (int mode, int start, int end
3358    
3359 root 1.54 void glTexEnv (int target, int pname, float param)
3360     CODE:
3361     glTexEnvf (target, pname, param);
3362    
3363     void glTexParameter (int target, int pname, float param)
3364     CODE:
3365     glTexParameterf (target, pname, param);
3366    
3367     void glBindTexture (int target, int name)
3368    
3369     void glConvolutionParameter (int target, int pname, float params)
3370     CODE:
3371 root 1.103 if (gl.ConvolutionParameterf)
3372     gl.ConvolutionParameterf (target, pname, params);
3373 root 1.54
3374     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
3375 root 1.64 CODE:
3376 root 1.103 if (gl.ConvolutionFilter2D)
3377     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
3378 root 1.54
3379 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
3380     CODE:
3381 root 1.103 if (gl.SeparableFilter2D)
3382     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
3383 root 1.69
3384 root 1.244 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data = 0)
3385 root 1.54
3386     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
3387    
3388 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
3389 root 1.68
3390 root 1.199 void glPixelZoom (float x, float y)
3391    
3392 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
3393    
3394 root 1.54 int glGenTexture ()
3395     CODE:
3396 root 1.192 RETVAL = gen_texture ();
3397 root 1.54 OUTPUT:
3398     RETVAL
3399    
3400     void glDeleteTexture (int name)
3401     CODE:
3402 root 1.192 del_texture (name);
3403    
3404 root 1.54 int glGenList ()
3405     CODE:
3406     RETVAL = glGenLists (1);
3407     OUTPUT:
3408     RETVAL
3409    
3410     void glDeleteList (int list)
3411     CODE:
3412     glDeleteLists (list, 1);
3413    
3414     void glNewList (int list, int mode = GL_COMPILE)
3415    
3416     void glEndList ()
3417    
3418     void glCallList (int list)
3419    
3420 root 1.296 void c_init ()
3421     CODE:
3422     glPixelStorei (GL_PACK_ALIGNMENT , 1);
3423     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
3424    
3425 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::UI::Base
3426 root 1.207
3427     PROTOTYPES: DISABLE
3428    
3429     void
3430 root 1.209 find_widget (SV *self, NV x, NV y)
3431 root 1.207 PPCODE:
3432     {
3433 root 1.321 if (within_widget (self, x, y))
3434 root 1.209 XPUSHs (self);
3435     }
3436    
3437     BOOT:
3438     {
3439 root 1.242 hover_gv = gv_fetchpv ("DC::UI::HOVER", 1, SVt_NV);
3440 root 1.209
3441 root 1.242 draw_x_gv = gv_fetchpv ("DC::UI::Base::draw_x", 1, SVt_NV);
3442     draw_y_gv = gv_fetchpv ("DC::UI::Base::draw_y", 1, SVt_NV);
3443     draw_w_gv = gv_fetchpv ("DC::UI::Base::draw_w", 1, SVt_NV);
3444     draw_h_gv = gv_fetchpv ("DC::UI::Base::draw_h", 1, SVt_NV);
3445 root 1.209 }
3446    
3447     void
3448     draw (SV *self)
3449     CODE:
3450     {
3451 root 1.321 HV *hv;
3452     SV **svp;
3453 root 1.209 NV x, y, w, h;
3454     SV *draw_x_sv = GvSV (draw_x_gv);
3455     SV *draw_y_sv = GvSV (draw_y_gv);
3456     SV *draw_w_sv = GvSV (draw_w_gv);
3457     SV *draw_h_sv = GvSV (draw_h_gv);
3458 root 1.228 double draw_x, draw_y;
3459 root 1.209
3460     if (!SvROK (self))
3461 root 1.242 croak ("DC::Base::draw: %s not a reference", SvPV_nolen (self));
3462 root 1.209
3463     hv = (HV *)SvRV (self);
3464    
3465     if (SvTYPE (hv) != SVt_PVHV)
3466 root 1.242 croak ("DC::Base::draw: %s not a hashref", SvPV_nolen (self));
3467 root 1.209
3468     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
3469     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
3470    
3471     if (!h || !w)
3472     XSRETURN_EMPTY;
3473    
3474     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
3475     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
3476    
3477     draw_x = SvNV (draw_x_sv) + x;
3478     draw_y = SvNV (draw_y_sv) + y;
3479    
3480     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
3481     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
3482     XSRETURN_EMPTY;
3483    
3484     sv_setnv (draw_x_sv, draw_x);
3485     sv_setnv (draw_y_sv, draw_y);
3486    
3487     glPushMatrix ();
3488     glTranslated (x, y, 0);
3489    
3490     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
3491     {
3492     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
3493    
3494     if (svp && SvTRUE (*svp))
3495     {
3496 root 1.228 glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f);
3497 root 1.209 glEnable (GL_BLEND);
3498     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3499     glBegin (GL_QUADS);
3500     glVertex2f (0, 0);
3501     glVertex2f (w, 0);
3502     glVertex2f (w, h);
3503     glVertex2f (0, h);
3504     glEnd ();
3505     glDisable (GL_BLEND);
3506     }
3507     }
3508     #if 0
3509 root 1.234 // draw borders, for debugging
3510     glPushMatrix ();
3511     glColor4f (1., 1., 0., 1.);
3512     glTranslatef (.5, .5, 0.);
3513     glBegin (GL_LINE_LOOP);
3514     glVertex2f (0 , 0);
3515     glVertex2f (w - 1, 0);
3516     glVertex2f (w - 1, h - 1);
3517     glVertex2f (0 , h - 1);
3518     glEnd ();
3519     glPopMatrix ();
3520 root 1.209 #endif
3521     PUSHMARK (SP);
3522     XPUSHs (self);
3523     PUTBACK;
3524     call_method ("_draw", G_VOID | G_DISCARD);
3525     SPAGAIN;
3526    
3527     glPopMatrix ();
3528    
3529     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
3530     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
3531 root 1.207 }
3532