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