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