ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.308
Committed: Fri Jul 29 08:35:35 2011 UTC (12 years, 9 months ago) by root
Branch: MAIN
Changes since 1.307: +4 -4 lines
Log Message:
avoid triggering undefined behaviour

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