ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.320
Committed: Sun Nov 18 01:00:10 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.319: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

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