ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.315
Committed: Wed Jan 18 23:34:44 2012 UTC (12 years, 3 months ago) by root
Branch: MAIN
Changes since 1.314: +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     {
1498     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.242 map1a_update (DC::Map self, SV *data_, int extmap)
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     if (extmap)
2069     {
2070     uint8_t ext, cmd;
2071    
2072     do
2073     {
2074     ext = *data++;
2075 root 1.261 cmd = ext & 0x7f;
2076 root 1.141
2077 root 1.147 if (cmd < 4)
2078 root 1.296 cell->darkness = 255 - ext * 64 + 1; /* make sure this doesn't collide with FOW_DARKNESS */
2079 root 1.147 else if (cmd == 5) // health
2080     {
2081     cell->stat_width = 1;
2082     cell->stat_hp = *data++;
2083     }
2084     else if (cmd == 6) // monster width
2085     cell->stat_width = *data++ + 1;
2086 root 1.169 else if (cmd == 0x47)
2087 root 1.153 {
2088 root 1.261 if (*data == 1) cell->player = data [1];
2089     else if (*data == 2) cell->player = data [2] + (data [1] << 8);
2090     else if (*data == 3) cell->player = data [3] + (data [2] << 8) + (data [1] << 16);
2091     else if (*data == 4) cell->player = data [4] + (data [3] << 8) + (data [2] << 16) + (data [1] << 24);
2092 root 1.153
2093     data += *data + 1;
2094     }
2095     else if (cmd == 8) // cell flags
2096     cell->flags = *data++;
2097 root 1.144 else if (ext & 0x40) // unknown, multibyte => skip
2098     data += *data + 1;
2099 root 1.147 else
2100     data++;
2101 root 1.141 }
2102 root 1.147 while (ext & 0x80);
2103 root 1.141 }
2104     else
2105 root 1.142 cell->darkness = *data++ + 1;
2106 root 1.141 }
2107 root 1.29
2108 root 1.221 for (z = 0; z <= 2; ++z)
2109     if (flags & (4 >> z))
2110     {
2111     faceid face = (data [0] << 8) + data [1]; data += 2;
2112     need_facenum (self, face);
2113     cell->tile [z] = self->face2tile [face];
2114 root 1.29
2115 root 1.221 if (cell->tile [z])
2116     {
2117     maptex *tex = self->tex + cell->tile [z];
2118 root 1.280 tex->unused = 0;
2119 root 1.221 if (!tex->name)
2120     av_push (missing, newSViv (cell->tile [z]));
2121 root 1.29
2122 root 1.221 if (tex->smoothtile)
2123     {
2124     maptex *smooth = self->tex + tex->smoothtile;
2125 root 1.280 smooth->unused = 0;
2126 root 1.221 if (!smooth->name)
2127     av_push (missing, newSViv (tex->smoothtile));
2128     }
2129     }
2130     }
2131 root 1.29 }
2132     else
2133 root 1.267 CELL_CLEAR (cell);
2134 root 1.29 }
2135 root 1.28 }
2136 root 1.221 OUTPUT:
2137     RETVAL
2138 root 1.28
2139 root 1.40 SV *
2140 root 1.242 mapmap (DC::Map self, int x0, int y0, int w, int h)
2141 root 1.40 CODE:
2142     {
2143 root 1.55 int x1, x;
2144     int y1, y;
2145 root 1.40 int z;
2146     SV *map_sv = newSV (w * h * sizeof (uint32_t));
2147     uint32_t *map = (uint32_t *)SvPVX (map_sv);
2148    
2149     SvPOK_only (map_sv);
2150     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
2151    
2152 root 1.55 x0 += self->x; x1 = x0 + w;
2153     y0 += self->y; y1 = y0 + h;
2154 root 1.40
2155     for (y = y0; y < y1; y++)
2156     {
2157     maprow *row = 0 <= y && y < self->rows
2158     ? self->row + y
2159     : 0;
2160    
2161     for (x = x0; x < x1; x++)
2162     {
2163 root 1.306 unsigned int r = 32, g = 32, b = 32, a = 192;
2164 root 1.40
2165     if (row && row->c0 <= x && x < row->c1)
2166     {
2167     mapcell *cell = row->col + (x - row->c0);
2168    
2169     for (z = 0; z <= 0; z++)
2170     {
2171 root 1.174 maptex tex = self->tex [cell->tile [z]];
2172     int a0 = 255 - tex.a;
2173     int a1 = tex.a;
2174    
2175 root 1.306 r = div255 (r * a0 + tex.r * a1);
2176     g = div255 (g * a0 + tex.g * a1);
2177     b = div255 (b * a0 + tex.b * a1);
2178     a = div255 (a * a0 + tex.a * a1);
2179 root 1.40 }
2180     }
2181    
2182     *map++ = (r )
2183     | (g << 8)
2184     | (b << 16)
2185     | (a << 24);
2186     }
2187     }
2188    
2189     RETVAL = map_sv;
2190     }
2191     OUTPUT:
2192     RETVAL
2193    
2194 root 1.221 void
2195 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)
2196 root 1.116 CODE:
2197 root 1.30 {
2198 root 1.223 int x, y, z;
2199    
2200 root 1.176 HV *smooth = (HV *)sv_2mortal ((SV *)newHV ());
2201     uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level
2202 root 1.226 static uint8_t smooth_max[256][256]; // egad, fast and wasteful on memory (64k)
2203 root 1.176 smooth_key skey;
2204 root 1.261 int pl_x, pl_y;
2205     maptex pl_tex;
2206 root 1.285 rc_t *rc = rc_alloc ();
2207     rc_t *rc_ov = rc_alloc ();
2208 root 1.223 rc_key_t key;
2209 root 1.297 rc_array_t *arr;
2210 root 1.48
2211 root 1.262 pl_tex.name = 0;
2212    
2213 pippijn 1.288 // that's current max. sorry.
2214 root 1.176 if (sw > 255) sw = 255;
2215     if (sh > 255) sh = 255;
2216    
2217     // clear key, in case of extra padding
2218     memset (&skey, 0, sizeof (skey));
2219    
2220 root 1.223 memset (&key, 0, sizeof (key));
2221     key.r = 255;
2222     key.g = 255;
2223     key.b = 255;
2224     key.a = 255;
2225     key.mode = GL_QUADS;
2226     key.format = GL_T2F_V3F;
2227 root 1.30
2228 root 1.164 mx += self->x;
2229     my += self->y;
2230    
2231 root 1.176 // first pass: determine smooth_max
2232     // rather ugly, if you ask me
2233     // could also be stored inside mapcell and updated on change
2234     memset (smooth_max, 0, sizeof (smooth_max));
2235    
2236     for (y = 0; y < sh; y++)
2237     if (0 <= y + my && y + my < self->rows)
2238     {
2239     maprow *row = self->row + (y + my);
2240    
2241     for (x = 0; x < sw; x++)
2242     if (row->c0 <= x + mx && x + mx < row->c1)
2243     {
2244     mapcell *cell = row->col + (x + mx - row->c0);
2245    
2246 root 1.177 smooth_max[x + 1][y + 1] =
2247     MAX (self->tex [cell->tile [0]].smoothlevel,
2248     MAX (self->tex [cell->tile [1]].smoothlevel,
2249     self->tex [cell->tile [2]].smoothlevel));
2250 root 1.176 }
2251     }
2252    
2253 root 1.223 glEnable (GL_BLEND);
2254     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2255     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2256    
2257 root 1.176 for (z = 0; z <= 2; z++)
2258     {
2259 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
2260 root 1.283 key.texname = -1;
2261 root 1.186
2262 root 1.176 for (y = 0; y < sh; y++)
2263     if (0 <= y + my && y + my < self->rows)
2264     {
2265     maprow *row = self->row + (y + my);
2266    
2267     for (x = 0; x < sw; x++)
2268     if (row->c0 <= x + mx && x + mx < row->c1)
2269     {
2270     mapcell *cell = row->col + (x + mx - row->c0);
2271     tileid tile = cell->tile [z];
2272    
2273     if (tile)
2274     {
2275     maptex tex = self->tex [tile];
2276 root 1.285 int px, py;
2277 root 1.176
2278 root 1.223 if (key.texname != tex.name)
2279 root 1.176 {
2280 root 1.280 self->tex [tile].unused = 0;
2281    
2282 root 1.176 if (!tex.name)
2283 root 1.285 tex = self->tex [TEXID_NOFACE]; /* missing, replace by noface */
2284 root 1.176
2285 root 1.223 key.texname = tex.name;
2286     arr = rc_array (rc, &key);
2287 root 1.176 }
2288    
2289 root 1.306 px = (x + 1) * Th - tex.w;
2290     py = (y + 1) * Tw - tex.h;
2291 root 1.285
2292 root 1.261 if (expect_false (cell->player == player) && expect_false (z == 2))
2293     {
2294     pl_x = px;
2295     pl_y = py;
2296     pl_tex = tex;
2297     continue;
2298     }
2299 root 1.219
2300 root 1.223 rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2301     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
2302     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
2303     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
2304 root 1.176
2305     // update smooth hash
2306     if (tex.smoothtile)
2307     {
2308     skey.tile = tex.smoothtile;
2309     skey.level = tex.smoothlevel;
2310    
2311     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
2312 root 1.30
2313 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
2314     // shifted +1|+1 so we always stay positive.
2315 root 1.30
2316 root 1.180 // bits is ___n cccc CCCC bbbb
2317     // n do not draw borders&corners
2318     // c draw these corners, but...
2319     // C ... not these
2320     // b draw these borders
2321    
2322     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
2323     // ┃· ·· ·┃ ━━
2324    
2325     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
2326     // ·· ·· ·┏ ┓·
2327    
2328 root 1.176 // full tile
2329     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
2330    
2331     // borders
2332 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
2333     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
2334 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
2335     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
2336    
2337     // corners
2338     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
2339     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
2340     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
2341     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
2342     }
2343     }
2344 root 1.285
2345 root 1.296 if (expect_false (z == 2) && expect_false (cell->flags))
2346 root 1.285 {
2347 root 1.296 // overlays such as the speech bubble, probably more to come
2348     if (cell->flags & 1)
2349 root 1.285 {
2350 root 1.296 rc_key_t key_ov = key;
2351     maptex tex = self->tex [TEXID_SPEECH];
2352     rc_array_t *arr;
2353 root 1.306 int px = x * Tw + Tw * 2 / 32;
2354     int py = y * Th - Th * 6 / 32;
2355 root 1.296
2356     key_ov.texname = tex.name;
2357     arr = rc_array (rc_ov, &key_ov);
2358    
2359 root 1.306 rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2360     rc_t2f_v3f (arr, 0 , tex.t, px , py + Th, 0);
2361     rc_t2f_v3f (arr, tex.s, tex.t, px + Tw, py + Th, 0);
2362     rc_t2f_v3f (arr, tex.s, 0 , px + Tw, py , 0);
2363 root 1.285 }
2364     }
2365 root 1.176 }
2366     }
2367 root 1.174
2368 root 1.224 rc_draw (rc);
2369     rc_clear (rc);
2370    
2371 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
2372     // this is basically counting sort
2373 root 1.176 {
2374 root 1.186 int w, b;
2375 root 1.30
2376 root 1.226 glEnable (GL_TEXTURE_2D);
2377     glBegin (GL_QUADS);
2378 root 1.186 for (w = 0; w < 256 / 32; ++w)
2379     {
2380     uint32_t smask = smooth_level [w];
2381     if (smask)
2382     for (b = 0; b < 32; ++b)
2383     if (smask & (((uint32_t)1) << b))
2384 root 1.176 {
2385 root 1.186 int level = (w << 5) | b;
2386     HE *he;
2387 root 1.153
2388 root 1.186 hv_iterinit (smooth);
2389     while ((he = hv_iternext (smooth)))
2390 root 1.153 {
2391 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
2392     IV bits = SvIVX (HeVAL (he));
2393 root 1.176
2394 root 1.186 if (!(bits & 0x1000)
2395     && skey->level == level
2396 root 1.191 && level > smooth_max [skey->x][skey->y])
2397 root 1.174 {
2398 root 1.186 maptex tex = self->tex [skey->tile];
2399 root 1.306 int px = (((int)skey->x) - 1) * Tw;
2400     int py = (((int)skey->y) - 1) * Th;
2401 root 1.186 int border = bits & 15;
2402     int corner = (bits >> 8) & ~(bits >> 4) & 15;
2403     float dx = tex.s * .0625f; // 16 images/row
2404     float dy = tex.t * .5f ; // 2 images/column
2405    
2406 root 1.223 if (tex.name)
2407 root 1.186 {
2408 root 1.223 // this time avoiding texture state changes
2409     // save gobs of state changes.
2410     if (key.texname != tex.name)
2411     {
2412 root 1.280 self->tex [skey->tile].unused = 0;
2413    
2414 root 1.226 glEnd ();
2415     glBindTexture (GL_TEXTURE_2D, key.texname = tex.name);
2416     glBegin (GL_QUADS);
2417 root 1.223 }
2418    
2419     if (border)
2420     {
2421     float ox = border * dx;
2422    
2423 root 1.306 glTexCoord2f (ox , 0.f ); glVertex2i (px , py );
2424     glTexCoord2f (ox , dy ); glVertex2i (px , py + Th);
2425     glTexCoord2f (ox + dx, dy ); glVertex2i (px + Tw, py + Th);
2426     glTexCoord2f (ox + dx, 0.f ); glVertex2i (px + Tw, py );
2427 root 1.223 }
2428    
2429     if (corner)
2430     {
2431     float ox = corner * dx;
2432    
2433 root 1.306 glTexCoord2f (ox , dy ); glVertex2i (px , py );
2434     glTexCoord2f (ox , dy * 2.f); glVertex2i (px , py + Th);
2435     glTexCoord2f (ox + dx, dy * 2.f); glVertex2i (px + Tw, py + Th);
2436     glTexCoord2f (ox + dx, dy ); glVertex2i (px + Tw, py );
2437 root 1.223 }
2438 root 1.186 }
2439 root 1.174 }
2440 root 1.153 }
2441     }
2442 root 1.186 }
2443 root 1.226
2444     glEnd ();
2445     glDisable (GL_TEXTURE_2D);
2446     key.texname = -1;
2447 root 1.176 }
2448    
2449 root 1.186 hv_clear (smooth);
2450     }
2451 root 1.30
2452 root 1.261 if (pl_tex.name)
2453     {
2454     maptex tex = pl_tex;
2455 root 1.266 int px = pl_x + sdx;
2456     int py = pl_y + sdy;
2457 root 1.261
2458     key.texname = tex.name;
2459     arr = rc_array (rc, &key);
2460    
2461     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2462     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
2463     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
2464     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
2465    
2466     rc_draw (rc);
2467     }
2468    
2469 root 1.285 rc_draw (rc_ov);
2470     rc_clear (rc_ov);
2471    
2472 root 1.152 glDisable (GL_BLEND);
2473 root 1.223 rc_free (rc);
2474 root 1.285 rc_free (rc_ov);
2475 root 1.143
2476 root 1.145 // top layer: overlays such as the health bar
2477 root 1.143 for (y = 0; y < sh; y++)
2478 root 1.164 if (0 <= y + my && y + my < self->rows)
2479 root 1.143 {
2480 root 1.164 maprow *row = self->row + (y + my);
2481 root 1.143
2482     for (x = 0; x < sw; x++)
2483 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2484 root 1.143 {
2485 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2486 root 1.143
2487 root 1.306 int px = x * Tw;
2488     int py = y * Th;
2489 root 1.143
2490 root 1.279 if (expect_false (cell->player == player))
2491     {
2492     px += sdx;
2493     py += sdy;
2494     }
2495    
2496 root 1.143 if (cell->stat_hp)
2497     {
2498 root 1.306 int width = cell->stat_width * Tw;
2499     int thick = (sh * Th / 32 + 27) / 28 + 1 + cell->stat_width;
2500 root 1.143
2501 root 1.152 glColor3ub (0, 0, 0);
2502 root 1.151 glRectf (px + 1, py - thick - 2,
2503     px + width - 1, py);
2504 root 1.147
2505 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
2506 root 1.147 glRectf (px + 2,
2507 root 1.151 py - thick - 1,
2508     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
2509 root 1.143 }
2510     }
2511     }
2512 root 1.116 }
2513    
2514     void
2515 root 1.295 draw_magicmap (DC::Map self, int w, int h, unsigned char *data)
2516 root 1.117 CODE:
2517     {
2518     static float color[16][3] = {
2519 root 1.295 { 0.00f, 0.00f, 0.00f },
2520     { 1.00f, 1.00f, 1.00f },
2521     { 0.00f, 0.00f, 0.55f },
2522     { 1.00f, 0.00f, 0.00f },
2523    
2524     { 1.00f, 0.54f, 0.00f },
2525     { 0.11f, 0.56f, 1.00f },
2526     { 0.93f, 0.46f, 0.00f },
2527     { 0.18f, 0.54f, 0.34f },
2528    
2529     { 0.56f, 0.73f, 0.56f },
2530     { 0.80f, 0.80f, 0.80f },
2531     { 0.55f, 0.41f, 0.13f },
2532     { 0.99f, 0.77f, 0.26f },
2533    
2534     { 0.74f, 0.65f, 0.41f },
2535    
2536     { 0.00f, 1.00f, 1.00f },
2537     { 1.00f, 0.00f, 1.00f },
2538     { 1.00f, 1.00f, 0.00f },
2539 root 1.117 };
2540    
2541     int x, y;
2542    
2543     glEnable (GL_TEXTURE_2D);
2544 root 1.290 /* GL_REPLACE would be correct, as we don't need to modulate alpha,
2545     * but the nvidia driver (185.18.14) mishandles alpha textures
2546 root 1.296 * and takes the colour from god knows where instead of using
2547 root 1.290 * Cp. MODULATE results in the same colour, but slightly different
2548     * alpha, but atcually gives us the correct colour with nvidia.
2549     */
2550     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2551 root 1.117 glEnable (GL_BLEND);
2552     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2553     glBegin (GL_QUADS);
2554    
2555     for (y = 0; y < h; y++)
2556     for (x = 0; x < w; x++)
2557     {
2558     unsigned char m = data [x + y * w];
2559    
2560 root 1.118 if (m)
2561     {
2562     float *c = color [m & 15];
2563    
2564 root 1.295 float tx1 = m & 0x40 ? 0.5f : 0.f;
2565     float tx2 = tx1 + 0.5f;
2566 root 1.118
2567 root 1.290 glColor4f (c[0], c[1], c[2], 1);
2568 root 1.118 glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2569     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2570     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2571     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2572     }
2573 root 1.117 }
2574    
2575     glEnd ();
2576     glDisable (GL_BLEND);
2577     glDisable (GL_TEXTURE_2D);
2578     }
2579    
2580     void
2581 root 1.242 fow_texture (DC::Map self, int mx, int my, int sw, int sh)
2582 root 1.116 PPCODE:
2583     {
2584     int x, y;
2585 root 1.296 int sw1 = sw + 2;
2586     int sh1 = sh + 2;
2587     int sh3 = sh * 3;
2588     int sw3 = sw * 3;
2589     SV *darkness3_sv = sv_2mortal (newSV (sw3 * sh3));
2590 root 1.204 uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2591 root 1.307 uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2592     memset (darkness1, 0, sw1*sh1);
2593 root 1.204
2594     SvPOK_only (darkness3_sv);
2595 root 1.296 SvCUR_set (darkness3_sv, sw3 * sh3);
2596 root 1.116
2597 root 1.204 mx += self->x - 1;
2598     my += self->y - 1;
2599 root 1.116
2600 root 1.204 for (y = 0; y < sh1; y++)
2601 root 1.164 if (0 <= y + my && y + my < self->rows)
2602 root 1.116 {
2603 root 1.164 maprow *row = self->row + (y + my);
2604 root 1.116
2605 root 1.204 for (x = 0; x < sw1; x++)
2606 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2607 root 1.116 {
2608 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2609 root 1.116
2610 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2611 root 1.294 ? DARKNESS_ADJUST (255 - (cell->darkness - 1))
2612     : DARKNESS_ADJUST (255 - FOW_DARKNESS);
2613 root 1.116 }
2614     }
2615 root 1.34
2616 root 1.204 for (y = 0; y < sh; ++y)
2617     for (x = 0; x < sw; ++x)
2618     {
2619     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2620     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2621     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2622     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2623     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2624     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2625     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2626     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2627     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2628    
2629     uint8_t r11 = (d11 + d21 + d12) / 3;
2630     uint8_t r21 = d21;
2631     uint8_t r31 = (d21 + d31 + d32) / 3;
2632    
2633     uint8_t r12 = d12;
2634     uint8_t r22 = d22;
2635     uint8_t r32 = d32;
2636    
2637     uint8_t r13 = (d13 + d23 + d12) / 3;
2638     uint8_t r23 = d23;
2639     uint8_t r33 = (d23 + d33 + d32) / 3;
2640    
2641 root 1.296 darkness3 [(y * 3 ) * sw3 + (x * 3 )] = MAX (d22, r11);
2642     darkness3 [(y * 3 ) * sw3 + (x * 3 + 1)] = MAX (d22, r21);
2643     darkness3 [(y * 3 ) * sw3 + (x * 3 + 2)] = MAX (d22, r31);
2644     darkness3 [(y * 3 + 1) * sw3 + (x * 3 )] = MAX (d22, r12);
2645     darkness3 [(y * 3 + 1) * sw3 + (x * 3 + 1)] = MAX (d22, r22); /* this MUST be == d22 */
2646     darkness3 [(y * 3 + 1) * sw3 + (x * 3 + 2)] = MAX (d22, r32);
2647     darkness3 [(y * 3 + 2) * sw3 + (x * 3 )] = MAX (d22, r13);
2648     darkness3 [(y * 3 + 2) * sw3 + (x * 3 + 1)] = MAX (d22, r23);
2649     darkness3 [(y * 3 + 2) * sw3 + (x * 3 + 2)] = MAX (d22, r33);
2650 root 1.204 }
2651 root 1.201
2652 root 1.204 free (darkness1);
2653 root 1.201
2654 root 1.32 EXTEND (SP, 3);
2655 root 1.296 PUSHs (sv_2mortal (newSViv (sw3)));
2656 root 1.204 PUSHs (sv_2mortal (newSViv (sh3)));
2657     PUSHs (darkness3_sv);
2658 root 1.30 }
2659    
2660 root 1.42 SV *
2661 root 1.242 get_rect (DC::Map self, int x0, int y0, int w, int h)
2662 root 1.42 CODE:
2663     {
2664     int x, y, x1, y1;
2665     SV *data_sv = newSV (w * h * 7 + 5);
2666     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2667    
2668     *data++ = 0; /* version 0 format */
2669     *data++ = w >> 8; *data++ = w;
2670     *data++ = h >> 8; *data++ = h;
2671    
2672     // we need to do this 'cause we don't keep an absolute coord system for rows
2673 root 1.55 // TODO: treat rows as we treat columns
2674 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2675     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2676    
2677     x0 += self->x - self->ox;
2678     y0 += self->y - self->oy;
2679    
2680     x1 = x0 + w;
2681     y1 = y0 + h;
2682    
2683     for (y = y0; y < y1; y++)
2684     {
2685     maprow *row = 0 <= y && y < self->rows
2686     ? self->row + y
2687     : 0;
2688    
2689     for (x = x0; x < x1; x++)
2690     {
2691     if (row && row->c0 <= x && x < row->c1)
2692     {
2693     mapcell *cell = row->col + (x - row->c0);
2694     uint8_t flags = 0;
2695    
2696 root 1.174 if (cell->tile [0]) flags |= 1;
2697     if (cell->tile [1]) flags |= 2;
2698     if (cell->tile [2]) flags |= 4;
2699 root 1.42
2700     *data++ = flags;
2701    
2702     if (flags & 1)
2703     {
2704 root 1.174 tileid tile = cell->tile [0];
2705     *data++ = tile >> 8;
2706     *data++ = tile;
2707 root 1.42 }
2708    
2709     if (flags & 2)
2710     {
2711 root 1.174 tileid tile = cell->tile [1];
2712     *data++ = tile >> 8;
2713     *data++ = tile;
2714 root 1.42 }
2715    
2716     if (flags & 4)
2717     {
2718 root 1.174 tileid tile = cell->tile [2];
2719     *data++ = tile >> 8;
2720     *data++ = tile;
2721 root 1.42 }
2722     }
2723     else
2724     *data++ = 0;
2725     }
2726     }
2727    
2728 root 1.260 /* if size is w*h + 5 then no data has been found */
2729     if (data - (uint8_t *)SvPVX (data_sv) != w * h + 5)
2730 root 1.259 {
2731     SvPOK_only (data_sv);
2732     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2733     }
2734 root 1.260
2735     RETVAL = data_sv;
2736 root 1.42 }
2737     OUTPUT:
2738     RETVAL
2739    
2740     void
2741 root 1.259 set_rect (DC::Map self, int x0, int y0, SV *data_sv)
2742 root 1.42 PPCODE:
2743     {
2744     int x, y, z;
2745 root 1.48 int w, h;
2746 root 1.42 int x1, y1;
2747 root 1.259 STRLEN len;
2748     uint8_t *data, *end;
2749    
2750     len = SvLEN (data_sv);
2751 root 1.260 SvGROW (data_sv, len + 8); // reserve at least 7+ bytes more
2752 root 1.259 data = SvPVbyte_nolen (data_sv);
2753 root 1.260 end = data + len + 8;
2754 root 1.259
2755     if (len < 5)
2756     XSRETURN_EMPTY;
2757 root 1.42
2758     if (*data++ != 0)
2759 root 1.227 XSRETURN_EMPTY; /* version mismatch */
2760 root 1.42
2761 root 1.48 w = *data++ << 8; w |= *data++;
2762     h = *data++ << 8; h |= *data++;
2763 root 1.42
2764     // we need to do this 'cause we don't keep an absolute coord system for rows
2765 root 1.55 // TODO: treat rows as we treat columns
2766 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2767     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2768    
2769     x0 += self->x - self->ox;
2770     y0 += self->y - self->oy;
2771    
2772     x1 = x0 + w;
2773     y1 = y0 + h;
2774    
2775     for (y = y0; y < y1; y++)
2776     {
2777     maprow *row = map_get_row (self, y);
2778    
2779     for (x = x0; x < x1; x++)
2780     {
2781 root 1.259 uint8_t flags;
2782    
2783     if (data + 7 >= end)
2784     XSRETURN_EMPTY;
2785    
2786     flags = *data++;
2787 root 1.42
2788     if (flags)
2789     {
2790     mapcell *cell = row_get_cell (row, x);
2791 root 1.174 tileid tile[3] = { 0, 0, 0 };
2792 root 1.42
2793 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2794     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2795     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2796 root 1.42
2797 root 1.143 if (cell->darkness == 0)
2798 root 1.42 {
2799 root 1.260 /*cell->darkness = 0;*/
2800     EXTEND (SP, 3);
2801 root 1.42
2802     for (z = 0; z <= 2; z++)
2803     {
2804 root 1.174 tileid t = tile [z];
2805    
2806 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2807 root 1.174 {
2808 root 1.260 PUSHs (sv_2mortal (newSViv (t)));
2809 root 1.174 need_texid (self, t);
2810     }
2811 root 1.42
2812 root 1.174 cell->tile [z] = t;
2813 root 1.42 }
2814     }
2815     }
2816     }
2817     }
2818     }
2819    
2820 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::RW
2821 root 1.205
2822 root 1.242 DC::RW
2823 root 1.211 new (SV *class, SV *data_sv)
2824     CODE:
2825     {
2826     STRLEN datalen;
2827     char *data = SvPVbyte (data_sv, datalen);
2828    
2829 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2830 root 1.211 }
2831     OUTPUT:
2832     RETVAL
2833    
2834 root 1.242 DC::RW
2835 root 1.212 new_from_file (SV *class, const char *path, const char *mode = "rb")
2836     CODE:
2837     RETVAL = SDL_RWFromFile (path, mode);
2838     OUTPUT:
2839     RETVAL
2840    
2841 root 1.218 # fails on win32:
2842 root 1.241 # dc.xs(2268) : error C2059: syntax error : '('
2843 root 1.218 #void
2844 root 1.242 #close (DC::RW self)
2845 root 1.218 # CODE:
2846     # (self->(close)) (self);
2847 root 1.212
2848 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Channel
2849 root 1.212
2850     PROTOTYPES: DISABLE
2851    
2852 root 1.242 DC::Channel
2853 root 1.215 find ()
2854     CODE:
2855     {
2856     RETVAL = Mix_GroupAvailable (-1);
2857    
2858     if (RETVAL < 0)
2859     {
2860     RETVAL = Mix_GroupOldest (-1);
2861    
2862     if (RETVAL < 0)
2863 root 1.302 {
2864     // happens sometimes, maybe it just stopped playing(?)
2865     RETVAL = Mix_GroupAvailable (-1);
2866 root 1.215
2867 root 1.302 if (RETVAL < 0)
2868     XSRETURN_UNDEF;
2869     }
2870     else
2871     Mix_HaltChannel (RETVAL);
2872 root 1.215 }
2873    
2874     Mix_UnregisterAllEffects (RETVAL);
2875     Mix_Volume (RETVAL, 128);
2876     }
2877     OUTPUT:
2878     RETVAL
2879    
2880 root 1.213 void
2881 root 1.242 halt (DC::Channel self)
2882 root 1.213 CODE:
2883     Mix_HaltChannel (self);
2884    
2885     void
2886 root 1.242 expire (DC::Channel self, int ticks = -1)
2887 root 1.213 CODE:
2888     Mix_ExpireChannel (self, ticks);
2889    
2890     void
2891 root 1.242 fade_out (DC::Channel self, int ticks = -1)
2892 root 1.213 CODE:
2893     Mix_FadeOutChannel (self, ticks);
2894    
2895 root 1.212 int
2896 root 1.242 volume (DC::Channel self, int volume)
2897 root 1.212 CODE:
2898 root 1.216 RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128));
2899 root 1.212 OUTPUT:
2900     RETVAL
2901    
2902 root 1.213 void
2903 root 1.242 unregister_all_effects (DC::Channel self)
2904 root 1.212 CODE:
2905 root 1.213 Mix_UnregisterAllEffects (self);
2906 root 1.212
2907 root 1.213 void
2908 root 1.242 set_panning (DC::Channel self, int left, int right)
2909 root 1.212 CODE:
2910 root 1.216 left = CLAMP (left , 0, 255);
2911     right = CLAMP (right, 0, 255);
2912 root 1.213 Mix_SetPanning (self, left, right);
2913 root 1.212
2914 root 1.213 void
2915 root 1.242 set_distance (DC::Channel self, int distance)
2916 root 1.212 CODE:
2917 root 1.216 Mix_SetDistance (self, CLAMP (distance, 0, 255));
2918 root 1.212
2919 root 1.213 void
2920 root 1.242 set_position (DC::Channel self, int angle, int distance)
2921 root 1.212 CODE:
2922 root 1.220
2923     void
2924 root 1.242 set_position_r (DC::Channel self, int dx, int dy, int maxdistance)
2925 root 1.220 CODE:
2926     {
2927     int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance));
2928 root 1.295 int angle = atan2f (dx, -dy) * 180.f / (float)M_PI + 360.f;
2929 root 1.216 Mix_SetPosition (self, angle, CLAMP (distance, 0, 255));
2930 root 1.220 }
2931 root 1.212
2932 root 1.213 void
2933 root 1.242 set_reverse_stereo (DC::Channel self, int flip)
2934 root 1.212 CODE:
2935 root 1.213 Mix_SetReverseStereo (self, flip);
2936 root 1.212
2937 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixChunk
2938 root 1.212
2939     PROTOTYPES: DISABLE
2940    
2941 root 1.301 void
2942     decoders ()
2943     PPCODE:
2944     #if SDL_MIXER_MAJOR_VERSION > 1 || SDL_MIXER_MINOR_VERSION > 2 || SDL_MIXER_PATCHLEVEL >= 10
2945     int i, num = Mix_GetNumChunkDecoders ();
2946     EXTEND (SP, num);
2947     for (i = 0; i < num; ++i)
2948     PUSHs (sv_2mortal (newSVpv (Mix_GetChunkDecoder (i), 0)));
2949     #else
2950     XPUSHs (sv_2mortal (newSVpv ("(sdl mixer too old)", 0)));
2951     #endif
2952    
2953 root 1.242 DC::MixChunk
2954     new (SV *class, DC::RW rwops)
2955 root 1.52 CODE:
2956 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2957 root 1.52 OUTPUT:
2958     RETVAL
2959    
2960     void
2961 root 1.242 DESTROY (DC::MixChunk self)
2962 root 1.52 CODE:
2963     Mix_FreeChunk (self);
2964    
2965     int
2966 root 1.242 volume (DC::MixChunk self, int volume = -1)
2967 root 1.52 CODE:
2968 root 1.216 if (items > 1)
2969     volume = CLAMP (volume, 0, 128);
2970 root 1.52 RETVAL = Mix_VolumeChunk (self, volume);
2971     OUTPUT:
2972     RETVAL
2973    
2974 root 1.242 DC::Channel
2975     play (DC::MixChunk self, DC::Channel channel = -1, int loops = 0, int ticks = -1)
2976 root 1.52 CODE:
2977 root 1.215 {
2978 root 1.52 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2979 root 1.215
2980     if (RETVAL < 0)
2981     XSRETURN_UNDEF;
2982    
2983     if (channel < 0)
2984     {
2985     Mix_UnregisterAllEffects (RETVAL);
2986     Mix_Volume (RETVAL, 128);
2987     }
2988     }
2989 root 1.52 OUTPUT:
2990     RETVAL
2991    
2992 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixMusic
2993 root 1.52
2994 root 1.301 void
2995     decoders ()
2996     PPCODE:
2997     #if SDL_MIXER_MAJOR_VERSION > 1 || SDL_MIXER_MINOR_VERSION > 2 || SDL_MIXER_PATCHLEVEL >= 10
2998     int i, num = Mix_GetNumMusicDecoders ();
2999     EXTEND (SP, num);
3000     for (i = 0; i < num; ++i)
3001     PUSHs (sv_2mortal (newSVpv (Mix_GetMusicDecoder (i), 0)));
3002     #else
3003     XPUSHs (sv_2mortal (newSVpv ("(sdl mixer too old)", 0)));
3004     #endif
3005    
3006 root 1.52 int
3007     volume (int volume = -1)
3008 root 1.205 PROTOTYPE: ;$
3009 root 1.52 CODE:
3010 root 1.216 if (items > 0)
3011     volume = CLAMP (volume, 0, 128);
3012 root 1.52 RETVAL = Mix_VolumeMusic (volume);
3013     OUTPUT:
3014     RETVAL
3015    
3016 root 1.213 void
3017 root 1.194 fade_out (int ms)
3018     CODE:
3019 root 1.213 Mix_FadeOutMusic (ms);
3020 root 1.194
3021 root 1.212 void
3022     halt ()
3023     CODE:
3024     Mix_HaltMusic ();
3025    
3026 root 1.301 int
3027     playing ()
3028     CODE:
3029     RETVAL = Mix_PlayingMusic ();
3030     OUTPUT:
3031     RETVAL
3032    
3033 root 1.242 DC::MixMusic
3034     new (SV *class, DC::RW rwops)
3035 root 1.52 CODE:
3036 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
3037 root 1.52 OUTPUT:
3038     RETVAL
3039    
3040     void
3041 root 1.242 DESTROY (DC::MixMusic self)
3042 root 1.52 CODE:
3043     Mix_FreeMusic (self);
3044    
3045     int
3046 root 1.242 play (DC::MixMusic self, int loops = -1)
3047 root 1.52 CODE:
3048     RETVAL = Mix_PlayMusic (self, loops);
3049     OUTPUT:
3050     RETVAL
3051    
3052 root 1.213 void
3053 root 1.242 fade_in_pos (DC::MixMusic self, int loops, int ms, double position)
3054 root 1.195 CODE:
3055 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
3056 root 1.195
3057 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::OpenGL
3058 root 1.54
3059 root 1.205 PROTOTYPES: ENABLE
3060    
3061 root 1.54 BOOT:
3062     {
3063 root 1.242 HV *stash = gv_stashpv ("DC::OpenGL", 1);
3064 root 1.54 static const struct {
3065     const char *name;
3066     IV iv;
3067     } *civ, const_iv[] = {
3068     # define const_iv(name) { # name, (IV)name }
3069 root 1.199 const_iv (GL_VENDOR),
3070     const_iv (GL_VERSION),
3071     const_iv (GL_EXTENSIONS),
3072 root 1.293 const_iv (GL_MAX_TEXTURE_UNITS),
3073 root 1.54 const_iv (GL_COLOR_MATERIAL),
3074     const_iv (GL_SMOOTH),
3075     const_iv (GL_FLAT),
3076 root 1.69 const_iv (GL_DITHER),
3077 root 1.54 const_iv (GL_BLEND),
3078 root 1.89 const_iv (GL_CULL_FACE),
3079 root 1.69 const_iv (GL_SCISSOR_TEST),
3080 root 1.89 const_iv (GL_DEPTH_TEST),
3081     const_iv (GL_ALPHA_TEST),
3082     const_iv (GL_NORMALIZE),
3083     const_iv (GL_RESCALE_NORMAL),
3084 root 1.119 const_iv (GL_FRONT),
3085     const_iv (GL_BACK),
3086 root 1.206 const_iv (GL_AUX0),
3087 root 1.54 const_iv (GL_AND),
3088 root 1.67 const_iv (GL_ONE),
3089     const_iv (GL_ZERO),
3090 root 1.54 const_iv (GL_SRC_ALPHA),
3091 root 1.104 const_iv (GL_DST_ALPHA),
3092 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
3093 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
3094 root 1.293 const_iv (GL_SRC_COLOR),
3095     const_iv (GL_DST_COLOR),
3096     const_iv (GL_ONE_MINUS_SRC_COLOR),
3097     const_iv (GL_ONE_MINUS_DST_COLOR),
3098 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
3099 root 1.54 const_iv (GL_RGB),
3100     const_iv (GL_RGBA),
3101 root 1.115 const_iv (GL_RGBA4),
3102     const_iv (GL_RGBA8),
3103     const_iv (GL_RGB5_A1),
3104 root 1.54 const_iv (GL_UNSIGNED_BYTE),
3105 root 1.89 const_iv (GL_UNSIGNED_SHORT),
3106     const_iv (GL_UNSIGNED_INT),
3107 root 1.54 const_iv (GL_ALPHA),
3108 root 1.86 const_iv (GL_INTENSITY),
3109 root 1.76 const_iv (GL_LUMINANCE),
3110 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
3111 root 1.54 const_iv (GL_FLOAT),
3112     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
3113 root 1.230 const_iv (GL_COMPRESSED_ALPHA_ARB),
3114     const_iv (GL_COMPRESSED_LUMINANCE_ARB),
3115     const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB),
3116     const_iv (GL_COMPRESSED_INTENSITY_ARB),
3117     const_iv (GL_COMPRESSED_RGB_ARB),
3118     const_iv (GL_COMPRESSED_RGBA_ARB),
3119 root 1.54 const_iv (GL_COMPILE),
3120 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
3121     const_iv (GL_PROXY_TEXTURE_2D),
3122 root 1.54 const_iv (GL_TEXTURE_1D),
3123     const_iv (GL_TEXTURE_2D),
3124     const_iv (GL_TEXTURE_ENV),
3125     const_iv (GL_TEXTURE_MAG_FILTER),
3126     const_iv (GL_TEXTURE_MIN_FILTER),
3127     const_iv (GL_TEXTURE_ENV_MODE),
3128     const_iv (GL_TEXTURE_WRAP_S),
3129     const_iv (GL_TEXTURE_WRAP_T),
3130 root 1.98 const_iv (GL_REPEAT),
3131 root 1.54 const_iv (GL_CLAMP),
3132 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
3133 root 1.54 const_iv (GL_NEAREST),
3134     const_iv (GL_LINEAR),
3135 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
3136     const_iv (GL_LINEAR_MIPMAP_NEAREST),
3137     const_iv (GL_NEAREST_MIPMAP_LINEAR),
3138     const_iv (GL_LINEAR_MIPMAP_LINEAR),
3139     const_iv (GL_GENERATE_MIPMAP),
3140 root 1.54 const_iv (GL_MODULATE),
3141 root 1.69 const_iv (GL_DECAL),
3142 root 1.54 const_iv (GL_REPLACE),
3143 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
3144 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
3145     const_iv (GL_PROJECTION),
3146     const_iv (GL_MODELVIEW),
3147     const_iv (GL_COLOR_LOGIC_OP),
3148 root 1.69 const_iv (GL_SEPARABLE_2D),
3149 root 1.54 const_iv (GL_CONVOLUTION_2D),
3150     const_iv (GL_CONVOLUTION_BORDER_MODE),
3151     const_iv (GL_CONSTANT_BORDER),
3152 root 1.208 const_iv (GL_POINTS),
3153 root 1.54 const_iv (GL_LINES),
3154 root 1.138 const_iv (GL_LINE_STRIP),
3155 root 1.89 const_iv (GL_LINE_LOOP),
3156 root 1.54 const_iv (GL_QUADS),
3157 root 1.89 const_iv (GL_QUAD_STRIP),
3158     const_iv (GL_TRIANGLES),
3159     const_iv (GL_TRIANGLE_STRIP),
3160     const_iv (GL_TRIANGLE_FAN),
3161 root 1.208 const_iv (GL_POLYGON),
3162 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
3163 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
3164     const_iv (GL_LINE_SMOOTH_HINT),
3165     const_iv (GL_POLYGON_SMOOTH_HINT),
3166     const_iv (GL_GENERATE_MIPMAP_HINT),
3167 root 1.232 const_iv (GL_TEXTURE_COMPRESSION_HINT),
3168 root 1.54 const_iv (GL_FASTEST),
3169 root 1.206 const_iv (GL_DONT_CARE),
3170     const_iv (GL_NICEST),
3171 root 1.89 const_iv (GL_V2F),
3172     const_iv (GL_V3F),
3173     const_iv (GL_T2F_V3F),
3174     const_iv (GL_T2F_N3F_V3F),
3175 root 1.291 const_iv (GL_FUNC_ADD),
3176     const_iv (GL_FUNC_SUBTRACT),
3177     const_iv (GL_FUNC_REVERSE_SUBTRACT),
3178 root 1.54 # undef const_iv
3179     };
3180    
3181 root 1.308 for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ > const_iv; civ--)
3182     newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
3183 root 1.188
3184     texture_av = newAV ();
3185     AvREAL_off (texture_av);
3186 root 1.54 }
3187    
3188 root 1.231 void
3189     disable_GL_EXT_blend_func_separate ()
3190     CODE:
3191     gl.BlendFuncSeparate = 0;
3192     gl.BlendFuncSeparateEXT = 0;
3193    
3194 root 1.291 void
3195     apple_nvidia_bug (int enable)
3196    
3197 root 1.97 char *
3198     gl_vendor ()
3199     CODE:
3200     RETVAL = (char *)glGetString (GL_VENDOR);
3201     OUTPUT:
3202     RETVAL
3203    
3204     char *
3205     gl_version ()
3206     CODE:
3207     RETVAL = (char *)glGetString (GL_VERSION);
3208     OUTPUT:
3209     RETVAL
3210    
3211     char *
3212     gl_extensions ()
3213     CODE:
3214     RETVAL = (char *)glGetString (GL_EXTENSIONS);
3215     OUTPUT:
3216     RETVAL
3217    
3218 root 1.201 const char *glGetString (GLenum pname)
3219 root 1.199
3220     GLint glGetInteger (GLenum pname)
3221     CODE:
3222     glGetIntegerv (pname, &RETVAL);
3223     OUTPUT:
3224     RETVAL
3225    
3226     GLdouble glGetDouble (GLenum pname)
3227     CODE:
3228     glGetDoublev (pname, &RETVAL);
3229     OUTPUT:
3230     RETVAL
3231    
3232 root 1.54 int glGetError ()
3233    
3234 root 1.114 void glFinish ()
3235    
3236 root 1.304 void glFlush ()
3237    
3238 root 1.54 void glClear (int mask)
3239    
3240     void glClearColor (float r, float g, float b, float a = 1.0)
3241     PROTOTYPE: @
3242    
3243     void glEnable (int cap)
3244    
3245     void glDisable (int cap)
3246    
3247     void glShadeModel (int mode)
3248    
3249     void glHint (int target, int mode)
3250    
3251     void glBlendFunc (int sfactor, int dfactor)
3252    
3253 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
3254     CODE:
3255     gl_BlendFuncSeparate (sa, da, saa, daa);
3256    
3257 root 1.292 # void glBlendEquation (int se)
3258 root 1.291
3259 root 1.89 void glDepthMask (int flag)
3260    
3261 root 1.54 void glLogicOp (int opcode)
3262    
3263 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
3264    
3265 root 1.54 void glMatrixMode (int mode)
3266    
3267     void glPushMatrix ()
3268    
3269     void glPopMatrix ()
3270    
3271     void glLoadIdentity ()
3272    
3273 root 1.119 void glDrawBuffer (int buffer)
3274    
3275     void glReadBuffer (int buffer)
3276    
3277 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
3278     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
3279    
3280     # near_ and far_ are due to microsofts buggy "c" compiler
3281 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
3282 root 1.54
3283 root 1.208 PROTOTYPES: DISABLE
3284    
3285 root 1.54 void glViewport (int x, int y, int width, int height)
3286    
3287 root 1.69 void glScissor (int x, int y, int width, int height)
3288    
3289 root 1.54 void glTranslate (float x, float y, float z = 0.)
3290     CODE:
3291     glTranslatef (x, y, z);
3292    
3293 root 1.62 void glScale (float x, float y, float z = 1.)
3294 root 1.54 CODE:
3295     glScalef (x, y, z);
3296    
3297     void glRotate (float angle, float x, float y, float z)
3298     CODE:
3299     glRotatef (angle, x, y, z);
3300    
3301     void glColor (float r, float g, float b, float a = 1.0)
3302 root 1.278 PROTOTYPE: @
3303 root 1.103 ALIAS:
3304     glColor_premultiply = 1
3305 root 1.54 CODE:
3306 root 1.103 if (ix)
3307     {
3308     r *= a;
3309     g *= a;
3310     b *= a;
3311     }
3312 root 1.90 // microsoft visual "c" rounds instead of truncating...
3313 root 1.130 glColor4f (r, g, b, a);
3314 root 1.54
3315 root 1.91 void glRasterPos (float x, float y, float z = 0.)
3316     CODE:
3317     glRasterPos3f (0, 0, z);
3318     glBitmap (0, 0, 0, 0, x, y, 0);
3319    
3320 root 1.54 void glVertex (float x, float y, float z = 0.)
3321     CODE:
3322     glVertex3f (x, y, z);
3323    
3324     void glTexCoord (float s, float t)
3325     CODE:
3326     glTexCoord2f (s, t);
3327    
3328 root 1.210 void glRect (float x1, float y1, float x2, float y2)
3329     CODE:
3330     glRectf (x1, y1, x2, y2);
3331    
3332 root 1.233 void glRect_lineloop (float x1, float y1, float x2, float y2)
3333     CODE:
3334     glBegin (GL_LINE_LOOP);
3335     glVertex2f (x1, y1);
3336     glVertex2f (x2, y1);
3337     glVertex2f (x2, y2);
3338     glVertex2f (x1, y2);
3339     glEnd ();
3340    
3341 root 1.208 PROTOTYPES: ENABLE
3342    
3343     void glBegin (int mode)
3344    
3345     void glEnd ()
3346    
3347     void glPointSize (GLfloat size)
3348    
3349     void glLineWidth (GLfloat width)
3350    
3351     void glInterleavedArrays (int format, int stride, char *data)
3352    
3353     void glDrawElements (int mode, int count, int type, char *indices)
3354    
3355     # 1.2 void glDrawRangeElements (int mode, int start, int end
3356    
3357 root 1.54 void glTexEnv (int target, int pname, float param)
3358     CODE:
3359     glTexEnvf (target, pname, param);
3360    
3361     void glTexParameter (int target, int pname, float param)
3362     CODE:
3363     glTexParameterf (target, pname, param);
3364    
3365     void glBindTexture (int target, int name)
3366    
3367     void glConvolutionParameter (int target, int pname, float params)
3368     CODE:
3369 root 1.103 if (gl.ConvolutionParameterf)
3370     gl.ConvolutionParameterf (target, pname, params);
3371 root 1.54
3372     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
3373 root 1.64 CODE:
3374 root 1.103 if (gl.ConvolutionFilter2D)
3375     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
3376 root 1.54
3377 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
3378     CODE:
3379 root 1.103 if (gl.SeparableFilter2D)
3380     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
3381 root 1.69
3382 root 1.244 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data = 0)
3383 root 1.54
3384     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
3385    
3386 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
3387 root 1.68
3388 root 1.199 void glPixelZoom (float x, float y)
3389    
3390 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
3391    
3392 root 1.54 int glGenTexture ()
3393     CODE:
3394 root 1.192 RETVAL = gen_texture ();
3395 root 1.54 OUTPUT:
3396     RETVAL
3397    
3398     void glDeleteTexture (int name)
3399     CODE:
3400 root 1.192 del_texture (name);
3401    
3402 root 1.54 int glGenList ()
3403     CODE:
3404     RETVAL = glGenLists (1);
3405     OUTPUT:
3406     RETVAL
3407    
3408     void glDeleteList (int list)
3409     CODE:
3410     glDeleteLists (list, 1);
3411    
3412     void glNewList (int list, int mode = GL_COMPILE)
3413    
3414     void glEndList ()
3415    
3416     void glCallList (int list)
3417    
3418 root 1.296 void c_init ()
3419     CODE:
3420     glPixelStorei (GL_PACK_ALIGNMENT , 1);
3421     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
3422    
3423 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::UI::Base
3424 root 1.207
3425     PROTOTYPES: DISABLE
3426    
3427     void
3428 root 1.209 find_widget (SV *self, NV x, NV y)
3429 root 1.207 PPCODE:
3430     {
3431 root 1.209 if (within_widget (self, x, y))
3432     XPUSHs (self);
3433     }
3434    
3435     BOOT:
3436     {
3437 root 1.242 hover_gv = gv_fetchpv ("DC::UI::HOVER", 1, SVt_NV);
3438 root 1.209
3439 root 1.242 draw_x_gv = gv_fetchpv ("DC::UI::Base::draw_x", 1, SVt_NV);
3440     draw_y_gv = gv_fetchpv ("DC::UI::Base::draw_y", 1, SVt_NV);
3441     draw_w_gv = gv_fetchpv ("DC::UI::Base::draw_w", 1, SVt_NV);
3442     draw_h_gv = gv_fetchpv ("DC::UI::Base::draw_h", 1, SVt_NV);
3443 root 1.209 }
3444    
3445     void
3446     draw (SV *self)
3447     CODE:
3448     {
3449     HV *hv;
3450     SV **svp;
3451     NV x, y, w, h;
3452     SV *draw_x_sv = GvSV (draw_x_gv);
3453     SV *draw_y_sv = GvSV (draw_y_gv);
3454     SV *draw_w_sv = GvSV (draw_w_gv);
3455     SV *draw_h_sv = GvSV (draw_h_gv);
3456 root 1.228 double draw_x, draw_y;
3457 root 1.209
3458     if (!SvROK (self))
3459 root 1.242 croak ("DC::Base::draw: %s not a reference", SvPV_nolen (self));
3460 root 1.209
3461     hv = (HV *)SvRV (self);
3462    
3463     if (SvTYPE (hv) != SVt_PVHV)
3464 root 1.242 croak ("DC::Base::draw: %s not a hashref", SvPV_nolen (self));
3465 root 1.209
3466     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
3467     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
3468    
3469     if (!h || !w)
3470     XSRETURN_EMPTY;
3471    
3472     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
3473     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
3474    
3475     draw_x = SvNV (draw_x_sv) + x;
3476     draw_y = SvNV (draw_y_sv) + y;
3477    
3478     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
3479     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
3480     XSRETURN_EMPTY;
3481    
3482     sv_setnv (draw_x_sv, draw_x);
3483     sv_setnv (draw_y_sv, draw_y);
3484    
3485     glPushMatrix ();
3486     glTranslated (x, y, 0);
3487    
3488     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
3489     {
3490     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
3491    
3492     if (svp && SvTRUE (*svp))
3493     {
3494 root 1.228 glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f);
3495 root 1.209 glEnable (GL_BLEND);
3496     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3497     glBegin (GL_QUADS);
3498     glVertex2f (0, 0);
3499     glVertex2f (w, 0);
3500     glVertex2f (w, h);
3501     glVertex2f (0, h);
3502     glEnd ();
3503     glDisable (GL_BLEND);
3504     }
3505     }
3506     #if 0
3507 root 1.234 // draw borders, for debugging
3508     glPushMatrix ();
3509     glColor4f (1., 1., 0., 1.);
3510     glTranslatef (.5, .5, 0.);
3511     glBegin (GL_LINE_LOOP);
3512     glVertex2f (0 , 0);
3513     glVertex2f (w - 1, 0);
3514     glVertex2f (w - 1, h - 1);
3515     glVertex2f (0 , h - 1);
3516     glEnd ();
3517     glPopMatrix ();
3518 root 1.209 #endif
3519     PUSHMARK (SP);
3520     XPUSHs (self);
3521     PUTBACK;
3522     call_method ("_draw", G_VOID | G_DISCARD);
3523     SPAGAIN;
3524    
3525     glPopMatrix ();
3526    
3527     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
3528     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
3529 root 1.207 }
3530