ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.283
Committed: Thu Dec 11 00:11:58 2008 UTC (15 years, 5 months ago) by root
Branch: MAIN
Changes since 1.282: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.48 #ifdef _WIN32
2 root 1.131 # define WIN32_LEAN_AND_MEAN
3 root 1.170 # define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls
4 root 1.48 # include <malloc.h>
5 root 1.79 # include <windows.h>
6 root 1.157 # include <wininet.h>
7 root 1.75 # pragma warning(disable:4244)
8 root 1.162 # pragma warning(disable:4761)
9 root 1.48 #endif
10    
11 root 1.193 //#define DEBUG 1
12     #if DEBUG
13     # include <valgrind/memcheck.h>
14     #endif
15    
16 root 1.1 #include "EXTERN.h"
17     #include "perl.h"
18     #include "XSUB.h"
19    
20 root 1.131 #ifdef _WIN32
21     # undef pipe
22 root 1.222 // microsoft vs. C
23     # define sqrtf(x) sqrt(x)
24     # define roundf(x) (int)(x)
25     # define atan2f(x,y) atan2(x,y)
26     # define M_PI 3.14159265f
27 root 1.131 #endif
28    
29 root 1.168 #include <assert.h>
30 root 1.80 #include <math.h>
31 root 1.5 #include <string.h>
32 root 1.25 #include <stdio.h>
33 root 1.111 #include <stdlib.h>
34 root 1.5
35 root 1.212 #define USE_RWOPS 1 // for SDL_mixer:LoadMUS_RW
36    
37 root 1.2 #include <SDL.h>
38 root 1.202 #include <SDL_thread.h>
39 root 1.76 #include <SDL_endian.h>
40 root 1.23 #include <SDL_image.h>
41 root 1.52 #include <SDL_mixer.h>
42 root 1.3 #include <SDL_opengl.h>
43 root 1.5
44 root 1.272 /* work around os x broken headers */
45     #ifdef __MACOSX__
46     typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
47     #endif
48    
49 root 1.124 #define PANGO_ENABLE_BACKEND
50     #define G_DISABLE_CAST_CHECKS
51    
52 root 1.30 #include <glib/gmacros.h>
53    
54 root 1.5 #include <pango/pango.h>
55    
56 root 1.254 #ifndef PANGO_VERSION_CHECK
57     # define PANGO_VERSION_CHECK(a,b,c) 0
58     #endif
59    
60     #if !PANGO_VERSION_CHECK (1, 15, 2)
61 root 1.255 # define pango_layout_get_line_readonly pango_layout_get_line
62     # define pango_layout_get_lines_readonly pango_layout_get_lines
63     # define pango_layout_iter_get_line_readonly pango_layout_iter_get_line
64     # define pango_layout_iter_get_run_readonly pango_layout_iter_get_run
65 root 1.249 #endif
66    
67 root 1.48 #ifndef _WIN32
68     # include <sys/types.h>
69     # include <sys/socket.h>
70     # include <netinet/in.h>
71     # include <netinet/tcp.h>
72     # include <inttypes.h>
73     #endif
74 root 1.28
75 root 1.261 #if __GNUC__ >= 4
76     # define expect(expr,value) __builtin_expect ((expr),(value))
77     #else
78     # define expect(expr,value) (expr)
79     #endif
80    
81     #define expect_false(expr) expect ((expr) != 0, 0)
82     #define expect_true(expr) expect ((expr) != 0, 1)
83    
84 root 1.162 #define OBJ_STR "\xef\xbf\xbc" /* U+FFFC, object replacement character */
85 root 1.121
86 root 1.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 root 1.223 // overlays such as the speech bubble, probably more to come
2109 root 1.176 if (cell->flags & 1)
2110     {
2111     maptex tex = self->tex [1];
2112     int px = x * T + T * 2 / 32;
2113     int py = y * T - T * 6 / 32;
2114    
2115 root 1.223 if (tex.name)
2116     {
2117     if (key.texname != tex.name)
2118     {
2119     key.texname = tex.name;
2120     arr = rc_array (rc, &key);
2121     }
2122    
2123     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2124     rc_t2f_v3f (arr, 0 , tex.t, px , py + T, 0);
2125     rc_t2f_v3f (arr, tex.s, tex.t, px + T, py + T, 0);
2126     rc_t2f_v3f (arr, tex.s, 0 , px + T, py , 0);
2127     }
2128 root 1.176 }
2129     }
2130    
2131     // update smooth hash
2132     if (tex.smoothtile)
2133     {
2134     skey.tile = tex.smoothtile;
2135     skey.level = tex.smoothlevel;
2136    
2137     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
2138 root 1.30
2139 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
2140     // shifted +1|+1 so we always stay positive.
2141 root 1.30
2142 root 1.180 // bits is ___n cccc CCCC bbbb
2143     // n do not draw borders&corners
2144     // c draw these corners, but...
2145     // C ... not these
2146     // b draw these borders
2147    
2148     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
2149     // ┃· ·· ·┃ ━━
2150    
2151     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
2152     // ·· ·· ·┏ ┓·
2153    
2154 root 1.176 // full tile
2155     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
2156    
2157     // borders
2158 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
2159     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
2160 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
2161     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
2162    
2163     // corners
2164     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
2165     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
2166     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
2167     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
2168     }
2169     }
2170     }
2171     }
2172 root 1.174
2173 root 1.224 rc_draw (rc);
2174     rc_clear (rc);
2175    
2176 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
2177     // this is basically counting sort
2178 root 1.176 {
2179 root 1.186 int w, b;
2180 root 1.30
2181 root 1.226 glEnable (GL_TEXTURE_2D);
2182     glBegin (GL_QUADS);
2183 root 1.186 for (w = 0; w < 256 / 32; ++w)
2184     {
2185     uint32_t smask = smooth_level [w];
2186     if (smask)
2187     for (b = 0; b < 32; ++b)
2188     if (smask & (((uint32_t)1) << b))
2189 root 1.176 {
2190 root 1.186 int level = (w << 5) | b;
2191     HE *he;
2192 root 1.153
2193 root 1.186 hv_iterinit (smooth);
2194     while ((he = hv_iternext (smooth)))
2195 root 1.153 {
2196 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
2197     IV bits = SvIVX (HeVAL (he));
2198 root 1.176
2199 root 1.186 if (!(bits & 0x1000)
2200     && skey->level == level
2201 root 1.191 && level > smooth_max [skey->x][skey->y])
2202 root 1.174 {
2203 root 1.186 maptex tex = self->tex [skey->tile];
2204     int px = (((int)skey->x) - 1) * T;
2205     int py = (((int)skey->y) - 1) * T;
2206     int border = bits & 15;
2207     int corner = (bits >> 8) & ~(bits >> 4) & 15;
2208     float dx = tex.s * .0625f; // 16 images/row
2209     float dy = tex.t * .5f ; // 2 images/column
2210    
2211 root 1.223 if (tex.name)
2212 root 1.186 {
2213 root 1.223 // this time avoiding texture state changes
2214     // save gobs of state changes.
2215     if (key.texname != tex.name)
2216     {
2217 root 1.280 self->tex [skey->tile].unused = 0;
2218    
2219 root 1.226 glEnd ();
2220     glBindTexture (GL_TEXTURE_2D, key.texname = tex.name);
2221     glBegin (GL_QUADS);
2222 root 1.223 }
2223    
2224     if (border)
2225     {
2226     float ox = border * dx;
2227    
2228 root 1.226 glTexCoord2f (ox , 0.f ); glVertex2i (px , py );
2229     glTexCoord2f (ox , dy ); glVertex2i (px , py + T);
2230     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py + T);
2231     glTexCoord2f (ox + dx, 0.f ); glVertex2i (px + T, py );
2232 root 1.223 }
2233    
2234     if (corner)
2235     {
2236     float ox = corner * dx;
2237    
2238 root 1.226 glTexCoord2f (ox , dy ); glVertex2i (px , py );
2239     glTexCoord2f (ox , dy * 2.f); glVertex2i (px , py + T);
2240     glTexCoord2f (ox + dx, dy * 2.f); glVertex2i (px + T, py + T);
2241     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py );
2242 root 1.223 }
2243 root 1.186 }
2244 root 1.174 }
2245 root 1.153 }
2246     }
2247 root 1.186 }
2248 root 1.226
2249     glEnd ();
2250     glDisable (GL_TEXTURE_2D);
2251     key.texname = -1;
2252 root 1.176 }
2253    
2254 root 1.186 hv_clear (smooth);
2255     }
2256 root 1.30
2257 root 1.261 if (pl_tex.name)
2258     {
2259     maptex tex = pl_tex;
2260 root 1.266 int px = pl_x + sdx;
2261     int py = pl_y + sdy;
2262 root 1.261
2263     key.texname = tex.name;
2264     arr = rc_array (rc, &key);
2265    
2266     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2267     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
2268     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
2269     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
2270    
2271     rc_draw (rc);
2272     }
2273    
2274 root 1.152 glDisable (GL_BLEND);
2275 root 1.223 rc_free (rc);
2276 root 1.143
2277 root 1.145 // top layer: overlays such as the health bar
2278 root 1.143 for (y = 0; y < sh; y++)
2279 root 1.164 if (0 <= y + my && y + my < self->rows)
2280 root 1.143 {
2281 root 1.164 maprow *row = self->row + (y + my);
2282 root 1.143
2283     for (x = 0; x < sw; x++)
2284 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2285 root 1.143 {
2286 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2287 root 1.143
2288 root 1.171 int px = x * T;
2289     int py = y * T;
2290 root 1.143
2291 root 1.279 if (expect_false (cell->player == player))
2292     {
2293     px += sdx;
2294     py += sdy;
2295     }
2296    
2297 root 1.143 if (cell->stat_hp)
2298     {
2299 root 1.171 int width = cell->stat_width * T;
2300 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
2301 root 1.143
2302 root 1.152 glColor3ub (0, 0, 0);
2303 root 1.151 glRectf (px + 1, py - thick - 2,
2304     px + width - 1, py);
2305 root 1.147
2306 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
2307 root 1.147 glRectf (px + 2,
2308 root 1.151 py - thick - 1,
2309     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
2310 root 1.143 }
2311     }
2312     }
2313 root 1.116 }
2314    
2315     void
2316 root 1.242 draw_magicmap (DC::Map self, int dx, int dy, int w, int h, unsigned char *data)
2317 root 1.117 CODE:
2318     {
2319     static float color[16][3] = {
2320 root 1.123 { 0.00F, 0.00F, 0.00F },
2321     { 1.00F, 1.00F, 1.00F },
2322     { 0.00F, 0.00F, 0.55F },
2323     { 1.00F, 0.00F, 0.00F },
2324    
2325     { 1.00F, 0.54F, 0.00F },
2326     { 0.11F, 0.56F, 1.00F },
2327     { 0.93F, 0.46F, 0.00F },
2328     { 0.18F, 0.54F, 0.34F },
2329    
2330     { 0.56F, 0.73F, 0.56F },
2331     { 0.80F, 0.80F, 0.80F },
2332     { 0.55F, 0.41F, 0.13F },
2333     { 0.99F, 0.77F, 0.26F },
2334    
2335     { 0.74F, 0.65F, 0.41F },
2336    
2337     { 0.00F, 1.00F, 1.00F },
2338     { 1.00F, 0.00F, 1.00F },
2339     { 1.00F, 1.00F, 0.00F },
2340 root 1.117 };
2341    
2342     int x, y;
2343    
2344     glEnable (GL_TEXTURE_2D);
2345     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2346     glEnable (GL_BLEND);
2347     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2348     glBegin (GL_QUADS);
2349    
2350     for (y = 0; y < h; y++)
2351     for (x = 0; x < w; x++)
2352     {
2353     unsigned char m = data [x + y * w];
2354    
2355 root 1.118 if (m)
2356     {
2357     float *c = color [m & 15];
2358    
2359     float tx1 = m & 0x40 ? 0.5 : 0.;
2360     float tx2 = tx1 + 0.5;
2361    
2362     glColor4f (c[0], c[1], c[2], 0.75);
2363     glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2364     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2365     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2366     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2367     }
2368 root 1.117 }
2369    
2370     glEnd ();
2371     glDisable (GL_BLEND);
2372     glDisable (GL_TEXTURE_2D);
2373     }
2374    
2375     void
2376 root 1.242 fow_texture (DC::Map self, int mx, int my, int sw, int sh)
2377 root 1.116 PPCODE:
2378     {
2379     int x, y;
2380 root 1.204 int sw1 = sw + 2;
2381     int sh1 = sh + 2;
2382     int sh3 = sh * 3;
2383     int sw34 = (sw * 3 + 3) & ~3;
2384     uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2385     SV *darkness3_sv = sv_2mortal (newSV (sw34 * sh3));
2386     uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2387    
2388     SvPOK_only (darkness3_sv);
2389     SvCUR_set (darkness3_sv, sw34 * sh3);
2390 root 1.116
2391 root 1.204 mx += self->x - 1;
2392     my += self->y - 1;
2393 root 1.116
2394 root 1.269 memset (darkness1, 255 - FOW_DARKNESS, sw1 * sh1);
2395 root 1.204
2396     for (y = 0; y < sh1; y++)
2397 root 1.164 if (0 <= y + my && y + my < self->rows)
2398 root 1.116 {
2399 root 1.164 maprow *row = self->row + (y + my);
2400 root 1.116
2401 root 1.204 for (x = 0; x < sw1; x++)
2402 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2403 root 1.116 {
2404 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2405 root 1.116
2406 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2407 root 1.143 ? 255 - (cell->darkness - 1)
2408 root 1.142 : 255 - FOW_DARKNESS;
2409 root 1.116 }
2410     }
2411 root 1.34
2412 root 1.204 for (y = 0; y < sh; ++y)
2413     for (x = 0; x < sw; ++x)
2414     {
2415     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2416     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2417     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2418     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2419     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2420     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2421     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2422     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2423     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2424    
2425     uint8_t r11 = (d11 + d21 + d12) / 3;
2426     uint8_t r21 = d21;
2427     uint8_t r31 = (d21 + d31 + d32) / 3;
2428    
2429     uint8_t r12 = d12;
2430     uint8_t r22 = d22;
2431     uint8_t r32 = d32;
2432    
2433     uint8_t r13 = (d13 + d23 + d12) / 3;
2434     uint8_t r23 = d23;
2435     uint8_t r33 = (d23 + d33 + d32) / 3;
2436    
2437     darkness3 [(y * 3 ) * sw34 + (x * 3 )] = MAX (d22, r11);
2438     darkness3 [(y * 3 ) * sw34 + (x * 3 + 1)] = MAX (d22, r21);
2439     darkness3 [(y * 3 ) * sw34 + (x * 3 + 2)] = MAX (d22, r31);
2440     darkness3 [(y * 3 + 1) * sw34 + (x * 3 )] = MAX (d22, r12);
2441     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 1)] = MAX (d22, r22);
2442     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 2)] = MAX (d22, r32);
2443     darkness3 [(y * 3 + 2) * sw34 + (x * 3 )] = MAX (d22, r13);
2444     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 1)] = MAX (d22, r23);
2445     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 2)] = MAX (d22, r33);
2446     }
2447 root 1.201
2448 root 1.204 free (darkness1);
2449 root 1.201
2450 root 1.32 EXTEND (SP, 3);
2451 root 1.204 PUSHs (sv_2mortal (newSViv (sw34)));
2452     PUSHs (sv_2mortal (newSViv (sh3)));
2453     PUSHs (darkness3_sv);
2454 root 1.30 }
2455    
2456 root 1.42 SV *
2457 root 1.242 get_rect (DC::Map self, int x0, int y0, int w, int h)
2458 root 1.42 CODE:
2459     {
2460     int x, y, x1, y1;
2461     SV *data_sv = newSV (w * h * 7 + 5);
2462     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2463    
2464     *data++ = 0; /* version 0 format */
2465     *data++ = w >> 8; *data++ = w;
2466     *data++ = h >> 8; *data++ = h;
2467    
2468     // we need to do this 'cause we don't keep an absolute coord system for rows
2469 root 1.55 // TODO: treat rows as we treat columns
2470 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2471     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2472    
2473     x0 += self->x - self->ox;
2474     y0 += self->y - self->oy;
2475    
2476     x1 = x0 + w;
2477     y1 = y0 + h;
2478    
2479     for (y = y0; y < y1; y++)
2480     {
2481     maprow *row = 0 <= y && y < self->rows
2482     ? self->row + y
2483     : 0;
2484    
2485     for (x = x0; x < x1; x++)
2486     {
2487     if (row && row->c0 <= x && x < row->c1)
2488     {
2489     mapcell *cell = row->col + (x - row->c0);
2490     uint8_t flags = 0;
2491    
2492 root 1.174 if (cell->tile [0]) flags |= 1;
2493     if (cell->tile [1]) flags |= 2;
2494     if (cell->tile [2]) flags |= 4;
2495 root 1.42
2496     *data++ = flags;
2497    
2498     if (flags & 1)
2499     {
2500 root 1.174 tileid tile = cell->tile [0];
2501     *data++ = tile >> 8;
2502     *data++ = tile;
2503 root 1.42 }
2504    
2505     if (flags & 2)
2506     {
2507 root 1.174 tileid tile = cell->tile [1];
2508     *data++ = tile >> 8;
2509     *data++ = tile;
2510 root 1.42 }
2511    
2512     if (flags & 4)
2513     {
2514 root 1.174 tileid tile = cell->tile [2];
2515     *data++ = tile >> 8;
2516     *data++ = tile;
2517 root 1.42 }
2518     }
2519     else
2520     *data++ = 0;
2521     }
2522     }
2523    
2524 root 1.260 /* if size is w*h + 5 then no data has been found */
2525     if (data - (uint8_t *)SvPVX (data_sv) != w * h + 5)
2526 root 1.259 {
2527     SvPOK_only (data_sv);
2528     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2529     }
2530 root 1.260
2531     RETVAL = data_sv;
2532 root 1.42 }
2533     OUTPUT:
2534     RETVAL
2535    
2536     void
2537 root 1.259 set_rect (DC::Map self, int x0, int y0, SV *data_sv)
2538 root 1.42 PPCODE:
2539     {
2540     int x, y, z;
2541 root 1.48 int w, h;
2542 root 1.42 int x1, y1;
2543 root 1.259 STRLEN len;
2544     uint8_t *data, *end;
2545    
2546     len = SvLEN (data_sv);
2547 root 1.260 SvGROW (data_sv, len + 8); // reserve at least 7+ bytes more
2548 root 1.259 data = SvPVbyte_nolen (data_sv);
2549 root 1.260 end = data + len + 8;
2550 root 1.259
2551     if (len < 5)
2552     XSRETURN_EMPTY;
2553 root 1.42
2554     if (*data++ != 0)
2555 root 1.227 XSRETURN_EMPTY; /* version mismatch */
2556 root 1.42
2557 root 1.48 w = *data++ << 8; w |= *data++;
2558     h = *data++ << 8; h |= *data++;
2559 root 1.42
2560     // we need to do this 'cause we don't keep an absolute coord system for rows
2561 root 1.55 // TODO: treat rows as we treat columns
2562 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2563     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2564    
2565     x0 += self->x - self->ox;
2566     y0 += self->y - self->oy;
2567    
2568     x1 = x0 + w;
2569     y1 = y0 + h;
2570    
2571     for (y = y0; y < y1; y++)
2572     {
2573     maprow *row = map_get_row (self, y);
2574    
2575     for (x = x0; x < x1; x++)
2576     {
2577 root 1.259 uint8_t flags;
2578    
2579     if (data + 7 >= end)
2580     XSRETURN_EMPTY;
2581    
2582     flags = *data++;
2583 root 1.42
2584     if (flags)
2585     {
2586     mapcell *cell = row_get_cell (row, x);
2587 root 1.174 tileid tile[3] = { 0, 0, 0 };
2588 root 1.42
2589 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2590     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2591     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2592 root 1.42
2593 root 1.143 if (cell->darkness == 0)
2594 root 1.42 {
2595 root 1.260 /*cell->darkness = 0;*/
2596     EXTEND (SP, 3);
2597 root 1.42
2598     for (z = 0; z <= 2; z++)
2599     {
2600 root 1.174 tileid t = tile [z];
2601    
2602 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2603 root 1.174 {
2604 root 1.260 PUSHs (sv_2mortal (newSViv (t)));
2605 root 1.174 need_texid (self, t);
2606     }
2607 root 1.42
2608 root 1.174 cell->tile [z] = t;
2609 root 1.42 }
2610     }
2611     }
2612     }
2613     }
2614     }
2615    
2616 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::RW
2617 root 1.205
2618 root 1.242 DC::RW
2619 root 1.211 new (SV *class, SV *data_sv)
2620     CODE:
2621     {
2622     STRLEN datalen;
2623     char *data = SvPVbyte (data_sv, datalen);
2624    
2625 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2626 root 1.211 }
2627     OUTPUT:
2628     RETVAL
2629    
2630 root 1.242 DC::RW
2631 root 1.212 new_from_file (SV *class, const char *path, const char *mode = "rb")
2632     CODE:
2633     RETVAL = SDL_RWFromFile (path, mode);
2634     OUTPUT:
2635     RETVAL
2636    
2637 root 1.218 # fails on win32:
2638 root 1.241 # dc.xs(2268) : error C2059: syntax error : '('
2639 root 1.218 #void
2640 root 1.242 #close (DC::RW self)
2641 root 1.218 # CODE:
2642     # (self->(close)) (self);
2643 root 1.212
2644 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Channel
2645 root 1.212
2646     PROTOTYPES: DISABLE
2647    
2648 root 1.242 DC::Channel
2649 root 1.215 find ()
2650     CODE:
2651     {
2652     RETVAL = Mix_GroupAvailable (-1);
2653    
2654     if (RETVAL < 0)
2655     {
2656     RETVAL = Mix_GroupOldest (-1);
2657    
2658     if (RETVAL < 0)
2659     XSRETURN_UNDEF;
2660    
2661     Mix_HaltChannel (RETVAL);
2662     }
2663    
2664     Mix_UnregisterAllEffects (RETVAL);
2665     Mix_Volume (RETVAL, 128);
2666     }
2667     OUTPUT:
2668     RETVAL
2669    
2670 root 1.213 void
2671 root 1.242 halt (DC::Channel self)
2672 root 1.213 CODE:
2673     Mix_HaltChannel (self);
2674    
2675     void
2676 root 1.242 expire (DC::Channel self, int ticks = -1)
2677 root 1.213 CODE:
2678     Mix_ExpireChannel (self, ticks);
2679    
2680     void
2681 root 1.242 fade_out (DC::Channel self, int ticks = -1)
2682 root 1.213 CODE:
2683     Mix_FadeOutChannel (self, ticks);
2684    
2685 root 1.212 int
2686 root 1.242 volume (DC::Channel self, int volume)
2687 root 1.212 CODE:
2688 root 1.216 RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128));
2689 root 1.212 OUTPUT:
2690     RETVAL
2691    
2692 root 1.213 void
2693 root 1.242 unregister_all_effects (DC::Channel self)
2694 root 1.212 CODE:
2695 root 1.213 Mix_UnregisterAllEffects (self);
2696 root 1.212
2697 root 1.213 void
2698 root 1.242 set_panning (DC::Channel self, int left, int right)
2699 root 1.212 CODE:
2700 root 1.216 left = CLAMP (left , 0, 255);
2701     right = CLAMP (right, 0, 255);
2702 root 1.213 Mix_SetPanning (self, left, right);
2703 root 1.212
2704 root 1.213 void
2705 root 1.242 set_distance (DC::Channel self, int distance)
2706 root 1.212 CODE:
2707 root 1.216 Mix_SetDistance (self, CLAMP (distance, 0, 255));
2708 root 1.212
2709 root 1.213 void
2710 root 1.242 set_position (DC::Channel self, int angle, int distance)
2711 root 1.212 CODE:
2712 root 1.220
2713     void
2714 root 1.242 set_position_r (DC::Channel self, int dx, int dy, int maxdistance)
2715 root 1.220 CODE:
2716     {
2717     int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance));
2718     int angle = 360 + (int)roundf (atan2f (dx, -dy) * 180.f / (float)M_PI);
2719 root 1.216 Mix_SetPosition (self, angle, CLAMP (distance, 0, 255));
2720 root 1.220 }
2721 root 1.212
2722 root 1.213 void
2723 root 1.242 set_reverse_stereo (DC::Channel self, int flip)
2724 root 1.212 CODE:
2725 root 1.213 Mix_SetReverseStereo (self, flip);
2726 root 1.212
2727 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixChunk
2728 root 1.212
2729     PROTOTYPES: DISABLE
2730    
2731 root 1.242 DC::MixChunk
2732     new (SV *class, DC::RW rwops)
2733 root 1.52 CODE:
2734 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2735 root 1.52 OUTPUT:
2736     RETVAL
2737    
2738     void
2739 root 1.242 DESTROY (DC::MixChunk self)
2740 root 1.52 CODE:
2741     Mix_FreeChunk (self);
2742    
2743     int
2744 root 1.242 volume (DC::MixChunk self, int volume = -1)
2745 root 1.52 CODE:
2746 root 1.216 if (items > 1)
2747     volume = CLAMP (volume, 0, 128);
2748 root 1.52 RETVAL = Mix_VolumeChunk (self, volume);
2749     OUTPUT:
2750     RETVAL
2751    
2752 root 1.242 DC::Channel
2753     play (DC::MixChunk self, DC::Channel channel = -1, int loops = 0, int ticks = -1)
2754 root 1.52 CODE:
2755 root 1.215 {
2756 root 1.52 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2757 root 1.215
2758     if (RETVAL < 0)
2759     XSRETURN_UNDEF;
2760    
2761     if (channel < 0)
2762     {
2763     Mix_UnregisterAllEffects (RETVAL);
2764     Mix_Volume (RETVAL, 128);
2765     }
2766     }
2767 root 1.52 OUTPUT:
2768     RETVAL
2769    
2770 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixMusic
2771 root 1.52
2772     int
2773     volume (int volume = -1)
2774 root 1.205 PROTOTYPE: ;$
2775 root 1.52 CODE:
2776 root 1.216 if (items > 0)
2777     volume = CLAMP (volume, 0, 128);
2778 root 1.52 RETVAL = Mix_VolumeMusic (volume);
2779     OUTPUT:
2780     RETVAL
2781    
2782 root 1.213 void
2783 root 1.194 fade_out (int ms)
2784     CODE:
2785 root 1.213 Mix_FadeOutMusic (ms);
2786 root 1.194
2787 root 1.212 void
2788     halt ()
2789     CODE:
2790     Mix_HaltMusic ();
2791    
2792 root 1.242 DC::MixMusic
2793     new (SV *class, DC::RW rwops)
2794 root 1.52 CODE:
2795 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
2796 root 1.52 OUTPUT:
2797     RETVAL
2798    
2799     void
2800 root 1.242 DESTROY (DC::MixMusic self)
2801 root 1.52 CODE:
2802     Mix_FreeMusic (self);
2803    
2804     int
2805 root 1.242 play (DC::MixMusic self, int loops = -1)
2806 root 1.52 CODE:
2807     RETVAL = Mix_PlayMusic (self, loops);
2808     OUTPUT:
2809     RETVAL
2810    
2811 root 1.213 void
2812 root 1.242 fade_in_pos (DC::MixMusic self, int loops, int ms, double position)
2813 root 1.195 CODE:
2814 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
2815 root 1.195
2816 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::OpenGL
2817 root 1.54
2818 root 1.205 PROTOTYPES: ENABLE
2819    
2820 root 1.54 BOOT:
2821     {
2822 root 1.242 HV *stash = gv_stashpv ("DC::OpenGL", 1);
2823 root 1.54 static const struct {
2824     const char *name;
2825     IV iv;
2826     } *civ, const_iv[] = {
2827     # define const_iv(name) { # name, (IV)name }
2828 root 1.199 const_iv (GL_VENDOR),
2829     const_iv (GL_VERSION),
2830     const_iv (GL_EXTENSIONS),
2831 root 1.54 const_iv (GL_COLOR_MATERIAL),
2832     const_iv (GL_SMOOTH),
2833     const_iv (GL_FLAT),
2834 root 1.69 const_iv (GL_DITHER),
2835 root 1.54 const_iv (GL_BLEND),
2836 root 1.89 const_iv (GL_CULL_FACE),
2837 root 1.69 const_iv (GL_SCISSOR_TEST),
2838 root 1.89 const_iv (GL_DEPTH_TEST),
2839     const_iv (GL_ALPHA_TEST),
2840     const_iv (GL_NORMALIZE),
2841     const_iv (GL_RESCALE_NORMAL),
2842 root 1.119 const_iv (GL_FRONT),
2843     const_iv (GL_BACK),
2844 root 1.206 const_iv (GL_AUX0),
2845 root 1.54 const_iv (GL_AND),
2846 root 1.67 const_iv (GL_ONE),
2847     const_iv (GL_ZERO),
2848 root 1.54 const_iv (GL_SRC_ALPHA),
2849 root 1.104 const_iv (GL_DST_ALPHA),
2850 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2851 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2852 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2853 root 1.54 const_iv (GL_RGB),
2854     const_iv (GL_RGBA),
2855 root 1.115 const_iv (GL_RGBA4),
2856     const_iv (GL_RGBA8),
2857     const_iv (GL_RGB5_A1),
2858 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2859 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2860     const_iv (GL_UNSIGNED_INT),
2861 root 1.54 const_iv (GL_ALPHA),
2862 root 1.86 const_iv (GL_INTENSITY),
2863 root 1.76 const_iv (GL_LUMINANCE),
2864 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2865 root 1.54 const_iv (GL_FLOAT),
2866     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2867 root 1.230 const_iv (GL_COMPRESSED_ALPHA_ARB),
2868     const_iv (GL_COMPRESSED_LUMINANCE_ARB),
2869     const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB),
2870     const_iv (GL_COMPRESSED_INTENSITY_ARB),
2871     const_iv (GL_COMPRESSED_RGB_ARB),
2872     const_iv (GL_COMPRESSED_RGBA_ARB),
2873 root 1.54 const_iv (GL_COMPILE),
2874 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
2875     const_iv (GL_PROXY_TEXTURE_2D),
2876 root 1.54 const_iv (GL_TEXTURE_1D),
2877     const_iv (GL_TEXTURE_2D),
2878     const_iv (GL_TEXTURE_ENV),
2879     const_iv (GL_TEXTURE_MAG_FILTER),
2880     const_iv (GL_TEXTURE_MIN_FILTER),
2881     const_iv (GL_TEXTURE_ENV_MODE),
2882     const_iv (GL_TEXTURE_WRAP_S),
2883     const_iv (GL_TEXTURE_WRAP_T),
2884 root 1.98 const_iv (GL_REPEAT),
2885 root 1.54 const_iv (GL_CLAMP),
2886 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2887 root 1.54 const_iv (GL_NEAREST),
2888     const_iv (GL_LINEAR),
2889 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2890     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2891     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2892     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2893     const_iv (GL_GENERATE_MIPMAP),
2894 root 1.54 const_iv (GL_MODULATE),
2895 root 1.69 const_iv (GL_DECAL),
2896 root 1.54 const_iv (GL_REPLACE),
2897 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2898 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2899     const_iv (GL_PROJECTION),
2900     const_iv (GL_MODELVIEW),
2901     const_iv (GL_COLOR_LOGIC_OP),
2902 root 1.69 const_iv (GL_SEPARABLE_2D),
2903 root 1.54 const_iv (GL_CONVOLUTION_2D),
2904     const_iv (GL_CONVOLUTION_BORDER_MODE),
2905     const_iv (GL_CONSTANT_BORDER),
2906 root 1.208 const_iv (GL_POINTS),
2907 root 1.54 const_iv (GL_LINES),
2908 root 1.138 const_iv (GL_LINE_STRIP),
2909 root 1.89 const_iv (GL_LINE_LOOP),
2910 root 1.54 const_iv (GL_QUADS),
2911 root 1.89 const_iv (GL_QUAD_STRIP),
2912     const_iv (GL_TRIANGLES),
2913     const_iv (GL_TRIANGLE_STRIP),
2914     const_iv (GL_TRIANGLE_FAN),
2915 root 1.208 const_iv (GL_POLYGON),
2916 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2917 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
2918     const_iv (GL_LINE_SMOOTH_HINT),
2919     const_iv (GL_POLYGON_SMOOTH_HINT),
2920     const_iv (GL_GENERATE_MIPMAP_HINT),
2921 root 1.232 const_iv (GL_TEXTURE_COMPRESSION_HINT),
2922 root 1.54 const_iv (GL_FASTEST),
2923 root 1.206 const_iv (GL_DONT_CARE),
2924     const_iv (GL_NICEST),
2925 root 1.89 const_iv (GL_V2F),
2926     const_iv (GL_V3F),
2927     const_iv (GL_T2F_V3F),
2928     const_iv (GL_T2F_N3F_V3F),
2929 root 1.54 # undef const_iv
2930     };
2931    
2932     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2933     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2934 root 1.188
2935     texture_av = newAV ();
2936     AvREAL_off (texture_av);
2937 root 1.54 }
2938    
2939 root 1.231 void
2940     disable_GL_EXT_blend_func_separate ()
2941     CODE:
2942     gl.BlendFuncSeparate = 0;
2943     gl.BlendFuncSeparateEXT = 0;
2944    
2945 root 1.97 char *
2946     gl_vendor ()
2947     CODE:
2948     RETVAL = (char *)glGetString (GL_VENDOR);
2949     OUTPUT:
2950     RETVAL
2951    
2952     char *
2953     gl_version ()
2954     CODE:
2955     RETVAL = (char *)glGetString (GL_VERSION);
2956     OUTPUT:
2957     RETVAL
2958    
2959     char *
2960     gl_extensions ()
2961     CODE:
2962     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2963     OUTPUT:
2964     RETVAL
2965    
2966 root 1.201 const char *glGetString (GLenum pname)
2967 root 1.199
2968     GLint glGetInteger (GLenum pname)
2969     CODE:
2970     glGetIntegerv (pname, &RETVAL);
2971     OUTPUT:
2972     RETVAL
2973    
2974     GLdouble glGetDouble (GLenum pname)
2975     CODE:
2976     glGetDoublev (pname, &RETVAL);
2977     OUTPUT:
2978     RETVAL
2979    
2980 root 1.54 int glGetError ()
2981    
2982 root 1.114 void glFinish ()
2983    
2984 root 1.54 void glClear (int mask)
2985    
2986     void glClearColor (float r, float g, float b, float a = 1.0)
2987     PROTOTYPE: @
2988    
2989     void glEnable (int cap)
2990    
2991     void glDisable (int cap)
2992    
2993     void glShadeModel (int mode)
2994    
2995     void glHint (int target, int mode)
2996    
2997     void glBlendFunc (int sfactor, int dfactor)
2998    
2999 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
3000     CODE:
3001     gl_BlendFuncSeparate (sa, da, saa, daa);
3002    
3003 root 1.89 void glDepthMask (int flag)
3004    
3005 root 1.54 void glLogicOp (int opcode)
3006    
3007 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
3008    
3009 root 1.54 void glMatrixMode (int mode)
3010    
3011     void glPushMatrix ()
3012    
3013     void glPopMatrix ()
3014    
3015     void glLoadIdentity ()
3016    
3017 root 1.119 void glDrawBuffer (int buffer)
3018    
3019     void glReadBuffer (int buffer)
3020    
3021 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
3022     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
3023    
3024     # near_ and far_ are due to microsofts buggy "c" compiler
3025 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
3026 root 1.54
3027 root 1.208 PROTOTYPES: DISABLE
3028    
3029 root 1.54 void glViewport (int x, int y, int width, int height)
3030    
3031 root 1.69 void glScissor (int x, int y, int width, int height)
3032    
3033 root 1.54 void glTranslate (float x, float y, float z = 0.)
3034     CODE:
3035     glTranslatef (x, y, z);
3036    
3037 root 1.62 void glScale (float x, float y, float z = 1.)
3038 root 1.54 CODE:
3039     glScalef (x, y, z);
3040    
3041     void glRotate (float angle, float x, float y, float z)
3042     CODE:
3043     glRotatef (angle, x, y, z);
3044    
3045     void glColor (float r, float g, float b, float a = 1.0)
3046 root 1.278 PROTOTYPE: @
3047 root 1.103 ALIAS:
3048     glColor_premultiply = 1
3049 root 1.54 CODE:
3050 root 1.103 if (ix)
3051     {
3052     r *= a;
3053     g *= a;
3054     b *= a;
3055     }
3056 root 1.90 // microsoft visual "c" rounds instead of truncating...
3057 root 1.130 glColor4f (r, g, b, a);
3058 root 1.54
3059 root 1.91 void glRasterPos (float x, float y, float z = 0.)
3060     CODE:
3061     glRasterPos3f (0, 0, z);
3062     glBitmap (0, 0, 0, 0, x, y, 0);
3063    
3064 root 1.54 void glVertex (float x, float y, float z = 0.)
3065     CODE:
3066     glVertex3f (x, y, z);
3067    
3068     void glTexCoord (float s, float t)
3069     CODE:
3070     glTexCoord2f (s, t);
3071    
3072 root 1.210 void glRect (float x1, float y1, float x2, float y2)
3073     CODE:
3074     glRectf (x1, y1, x2, y2);
3075    
3076 root 1.233 void glRect_lineloop (float x1, float y1, float x2, float y2)
3077     CODE:
3078     glBegin (GL_LINE_LOOP);
3079     glVertex2f (x1, y1);
3080     glVertex2f (x2, y1);
3081     glVertex2f (x2, y2);
3082     glVertex2f (x1, y2);
3083     glEnd ();
3084    
3085 root 1.208 PROTOTYPES: ENABLE
3086    
3087     void glBegin (int mode)
3088    
3089     void glEnd ()
3090    
3091     void glPointSize (GLfloat size)
3092    
3093     void glLineWidth (GLfloat width)
3094    
3095     void glInterleavedArrays (int format, int stride, char *data)
3096    
3097     void glDrawElements (int mode, int count, int type, char *indices)
3098    
3099     # 1.2 void glDrawRangeElements (int mode, int start, int end
3100    
3101 root 1.54 void glTexEnv (int target, int pname, float param)
3102     CODE:
3103     glTexEnvf (target, pname, param);
3104    
3105     void glTexParameter (int target, int pname, float param)
3106     CODE:
3107     glTexParameterf (target, pname, param);
3108    
3109     void glBindTexture (int target, int name)
3110    
3111     void glConvolutionParameter (int target, int pname, float params)
3112     CODE:
3113 root 1.103 if (gl.ConvolutionParameterf)
3114     gl.ConvolutionParameterf (target, pname, params);
3115 root 1.54
3116     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
3117 root 1.64 CODE:
3118 root 1.103 if (gl.ConvolutionFilter2D)
3119     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
3120 root 1.54
3121 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
3122     CODE:
3123 root 1.103 if (gl.SeparableFilter2D)
3124     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
3125 root 1.69
3126 root 1.244 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data = 0)
3127 root 1.54
3128     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
3129    
3130 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
3131 root 1.68
3132 root 1.199 void glPixelZoom (float x, float y)
3133    
3134 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
3135    
3136 root 1.54 int glGenTexture ()
3137     CODE:
3138 root 1.192 RETVAL = gen_texture ();
3139 root 1.54 OUTPUT:
3140     RETVAL
3141    
3142     void glDeleteTexture (int name)
3143     CODE:
3144 root 1.192 del_texture (name);
3145    
3146 root 1.54 int glGenList ()
3147     CODE:
3148     RETVAL = glGenLists (1);
3149     OUTPUT:
3150     RETVAL
3151    
3152     void glDeleteList (int list)
3153     CODE:
3154     glDeleteLists (list, 1);
3155    
3156     void glNewList (int list, int mode = GL_COMPILE)
3157    
3158     void glEndList ()
3159    
3160     void glCallList (int list)
3161    
3162 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::UI::Base
3163 root 1.207
3164     PROTOTYPES: DISABLE
3165    
3166     void
3167 root 1.209 find_widget (SV *self, NV x, NV y)
3168 root 1.207 PPCODE:
3169     {
3170 root 1.209 if (within_widget (self, x, y))
3171     XPUSHs (self);
3172     }
3173    
3174     BOOT:
3175     {
3176 root 1.242 hover_gv = gv_fetchpv ("DC::UI::HOVER", 1, SVt_NV);
3177 root 1.209
3178 root 1.242 draw_x_gv = gv_fetchpv ("DC::UI::Base::draw_x", 1, SVt_NV);
3179     draw_y_gv = gv_fetchpv ("DC::UI::Base::draw_y", 1, SVt_NV);
3180     draw_w_gv = gv_fetchpv ("DC::UI::Base::draw_w", 1, SVt_NV);
3181     draw_h_gv = gv_fetchpv ("DC::UI::Base::draw_h", 1, SVt_NV);
3182 root 1.209 }
3183    
3184     void
3185     draw (SV *self)
3186     CODE:
3187     {
3188     HV *hv;
3189     SV **svp;
3190     NV x, y, w, h;
3191     SV *draw_x_sv = GvSV (draw_x_gv);
3192     SV *draw_y_sv = GvSV (draw_y_gv);
3193     SV *draw_w_sv = GvSV (draw_w_gv);
3194     SV *draw_h_sv = GvSV (draw_h_gv);
3195 root 1.228 double draw_x, draw_y;
3196 root 1.209
3197     if (!SvROK (self))
3198 root 1.242 croak ("DC::Base::draw: %s not a reference", SvPV_nolen (self));
3199 root 1.209
3200     hv = (HV *)SvRV (self);
3201    
3202     if (SvTYPE (hv) != SVt_PVHV)
3203 root 1.242 croak ("DC::Base::draw: %s not a hashref", SvPV_nolen (self));
3204 root 1.209
3205     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
3206     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
3207    
3208     if (!h || !w)
3209     XSRETURN_EMPTY;
3210    
3211     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
3212     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
3213    
3214     draw_x = SvNV (draw_x_sv) + x;
3215     draw_y = SvNV (draw_y_sv) + y;
3216    
3217     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
3218     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
3219     XSRETURN_EMPTY;
3220    
3221     sv_setnv (draw_x_sv, draw_x);
3222     sv_setnv (draw_y_sv, draw_y);
3223    
3224     glPushMatrix ();
3225     glTranslated (x, y, 0);
3226    
3227     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
3228     {
3229     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
3230    
3231     if (svp && SvTRUE (*svp))
3232     {
3233 root 1.228 glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f);
3234 root 1.209 glEnable (GL_BLEND);
3235     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3236     glBegin (GL_QUADS);
3237     glVertex2f (0, 0);
3238     glVertex2f (w, 0);
3239     glVertex2f (w, h);
3240     glVertex2f (0, h);
3241     glEnd ();
3242     glDisable (GL_BLEND);
3243     }
3244     }
3245     #if 0
3246 root 1.234 // draw borders, for debugging
3247     glPushMatrix ();
3248     glColor4f (1., 1., 0., 1.);
3249     glTranslatef (.5, .5, 0.);
3250     glBegin (GL_LINE_LOOP);
3251     glVertex2f (0 , 0);
3252     glVertex2f (w - 1, 0);
3253     glVertex2f (w - 1, h - 1);
3254     glVertex2f (0 , h - 1);
3255     glEnd ();
3256     glPopMatrix ();
3257 root 1.209 #endif
3258     PUSHMARK (SP);
3259     XPUSHs (self);
3260     PUTBACK;
3261     call_method ("_draw", G_VOID | G_DISCARD);
3262     SPAGAIN;
3263    
3264     glPopMatrix ();
3265    
3266     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
3267     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
3268 root 1.207 }
3269