ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.294
Committed: Sat Dec 19 05:06:56 2009 UTC (14 years, 4 months ago) by root
Branch: MAIN
Changes since 1.293: +74 -13 lines
Log Message:
implement shadow blending

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