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