ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.273
Committed: Wed Aug 20 13:30:02 2008 UTC (15 years, 8 months ago) by root
Branch: MAIN
Changes since 1.272: +2 -1 lines
Log Message:
*** empty log message ***

File Contents

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