ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.321
Committed: Sun Nov 18 01:15:04 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.320: +12 -11 lines
Log Message:
editorial

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