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