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