ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.275
Committed: Thu Aug 28 00:53:53 2008 UTC (15 years, 8 months ago) by root
Branch: MAIN
Changes since 1.274: +50 -0 lines
Log Message:
*** empty log message ***

File Contents

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