ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.303
Committed: Thu Apr 22 11:18:04 2010 UTC (14 years ago) by root
Branch: MAIN
Changes since 1.302: +13 -0 lines
Log Message:
display name of audiodriver

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