ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.311
Committed: Tue Dec 27 09:17:27 2011 UTC (12 years, 4 months ago) by root
Branch: MAIN
Changes since 1.310: +8 -1 lines
Log Message:
*** empty log message ***

File Contents

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