ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.284
Committed: Thu Dec 11 00:17:47 2008 UTC (15 years, 5 months ago) by elmex
Branch: MAIN
Changes since 1.283: +6 -0 lines
Log Message:
speech bubble fix for "wall-NPCs".

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