ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.312
Committed: Thu Dec 29 07:13:44 2011 UTC (12 years, 4 months ago) by root
Branch: MAIN
Changes since 1.311: +2 -1 lines
Log Message:
*** empty log message ***

File Contents

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