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