ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.305
Committed: Sun May 2 21:22:20 2010 UTC (14 years ago) by root
Branch: MAIN
Changes since 1.304: +3 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.48 #ifdef _WIN32
2 root 1.131 # define WIN32_LEAN_AND_MEAN
3 root 1.170 # define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls
4 root 1.48 # include <malloc.h>
5 root 1.79 # include <windows.h>
6 root 1.157 # include <wininet.h>
7 root 1.75 # pragma warning(disable:4244)
8 root 1.162 # pragma warning(disable:4761)
9 root 1.48 #endif
10    
11 root 1.193 //#define DEBUG 1
12     #if DEBUG
13     # include <valgrind/memcheck.h>
14     #endif
15    
16 root 1.1 #include "EXTERN.h"
17     #include "perl.h"
18     #include "XSUB.h"
19    
20 root 1.131 #ifdef _WIN32
21     # undef pipe
22 root 1.222 // microsoft vs. C
23     # define sqrtf(x) sqrt(x)
24     # define atan2f(x,y) atan2(x,y)
25     # define M_PI 3.14159265f
26 root 1.131 #endif
27    
28 root 1.168 #include <assert.h>
29 root 1.80 #include <math.h>
30 root 1.5 #include <string.h>
31 root 1.25 #include <stdio.h>
32 root 1.111 #include <stdlib.h>
33 root 1.5
34 root 1.212 #define USE_RWOPS 1 // for SDL_mixer:LoadMUS_RW
35    
36 root 1.2 #include <SDL.h>
37 root 1.202 #include <SDL_thread.h>
38 root 1.76 #include <SDL_endian.h>
39 root 1.23 #include <SDL_image.h>
40 root 1.52 #include <SDL_mixer.h>
41 root 1.3 #include <SDL_opengl.h>
42 root 1.5
43 root 1.272 /* work around os x broken headers */
44     #ifdef __MACOSX__
45     typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
46 root 1.298 typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
47     typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
48 root 1.272 #endif
49    
50 root 1.124 #define PANGO_ENABLE_BACKEND
51     #define G_DISABLE_CAST_CHECKS
52    
53 root 1.30 #include <glib/gmacros.h>
54    
55 root 1.5 #include <pango/pango.h>
56    
57 root 1.254 #ifndef PANGO_VERSION_CHECK
58     # define PANGO_VERSION_CHECK(a,b,c) 0
59     #endif
60    
61     #if !PANGO_VERSION_CHECK (1, 15, 2)
62 root 1.255 # define pango_layout_get_line_readonly pango_layout_get_line
63     # define pango_layout_get_lines_readonly pango_layout_get_lines
64     # define pango_layout_iter_get_line_readonly pango_layout_iter_get_line
65     # define pango_layout_iter_get_run_readonly pango_layout_iter_get_run
66 root 1.249 #endif
67    
68 root 1.48 #ifndef _WIN32
69     # include <sys/types.h>
70     # include <sys/socket.h>
71     # include <netinet/in.h>
72     # include <netinet/tcp.h>
73     # include <inttypes.h>
74     #endif
75 root 1.28
76 root 1.261 #if __GNUC__ >= 4
77     # define expect(expr,value) __builtin_expect ((expr),(value))
78     #else
79     # define expect(expr,value) (expr)
80     #endif
81    
82     #define expect_false(expr) expect ((expr) != 0, 0)
83     #define expect_true(expr) expect ((expr) != 0, 1)
84    
85 root 1.162 #define OBJ_STR "\xef\xbf\xbc" /* U+FFFC, object replacement character */
86 root 1.121
87 root 1.296 /* this is used as fow flag as well, so has to have a different value */
88     /* then anything that is computed by incoming darkness */
89     #define FOW_DARKNESS 50
90     #define DARKNESS_ADJUST(n) (n)
91 root 1.29
92     #define MAP_EXTEND_X 32
93     #define MAP_EXTEND_Y 512
94    
95 root 1.63 #define MIN_FONT_HEIGHT 10
96 root 1.58
97 root 1.253 /* mask out modifiers we are not interested in */
98     #define MOD_MASK (KMOD_CTRL | KMOD_SHIFT | KMOD_ALT | KMOD_META)
99    
100 root 1.276 #define KMOD_LRAM 0x10000 // our extension
101    
102 root 1.285 #define TEXID_SPEECH 1
103     #define TEXID_NOFACE 2
104    
105 root 1.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.305 IMG_Init (int flags = IMG_INIT_JPG | IMG_INIT_PNG)
1119    
1120     void
1121 root 1.23 load_image_inline (SV *image_)
1122     ALIAS:
1123     load_image_file = 1
1124     PPCODE:
1125     {
1126     STRLEN image_len;
1127     char *image = (char *)SvPVbyte (image_, image_len);
1128     SDL_Surface *surface, *surface2;
1129     SDL_PixelFormat fmt;
1130     SDL_RWops *rw = ix
1131 root 1.212 ? SDL_RWFromFile (image, "rb")
1132 root 1.23 : SDL_RWFromConstMem (image, image_len);
1133    
1134     if (!rw)
1135 root 1.41 croak ("load_image: %s", SDL_GetError ());
1136 root 1.23
1137     surface = IMG_Load_RW (rw, 1);
1138     if (!surface)
1139 root 1.41 croak ("load_image: %s", SDL_GetError ());
1140 root 1.23
1141     fmt.palette = NULL;
1142     fmt.BitsPerPixel = 32;
1143     fmt.BytesPerPixel = 4;
1144 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1145 root 1.23 fmt.Rmask = 0x000000ff;
1146     fmt.Gmask = 0x0000ff00;
1147     fmt.Bmask = 0x00ff0000;
1148     fmt.Amask = 0xff000000;
1149 root 1.49 #else
1150     fmt.Rmask = 0xff000000;
1151     fmt.Gmask = 0x00ff0000;
1152     fmt.Bmask = 0x0000ff00;
1153     fmt.Amask = 0x000000ff;
1154     #endif
1155 root 1.23 fmt.Rloss = 0;
1156     fmt.Gloss = 0;
1157     fmt.Bloss = 0;
1158     fmt.Aloss = 0;
1159     fmt.Rshift = 0;
1160     fmt.Gshift = 8;
1161     fmt.Bshift = 16;
1162     fmt.Ashift = 24;
1163     fmt.colorkey = 0;
1164     fmt.alpha = 0;
1165    
1166     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
1167    
1168 root 1.39 assert (surface2->pitch == surface2->w * 4);
1169    
1170 root 1.129 SDL_LockSurface (surface2);
1171     EXTEND (SP, 6);
1172 root 1.23 PUSHs (sv_2mortal (newSViv (surface2->w)));
1173     PUSHs (sv_2mortal (newSViv (surface2->h)));
1174     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
1175 root 1.116 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
1176 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
1177 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
1178 root 1.129 SDL_UnlockSurface (surface2);
1179 root 1.23
1180     SDL_FreeSurface (surface);
1181     SDL_FreeSurface (surface2);
1182     }
1183    
1184 root 1.25 void
1185 root 1.39 average (int x, int y, uint32_t *data)
1186     PPCODE:
1187     {
1188     uint32_t r = 0, g = 0, b = 0, a = 0;
1189    
1190     x = y = x * y;
1191    
1192     while (x--)
1193     {
1194     uint32_t p = *data++;
1195    
1196     r += (p ) & 255;
1197     g += (p >> 8) & 255;
1198     b += (p >> 16) & 255;
1199     a += (p >> 24) & 255;
1200     }
1201    
1202     EXTEND (SP, 4);
1203 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
1204     PUSHs (sv_2mortal (newSViv (g / y)));
1205     PUSHs (sv_2mortal (newSViv (b / y)));
1206     PUSHs (sv_2mortal (newSViv (a / y)));
1207 root 1.39 }
1208    
1209     void
1210 root 1.66 error (char *message)
1211     CODE:
1212 root 1.86 fprintf (stderr, "ERROR: %s\n", message);
1213 root 1.66 #ifdef _WIN32
1214 root 1.240 MessageBox (0, message, "Deliantra Client Error", MB_OK | MB_ICONERROR);
1215 root 1.66 #endif
1216    
1217     void
1218 root 1.25 fatal (char *message)
1219     CODE:
1220 root 1.86 fprintf (stderr, "FATAL: %s\n", message);
1221 root 1.50 #ifdef _WIN32
1222 root 1.240 MessageBox (0, message, "Deliantra Client Fatal Error", MB_OK | MB_ICONERROR);
1223 root 1.25 #endif
1224 root 1.112 _exit (1);
1225 root 1.111
1226     void
1227 root 1.158 _exit (int retval = 0)
1228 root 1.111 CODE:
1229 root 1.161 #ifdef WIN32
1230     ExitThread (retval); // unclean, please beam me up
1231     #else
1232 root 1.112 _exit (retval);
1233 root 1.161 #endif
1234 root 1.25
1235 root 1.193 void
1236     debug ()
1237     CODE:
1238     {
1239     #if DEBUG
1240     VALGRIND_DO_LEAK_CHECK;
1241     #endif
1242     }
1243    
1244 root 1.280 int
1245     SvREFCNT (SV *sv)
1246     CODE:
1247     RETVAL = SvREFCNT (sv);
1248     OUTPUT:
1249     RETVAL
1250    
1251 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Font
1252 root 1.61
1253 root 1.205 PROTOTYPES: DISABLE
1254    
1255 root 1.242 DC::Font
1256 root 1.70 new_from_file (SV *class, char *path, int id = 0)
1257 root 1.61 CODE:
1258     {
1259     int count;
1260 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
1261 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
1262     FcPatternDestroy (pattern);
1263     }
1264     OUTPUT:
1265     RETVAL
1266    
1267     void
1268 root 1.242 DESTROY (DC::Font self)
1269 root 1.61 CODE:
1270     pango_font_description_free (self);
1271    
1272     void
1273 root 1.242 make_default (DC::Font self)
1274 root 1.205 PROTOTYPE: $
1275 root 1.61 CODE:
1276     default_font = self;
1277    
1278 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Layout
1279 root 1.14
1280 root 1.205 PROTOTYPES: DISABLE
1281    
1282 root 1.124 void
1283 root 1.239 glyph_cache_backup ()
1284 root 1.205 PROTOTYPE:
1285 root 1.124 CODE:
1286 root 1.239 tc_backup ();
1287    
1288     void
1289     glyph_cache_restore ()
1290     PROTOTYPE:
1291     CODE:
1292     tc_restore ();
1293 root 1.124
1294 root 1.242 DC::Layout
1295 root 1.128 new (SV *class)
1296 root 1.14 CODE:
1297     New (0, RETVAL, 1, struct cf_layout);
1298 root 1.76
1299 root 1.124 RETVAL->pl = pango_layout_new (opengl_context);
1300 root 1.76 RETVAL->r = 1.;
1301     RETVAL->g = 1.;
1302     RETVAL->b = 1.;
1303     RETVAL->a = 1.;
1304     RETVAL->base_height = MIN_FONT_HEIGHT;
1305     RETVAL->font = 0;
1306 root 1.225 RETVAL->rc = rc_alloc ();
1307 root 1.76
1308 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
1309 root 1.76 layout_update_font (RETVAL);
1310 root 1.14 OUTPUT:
1311     RETVAL
1312    
1313     void
1314 root 1.242 DESTROY (DC::Layout self)
1315 root 1.14 CODE:
1316     g_object_unref (self->pl);
1317 root 1.225 rc_free (self->rc);
1318 root 1.14 Safefree (self);
1319 root 1.13
1320 root 1.8 void
1321 root 1.242 set_text (DC::Layout self, SV *text_)
1322 root 1.35 CODE:
1323     {
1324     STRLEN textlen;
1325     char *text = SvPVutf8 (text_, textlen);
1326    
1327     pango_layout_set_text (self->pl, text, textlen);
1328     }
1329    
1330     void
1331 root 1.242 set_markup (DC::Layout self, SV *text_)
1332 root 1.14 CODE:
1333 root 1.5 {
1334     STRLEN textlen;
1335     char *text = SvPVutf8 (text_, textlen);
1336 root 1.14
1337     pango_layout_set_markup (self->pl, text, textlen);
1338     }
1339    
1340 root 1.121 void
1341 root 1.242 set_shapes (DC::Layout self, ...)
1342 root 1.121 CODE:
1343     {
1344     PangoAttrList *attrs = 0;
1345     const char *text = pango_layout_get_text (self->pl);
1346     const char *pos = text;
1347 root 1.122 int arg = 4;
1348 root 1.121
1349     while (arg < items && (pos = strstr (pos, OBJ_STR)))
1350     {
1351 root 1.122 PangoRectangle inkrect, rect;
1352 root 1.121 PangoAttribute *attr;
1353    
1354 root 1.122 int x = SvIV (ST (arg - 3));
1355     int y = SvIV (ST (arg - 2));
1356 root 1.121 int w = SvIV (ST (arg - 1));
1357 root 1.122 int h = SvIV (ST (arg ));
1358 root 1.121
1359 root 1.122 inkrect.x = 0;
1360     inkrect.y = 0;
1361     inkrect.width = 0;
1362     inkrect.height = 0;
1363    
1364     rect.x = x * PANGO_SCALE;
1365     rect.y = y * PANGO_SCALE;
1366     rect.width = w * PANGO_SCALE;
1367 root 1.121 rect.height = h * PANGO_SCALE;
1368    
1369     if (!attrs)
1370     attrs = pango_layout_get_attributes (self->pl);
1371    
1372 root 1.122 attr = pango_attr_shape_new (&inkrect, &rect);
1373 root 1.121 attr->start_index = pos - text;
1374     attr->end_index = attr->start_index + sizeof (OBJ_STR) - 1;
1375     pango_attr_list_insert (attrs, attr);
1376    
1377 root 1.122 arg += 4;
1378 root 1.121 pos += sizeof (OBJ_STR) - 1;
1379     }
1380    
1381     if (attrs)
1382     pango_layout_set_attributes (self->pl, attrs);
1383     }
1384    
1385     void
1386 root 1.242 get_shapes (DC::Layout self)
1387 root 1.121 PPCODE:
1388     {
1389     PangoLayoutIter *iter = pango_layout_get_iter (self->pl);
1390    
1391     do
1392     {
1393 root 1.249 PangoLayoutRun *run = pango_layout_iter_get_run_readonly (iter);
1394 root 1.121
1395     if (run && shape_attr_p (run))
1396     {
1397     PangoRectangle extents;
1398     pango_layout_iter_get_run_extents (iter, 0, &extents);
1399    
1400 root 1.129 EXTEND (SP, 2);
1401 root 1.121 PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.x))));
1402     PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.y))));
1403     }
1404     }
1405     while (pango_layout_iter_next_run (iter));
1406    
1407     pango_layout_iter_free (iter);
1408     }
1409    
1410     int
1411 root 1.242 has_wrapped (DC::Layout self)
1412 root 1.121 CODE:
1413     {
1414     int lines = 1;
1415     const char *text = pango_layout_get_text (self->pl);
1416    
1417     while (*text)
1418     lines += *text++ == '\n';
1419    
1420     RETVAL = lines < pango_layout_get_line_count (self->pl);
1421     }
1422     OUTPUT:
1423     RETVAL
1424    
1425 root 1.46 SV *
1426 root 1.242 get_text (DC::Layout self)
1427 root 1.46 CODE:
1428 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
1429 root 1.107 sv_utf8_decode (RETVAL);
1430 root 1.46 OUTPUT:
1431     RETVAL
1432    
1433 root 1.14 void
1434 root 1.242 set_foreground (DC::Layout self, float r, float g, float b, float a = 1.)
1435 root 1.76 CODE:
1436     self->r = r;
1437     self->g = g;
1438     self->b = b;
1439     self->a = a;
1440    
1441     void
1442 root 1.242 set_font (DC::Layout self, DC::Font font = 0)
1443 root 1.61 CODE:
1444     if (self->font != font)
1445     {
1446     self->font = font;
1447     layout_update_font (self);
1448     }
1449    
1450     void
1451 root 1.242 set_height (DC::Layout self, int base_height)
1452 root 1.16 CODE:
1453 root 1.61 if (self->base_height != base_height)
1454     {
1455     self->base_height = base_height;
1456     layout_update_font (self);
1457     }
1458 root 1.16
1459     void
1460 root 1.242 set_width (DC::Layout self, int max_width = -1)
1461 root 1.14 CODE:
1462     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
1463    
1464     void
1465 root 1.242 set_indent (DC::Layout self, int indent)
1466 root 1.84 CODE:
1467     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
1468    
1469     void
1470 root 1.242 set_spacing (DC::Layout self, int spacing)
1471 root 1.84 CODE:
1472     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
1473    
1474     void
1475 root 1.242 set_ellipsise (DC::Layout self, int ellipsise)
1476 root 1.84 CODE:
1477     pango_layout_set_ellipsize (self->pl,
1478     ellipsise == 1 ? PANGO_ELLIPSIZE_START
1479     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
1480     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
1481     : PANGO_ELLIPSIZE_NONE
1482     );
1483    
1484     void
1485 root 1.242 set_single_paragraph_mode (DC::Layout self, int spm)
1486 root 1.84 CODE:
1487     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
1488    
1489     void
1490 root 1.242 size (DC::Layout self)
1491 root 1.14 PPCODE:
1492     {
1493     int w, h;
1494    
1495     layout_get_pixel_size (self, &w, &h);
1496    
1497     EXTEND (SP, 2);
1498     PUSHs (sv_2mortal (newSViv (w)));
1499     PUSHs (sv_2mortal (newSViv (h)));
1500     }
1501    
1502 root 1.17 int
1503 root 1.242 descent (DC::Layout self)
1504 root 1.122 CODE:
1505     {
1506     PangoRectangle rect;
1507 root 1.249 PangoLayoutLine *line = pango_layout_get_line_readonly (self->pl, 0);
1508 root 1.122 pango_layout_line_get_pixel_extents (line, 0, &rect);
1509     RETVAL = PANGO_DESCENT (rect);
1510     }
1511     OUTPUT:
1512     RETVAL
1513    
1514     int
1515 root 1.242 xy_to_index (DC::Layout self, int x, int y)
1516 root 1.17 CODE:
1517     {
1518     int index, trailing;
1519     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
1520 root 1.165 RETVAL = index + trailing;
1521 root 1.17 }
1522     OUTPUT:
1523     RETVAL
1524    
1525     void
1526 root 1.242 cursor_pos (DC::Layout self, int index)
1527 root 1.17 PPCODE:
1528     {
1529 root 1.251 PangoRectangle pos;
1530 root 1.252 pango_layout_get_cursor_pos (self->pl, index, &pos, 0);
1531 root 1.30
1532 root 1.17 EXTEND (SP, 3);
1533 root 1.251 PUSHs (sv_2mortal (newSViv (pos.x / PANGO_SCALE)));
1534     PUSHs (sv_2mortal (newSViv (pos.y / PANGO_SCALE)));
1535     PUSHs (sv_2mortal (newSViv (pos.height / PANGO_SCALE)));
1536 root 1.17 }
1537    
1538 root 1.14 void
1539 root 1.242 index_to_line_x (DC::Layout self, int index, int trailing = 0)
1540 root 1.165 PPCODE:
1541     {
1542     int line, x;
1543    
1544     pango_layout_index_to_line_x (self->pl, index, trailing, &line, &x);
1545 root 1.254 #if !PANGO_VERSION_CHECK (1, 17, 3)
1546 root 1.165 /* pango bug: line is between 1..numlines, not 0..numlines-1 */
1547 root 1.245 --line;
1548     #endif
1549 root 1.165 EXTEND (SP, 2);
1550 root 1.245 PUSHs (sv_2mortal (newSViv (line)));
1551 root 1.165 PUSHs (sv_2mortal (newSViv (x / PANGO_SCALE)));
1552     }
1553    
1554     void
1555 root 1.242 line_x_to_index (DC::Layout self, int line, int x)
1556 root 1.165 PPCODE:
1557     {
1558     PangoLayoutLine *lp;
1559     int index, trailing;
1560    
1561     if (line < 0)
1562     XSRETURN_EMPTY;
1563    
1564 root 1.249 if (!(lp = pango_layout_get_line_readonly (self->pl, line)))
1565 root 1.165 XSRETURN_EMPTY; /* do better */
1566    
1567 root 1.166 pango_layout_line_x_to_index (lp, x * PANGO_SCALE, &index, &trailing);
1568 root 1.165
1569     EXTEND (SP, 2);
1570     if (GIMME_V == G_SCALAR)
1571     PUSHs (sv_2mortal (newSViv (index + trailing)));
1572     else
1573     {
1574     PUSHs (sv_2mortal (newSViv (index)));
1575     PUSHs (sv_2mortal (newSViv (trailing)));
1576     }
1577     }
1578    
1579     void
1580 root 1.242 render (DC::Layout self, float x, float y, int flags = 0)
1581 root 1.225 CODE:
1582     rc_clear (self->rc);
1583 root 1.124 pango_opengl_render_layout_subpixel (
1584     self->pl,
1585 root 1.225 self->rc,
1586 root 1.124 x * PANGO_SCALE, y * PANGO_SCALE,
1587 root 1.135 self->r, self->g, self->b, self->a,
1588     flags
1589 root 1.124 );
1590 root 1.225 // we assume that context_change actually clears/frees stuff
1591     // and does not do any recomputation...
1592     pango_layout_context_changed (self->pl);
1593    
1594     void
1595 root 1.242 draw (DC::Layout self)
1596 root 1.225 CODE:
1597     {
1598     glEnable (GL_TEXTURE_2D);
1599     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1600     glEnable (GL_BLEND);
1601     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1602     GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1603     glEnable (GL_ALPHA_TEST);
1604     glAlphaFunc (GL_GREATER, 7.f / 255.f);
1605    
1606     rc_draw (self->rc);
1607    
1608     glDisable (GL_ALPHA_TEST);
1609     glDisable (GL_BLEND);
1610     glDisable (GL_TEXTURE_2D);
1611     }
1612 root 1.11
1613 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Texture
1614 root 1.11
1615 root 1.205 PROTOTYPES: ENABLE
1616    
1617 root 1.11 void
1618 root 1.203 pad (SV *data_, int ow, int oh, int nw, int nh)
1619 root 1.113 CODE:
1620     {
1621 root 1.203 if ((nw != ow || nh != oh) && SvOK (data_))
1622 root 1.113 {
1623 root 1.203 STRLEN datalen;
1624     char *data = SvPVbyte (data_, datalen);
1625     int bpp = datalen / (ow * oh);
1626     SV *result_ = sv_2mortal (newSV (nw * nh * bpp));
1627    
1628     SvPOK_only (result_);
1629     SvCUR_set (result_, nw * nh * bpp);
1630    
1631     memset (SvPVX (result_), 0, nw * nh * bpp);
1632     while (oh--)
1633     memcpy (SvPVX (result_) + oh * nw * bpp, data + oh * ow * bpp, ow * bpp);
1634 root 1.113
1635 root 1.203 sv_setsv (data_, result_);
1636 root 1.113 }
1637     }
1638    
1639     void
1640 root 1.114 draw_quad (SV *self, float x, float y, float w = 0., float h = 0.)
1641 root 1.12 PROTOTYPE: $$$;$$
1642 root 1.76 ALIAS:
1643     draw_quad_alpha = 1
1644     draw_quad_alpha_premultiplied = 2
1645 root 1.11 CODE:
1646     {
1647 root 1.12 HV *hv = (HV *)SvRV (self);
1648 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
1649     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
1650 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
1651    
1652 root 1.219 if (name <= 0)
1653     XSRETURN_EMPTY;
1654    
1655 root 1.12 if (items < 5)
1656     {
1657 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1658     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1659 root 1.12 }
1660    
1661 root 1.76 if (ix)
1662     {
1663     glEnable (GL_BLEND);
1664 root 1.103
1665     if (ix == 2)
1666     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1667     else
1668     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1669 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1670 root 1.103
1671 root 1.86 glEnable (GL_ALPHA_TEST);
1672     glAlphaFunc (GL_GREATER, 0.01f);
1673 root 1.76 }
1674    
1675 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1676 root 1.76
1677 root 1.12 glBegin (GL_QUADS);
1678 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1679     glTexCoord2f (0, t); glVertex2f (x , y + h);
1680     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1681     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1682 root 1.12 glEnd ();
1683 root 1.76
1684     if (ix)
1685 root 1.86 {
1686     glDisable (GL_ALPHA_TEST);
1687     glDisable (GL_BLEND);
1688     }
1689 root 1.11 }
1690 root 1.28
1691 root 1.293 void
1692 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)
1693 root 1.293 PROTOTYPE: @
1694     CODE:
1695     {
1696     glEnable (GL_BLEND);
1697 root 1.300 glBlendFunc (intensity ? GL_SRC_ALPHA : GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1698 root 1.299 glEnable (GL_TEXTURE_2D);
1699 root 1.294 glBindTexture (GL_TEXTURE_2D, name1);
1700 root 1.293
1701 root 1.294 glColor3f (intensity, intensity, intensity);
1702 root 1.293 glPushMatrix ();
1703     glScalef (1./3, 1./3, 1.);
1704    
1705 root 1.294 if (blend > 0.f)
1706     {
1707 root 1.296 float dx3 = dx * -3.f / w;
1708     float dy3 = dy * -3.f / h;
1709 root 1.294 GLfloat env_color[4] = { 0., 0., 0., blend };
1710    
1711     /* interpolate the two shadow textures */
1712     /* stage 0 == rgb(glcolor) + alpha(t0) */
1713     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1714    
1715     /* stage 1 == rgb(glcolor) + alpha(interpolate t0, t1, texenv) */
1716     gl.ActiveTexture (GL_TEXTURE1);
1717     glEnable (GL_TEXTURE_2D);
1718     glBindTexture (GL_TEXTURE_2D, name2);
1719     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1720    
1721     /* rgb == rgb(glcolor) */
1722     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
1723 root 1.300 glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
1724 root 1.294 glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1725    
1726     /* alpha = interpolate t0, t1 by env_alpha */
1727     glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env_color);
1728    
1729     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);
1730     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
1731     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1732    
1733     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
1734     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
1735    
1736     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_CONSTANT);
1737     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
1738    
1739     glBegin (GL_QUADS);
1740 root 1.296 gl.MultiTexCoord2f (GL_TEXTURE0, 0, 0); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 , dy3 ); glVertex2i (0, 0);
1741     gl.MultiTexCoord2f (GL_TEXTURE0, 0, t); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 , dy3 + t); glVertex2i (0, h);
1742     gl.MultiTexCoord2f (GL_TEXTURE0, s, t); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 + s, dy3 + t); glVertex2i (w, h);
1743     gl.MultiTexCoord2f (GL_TEXTURE0, s, 0); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 + s, dy3 ); glVertex2i (w, 0);
1744 root 1.294 glEnd ();
1745    
1746     glDisable (GL_TEXTURE_2D);
1747     gl.ActiveTexture (GL_TEXTURE0);
1748     }
1749     else
1750     {
1751     /* simple blending of one texture, also opengl <1.3 path */
1752     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1753 root 1.293
1754 root 1.294 glBegin (GL_QUADS);
1755 root 1.296 glTexCoord2f (0, 0); glVertex2f (0, 0);
1756     glTexCoord2f (0, t); glVertex2f (0, h);
1757     glTexCoord2f (s, t); glVertex2f (w, h);
1758     glTexCoord2f (s, 0); glVertex2f (w, 0);
1759 root 1.294 glEnd ();
1760     }
1761 root 1.293
1762 root 1.296 /* draw ?-marks or equivalent, this is very clumsy code :/ */
1763     {
1764     int x, y;
1765     int dx3 = dx * 3;
1766     int dy3 = dy * 3;
1767    
1768     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1769     glBindTexture (GL_TEXTURE_2D, hidden_tex);
1770     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1771     glTranslatef (-1., -1., 0);
1772     glBegin (GL_QUADS);
1773    
1774     for (y = 1; y < h; y += 3)
1775     {
1776     int y1 = y - dy3;
1777     int y1valid = y1 >= 0 && y1 < h;
1778    
1779     for (x = 1; x < w; x += 3)
1780     {
1781     int x1 = x - dx3;
1782     uint8_t h1 = data1 [x + y * w] == DARKNESS_ADJUST (255 - FOW_DARKNESS);
1783     uint8_t h2;
1784    
1785     if (y1valid && x1 >= 0 && x1 < w)
1786     h2 = data2 [x1 + y1 * w] == DARKNESS_ADJUST (255 - FOW_DARKNESS);
1787     else
1788     h2 = 1; /* out of range == invisible */
1789    
1790     if (h1 || h2)
1791     {
1792     float alpha = h1 == h2 ? 1.f : h1 ? 1.f - blend : blend;
1793     glColor4f (1., 1., 1., alpha);
1794    
1795     glTexCoord2f (0, 0.); glVertex2i (x , y );
1796     glTexCoord2f (0, 1.); glVertex2i (x , y + 3);
1797     glTexCoord2f (1, 1.); glVertex2i (x + 3, y + 3);
1798     glTexCoord2f (1, 0.); glVertex2i (x + 3, y );
1799     }
1800     }
1801     }
1802     }
1803    
1804     glEnd ();
1805    
1806 root 1.293 glPopMatrix ();
1807    
1808     glDisable (GL_TEXTURE_2D);
1809     glDisable (GL_BLEND);
1810     }
1811    
1812 root 1.199 IV texture_valid_2d (GLint internalformat, GLsizei w, GLsizei h, GLenum format, GLenum type)
1813     CODE:
1814     {
1815     GLint width;
1816     glTexImage2D (GL_PROXY_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, 0);
1817     glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
1818     RETVAL = width > 0;
1819     }
1820     OUTPUT:
1821     RETVAL
1822    
1823 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Map
1824 root 1.28
1825 root 1.205 PROTOTYPES: DISABLE
1826    
1827 root 1.242 DC::Map
1828 root 1.164 new (SV *class)
1829 root 1.28 CODE:
1830     New (0, RETVAL, 1, struct map);
1831 root 1.42 RETVAL->x = 0;
1832     RETVAL->y = 0;
1833 root 1.164 RETVAL->w = 0;
1834     RETVAL->h = 0;
1835 root 1.42 RETVAL->ox = 0;
1836     RETVAL->oy = 0;
1837 root 1.174 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1838     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1839 root 1.28 RETVAL->rows = 0;
1840     RETVAL->row = 0;
1841     OUTPUT:
1842     RETVAL
1843    
1844     void
1845 root 1.242 DESTROY (DC::Map self)
1846 root 1.28 CODE:
1847     {
1848 root 1.30 map_clear (self);
1849 root 1.174 Safefree (self->face2tile);
1850 root 1.111 Safefree (self->tex);
1851 root 1.29 Safefree (self);
1852     }
1853    
1854     void
1855 root 1.242 resize (DC::Map self, int map_width, int map_height)
1856 root 1.164 CODE:
1857     self->w = map_width;
1858     self->h = map_height;
1859    
1860     void
1861 root 1.242 clear (DC::Map self)
1862 root 1.30 CODE:
1863     map_clear (self);
1864    
1865     void
1866 root 1.242 set_tileid (DC::Map self, int face, int tile)
1867 root 1.29 CODE:
1868     {
1869 root 1.174 need_facenum (self, face); self->face2tile [face] = tile;
1870     need_texid (self, tile);
1871 root 1.42 }
1872    
1873     void
1874 root 1.242 set_smooth (DC::Map self, int face, int smooth, int level)
1875 root 1.176 CODE:
1876     {
1877     tileid texid;
1878     maptex *tex;
1879    
1880     if (face < 0 || face >= self->faces)
1881     return;
1882    
1883     if (smooth < 0 || smooth >= self->faces)
1884     return;
1885    
1886     texid = self->face2tile [face];
1887    
1888     if (!texid)
1889     return;
1890    
1891     tex = self->tex + texid;
1892     tex->smoothtile = self->face2tile [smooth];
1893     tex->smoothlevel = level;
1894     }
1895    
1896     void
1897 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)
1898 root 1.42 CODE:
1899     {
1900 root 1.174 need_texid (self, texid);
1901 root 1.42
1902 root 1.48 {
1903     maptex *tex = self->tex + texid;
1904 root 1.39
1905 root 1.48 tex->name = name;
1906     tex->w = w;
1907     tex->h = h;
1908     tex->s = s;
1909     tex->t = t;
1910     tex->r = r;
1911     tex->g = g;
1912     tex->b = b;
1913     tex->a = a;
1914     }
1915 root 1.95
1916     // somewhat hackish, but for textures that require it, it really
1917     // improves the look, and most others don't suffer.
1918     glBindTexture (GL_TEXTURE_2D, name);
1919 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1920     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1921     // use uglier nearest interpolation because linear suffers
1922     // from transparent color bleeding and ugly wrapping effects.
1923     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1924 root 1.29 }
1925    
1926 root 1.280 void
1927     expire_textures (DC::Map self, int texid, int count)
1928     PPCODE:
1929     for (; texid < self->texs && count; ++texid, --count)
1930     {
1931     maptex *tex = self->tex + texid;
1932    
1933     if (tex->name)
1934     {
1935     if (tex->unused)
1936     {
1937     tex->name = 0;
1938 root 1.282 tex->unused = 0;
1939 root 1.280 XPUSHs (sv_2mortal (newSViv (texid)));
1940     }
1941     else
1942     tex->unused = 1;
1943     }
1944     }
1945    
1946 root 1.42 int
1947 root 1.242 ox (DC::Map self)
1948 root 1.42 ALIAS:
1949     oy = 1
1950 root 1.101 x = 2
1951     y = 3
1952 root 1.102 w = 4
1953     h = 5
1954 root 1.42 CODE:
1955     switch (ix)
1956     {
1957     case 0: RETVAL = self->ox; break;
1958     case 1: RETVAL = self->oy; break;
1959 root 1.101 case 2: RETVAL = self->x; break;
1960     case 3: RETVAL = self->y; break;
1961 root 1.102 case 4: RETVAL = self->w; break;
1962     case 5: RETVAL = self->h; break;
1963 root 1.42 }
1964     OUTPUT:
1965     RETVAL
1966    
1967 root 1.29 void
1968 root 1.242 scroll (DC::Map self, int dx, int dy)
1969 root 1.43 CODE:
1970     {
1971 root 1.44 if (dx > 0)
1972 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
1973 root 1.44 else if (dx < 0)
1974 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
1975 root 1.44
1976     if (dy > 0)
1977 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
1978 root 1.44 else if (dy < 0)
1979 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
1980 root 1.43
1981 root 1.44 self->ox += dx; self->x += dx;
1982     self->oy += dy; self->y += dy;
1983 root 1.43
1984     while (self->y < 0)
1985     {
1986     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1987    
1988     self->rows += MAP_EXTEND_Y;
1989     self->y += MAP_EXTEND_Y;
1990     }
1991 root 1.44 }
1992 root 1.43
1993 root 1.221 SV *
1994 root 1.242 map1a_update (DC::Map self, SV *data_, int extmap)
1995 root 1.44 CODE:
1996     {
1997 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1998     uint8_t *data_end = (uint8_t *)SvEND (data_);
1999 root 1.48 mapcell *cell;
2000 root 1.221 int x, y, z, flags;
2001     AV *missing = newAV ();
2002     RETVAL = newRV_noinc ((SV *)missing);
2003 root 1.43
2004 root 1.150 while (data < data_end - 1)
2005 root 1.29 {
2006 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
2007 root 1.30
2008 root 1.120 x = self->x + ((flags >> 10) & 63);
2009     y = self->y + ((flags >> 4) & 63);
2010 root 1.29
2011 root 1.48 cell = map_get_cell (self, x, y);
2012 root 1.29
2013     if (flags & 15)
2014     {
2015 root 1.142 if (!cell->darkness)
2016 root 1.29 {
2017 root 1.154 memset (cell, 0, sizeof (*cell));
2018 root 1.142 cell->darkness = 256;
2019 root 1.29 }
2020 root 1.45
2021 root 1.142 //TODO: don't trust server data to be in-range(!)
2022    
2023 root 1.141 if (flags & 8)
2024     {
2025     if (extmap)
2026     {
2027     uint8_t ext, cmd;
2028    
2029     do
2030     {
2031     ext = *data++;
2032 root 1.261 cmd = ext & 0x7f;
2033 root 1.141
2034 root 1.147 if (cmd < 4)
2035 root 1.296 cell->darkness = 255 - ext * 64 + 1; /* make sure this doesn't collide with FOW_DARKNESS */
2036 root 1.147 else if (cmd == 5) // health
2037     {
2038     cell->stat_width = 1;
2039     cell->stat_hp = *data++;
2040     }
2041     else if (cmd == 6) // monster width
2042     cell->stat_width = *data++ + 1;
2043 root 1.169 else if (cmd == 0x47)
2044 root 1.153 {
2045 root 1.261 if (*data == 1) cell->player = data [1];
2046     else if (*data == 2) cell->player = data [2] + (data [1] << 8);
2047     else if (*data == 3) cell->player = data [3] + (data [2] << 8) + (data [1] << 16);
2048     else if (*data == 4) cell->player = data [4] + (data [3] << 8) + (data [2] << 16) + (data [1] << 24);
2049 root 1.153
2050     data += *data + 1;
2051     }
2052     else if (cmd == 8) // cell flags
2053     cell->flags = *data++;
2054 root 1.144 else if (ext & 0x40) // unknown, multibyte => skip
2055     data += *data + 1;
2056 root 1.147 else
2057     data++;
2058 root 1.141 }
2059 root 1.147 while (ext & 0x80);
2060 root 1.141 }
2061     else
2062 root 1.142 cell->darkness = *data++ + 1;
2063 root 1.141 }
2064 root 1.29
2065 root 1.221 for (z = 0; z <= 2; ++z)
2066     if (flags & (4 >> z))
2067     {
2068     faceid face = (data [0] << 8) + data [1]; data += 2;
2069     need_facenum (self, face);
2070     cell->tile [z] = self->face2tile [face];
2071 root 1.29
2072 root 1.221 if (cell->tile [z])
2073     {
2074     maptex *tex = self->tex + cell->tile [z];
2075 root 1.280 tex->unused = 0;
2076 root 1.221 if (!tex->name)
2077     av_push (missing, newSViv (cell->tile [z]));
2078 root 1.29
2079 root 1.221 if (tex->smoothtile)
2080     {
2081     maptex *smooth = self->tex + tex->smoothtile;
2082 root 1.280 smooth->unused = 0;
2083 root 1.221 if (!smooth->name)
2084     av_push (missing, newSViv (tex->smoothtile));
2085     }
2086     }
2087     }
2088 root 1.29 }
2089     else
2090 root 1.267 CELL_CLEAR (cell);
2091 root 1.29 }
2092 root 1.28 }
2093 root 1.221 OUTPUT:
2094     RETVAL
2095 root 1.28
2096 root 1.40 SV *
2097 root 1.242 mapmap (DC::Map self, int x0, int y0, int w, int h)
2098 root 1.40 CODE:
2099     {
2100 root 1.55 int x1, x;
2101     int y1, y;
2102 root 1.40 int z;
2103     SV *map_sv = newSV (w * h * sizeof (uint32_t));
2104     uint32_t *map = (uint32_t *)SvPVX (map_sv);
2105    
2106     SvPOK_only (map_sv);
2107     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
2108    
2109 root 1.55 x0 += self->x; x1 = x0 + w;
2110     y0 += self->y; y1 = y0 + h;
2111 root 1.40
2112     for (y = y0; y < y1; y++)
2113     {
2114     maprow *row = 0 <= y && y < self->rows
2115     ? self->row + y
2116     : 0;
2117    
2118     for (x = x0; x < x1; x++)
2119     {
2120     int r = 32, g = 32, b = 32, a = 192;
2121    
2122     if (row && row->c0 <= x && x < row->c1)
2123     {
2124     mapcell *cell = row->col + (x - row->c0);
2125    
2126     for (z = 0; z <= 0; z++)
2127     {
2128 root 1.174 maptex tex = self->tex [cell->tile [z]];
2129     int a0 = 255 - tex.a;
2130     int a1 = tex.a;
2131    
2132     r = (r * a0 + tex.r * a1) / 255;
2133     g = (g * a0 + tex.g * a1) / 255;
2134     b = (b * a0 + tex.b * a1) / 255;
2135     a = (a * a0 + tex.a * a1) / 255;
2136 root 1.40 }
2137     }
2138    
2139     *map++ = (r )
2140     | (g << 8)
2141     | (b << 16)
2142     | (a << 24);
2143     }
2144     }
2145    
2146     RETVAL = map_sv;
2147     }
2148     OUTPUT:
2149     RETVAL
2150    
2151 root 1.221 void
2152 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)
2153 root 1.116 CODE:
2154 root 1.30 {
2155 root 1.223 int x, y, z;
2156    
2157 root 1.176 HV *smooth = (HV *)sv_2mortal ((SV *)newHV ());
2158     uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level
2159 root 1.226 static uint8_t smooth_max[256][256]; // egad, fast and wasteful on memory (64k)
2160 root 1.176 smooth_key skey;
2161 root 1.261 int pl_x, pl_y;
2162     maptex pl_tex;
2163 root 1.285 rc_t *rc = rc_alloc ();
2164     rc_t *rc_ov = rc_alloc ();
2165 root 1.223 rc_key_t key;
2166 root 1.297 rc_array_t *arr;
2167 root 1.48
2168 root 1.262 pl_tex.name = 0;
2169    
2170 pippijn 1.288 // that's current max. sorry.
2171 root 1.176 if (sw > 255) sw = 255;
2172     if (sh > 255) sh = 255;
2173    
2174     // clear key, in case of extra padding
2175     memset (&skey, 0, sizeof (skey));
2176    
2177 root 1.223 memset (&key, 0, sizeof (key));
2178     key.r = 255;
2179     key.g = 255;
2180     key.b = 255;
2181     key.a = 255;
2182     key.mode = GL_QUADS;
2183     key.format = GL_T2F_V3F;
2184 root 1.30
2185 root 1.164 mx += self->x;
2186     my += self->y;
2187    
2188 root 1.176 // first pass: determine smooth_max
2189     // rather ugly, if you ask me
2190     // could also be stored inside mapcell and updated on change
2191     memset (smooth_max, 0, sizeof (smooth_max));
2192    
2193     for (y = 0; y < sh; y++)
2194     if (0 <= y + my && y + my < self->rows)
2195     {
2196     maprow *row = self->row + (y + my);
2197    
2198     for (x = 0; x < sw; x++)
2199     if (row->c0 <= x + mx && x + mx < row->c1)
2200     {
2201     mapcell *cell = row->col + (x + mx - row->c0);
2202    
2203 root 1.177 smooth_max[x + 1][y + 1] =
2204     MAX (self->tex [cell->tile [0]].smoothlevel,
2205     MAX (self->tex [cell->tile [1]].smoothlevel,
2206     self->tex [cell->tile [2]].smoothlevel));
2207 root 1.176 }
2208     }
2209    
2210 root 1.223 glEnable (GL_BLEND);
2211     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2212     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2213    
2214 root 1.176 for (z = 0; z <= 2; z++)
2215     {
2216 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
2217 root 1.283 key.texname = -1;
2218 root 1.186
2219 root 1.176 for (y = 0; y < sh; y++)
2220     if (0 <= y + my && y + my < self->rows)
2221     {
2222     maprow *row = self->row + (y + my);
2223    
2224     for (x = 0; x < sw; x++)
2225     if (row->c0 <= x + mx && x + mx < row->c1)
2226     {
2227     mapcell *cell = row->col + (x + mx - row->c0);
2228     tileid tile = cell->tile [z];
2229    
2230     if (tile)
2231     {
2232     maptex tex = self->tex [tile];
2233 root 1.285 int px, py;
2234 root 1.176
2235 root 1.223 if (key.texname != tex.name)
2236 root 1.176 {
2237 root 1.280 self->tex [tile].unused = 0;
2238    
2239 root 1.176 if (!tex.name)
2240 root 1.285 tex = self->tex [TEXID_NOFACE]; /* missing, replace by noface */
2241 root 1.176
2242 root 1.223 key.texname = tex.name;
2243     arr = rc_array (rc, &key);
2244 root 1.176 }
2245    
2246 root 1.285 px = (x + 1) * T - tex.w;
2247     py = (y + 1) * T - tex.h;
2248    
2249 root 1.261 if (expect_false (cell->player == player) && expect_false (z == 2))
2250     {
2251     pl_x = px;
2252     pl_y = py;
2253     pl_tex = tex;
2254     continue;
2255     }
2256 root 1.219
2257 root 1.223 rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2258     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
2259     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
2260     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
2261 root 1.176
2262     // update smooth hash
2263     if (tex.smoothtile)
2264     {
2265     skey.tile = tex.smoothtile;
2266     skey.level = tex.smoothlevel;
2267    
2268     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
2269 root 1.30
2270 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
2271     // shifted +1|+1 so we always stay positive.
2272 root 1.30
2273 root 1.180 // bits is ___n cccc CCCC bbbb
2274     // n do not draw borders&corners
2275     // c draw these corners, but...
2276     // C ... not these
2277     // b draw these borders
2278    
2279     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
2280     // ┃· ·· ·┃ ━━
2281    
2282     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
2283     // ·· ·· ·┏ ┓·
2284    
2285 root 1.176 // full tile
2286     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
2287    
2288     // borders
2289 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
2290     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
2291 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
2292     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
2293    
2294     // corners
2295     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
2296     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
2297     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
2298     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
2299     }
2300     }
2301 root 1.285
2302 root 1.296 if (expect_false (z == 2) && expect_false (cell->flags))
2303 root 1.285 {
2304 root 1.296 // overlays such as the speech bubble, probably more to come
2305     if (cell->flags & 1)
2306 root 1.285 {
2307 root 1.296 rc_key_t key_ov = key;
2308     maptex tex = self->tex [TEXID_SPEECH];
2309     rc_array_t *arr;
2310     int px = x * T + T * 2 / 32;
2311     int py = y * T - T * 6 / 32;
2312    
2313     key_ov.texname = tex.name;
2314     arr = rc_array (rc_ov, &key_ov);
2315    
2316     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2317     rc_t2f_v3f (arr, 0 , tex.t, px , py + T, 0);
2318     rc_t2f_v3f (arr, tex.s, tex.t, px + T, py + T, 0);
2319     rc_t2f_v3f (arr, tex.s, 0 , px + T, py , 0);
2320 root 1.285 }
2321     }
2322 root 1.176 }
2323     }
2324 root 1.174
2325 root 1.224 rc_draw (rc);
2326     rc_clear (rc);
2327    
2328 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
2329     // this is basically counting sort
2330 root 1.176 {
2331 root 1.186 int w, b;
2332 root 1.30
2333 root 1.226 glEnable (GL_TEXTURE_2D);
2334     glBegin (GL_QUADS);
2335 root 1.186 for (w = 0; w < 256 / 32; ++w)
2336     {
2337     uint32_t smask = smooth_level [w];
2338     if (smask)
2339     for (b = 0; b < 32; ++b)
2340     if (smask & (((uint32_t)1) << b))
2341 root 1.176 {
2342 root 1.186 int level = (w << 5) | b;
2343     HE *he;
2344 root 1.153
2345 root 1.186 hv_iterinit (smooth);
2346     while ((he = hv_iternext (smooth)))
2347 root 1.153 {
2348 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
2349     IV bits = SvIVX (HeVAL (he));
2350 root 1.176
2351 root 1.186 if (!(bits & 0x1000)
2352     && skey->level == level
2353 root 1.191 && level > smooth_max [skey->x][skey->y])
2354 root 1.174 {
2355 root 1.186 maptex tex = self->tex [skey->tile];
2356     int px = (((int)skey->x) - 1) * T;
2357     int py = (((int)skey->y) - 1) * T;
2358     int border = bits & 15;
2359     int corner = (bits >> 8) & ~(bits >> 4) & 15;
2360     float dx = tex.s * .0625f; // 16 images/row
2361     float dy = tex.t * .5f ; // 2 images/column
2362    
2363 root 1.223 if (tex.name)
2364 root 1.186 {
2365 root 1.223 // this time avoiding texture state changes
2366     // save gobs of state changes.
2367     if (key.texname != tex.name)
2368     {
2369 root 1.280 self->tex [skey->tile].unused = 0;
2370    
2371 root 1.226 glEnd ();
2372     glBindTexture (GL_TEXTURE_2D, key.texname = tex.name);
2373     glBegin (GL_QUADS);
2374 root 1.223 }
2375    
2376     if (border)
2377     {
2378     float ox = border * dx;
2379    
2380 root 1.226 glTexCoord2f (ox , 0.f ); glVertex2i (px , py );
2381     glTexCoord2f (ox , dy ); glVertex2i (px , py + T);
2382     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py + T);
2383     glTexCoord2f (ox + dx, 0.f ); glVertex2i (px + T, py );
2384 root 1.223 }
2385    
2386     if (corner)
2387     {
2388     float ox = corner * dx;
2389    
2390 root 1.226 glTexCoord2f (ox , dy ); glVertex2i (px , py );
2391     glTexCoord2f (ox , dy * 2.f); glVertex2i (px , py + T);
2392     glTexCoord2f (ox + dx, dy * 2.f); glVertex2i (px + T, py + T);
2393     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py );
2394 root 1.223 }
2395 root 1.186 }
2396 root 1.174 }
2397 root 1.153 }
2398     }
2399 root 1.186 }
2400 root 1.226
2401     glEnd ();
2402     glDisable (GL_TEXTURE_2D);
2403     key.texname = -1;
2404 root 1.176 }
2405    
2406 root 1.186 hv_clear (smooth);
2407     }
2408 root 1.30
2409 root 1.261 if (pl_tex.name)
2410     {
2411     maptex tex = pl_tex;
2412 root 1.266 int px = pl_x + sdx;
2413     int py = pl_y + sdy;
2414 root 1.261
2415     key.texname = tex.name;
2416     arr = rc_array (rc, &key);
2417    
2418     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2419     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
2420     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
2421     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
2422    
2423     rc_draw (rc);
2424     }
2425    
2426 root 1.285 rc_draw (rc_ov);
2427     rc_clear (rc_ov);
2428    
2429 root 1.152 glDisable (GL_BLEND);
2430 root 1.223 rc_free (rc);
2431 root 1.285 rc_free (rc_ov);
2432 root 1.143
2433 root 1.145 // top layer: overlays such as the health bar
2434 root 1.143 for (y = 0; y < sh; y++)
2435 root 1.164 if (0 <= y + my && y + my < self->rows)
2436 root 1.143 {
2437 root 1.164 maprow *row = self->row + (y + my);
2438 root 1.143
2439     for (x = 0; x < sw; x++)
2440 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2441 root 1.143 {
2442 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2443 root 1.143
2444 root 1.171 int px = x * T;
2445     int py = y * T;
2446 root 1.143
2447 root 1.279 if (expect_false (cell->player == player))
2448     {
2449     px += sdx;
2450     py += sdy;
2451     }
2452    
2453 root 1.143 if (cell->stat_hp)
2454     {
2455 root 1.171 int width = cell->stat_width * T;
2456 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
2457 root 1.143
2458 root 1.152 glColor3ub (0, 0, 0);
2459 root 1.151 glRectf (px + 1, py - thick - 2,
2460     px + width - 1, py);
2461 root 1.147
2462 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
2463 root 1.147 glRectf (px + 2,
2464 root 1.151 py - thick - 1,
2465     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
2466 root 1.143 }
2467     }
2468     }
2469 root 1.116 }
2470    
2471     void
2472 root 1.295 draw_magicmap (DC::Map self, int w, int h, unsigned char *data)
2473 root 1.117 CODE:
2474     {
2475     static float color[16][3] = {
2476 root 1.295 { 0.00f, 0.00f, 0.00f },
2477     { 1.00f, 1.00f, 1.00f },
2478     { 0.00f, 0.00f, 0.55f },
2479     { 1.00f, 0.00f, 0.00f },
2480    
2481     { 1.00f, 0.54f, 0.00f },
2482     { 0.11f, 0.56f, 1.00f },
2483     { 0.93f, 0.46f, 0.00f },
2484     { 0.18f, 0.54f, 0.34f },
2485    
2486     { 0.56f, 0.73f, 0.56f },
2487     { 0.80f, 0.80f, 0.80f },
2488     { 0.55f, 0.41f, 0.13f },
2489     { 0.99f, 0.77f, 0.26f },
2490    
2491     { 0.74f, 0.65f, 0.41f },
2492    
2493     { 0.00f, 1.00f, 1.00f },
2494     { 1.00f, 0.00f, 1.00f },
2495     { 1.00f, 1.00f, 0.00f },
2496 root 1.117 };
2497    
2498     int x, y;
2499    
2500     glEnable (GL_TEXTURE_2D);
2501 root 1.290 /* GL_REPLACE would be correct, as we don't need to modulate alpha,
2502     * but the nvidia driver (185.18.14) mishandles alpha textures
2503 root 1.296 * and takes the colour from god knows where instead of using
2504 root 1.290 * Cp. MODULATE results in the same colour, but slightly different
2505     * alpha, but atcually gives us the correct colour with nvidia.
2506     */
2507     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2508 root 1.117 glEnable (GL_BLEND);
2509     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2510     glBegin (GL_QUADS);
2511    
2512     for (y = 0; y < h; y++)
2513     for (x = 0; x < w; x++)
2514     {
2515     unsigned char m = data [x + y * w];
2516    
2517 root 1.118 if (m)
2518     {
2519     float *c = color [m & 15];
2520    
2521 root 1.295 float tx1 = m & 0x40 ? 0.5f : 0.f;
2522     float tx2 = tx1 + 0.5f;
2523 root 1.118
2524 root 1.290 glColor4f (c[0], c[1], c[2], 1);
2525 root 1.118 glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2526     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2527     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2528     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2529     }
2530 root 1.117 }
2531    
2532     glEnd ();
2533     glDisable (GL_BLEND);
2534     glDisable (GL_TEXTURE_2D);
2535     }
2536    
2537     void
2538 root 1.242 fow_texture (DC::Map self, int mx, int my, int sw, int sh)
2539 root 1.116 PPCODE:
2540     {
2541     int x, y;
2542 root 1.296 int sw1 = sw + 2;
2543     int sh1 = sh + 2;
2544     int sh3 = sh * 3;
2545     int sw3 = sw * 3;
2546 root 1.204 uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2547 root 1.296 SV *darkness3_sv = sv_2mortal (newSV (sw3 * sh3));
2548 root 1.204 uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2549    
2550     SvPOK_only (darkness3_sv);
2551 root 1.296 SvCUR_set (darkness3_sv, sw3 * sh3);
2552 root 1.116
2553 root 1.204 mx += self->x - 1;
2554     my += self->y - 1;
2555 root 1.116
2556 root 1.204 for (y = 0; y < sh1; y++)
2557 root 1.164 if (0 <= y + my && y + my < self->rows)
2558 root 1.116 {
2559 root 1.164 maprow *row = self->row + (y + my);
2560 root 1.116
2561 root 1.204 for (x = 0; x < sw1; x++)
2562 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2563 root 1.116 {
2564 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2565 root 1.116
2566 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2567 root 1.294 ? DARKNESS_ADJUST (255 - (cell->darkness - 1))
2568     : DARKNESS_ADJUST (255 - FOW_DARKNESS);
2569 root 1.116 }
2570     }
2571 root 1.34
2572 root 1.204 for (y = 0; y < sh; ++y)
2573     for (x = 0; x < sw; ++x)
2574     {
2575     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2576     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2577     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2578     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2579     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2580     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2581     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2582     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2583     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2584    
2585     uint8_t r11 = (d11 + d21 + d12) / 3;
2586     uint8_t r21 = d21;
2587     uint8_t r31 = (d21 + d31 + d32) / 3;
2588    
2589     uint8_t r12 = d12;
2590     uint8_t r22 = d22;
2591     uint8_t r32 = d32;
2592    
2593     uint8_t r13 = (d13 + d23 + d12) / 3;
2594     uint8_t r23 = d23;
2595     uint8_t r33 = (d23 + d33 + d32) / 3;
2596    
2597 root 1.296 darkness3 [(y * 3 ) * sw3 + (x * 3 )] = MAX (d22, r11);
2598     darkness3 [(y * 3 ) * sw3 + (x * 3 + 1)] = MAX (d22, r21);
2599     darkness3 [(y * 3 ) * sw3 + (x * 3 + 2)] = MAX (d22, r31);
2600     darkness3 [(y * 3 + 1) * sw3 + (x * 3 )] = MAX (d22, r12);
2601     darkness3 [(y * 3 + 1) * sw3 + (x * 3 + 1)] = MAX (d22, r22); /* this MUST be == d22 */
2602     darkness3 [(y * 3 + 1) * sw3 + (x * 3 + 2)] = MAX (d22, r32);
2603     darkness3 [(y * 3 + 2) * sw3 + (x * 3 )] = MAX (d22, r13);
2604     darkness3 [(y * 3 + 2) * sw3 + (x * 3 + 1)] = MAX (d22, r23);
2605     darkness3 [(y * 3 + 2) * sw3 + (x * 3 + 2)] = MAX (d22, r33);
2606 root 1.204 }
2607 root 1.201
2608 root 1.204 free (darkness1);
2609 root 1.201
2610 root 1.32 EXTEND (SP, 3);
2611 root 1.296 PUSHs (sv_2mortal (newSViv (sw3)));
2612 root 1.204 PUSHs (sv_2mortal (newSViv (sh3)));
2613     PUSHs (darkness3_sv);
2614 root 1.30 }
2615    
2616 root 1.42 SV *
2617 root 1.242 get_rect (DC::Map self, int x0, int y0, int w, int h)
2618 root 1.42 CODE:
2619     {
2620     int x, y, x1, y1;
2621     SV *data_sv = newSV (w * h * 7 + 5);
2622     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2623    
2624     *data++ = 0; /* version 0 format */
2625     *data++ = w >> 8; *data++ = w;
2626     *data++ = h >> 8; *data++ = h;
2627    
2628     // we need to do this 'cause we don't keep an absolute coord system for rows
2629 root 1.55 // TODO: treat rows as we treat columns
2630 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2631     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2632    
2633     x0 += self->x - self->ox;
2634     y0 += self->y - self->oy;
2635    
2636     x1 = x0 + w;
2637     y1 = y0 + h;
2638    
2639     for (y = y0; y < y1; y++)
2640     {
2641     maprow *row = 0 <= y && y < self->rows
2642     ? self->row + y
2643     : 0;
2644    
2645     for (x = x0; x < x1; x++)
2646     {
2647     if (row && row->c0 <= x && x < row->c1)
2648     {
2649     mapcell *cell = row->col + (x - row->c0);
2650     uint8_t flags = 0;
2651    
2652 root 1.174 if (cell->tile [0]) flags |= 1;
2653     if (cell->tile [1]) flags |= 2;
2654     if (cell->tile [2]) flags |= 4;
2655 root 1.42
2656     *data++ = flags;
2657    
2658     if (flags & 1)
2659     {
2660 root 1.174 tileid tile = cell->tile [0];
2661     *data++ = tile >> 8;
2662     *data++ = tile;
2663 root 1.42 }
2664    
2665     if (flags & 2)
2666     {
2667 root 1.174 tileid tile = cell->tile [1];
2668     *data++ = tile >> 8;
2669     *data++ = tile;
2670 root 1.42 }
2671    
2672     if (flags & 4)
2673     {
2674 root 1.174 tileid tile = cell->tile [2];
2675     *data++ = tile >> 8;
2676     *data++ = tile;
2677 root 1.42 }
2678     }
2679     else
2680     *data++ = 0;
2681     }
2682     }
2683    
2684 root 1.260 /* if size is w*h + 5 then no data has been found */
2685     if (data - (uint8_t *)SvPVX (data_sv) != w * h + 5)
2686 root 1.259 {
2687     SvPOK_only (data_sv);
2688     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2689     }
2690 root 1.260
2691     RETVAL = data_sv;
2692 root 1.42 }
2693     OUTPUT:
2694     RETVAL
2695    
2696     void
2697 root 1.259 set_rect (DC::Map self, int x0, int y0, SV *data_sv)
2698 root 1.42 PPCODE:
2699     {
2700     int x, y, z;
2701 root 1.48 int w, h;
2702 root 1.42 int x1, y1;
2703 root 1.259 STRLEN len;
2704     uint8_t *data, *end;
2705    
2706     len = SvLEN (data_sv);
2707 root 1.260 SvGROW (data_sv, len + 8); // reserve at least 7+ bytes more
2708 root 1.259 data = SvPVbyte_nolen (data_sv);
2709 root 1.260 end = data + len + 8;
2710 root 1.259
2711     if (len < 5)
2712     XSRETURN_EMPTY;
2713 root 1.42
2714     if (*data++ != 0)
2715 root 1.227 XSRETURN_EMPTY; /* version mismatch */
2716 root 1.42
2717 root 1.48 w = *data++ << 8; w |= *data++;
2718     h = *data++ << 8; h |= *data++;
2719 root 1.42
2720     // we need to do this 'cause we don't keep an absolute coord system for rows
2721 root 1.55 // TODO: treat rows as we treat columns
2722 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2723     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2724    
2725     x0 += self->x - self->ox;
2726     y0 += self->y - self->oy;
2727    
2728     x1 = x0 + w;
2729     y1 = y0 + h;
2730    
2731     for (y = y0; y < y1; y++)
2732     {
2733     maprow *row = map_get_row (self, y);
2734    
2735     for (x = x0; x < x1; x++)
2736     {
2737 root 1.259 uint8_t flags;
2738    
2739     if (data + 7 >= end)
2740     XSRETURN_EMPTY;
2741    
2742     flags = *data++;
2743 root 1.42
2744     if (flags)
2745     {
2746     mapcell *cell = row_get_cell (row, x);
2747 root 1.174 tileid tile[3] = { 0, 0, 0 };
2748 root 1.42
2749 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2750     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2751     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2752 root 1.42
2753 root 1.143 if (cell->darkness == 0)
2754 root 1.42 {
2755 root 1.260 /*cell->darkness = 0;*/
2756     EXTEND (SP, 3);
2757 root 1.42
2758     for (z = 0; z <= 2; z++)
2759     {
2760 root 1.174 tileid t = tile [z];
2761    
2762 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2763 root 1.174 {
2764 root 1.260 PUSHs (sv_2mortal (newSViv (t)));
2765 root 1.174 need_texid (self, t);
2766     }
2767 root 1.42
2768 root 1.174 cell->tile [z] = t;
2769 root 1.42 }
2770     }
2771     }
2772     }
2773     }
2774     }
2775    
2776 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::RW
2777 root 1.205
2778 root 1.242 DC::RW
2779 root 1.211 new (SV *class, SV *data_sv)
2780     CODE:
2781     {
2782     STRLEN datalen;
2783     char *data = SvPVbyte (data_sv, datalen);
2784    
2785 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2786 root 1.211 }
2787     OUTPUT:
2788     RETVAL
2789    
2790 root 1.242 DC::RW
2791 root 1.212 new_from_file (SV *class, const char *path, const char *mode = "rb")
2792     CODE:
2793     RETVAL = SDL_RWFromFile (path, mode);
2794     OUTPUT:
2795     RETVAL
2796    
2797 root 1.218 # fails on win32:
2798 root 1.241 # dc.xs(2268) : error C2059: syntax error : '('
2799 root 1.218 #void
2800 root 1.242 #close (DC::RW self)
2801 root 1.218 # CODE:
2802     # (self->(close)) (self);
2803 root 1.212
2804 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Channel
2805 root 1.212
2806     PROTOTYPES: DISABLE
2807    
2808 root 1.242 DC::Channel
2809 root 1.215 find ()
2810     CODE:
2811     {
2812     RETVAL = Mix_GroupAvailable (-1);
2813    
2814     if (RETVAL < 0)
2815     {
2816     RETVAL = Mix_GroupOldest (-1);
2817    
2818     if (RETVAL < 0)
2819 root 1.302 {
2820     // happens sometimes, maybe it just stopped playing(?)
2821     RETVAL = Mix_GroupAvailable (-1);
2822 root 1.215
2823 root 1.302 if (RETVAL < 0)
2824     XSRETURN_UNDEF;
2825     }
2826     else
2827     Mix_HaltChannel (RETVAL);
2828 root 1.215 }
2829    
2830     Mix_UnregisterAllEffects (RETVAL);
2831     Mix_Volume (RETVAL, 128);
2832     }
2833     OUTPUT:
2834     RETVAL
2835    
2836 root 1.213 void
2837 root 1.242 halt (DC::Channel self)
2838 root 1.213 CODE:
2839     Mix_HaltChannel (self);
2840    
2841     void
2842 root 1.242 expire (DC::Channel self, int ticks = -1)
2843 root 1.213 CODE:
2844     Mix_ExpireChannel (self, ticks);
2845    
2846     void
2847 root 1.242 fade_out (DC::Channel self, int ticks = -1)
2848 root 1.213 CODE:
2849     Mix_FadeOutChannel (self, ticks);
2850    
2851 root 1.212 int
2852 root 1.242 volume (DC::Channel self, int volume)
2853 root 1.212 CODE:
2854 root 1.216 RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128));
2855 root 1.212 OUTPUT:
2856     RETVAL
2857    
2858 root 1.213 void
2859 root 1.242 unregister_all_effects (DC::Channel self)
2860 root 1.212 CODE:
2861 root 1.213 Mix_UnregisterAllEffects (self);
2862 root 1.212
2863 root 1.213 void
2864 root 1.242 set_panning (DC::Channel self, int left, int right)
2865 root 1.212 CODE:
2866 root 1.216 left = CLAMP (left , 0, 255);
2867     right = CLAMP (right, 0, 255);
2868 root 1.213 Mix_SetPanning (self, left, right);
2869 root 1.212
2870 root 1.213 void
2871 root 1.242 set_distance (DC::Channel self, int distance)
2872 root 1.212 CODE:
2873 root 1.216 Mix_SetDistance (self, CLAMP (distance, 0, 255));
2874 root 1.212
2875 root 1.213 void
2876 root 1.242 set_position (DC::Channel self, int angle, int distance)
2877 root 1.212 CODE:
2878 root 1.220
2879     void
2880 root 1.242 set_position_r (DC::Channel self, int dx, int dy, int maxdistance)
2881 root 1.220 CODE:
2882     {
2883     int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance));
2884 root 1.295 int angle = atan2f (dx, -dy) * 180.f / (float)M_PI + 360.f;
2885 root 1.216 Mix_SetPosition (self, angle, CLAMP (distance, 0, 255));
2886 root 1.220 }
2887 root 1.212
2888 root 1.213 void
2889 root 1.242 set_reverse_stereo (DC::Channel self, int flip)
2890 root 1.212 CODE:
2891 root 1.213 Mix_SetReverseStereo (self, flip);
2892 root 1.212
2893 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixChunk
2894 root 1.212
2895     PROTOTYPES: DISABLE
2896    
2897 root 1.301 void
2898     decoders ()
2899     PPCODE:
2900     #if SDL_MIXER_MAJOR_VERSION > 1 || SDL_MIXER_MINOR_VERSION > 2 || SDL_MIXER_PATCHLEVEL >= 10
2901     int i, num = Mix_GetNumChunkDecoders ();
2902     EXTEND (SP, num);
2903     for (i = 0; i < num; ++i)
2904     PUSHs (sv_2mortal (newSVpv (Mix_GetChunkDecoder (i), 0)));
2905     #else
2906     XPUSHs (sv_2mortal (newSVpv ("(sdl mixer too old)", 0)));
2907     #endif
2908    
2909 root 1.242 DC::MixChunk
2910     new (SV *class, DC::RW rwops)
2911 root 1.52 CODE:
2912 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2913 root 1.52 OUTPUT:
2914     RETVAL
2915    
2916     void
2917 root 1.242 DESTROY (DC::MixChunk self)
2918 root 1.52 CODE:
2919     Mix_FreeChunk (self);
2920    
2921     int
2922 root 1.242 volume (DC::MixChunk self, int volume = -1)
2923 root 1.52 CODE:
2924 root 1.216 if (items > 1)
2925     volume = CLAMP (volume, 0, 128);
2926 root 1.52 RETVAL = Mix_VolumeChunk (self, volume);
2927     OUTPUT:
2928     RETVAL
2929    
2930 root 1.242 DC::Channel
2931     play (DC::MixChunk self, DC::Channel channel = -1, int loops = 0, int ticks = -1)
2932 root 1.52 CODE:
2933 root 1.215 {
2934 root 1.52 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2935 root 1.215
2936     if (RETVAL < 0)
2937     XSRETURN_UNDEF;
2938    
2939     if (channel < 0)
2940     {
2941     Mix_UnregisterAllEffects (RETVAL);
2942     Mix_Volume (RETVAL, 128);
2943     }
2944     }
2945 root 1.52 OUTPUT:
2946     RETVAL
2947    
2948 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixMusic
2949 root 1.52
2950 root 1.301 void
2951     decoders ()
2952     PPCODE:
2953     #if SDL_MIXER_MAJOR_VERSION > 1 || SDL_MIXER_MINOR_VERSION > 2 || SDL_MIXER_PATCHLEVEL >= 10
2954     int i, num = Mix_GetNumMusicDecoders ();
2955     EXTEND (SP, num);
2956     for (i = 0; i < num; ++i)
2957     PUSHs (sv_2mortal (newSVpv (Mix_GetMusicDecoder (i), 0)));
2958     #else
2959     XPUSHs (sv_2mortal (newSVpv ("(sdl mixer too old)", 0)));
2960     #endif
2961    
2962 root 1.52 int
2963     volume (int volume = -1)
2964 root 1.205 PROTOTYPE: ;$
2965 root 1.52 CODE:
2966 root 1.216 if (items > 0)
2967     volume = CLAMP (volume, 0, 128);
2968 root 1.52 RETVAL = Mix_VolumeMusic (volume);
2969     OUTPUT:
2970     RETVAL
2971    
2972 root 1.213 void
2973 root 1.194 fade_out (int ms)
2974     CODE:
2975 root 1.213 Mix_FadeOutMusic (ms);
2976 root 1.194
2977 root 1.212 void
2978     halt ()
2979     CODE:
2980     Mix_HaltMusic ();
2981    
2982 root 1.301 int
2983     playing ()
2984     CODE:
2985     RETVAL = Mix_PlayingMusic ();
2986     OUTPUT:
2987     RETVAL
2988    
2989 root 1.242 DC::MixMusic
2990     new (SV *class, DC::RW rwops)
2991 root 1.52 CODE:
2992 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
2993 root 1.52 OUTPUT:
2994     RETVAL
2995    
2996     void
2997 root 1.242 DESTROY (DC::MixMusic self)
2998 root 1.52 CODE:
2999     Mix_FreeMusic (self);
3000    
3001     int
3002 root 1.242 play (DC::MixMusic self, int loops = -1)
3003 root 1.52 CODE:
3004     RETVAL = Mix_PlayMusic (self, loops);
3005     OUTPUT:
3006     RETVAL
3007    
3008 root 1.213 void
3009 root 1.242 fade_in_pos (DC::MixMusic self, int loops, int ms, double position)
3010 root 1.195 CODE:
3011 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
3012 root 1.195
3013 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::OpenGL
3014 root 1.54
3015 root 1.205 PROTOTYPES: ENABLE
3016    
3017 root 1.54 BOOT:
3018     {
3019 root 1.242 HV *stash = gv_stashpv ("DC::OpenGL", 1);
3020 root 1.54 static const struct {
3021     const char *name;
3022     IV iv;
3023     } *civ, const_iv[] = {
3024     # define const_iv(name) { # name, (IV)name }
3025 root 1.199 const_iv (GL_VENDOR),
3026     const_iv (GL_VERSION),
3027     const_iv (GL_EXTENSIONS),
3028 root 1.293 const_iv (GL_MAX_TEXTURE_UNITS),
3029 root 1.54 const_iv (GL_COLOR_MATERIAL),
3030     const_iv (GL_SMOOTH),
3031     const_iv (GL_FLAT),
3032 root 1.69 const_iv (GL_DITHER),
3033 root 1.54 const_iv (GL_BLEND),
3034 root 1.89 const_iv (GL_CULL_FACE),
3035 root 1.69 const_iv (GL_SCISSOR_TEST),
3036 root 1.89 const_iv (GL_DEPTH_TEST),
3037     const_iv (GL_ALPHA_TEST),
3038     const_iv (GL_NORMALIZE),
3039     const_iv (GL_RESCALE_NORMAL),
3040 root 1.119 const_iv (GL_FRONT),
3041     const_iv (GL_BACK),
3042 root 1.206 const_iv (GL_AUX0),
3043 root 1.54 const_iv (GL_AND),
3044 root 1.67 const_iv (GL_ONE),
3045     const_iv (GL_ZERO),
3046 root 1.54 const_iv (GL_SRC_ALPHA),
3047 root 1.104 const_iv (GL_DST_ALPHA),
3048 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
3049 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
3050 root 1.293 const_iv (GL_SRC_COLOR),
3051     const_iv (GL_DST_COLOR),
3052     const_iv (GL_ONE_MINUS_SRC_COLOR),
3053     const_iv (GL_ONE_MINUS_DST_COLOR),
3054 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
3055 root 1.54 const_iv (GL_RGB),
3056     const_iv (GL_RGBA),
3057 root 1.115 const_iv (GL_RGBA4),
3058     const_iv (GL_RGBA8),
3059     const_iv (GL_RGB5_A1),
3060 root 1.54 const_iv (GL_UNSIGNED_BYTE),
3061 root 1.89 const_iv (GL_UNSIGNED_SHORT),
3062     const_iv (GL_UNSIGNED_INT),
3063 root 1.54 const_iv (GL_ALPHA),
3064 root 1.86 const_iv (GL_INTENSITY),
3065 root 1.76 const_iv (GL_LUMINANCE),
3066 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
3067 root 1.54 const_iv (GL_FLOAT),
3068     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
3069 root 1.230 const_iv (GL_COMPRESSED_ALPHA_ARB),
3070     const_iv (GL_COMPRESSED_LUMINANCE_ARB),
3071     const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB),
3072     const_iv (GL_COMPRESSED_INTENSITY_ARB),
3073     const_iv (GL_COMPRESSED_RGB_ARB),
3074     const_iv (GL_COMPRESSED_RGBA_ARB),
3075 root 1.54 const_iv (GL_COMPILE),
3076 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
3077     const_iv (GL_PROXY_TEXTURE_2D),
3078 root 1.54 const_iv (GL_TEXTURE_1D),
3079     const_iv (GL_TEXTURE_2D),
3080     const_iv (GL_TEXTURE_ENV),
3081     const_iv (GL_TEXTURE_MAG_FILTER),
3082     const_iv (GL_TEXTURE_MIN_FILTER),
3083     const_iv (GL_TEXTURE_ENV_MODE),
3084     const_iv (GL_TEXTURE_WRAP_S),
3085     const_iv (GL_TEXTURE_WRAP_T),
3086 root 1.98 const_iv (GL_REPEAT),
3087 root 1.54 const_iv (GL_CLAMP),
3088 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
3089 root 1.54 const_iv (GL_NEAREST),
3090     const_iv (GL_LINEAR),
3091 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
3092     const_iv (GL_LINEAR_MIPMAP_NEAREST),
3093     const_iv (GL_NEAREST_MIPMAP_LINEAR),
3094     const_iv (GL_LINEAR_MIPMAP_LINEAR),
3095     const_iv (GL_GENERATE_MIPMAP),
3096 root 1.54 const_iv (GL_MODULATE),
3097 root 1.69 const_iv (GL_DECAL),
3098 root 1.54 const_iv (GL_REPLACE),
3099 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
3100 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
3101     const_iv (GL_PROJECTION),
3102     const_iv (GL_MODELVIEW),
3103     const_iv (GL_COLOR_LOGIC_OP),
3104 root 1.69 const_iv (GL_SEPARABLE_2D),
3105 root 1.54 const_iv (GL_CONVOLUTION_2D),
3106     const_iv (GL_CONVOLUTION_BORDER_MODE),
3107     const_iv (GL_CONSTANT_BORDER),
3108 root 1.208 const_iv (GL_POINTS),
3109 root 1.54 const_iv (GL_LINES),
3110 root 1.138 const_iv (GL_LINE_STRIP),
3111 root 1.89 const_iv (GL_LINE_LOOP),
3112 root 1.54 const_iv (GL_QUADS),
3113 root 1.89 const_iv (GL_QUAD_STRIP),
3114     const_iv (GL_TRIANGLES),
3115     const_iv (GL_TRIANGLE_STRIP),
3116     const_iv (GL_TRIANGLE_FAN),
3117 root 1.208 const_iv (GL_POLYGON),
3118 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
3119 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
3120     const_iv (GL_LINE_SMOOTH_HINT),
3121     const_iv (GL_POLYGON_SMOOTH_HINT),
3122     const_iv (GL_GENERATE_MIPMAP_HINT),
3123 root 1.232 const_iv (GL_TEXTURE_COMPRESSION_HINT),
3124 root 1.54 const_iv (GL_FASTEST),
3125 root 1.206 const_iv (GL_DONT_CARE),
3126     const_iv (GL_NICEST),
3127 root 1.89 const_iv (GL_V2F),
3128     const_iv (GL_V3F),
3129     const_iv (GL_T2F_V3F),
3130     const_iv (GL_T2F_N3F_V3F),
3131 root 1.291 const_iv (GL_FUNC_ADD),
3132     const_iv (GL_FUNC_SUBTRACT),
3133     const_iv (GL_FUNC_REVERSE_SUBTRACT),
3134 root 1.54 # undef const_iv
3135     };
3136    
3137     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
3138     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
3139 root 1.188
3140     texture_av = newAV ();
3141     AvREAL_off (texture_av);
3142 root 1.54 }
3143    
3144 root 1.231 void
3145     disable_GL_EXT_blend_func_separate ()
3146     CODE:
3147     gl.BlendFuncSeparate = 0;
3148     gl.BlendFuncSeparateEXT = 0;
3149    
3150 root 1.291 void
3151     apple_nvidia_bug (int enable)
3152    
3153 root 1.97 char *
3154     gl_vendor ()
3155     CODE:
3156     RETVAL = (char *)glGetString (GL_VENDOR);
3157     OUTPUT:
3158     RETVAL
3159    
3160     char *
3161     gl_version ()
3162     CODE:
3163     RETVAL = (char *)glGetString (GL_VERSION);
3164     OUTPUT:
3165     RETVAL
3166    
3167     char *
3168     gl_extensions ()
3169     CODE:
3170     RETVAL = (char *)glGetString (GL_EXTENSIONS);
3171     OUTPUT:
3172     RETVAL
3173    
3174 root 1.201 const char *glGetString (GLenum pname)
3175 root 1.199
3176     GLint glGetInteger (GLenum pname)
3177     CODE:
3178     glGetIntegerv (pname, &RETVAL);
3179     OUTPUT:
3180     RETVAL
3181    
3182     GLdouble glGetDouble (GLenum pname)
3183     CODE:
3184     glGetDoublev (pname, &RETVAL);
3185     OUTPUT:
3186     RETVAL
3187    
3188 root 1.54 int glGetError ()
3189    
3190 root 1.114 void glFinish ()
3191    
3192 root 1.304 void glFlush ()
3193    
3194 root 1.54 void glClear (int mask)
3195    
3196     void glClearColor (float r, float g, float b, float a = 1.0)
3197     PROTOTYPE: @
3198    
3199     void glEnable (int cap)
3200    
3201     void glDisable (int cap)
3202    
3203     void glShadeModel (int mode)
3204    
3205     void glHint (int target, int mode)
3206    
3207     void glBlendFunc (int sfactor, int dfactor)
3208    
3209 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
3210     CODE:
3211     gl_BlendFuncSeparate (sa, da, saa, daa);
3212    
3213 root 1.292 # void glBlendEquation (int se)
3214 root 1.291
3215 root 1.89 void glDepthMask (int flag)
3216    
3217 root 1.54 void glLogicOp (int opcode)
3218    
3219 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
3220    
3221 root 1.54 void glMatrixMode (int mode)
3222    
3223     void glPushMatrix ()
3224    
3225     void glPopMatrix ()
3226    
3227     void glLoadIdentity ()
3228    
3229 root 1.119 void glDrawBuffer (int buffer)
3230    
3231     void glReadBuffer (int buffer)
3232    
3233 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
3234     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
3235    
3236     # near_ and far_ are due to microsofts buggy "c" compiler
3237 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
3238 root 1.54
3239 root 1.208 PROTOTYPES: DISABLE
3240    
3241 root 1.54 void glViewport (int x, int y, int width, int height)
3242    
3243 root 1.69 void glScissor (int x, int y, int width, int height)
3244    
3245 root 1.54 void glTranslate (float x, float y, float z = 0.)
3246     CODE:
3247     glTranslatef (x, y, z);
3248    
3249 root 1.62 void glScale (float x, float y, float z = 1.)
3250 root 1.54 CODE:
3251     glScalef (x, y, z);
3252    
3253     void glRotate (float angle, float x, float y, float z)
3254     CODE:
3255     glRotatef (angle, x, y, z);
3256    
3257     void glColor (float r, float g, float b, float a = 1.0)
3258 root 1.278 PROTOTYPE: @
3259 root 1.103 ALIAS:
3260     glColor_premultiply = 1
3261 root 1.54 CODE:
3262 root 1.103 if (ix)
3263     {
3264     r *= a;
3265     g *= a;
3266     b *= a;
3267     }
3268 root 1.90 // microsoft visual "c" rounds instead of truncating...
3269 root 1.130 glColor4f (r, g, b, a);
3270 root 1.54
3271 root 1.91 void glRasterPos (float x, float y, float z = 0.)
3272     CODE:
3273     glRasterPos3f (0, 0, z);
3274     glBitmap (0, 0, 0, 0, x, y, 0);
3275    
3276 root 1.54 void glVertex (float x, float y, float z = 0.)
3277     CODE:
3278     glVertex3f (x, y, z);
3279    
3280     void glTexCoord (float s, float t)
3281     CODE:
3282     glTexCoord2f (s, t);
3283    
3284 root 1.210 void glRect (float x1, float y1, float x2, float y2)
3285     CODE:
3286     glRectf (x1, y1, x2, y2);
3287    
3288 root 1.233 void glRect_lineloop (float x1, float y1, float x2, float y2)
3289     CODE:
3290     glBegin (GL_LINE_LOOP);
3291     glVertex2f (x1, y1);
3292     glVertex2f (x2, y1);
3293     glVertex2f (x2, y2);
3294     glVertex2f (x1, y2);
3295     glEnd ();
3296    
3297 root 1.208 PROTOTYPES: ENABLE
3298    
3299     void glBegin (int mode)
3300    
3301     void glEnd ()
3302    
3303     void glPointSize (GLfloat size)
3304    
3305     void glLineWidth (GLfloat width)
3306    
3307     void glInterleavedArrays (int format, int stride, char *data)
3308    
3309     void glDrawElements (int mode, int count, int type, char *indices)
3310    
3311     # 1.2 void glDrawRangeElements (int mode, int start, int end
3312    
3313 root 1.54 void glTexEnv (int target, int pname, float param)
3314     CODE:
3315     glTexEnvf (target, pname, param);
3316    
3317     void glTexParameter (int target, int pname, float param)
3318     CODE:
3319     glTexParameterf (target, pname, param);
3320    
3321     void glBindTexture (int target, int name)
3322    
3323     void glConvolutionParameter (int target, int pname, float params)
3324     CODE:
3325 root 1.103 if (gl.ConvolutionParameterf)
3326     gl.ConvolutionParameterf (target, pname, params);
3327 root 1.54
3328     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
3329 root 1.64 CODE:
3330 root 1.103 if (gl.ConvolutionFilter2D)
3331     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
3332 root 1.54
3333 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
3334     CODE:
3335 root 1.103 if (gl.SeparableFilter2D)
3336     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
3337 root 1.69
3338 root 1.244 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data = 0)
3339 root 1.54
3340     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
3341    
3342 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
3343 root 1.68
3344 root 1.199 void glPixelZoom (float x, float y)
3345    
3346 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
3347    
3348 root 1.54 int glGenTexture ()
3349     CODE:
3350 root 1.192 RETVAL = gen_texture ();
3351 root 1.54 OUTPUT:
3352     RETVAL
3353    
3354     void glDeleteTexture (int name)
3355     CODE:
3356 root 1.192 del_texture (name);
3357    
3358 root 1.54 int glGenList ()
3359     CODE:
3360     RETVAL = glGenLists (1);
3361     OUTPUT:
3362     RETVAL
3363    
3364     void glDeleteList (int list)
3365     CODE:
3366     glDeleteLists (list, 1);
3367    
3368     void glNewList (int list, int mode = GL_COMPILE)
3369    
3370     void glEndList ()
3371    
3372     void glCallList (int list)
3373    
3374 root 1.296 void c_init ()
3375     CODE:
3376     glPixelStorei (GL_PACK_ALIGNMENT , 1);
3377     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
3378    
3379 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::UI::Base
3380 root 1.207
3381     PROTOTYPES: DISABLE
3382    
3383     void
3384 root 1.209 find_widget (SV *self, NV x, NV y)
3385 root 1.207 PPCODE:
3386     {
3387 root 1.209 if (within_widget (self, x, y))
3388     XPUSHs (self);
3389     }
3390    
3391     BOOT:
3392     {
3393 root 1.242 hover_gv = gv_fetchpv ("DC::UI::HOVER", 1, SVt_NV);
3394 root 1.209
3395 root 1.242 draw_x_gv = gv_fetchpv ("DC::UI::Base::draw_x", 1, SVt_NV);
3396     draw_y_gv = gv_fetchpv ("DC::UI::Base::draw_y", 1, SVt_NV);
3397     draw_w_gv = gv_fetchpv ("DC::UI::Base::draw_w", 1, SVt_NV);
3398     draw_h_gv = gv_fetchpv ("DC::UI::Base::draw_h", 1, SVt_NV);
3399 root 1.209 }
3400    
3401     void
3402     draw (SV *self)
3403     CODE:
3404     {
3405     HV *hv;
3406     SV **svp;
3407     NV x, y, w, h;
3408     SV *draw_x_sv = GvSV (draw_x_gv);
3409     SV *draw_y_sv = GvSV (draw_y_gv);
3410     SV *draw_w_sv = GvSV (draw_w_gv);
3411     SV *draw_h_sv = GvSV (draw_h_gv);
3412 root 1.228 double draw_x, draw_y;
3413 root 1.209
3414     if (!SvROK (self))
3415 root 1.242 croak ("DC::Base::draw: %s not a reference", SvPV_nolen (self));
3416 root 1.209
3417     hv = (HV *)SvRV (self);
3418    
3419     if (SvTYPE (hv) != SVt_PVHV)
3420 root 1.242 croak ("DC::Base::draw: %s not a hashref", SvPV_nolen (self));
3421 root 1.209
3422     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
3423     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
3424    
3425     if (!h || !w)
3426     XSRETURN_EMPTY;
3427    
3428     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
3429     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
3430    
3431     draw_x = SvNV (draw_x_sv) + x;
3432     draw_y = SvNV (draw_y_sv) + y;
3433    
3434     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
3435     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
3436     XSRETURN_EMPTY;
3437    
3438     sv_setnv (draw_x_sv, draw_x);
3439     sv_setnv (draw_y_sv, draw_y);
3440    
3441     glPushMatrix ();
3442     glTranslated (x, y, 0);
3443    
3444     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
3445     {
3446     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
3447    
3448     if (svp && SvTRUE (*svp))
3449     {
3450 root 1.228 glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f);
3451 root 1.209 glEnable (GL_BLEND);
3452     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3453     glBegin (GL_QUADS);
3454     glVertex2f (0, 0);
3455     glVertex2f (w, 0);
3456     glVertex2f (w, h);
3457     glVertex2f (0, h);
3458     glEnd ();
3459     glDisable (GL_BLEND);
3460     }
3461     }
3462     #if 0
3463 root 1.234 // draw borders, for debugging
3464     glPushMatrix ();
3465     glColor4f (1., 1., 0., 1.);
3466     glTranslatef (.5, .5, 0.);
3467     glBegin (GL_LINE_LOOP);
3468     glVertex2f (0 , 0);
3469     glVertex2f (w - 1, 0);
3470     glVertex2f (w - 1, h - 1);
3471     glVertex2f (0 , h - 1);
3472     glEnd ();
3473     glPopMatrix ();
3474 root 1.209 #endif
3475     PUSHMARK (SP);
3476     XPUSHs (self);
3477     PUTBACK;
3478     call_method ("_draw", G_VOID | G_DISCARD);
3479     SPAGAIN;
3480    
3481     glPopMatrix ();
3482    
3483     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
3484     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
3485 root 1.207 }
3486