ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.290
Committed: Wed Nov 4 14:40:51 2009 UTC (14 years, 6 months ago) by root
Branch: MAIN
Changes since 1.289: +8 -2 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 root 1.290 /* GL_REPLACE would be correct, as we don't need to modulate alpha,
2372     * but the nvidia driver (185.18.14) mishandles alpha textures
2373     * ansd takes the colour from god knows where instead of using
2374     * Cp. MODULATE results in the same colour, but slightly different
2375     * alpha, but atcually gives us the correct colour with nvidia.
2376     */
2377     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2378 root 1.117 glEnable (GL_BLEND);
2379     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2380     glBegin (GL_QUADS);
2381    
2382     for (y = 0; y < h; y++)
2383     for (x = 0; x < w; x++)
2384     {
2385     unsigned char m = data [x + y * w];
2386    
2387 root 1.118 if (m)
2388     {
2389     float *c = color [m & 15];
2390    
2391     float tx1 = m & 0x40 ? 0.5 : 0.;
2392     float tx2 = tx1 + 0.5;
2393    
2394 root 1.290 glColor4f (c[0], c[1], c[2], 1);
2395 root 1.118 glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2396     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2397     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2398     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2399     }
2400 root 1.117 }
2401    
2402     glEnd ();
2403     glDisable (GL_BLEND);
2404     glDisable (GL_TEXTURE_2D);
2405     }
2406    
2407     void
2408 root 1.242 fow_texture (DC::Map self, int mx, int my, int sw, int sh)
2409 root 1.116 PPCODE:
2410     {
2411     int x, y;
2412 root 1.204 int sw1 = sw + 2;
2413     int sh1 = sh + 2;
2414     int sh3 = sh * 3;
2415     int sw34 = (sw * 3 + 3) & ~3;
2416     uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2417     SV *darkness3_sv = sv_2mortal (newSV (sw34 * sh3));
2418     uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2419    
2420     SvPOK_only (darkness3_sv);
2421     SvCUR_set (darkness3_sv, sw34 * sh3);
2422 root 1.116
2423 root 1.204 mx += self->x - 1;
2424     my += self->y - 1;
2425 root 1.116
2426 root 1.269 memset (darkness1, 255 - FOW_DARKNESS, sw1 * sh1);
2427 root 1.204
2428     for (y = 0; y < sh1; y++)
2429 root 1.164 if (0 <= y + my && y + my < self->rows)
2430 root 1.116 {
2431 root 1.164 maprow *row = self->row + (y + my);
2432 root 1.116
2433 root 1.204 for (x = 0; x < sw1; x++)
2434 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2435 root 1.116 {
2436 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2437 root 1.116
2438 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2439 root 1.143 ? 255 - (cell->darkness - 1)
2440 root 1.142 : 255 - FOW_DARKNESS;
2441 root 1.116 }
2442     }
2443 root 1.34
2444 root 1.204 for (y = 0; y < sh; ++y)
2445     for (x = 0; x < sw; ++x)
2446     {
2447     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2448     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2449     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2450     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2451     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2452     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2453     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2454     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2455     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2456    
2457     uint8_t r11 = (d11 + d21 + d12) / 3;
2458     uint8_t r21 = d21;
2459     uint8_t r31 = (d21 + d31 + d32) / 3;
2460    
2461     uint8_t r12 = d12;
2462     uint8_t r22 = d22;
2463     uint8_t r32 = d32;
2464    
2465     uint8_t r13 = (d13 + d23 + d12) / 3;
2466     uint8_t r23 = d23;
2467     uint8_t r33 = (d23 + d33 + d32) / 3;
2468    
2469     darkness3 [(y * 3 ) * sw34 + (x * 3 )] = MAX (d22, r11);
2470     darkness3 [(y * 3 ) * sw34 + (x * 3 + 1)] = MAX (d22, r21);
2471     darkness3 [(y * 3 ) * sw34 + (x * 3 + 2)] = MAX (d22, r31);
2472     darkness3 [(y * 3 + 1) * sw34 + (x * 3 )] = MAX (d22, r12);
2473     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 1)] = MAX (d22, r22);
2474     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 2)] = MAX (d22, r32);
2475     darkness3 [(y * 3 + 2) * sw34 + (x * 3 )] = MAX (d22, r13);
2476     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 1)] = MAX (d22, r23);
2477     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 2)] = MAX (d22, r33);
2478     }
2479 root 1.201
2480 root 1.204 free (darkness1);
2481 root 1.201
2482 root 1.32 EXTEND (SP, 3);
2483 root 1.204 PUSHs (sv_2mortal (newSViv (sw34)));
2484     PUSHs (sv_2mortal (newSViv (sh3)));
2485     PUSHs (darkness3_sv);
2486 root 1.30 }
2487    
2488 root 1.42 SV *
2489 root 1.242 get_rect (DC::Map self, int x0, int y0, int w, int h)
2490 root 1.42 CODE:
2491     {
2492     int x, y, x1, y1;
2493     SV *data_sv = newSV (w * h * 7 + 5);
2494     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2495    
2496     *data++ = 0; /* version 0 format */
2497     *data++ = w >> 8; *data++ = w;
2498     *data++ = h >> 8; *data++ = h;
2499    
2500     // we need to do this 'cause we don't keep an absolute coord system for rows
2501 root 1.55 // TODO: treat rows as we treat columns
2502 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2503     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2504    
2505     x0 += self->x - self->ox;
2506     y0 += self->y - self->oy;
2507    
2508     x1 = x0 + w;
2509     y1 = y0 + h;
2510    
2511     for (y = y0; y < y1; y++)
2512     {
2513     maprow *row = 0 <= y && y < self->rows
2514     ? self->row + y
2515     : 0;
2516    
2517     for (x = x0; x < x1; x++)
2518     {
2519     if (row && row->c0 <= x && x < row->c1)
2520     {
2521     mapcell *cell = row->col + (x - row->c0);
2522     uint8_t flags = 0;
2523    
2524 root 1.174 if (cell->tile [0]) flags |= 1;
2525     if (cell->tile [1]) flags |= 2;
2526     if (cell->tile [2]) flags |= 4;
2527 root 1.42
2528     *data++ = flags;
2529    
2530     if (flags & 1)
2531     {
2532 root 1.174 tileid tile = cell->tile [0];
2533     *data++ = tile >> 8;
2534     *data++ = tile;
2535 root 1.42 }
2536    
2537     if (flags & 2)
2538     {
2539 root 1.174 tileid tile = cell->tile [1];
2540     *data++ = tile >> 8;
2541     *data++ = tile;
2542 root 1.42 }
2543    
2544     if (flags & 4)
2545     {
2546 root 1.174 tileid tile = cell->tile [2];
2547     *data++ = tile >> 8;
2548     *data++ = tile;
2549 root 1.42 }
2550     }
2551     else
2552     *data++ = 0;
2553     }
2554     }
2555    
2556 root 1.260 /* if size is w*h + 5 then no data has been found */
2557     if (data - (uint8_t *)SvPVX (data_sv) != w * h + 5)
2558 root 1.259 {
2559     SvPOK_only (data_sv);
2560     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2561     }
2562 root 1.260
2563     RETVAL = data_sv;
2564 root 1.42 }
2565     OUTPUT:
2566     RETVAL
2567    
2568     void
2569 root 1.259 set_rect (DC::Map self, int x0, int y0, SV *data_sv)
2570 root 1.42 PPCODE:
2571     {
2572     int x, y, z;
2573 root 1.48 int w, h;
2574 root 1.42 int x1, y1;
2575 root 1.259 STRLEN len;
2576     uint8_t *data, *end;
2577    
2578     len = SvLEN (data_sv);
2579 root 1.260 SvGROW (data_sv, len + 8); // reserve at least 7+ bytes more
2580 root 1.259 data = SvPVbyte_nolen (data_sv);
2581 root 1.260 end = data + len + 8;
2582 root 1.259
2583     if (len < 5)
2584     XSRETURN_EMPTY;
2585 root 1.42
2586     if (*data++ != 0)
2587 root 1.227 XSRETURN_EMPTY; /* version mismatch */
2588 root 1.42
2589 root 1.48 w = *data++ << 8; w |= *data++;
2590     h = *data++ << 8; h |= *data++;
2591 root 1.42
2592     // we need to do this 'cause we don't keep an absolute coord system for rows
2593 root 1.55 // TODO: treat rows as we treat columns
2594 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2595     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2596    
2597     x0 += self->x - self->ox;
2598     y0 += self->y - self->oy;
2599    
2600     x1 = x0 + w;
2601     y1 = y0 + h;
2602    
2603     for (y = y0; y < y1; y++)
2604     {
2605     maprow *row = map_get_row (self, y);
2606    
2607     for (x = x0; x < x1; x++)
2608     {
2609 root 1.259 uint8_t flags;
2610    
2611     if (data + 7 >= end)
2612     XSRETURN_EMPTY;
2613    
2614     flags = *data++;
2615 root 1.42
2616     if (flags)
2617     {
2618     mapcell *cell = row_get_cell (row, x);
2619 root 1.174 tileid tile[3] = { 0, 0, 0 };
2620 root 1.42
2621 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2622     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2623     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2624 root 1.42
2625 root 1.143 if (cell->darkness == 0)
2626 root 1.42 {
2627 root 1.260 /*cell->darkness = 0;*/
2628     EXTEND (SP, 3);
2629 root 1.42
2630     for (z = 0; z <= 2; z++)
2631     {
2632 root 1.174 tileid t = tile [z];
2633    
2634 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2635 root 1.174 {
2636 root 1.260 PUSHs (sv_2mortal (newSViv (t)));
2637 root 1.174 need_texid (self, t);
2638     }
2639 root 1.42
2640 root 1.174 cell->tile [z] = t;
2641 root 1.42 }
2642     }
2643     }
2644     }
2645     }
2646     }
2647    
2648 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::RW
2649 root 1.205
2650 root 1.242 DC::RW
2651 root 1.211 new (SV *class, SV *data_sv)
2652     CODE:
2653     {
2654     STRLEN datalen;
2655     char *data = SvPVbyte (data_sv, datalen);
2656    
2657 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2658 root 1.211 }
2659     OUTPUT:
2660     RETVAL
2661    
2662 root 1.242 DC::RW
2663 root 1.212 new_from_file (SV *class, const char *path, const char *mode = "rb")
2664     CODE:
2665     RETVAL = SDL_RWFromFile (path, mode);
2666     OUTPUT:
2667     RETVAL
2668    
2669 root 1.218 # fails on win32:
2670 root 1.241 # dc.xs(2268) : error C2059: syntax error : '('
2671 root 1.218 #void
2672 root 1.242 #close (DC::RW self)
2673 root 1.218 # CODE:
2674     # (self->(close)) (self);
2675 root 1.212
2676 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Channel
2677 root 1.212
2678     PROTOTYPES: DISABLE
2679    
2680 root 1.242 DC::Channel
2681 root 1.215 find ()
2682     CODE:
2683     {
2684     RETVAL = Mix_GroupAvailable (-1);
2685    
2686     if (RETVAL < 0)
2687     {
2688     RETVAL = Mix_GroupOldest (-1);
2689    
2690     if (RETVAL < 0)
2691     XSRETURN_UNDEF;
2692    
2693     Mix_HaltChannel (RETVAL);
2694     }
2695    
2696     Mix_UnregisterAllEffects (RETVAL);
2697     Mix_Volume (RETVAL, 128);
2698     }
2699     OUTPUT:
2700     RETVAL
2701    
2702 root 1.213 void
2703 root 1.242 halt (DC::Channel self)
2704 root 1.213 CODE:
2705     Mix_HaltChannel (self);
2706    
2707     void
2708 root 1.242 expire (DC::Channel self, int ticks = -1)
2709 root 1.213 CODE:
2710     Mix_ExpireChannel (self, ticks);
2711    
2712     void
2713 root 1.242 fade_out (DC::Channel self, int ticks = -1)
2714 root 1.213 CODE:
2715     Mix_FadeOutChannel (self, ticks);
2716    
2717 root 1.212 int
2718 root 1.242 volume (DC::Channel self, int volume)
2719 root 1.212 CODE:
2720 root 1.216 RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128));
2721 root 1.212 OUTPUT:
2722     RETVAL
2723    
2724 root 1.213 void
2725 root 1.242 unregister_all_effects (DC::Channel self)
2726 root 1.212 CODE:
2727 root 1.213 Mix_UnregisterAllEffects (self);
2728 root 1.212
2729 root 1.213 void
2730 root 1.242 set_panning (DC::Channel self, int left, int right)
2731 root 1.212 CODE:
2732 root 1.216 left = CLAMP (left , 0, 255);
2733     right = CLAMP (right, 0, 255);
2734 root 1.213 Mix_SetPanning (self, left, right);
2735 root 1.212
2736 root 1.213 void
2737 root 1.242 set_distance (DC::Channel self, int distance)
2738 root 1.212 CODE:
2739 root 1.216 Mix_SetDistance (self, CLAMP (distance, 0, 255));
2740 root 1.212
2741 root 1.213 void
2742 root 1.242 set_position (DC::Channel self, int angle, int distance)
2743 root 1.212 CODE:
2744 root 1.220
2745     void
2746 root 1.242 set_position_r (DC::Channel self, int dx, int dy, int maxdistance)
2747 root 1.220 CODE:
2748     {
2749     int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance));
2750     int angle = 360 + (int)roundf (atan2f (dx, -dy) * 180.f / (float)M_PI);
2751 root 1.216 Mix_SetPosition (self, angle, CLAMP (distance, 0, 255));
2752 root 1.220 }
2753 root 1.212
2754 root 1.213 void
2755 root 1.242 set_reverse_stereo (DC::Channel self, int flip)
2756 root 1.212 CODE:
2757 root 1.213 Mix_SetReverseStereo (self, flip);
2758 root 1.212
2759 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixChunk
2760 root 1.212
2761     PROTOTYPES: DISABLE
2762    
2763 root 1.242 DC::MixChunk
2764     new (SV *class, DC::RW rwops)
2765 root 1.52 CODE:
2766 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2767 root 1.52 OUTPUT:
2768     RETVAL
2769    
2770     void
2771 root 1.242 DESTROY (DC::MixChunk self)
2772 root 1.52 CODE:
2773     Mix_FreeChunk (self);
2774    
2775     int
2776 root 1.242 volume (DC::MixChunk self, int volume = -1)
2777 root 1.52 CODE:
2778 root 1.216 if (items > 1)
2779     volume = CLAMP (volume, 0, 128);
2780 root 1.52 RETVAL = Mix_VolumeChunk (self, volume);
2781     OUTPUT:
2782     RETVAL
2783    
2784 root 1.242 DC::Channel
2785     play (DC::MixChunk self, DC::Channel channel = -1, int loops = 0, int ticks = -1)
2786 root 1.52 CODE:
2787 root 1.215 {
2788 root 1.52 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2789 root 1.215
2790     if (RETVAL < 0)
2791     XSRETURN_UNDEF;
2792    
2793     if (channel < 0)
2794     {
2795     Mix_UnregisterAllEffects (RETVAL);
2796     Mix_Volume (RETVAL, 128);
2797     }
2798     }
2799 root 1.52 OUTPUT:
2800     RETVAL
2801    
2802 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixMusic
2803 root 1.52
2804     int
2805     volume (int volume = -1)
2806 root 1.205 PROTOTYPE: ;$
2807 root 1.52 CODE:
2808 root 1.216 if (items > 0)
2809     volume = CLAMP (volume, 0, 128);
2810 root 1.52 RETVAL = Mix_VolumeMusic (volume);
2811     OUTPUT:
2812     RETVAL
2813    
2814 root 1.213 void
2815 root 1.194 fade_out (int ms)
2816     CODE:
2817 root 1.213 Mix_FadeOutMusic (ms);
2818 root 1.194
2819 root 1.212 void
2820     halt ()
2821     CODE:
2822     Mix_HaltMusic ();
2823    
2824 root 1.242 DC::MixMusic
2825     new (SV *class, DC::RW rwops)
2826 root 1.52 CODE:
2827 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
2828 root 1.52 OUTPUT:
2829     RETVAL
2830    
2831     void
2832 root 1.242 DESTROY (DC::MixMusic self)
2833 root 1.52 CODE:
2834     Mix_FreeMusic (self);
2835    
2836     int
2837 root 1.242 play (DC::MixMusic self, int loops = -1)
2838 root 1.52 CODE:
2839     RETVAL = Mix_PlayMusic (self, loops);
2840     OUTPUT:
2841     RETVAL
2842    
2843 root 1.213 void
2844 root 1.242 fade_in_pos (DC::MixMusic self, int loops, int ms, double position)
2845 root 1.195 CODE:
2846 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
2847 root 1.195
2848 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::OpenGL
2849 root 1.54
2850 root 1.205 PROTOTYPES: ENABLE
2851    
2852 root 1.54 BOOT:
2853     {
2854 root 1.242 HV *stash = gv_stashpv ("DC::OpenGL", 1);
2855 root 1.54 static const struct {
2856     const char *name;
2857     IV iv;
2858     } *civ, const_iv[] = {
2859     # define const_iv(name) { # name, (IV)name }
2860 root 1.199 const_iv (GL_VENDOR),
2861     const_iv (GL_VERSION),
2862     const_iv (GL_EXTENSIONS),
2863 root 1.54 const_iv (GL_COLOR_MATERIAL),
2864     const_iv (GL_SMOOTH),
2865     const_iv (GL_FLAT),
2866 root 1.69 const_iv (GL_DITHER),
2867 root 1.54 const_iv (GL_BLEND),
2868 root 1.89 const_iv (GL_CULL_FACE),
2869 root 1.69 const_iv (GL_SCISSOR_TEST),
2870 root 1.89 const_iv (GL_DEPTH_TEST),
2871     const_iv (GL_ALPHA_TEST),
2872     const_iv (GL_NORMALIZE),
2873     const_iv (GL_RESCALE_NORMAL),
2874 root 1.119 const_iv (GL_FRONT),
2875     const_iv (GL_BACK),
2876 root 1.206 const_iv (GL_AUX0),
2877 root 1.54 const_iv (GL_AND),
2878 root 1.67 const_iv (GL_ONE),
2879     const_iv (GL_ZERO),
2880 root 1.54 const_iv (GL_SRC_ALPHA),
2881 root 1.104 const_iv (GL_DST_ALPHA),
2882 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2883 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2884 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2885 root 1.54 const_iv (GL_RGB),
2886     const_iv (GL_RGBA),
2887 root 1.115 const_iv (GL_RGBA4),
2888     const_iv (GL_RGBA8),
2889     const_iv (GL_RGB5_A1),
2890 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2891 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2892     const_iv (GL_UNSIGNED_INT),
2893 root 1.54 const_iv (GL_ALPHA),
2894 root 1.86 const_iv (GL_INTENSITY),
2895 root 1.76 const_iv (GL_LUMINANCE),
2896 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2897 root 1.54 const_iv (GL_FLOAT),
2898     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2899 root 1.230 const_iv (GL_COMPRESSED_ALPHA_ARB),
2900     const_iv (GL_COMPRESSED_LUMINANCE_ARB),
2901     const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB),
2902     const_iv (GL_COMPRESSED_INTENSITY_ARB),
2903     const_iv (GL_COMPRESSED_RGB_ARB),
2904     const_iv (GL_COMPRESSED_RGBA_ARB),
2905 root 1.54 const_iv (GL_COMPILE),
2906 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
2907     const_iv (GL_PROXY_TEXTURE_2D),
2908 root 1.54 const_iv (GL_TEXTURE_1D),
2909     const_iv (GL_TEXTURE_2D),
2910     const_iv (GL_TEXTURE_ENV),
2911     const_iv (GL_TEXTURE_MAG_FILTER),
2912     const_iv (GL_TEXTURE_MIN_FILTER),
2913     const_iv (GL_TEXTURE_ENV_MODE),
2914     const_iv (GL_TEXTURE_WRAP_S),
2915     const_iv (GL_TEXTURE_WRAP_T),
2916 root 1.98 const_iv (GL_REPEAT),
2917 root 1.54 const_iv (GL_CLAMP),
2918 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2919 root 1.54 const_iv (GL_NEAREST),
2920     const_iv (GL_LINEAR),
2921 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2922     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2923     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2924     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2925     const_iv (GL_GENERATE_MIPMAP),
2926 root 1.54 const_iv (GL_MODULATE),
2927 root 1.69 const_iv (GL_DECAL),
2928 root 1.54 const_iv (GL_REPLACE),
2929 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2930 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2931     const_iv (GL_PROJECTION),
2932     const_iv (GL_MODELVIEW),
2933     const_iv (GL_COLOR_LOGIC_OP),
2934 root 1.69 const_iv (GL_SEPARABLE_2D),
2935 root 1.54 const_iv (GL_CONVOLUTION_2D),
2936     const_iv (GL_CONVOLUTION_BORDER_MODE),
2937     const_iv (GL_CONSTANT_BORDER),
2938 root 1.208 const_iv (GL_POINTS),
2939 root 1.54 const_iv (GL_LINES),
2940 root 1.138 const_iv (GL_LINE_STRIP),
2941 root 1.89 const_iv (GL_LINE_LOOP),
2942 root 1.54 const_iv (GL_QUADS),
2943 root 1.89 const_iv (GL_QUAD_STRIP),
2944     const_iv (GL_TRIANGLES),
2945     const_iv (GL_TRIANGLE_STRIP),
2946     const_iv (GL_TRIANGLE_FAN),
2947 root 1.208 const_iv (GL_POLYGON),
2948 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2949 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
2950     const_iv (GL_LINE_SMOOTH_HINT),
2951     const_iv (GL_POLYGON_SMOOTH_HINT),
2952     const_iv (GL_GENERATE_MIPMAP_HINT),
2953 root 1.232 const_iv (GL_TEXTURE_COMPRESSION_HINT),
2954 root 1.54 const_iv (GL_FASTEST),
2955 root 1.206 const_iv (GL_DONT_CARE),
2956     const_iv (GL_NICEST),
2957 root 1.89 const_iv (GL_V2F),
2958     const_iv (GL_V3F),
2959     const_iv (GL_T2F_V3F),
2960     const_iv (GL_T2F_N3F_V3F),
2961 root 1.54 # undef const_iv
2962     };
2963    
2964     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2965     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2966 root 1.188
2967     texture_av = newAV ();
2968     AvREAL_off (texture_av);
2969 root 1.54 }
2970    
2971 root 1.231 void
2972     disable_GL_EXT_blend_func_separate ()
2973     CODE:
2974     gl.BlendFuncSeparate = 0;
2975     gl.BlendFuncSeparateEXT = 0;
2976    
2977 root 1.97 char *
2978     gl_vendor ()
2979     CODE:
2980     RETVAL = (char *)glGetString (GL_VENDOR);
2981     OUTPUT:
2982     RETVAL
2983    
2984     char *
2985     gl_version ()
2986     CODE:
2987     RETVAL = (char *)glGetString (GL_VERSION);
2988     OUTPUT:
2989     RETVAL
2990    
2991     char *
2992     gl_extensions ()
2993     CODE:
2994     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2995     OUTPUT:
2996     RETVAL
2997    
2998 root 1.201 const char *glGetString (GLenum pname)
2999 root 1.199
3000     GLint glGetInteger (GLenum pname)
3001     CODE:
3002     glGetIntegerv (pname, &RETVAL);
3003     OUTPUT:
3004     RETVAL
3005    
3006     GLdouble glGetDouble (GLenum pname)
3007     CODE:
3008     glGetDoublev (pname, &RETVAL);
3009     OUTPUT:
3010     RETVAL
3011    
3012 root 1.54 int glGetError ()
3013    
3014 root 1.114 void glFinish ()
3015    
3016 root 1.54 void glClear (int mask)
3017    
3018     void glClearColor (float r, float g, float b, float a = 1.0)
3019     PROTOTYPE: @
3020    
3021     void glEnable (int cap)
3022    
3023     void glDisable (int cap)
3024    
3025     void glShadeModel (int mode)
3026    
3027     void glHint (int target, int mode)
3028    
3029     void glBlendFunc (int sfactor, int dfactor)
3030    
3031 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
3032     CODE:
3033     gl_BlendFuncSeparate (sa, da, saa, daa);
3034    
3035 root 1.89 void glDepthMask (int flag)
3036    
3037 root 1.54 void glLogicOp (int opcode)
3038    
3039 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
3040    
3041 root 1.54 void glMatrixMode (int mode)
3042    
3043     void glPushMatrix ()
3044    
3045     void glPopMatrix ()
3046    
3047     void glLoadIdentity ()
3048    
3049 root 1.119 void glDrawBuffer (int buffer)
3050    
3051     void glReadBuffer (int buffer)
3052    
3053 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
3054     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
3055    
3056     # near_ and far_ are due to microsofts buggy "c" compiler
3057 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
3058 root 1.54
3059 root 1.208 PROTOTYPES: DISABLE
3060    
3061 root 1.54 void glViewport (int x, int y, int width, int height)
3062    
3063 root 1.69 void glScissor (int x, int y, int width, int height)
3064    
3065 root 1.54 void glTranslate (float x, float y, float z = 0.)
3066     CODE:
3067     glTranslatef (x, y, z);
3068    
3069 root 1.62 void glScale (float x, float y, float z = 1.)
3070 root 1.54 CODE:
3071     glScalef (x, y, z);
3072    
3073     void glRotate (float angle, float x, float y, float z)
3074     CODE:
3075     glRotatef (angle, x, y, z);
3076    
3077     void glColor (float r, float g, float b, float a = 1.0)
3078 root 1.278 PROTOTYPE: @
3079 root 1.103 ALIAS:
3080     glColor_premultiply = 1
3081 root 1.54 CODE:
3082 root 1.103 if (ix)
3083     {
3084     r *= a;
3085     g *= a;
3086     b *= a;
3087     }
3088 root 1.90 // microsoft visual "c" rounds instead of truncating...
3089 root 1.130 glColor4f (r, g, b, a);
3090 root 1.54
3091 root 1.91 void glRasterPos (float x, float y, float z = 0.)
3092     CODE:
3093     glRasterPos3f (0, 0, z);
3094     glBitmap (0, 0, 0, 0, x, y, 0);
3095    
3096 root 1.54 void glVertex (float x, float y, float z = 0.)
3097     CODE:
3098     glVertex3f (x, y, z);
3099    
3100     void glTexCoord (float s, float t)
3101     CODE:
3102     glTexCoord2f (s, t);
3103    
3104 root 1.210 void glRect (float x1, float y1, float x2, float y2)
3105     CODE:
3106     glRectf (x1, y1, x2, y2);
3107    
3108 root 1.233 void glRect_lineloop (float x1, float y1, float x2, float y2)
3109     CODE:
3110     glBegin (GL_LINE_LOOP);
3111     glVertex2f (x1, y1);
3112     glVertex2f (x2, y1);
3113     glVertex2f (x2, y2);
3114     glVertex2f (x1, y2);
3115     glEnd ();
3116    
3117 root 1.208 PROTOTYPES: ENABLE
3118    
3119     void glBegin (int mode)
3120    
3121     void glEnd ()
3122    
3123     void glPointSize (GLfloat size)
3124    
3125     void glLineWidth (GLfloat width)
3126    
3127     void glInterleavedArrays (int format, int stride, char *data)
3128    
3129     void glDrawElements (int mode, int count, int type, char *indices)
3130    
3131     # 1.2 void glDrawRangeElements (int mode, int start, int end
3132    
3133 root 1.54 void glTexEnv (int target, int pname, float param)
3134     CODE:
3135     glTexEnvf (target, pname, param);
3136    
3137     void glTexParameter (int target, int pname, float param)
3138     CODE:
3139     glTexParameterf (target, pname, param);
3140    
3141     void glBindTexture (int target, int name)
3142    
3143     void glConvolutionParameter (int target, int pname, float params)
3144     CODE:
3145 root 1.103 if (gl.ConvolutionParameterf)
3146     gl.ConvolutionParameterf (target, pname, params);
3147 root 1.54
3148     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
3149 root 1.64 CODE:
3150 root 1.103 if (gl.ConvolutionFilter2D)
3151     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
3152 root 1.54
3153 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
3154     CODE:
3155 root 1.103 if (gl.SeparableFilter2D)
3156     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
3157 root 1.69
3158 root 1.244 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data = 0)
3159 root 1.54
3160     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
3161    
3162 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
3163 root 1.68
3164 root 1.199 void glPixelZoom (float x, float y)
3165    
3166 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
3167    
3168 root 1.54 int glGenTexture ()
3169     CODE:
3170 root 1.192 RETVAL = gen_texture ();
3171 root 1.54 OUTPUT:
3172     RETVAL
3173    
3174     void glDeleteTexture (int name)
3175     CODE:
3176 root 1.192 del_texture (name);
3177    
3178 root 1.54 int glGenList ()
3179     CODE:
3180     RETVAL = glGenLists (1);
3181     OUTPUT:
3182     RETVAL
3183    
3184     void glDeleteList (int list)
3185     CODE:
3186     glDeleteLists (list, 1);
3187    
3188     void glNewList (int list, int mode = GL_COMPILE)
3189    
3190     void glEndList ()
3191    
3192     void glCallList (int list)
3193    
3194 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::UI::Base
3195 root 1.207
3196     PROTOTYPES: DISABLE
3197    
3198     void
3199 root 1.209 find_widget (SV *self, NV x, NV y)
3200 root 1.207 PPCODE:
3201     {
3202 root 1.209 if (within_widget (self, x, y))
3203     XPUSHs (self);
3204     }
3205    
3206     BOOT:
3207     {
3208 root 1.242 hover_gv = gv_fetchpv ("DC::UI::HOVER", 1, SVt_NV);
3209 root 1.209
3210 root 1.242 draw_x_gv = gv_fetchpv ("DC::UI::Base::draw_x", 1, SVt_NV);
3211     draw_y_gv = gv_fetchpv ("DC::UI::Base::draw_y", 1, SVt_NV);
3212     draw_w_gv = gv_fetchpv ("DC::UI::Base::draw_w", 1, SVt_NV);
3213     draw_h_gv = gv_fetchpv ("DC::UI::Base::draw_h", 1, SVt_NV);
3214 root 1.209 }
3215    
3216     void
3217     draw (SV *self)
3218     CODE:
3219     {
3220     HV *hv;
3221     SV **svp;
3222     NV x, y, w, h;
3223     SV *draw_x_sv = GvSV (draw_x_gv);
3224     SV *draw_y_sv = GvSV (draw_y_gv);
3225     SV *draw_w_sv = GvSV (draw_w_gv);
3226     SV *draw_h_sv = GvSV (draw_h_gv);
3227 root 1.228 double draw_x, draw_y;
3228 root 1.209
3229     if (!SvROK (self))
3230 root 1.242 croak ("DC::Base::draw: %s not a reference", SvPV_nolen (self));
3231 root 1.209
3232     hv = (HV *)SvRV (self);
3233    
3234     if (SvTYPE (hv) != SVt_PVHV)
3235 root 1.242 croak ("DC::Base::draw: %s not a hashref", SvPV_nolen (self));
3236 root 1.209
3237     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
3238     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
3239    
3240     if (!h || !w)
3241     XSRETURN_EMPTY;
3242    
3243     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
3244     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
3245    
3246     draw_x = SvNV (draw_x_sv) + x;
3247     draw_y = SvNV (draw_y_sv) + y;
3248    
3249     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
3250     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
3251     XSRETURN_EMPTY;
3252    
3253     sv_setnv (draw_x_sv, draw_x);
3254     sv_setnv (draw_y_sv, draw_y);
3255    
3256     glPushMatrix ();
3257     glTranslated (x, y, 0);
3258    
3259     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
3260     {
3261     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
3262    
3263     if (svp && SvTRUE (*svp))
3264     {
3265 root 1.228 glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f);
3266 root 1.209 glEnable (GL_BLEND);
3267     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3268     glBegin (GL_QUADS);
3269     glVertex2f (0, 0);
3270     glVertex2f (w, 0);
3271     glVertex2f (w, h);
3272     glVertex2f (0, h);
3273     glEnd ();
3274     glDisable (GL_BLEND);
3275     }
3276     }
3277     #if 0
3278 root 1.234 // draw borders, for debugging
3279     glPushMatrix ();
3280     glColor4f (1., 1., 0., 1.);
3281     glTranslatef (.5, .5, 0.);
3282     glBegin (GL_LINE_LOOP);
3283     glVertex2f (0 , 0);
3284     glVertex2f (w - 1, 0);
3285     glVertex2f (w - 1, h - 1);
3286     glVertex2f (0 , h - 1);
3287     glEnd ();
3288     glPopMatrix ();
3289 root 1.209 #endif
3290     PUSHMARK (SP);
3291     XPUSHs (self);
3292     PUTBACK;
3293     call_method ("_draw", G_VOID | G_DISCARD);
3294     SPAGAIN;
3295    
3296     glPopMatrix ();
3297    
3298     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
3299     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
3300 root 1.207 }
3301