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