ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.297
Committed: Tue Dec 22 00:08:11 2009 UTC (14 years, 4 months ago) by root
Branch: MAIN
Changes since 1.296: +1 -5 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.48 #ifdef _WIN32
2 root 1.131 # define WIN32_LEAN_AND_MEAN
3 root 1.170 # define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls
4 root 1.48 # include <malloc.h>
5 root 1.79 # include <windows.h>
6 root 1.157 # include <wininet.h>
7 root 1.75 # pragma warning(disable:4244)
8 root 1.162 # pragma warning(disable:4761)
9 root 1.48 #endif
10    
11 root 1.193 //#define DEBUG 1
12     #if DEBUG
13     # include <valgrind/memcheck.h>
14     #endif
15    
16 root 1.1 #include "EXTERN.h"
17     #include "perl.h"
18     #include "XSUB.h"
19    
20 root 1.131 #ifdef _WIN32
21     # undef pipe
22 root 1.222 // microsoft vs. C
23     # define sqrtf(x) sqrt(x)
24     # define atan2f(x,y) atan2(x,y)
25     # define M_PI 3.14159265f
26 root 1.131 #endif
27    
28 root 1.168 #include <assert.h>
29 root 1.80 #include <math.h>
30 root 1.5 #include <string.h>
31 root 1.25 #include <stdio.h>
32 root 1.111 #include <stdlib.h>
33 root 1.5
34 root 1.212 #define USE_RWOPS 1 // for SDL_mixer:LoadMUS_RW
35    
36 root 1.2 #include <SDL.h>
37 root 1.202 #include <SDL_thread.h>
38 root 1.76 #include <SDL_endian.h>
39 root 1.23 #include <SDL_image.h>
40 root 1.52 #include <SDL_mixer.h>
41 root 1.3 #include <SDL_opengl.h>
42 root 1.5
43 root 1.272 /* work around os x broken headers */
44     #ifdef __MACOSX__
45     typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
46     #endif
47    
48 root 1.124 #define PANGO_ENABLE_BACKEND
49     #define G_DISABLE_CAST_CHECKS
50    
51 root 1.30 #include <glib/gmacros.h>
52    
53 root 1.5 #include <pango/pango.h>
54    
55 root 1.254 #ifndef PANGO_VERSION_CHECK
56     # define PANGO_VERSION_CHECK(a,b,c) 0
57     #endif
58    
59     #if !PANGO_VERSION_CHECK (1, 15, 2)
60 root 1.255 # define pango_layout_get_line_readonly pango_layout_get_line
61     # define pango_layout_get_lines_readonly pango_layout_get_lines
62     # define pango_layout_iter_get_line_readonly pango_layout_iter_get_line
63     # define pango_layout_iter_get_run_readonly pango_layout_iter_get_run
64 root 1.249 #endif
65    
66 root 1.48 #ifndef _WIN32
67     # include <sys/types.h>
68     # include <sys/socket.h>
69     # include <netinet/in.h>
70     # include <netinet/tcp.h>
71     # include <inttypes.h>
72     #endif
73 root 1.28
74 root 1.261 #if __GNUC__ >= 4
75     # define expect(expr,value) __builtin_expect ((expr),(value))
76     #else
77     # define expect(expr,value) (expr)
78     #endif
79    
80     #define expect_false(expr) expect ((expr) != 0, 0)
81     #define expect_true(expr) expect ((expr) != 0, 1)
82    
83 root 1.162 #define OBJ_STR "\xef\xbf\xbc" /* U+FFFC, object replacement character */
84 root 1.121
85 root 1.296 /* this is used as fow flag as well, so has to have a different value */
86     /* then anything that is computed by incoming darkness */
87     #define FOW_DARKNESS 50
88     #define DARKNESS_ADJUST(n) (n)
89 root 1.29
90     #define MAP_EXTEND_X 32
91     #define MAP_EXTEND_Y 512
92    
93 root 1.63 #define MIN_FONT_HEIGHT 10
94 root 1.58
95 root 1.253 /* mask out modifiers we are not interested in */
96     #define MOD_MASK (KMOD_CTRL | KMOD_SHIFT | KMOD_ALT | KMOD_META)
97    
98 root 1.276 #define KMOD_LRAM 0x10000 // our extension
99    
100 root 1.285 #define TEXID_SPEECH 1
101     #define TEXID_NOFACE 2
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.295 NV distance (NV dx, NV dy)
828     CODE:
829     RETVAL = pow (dx * dx + dy * dy, 0.5);
830     OUTPUT:
831     RETVAL
832    
833 root 1.79 void
834     pango_init ()
835     CODE:
836     {
837 root 1.124 opengl_fontmap = pango_opengl_font_map_new ();
838     pango_opengl_font_map_set_default_substitute ((PangoOpenGLFontMap *)opengl_fontmap, substitute_func, 0, 0);
839     opengl_context = pango_opengl_font_map_create_context ((PangoOpenGLFontMap *)opengl_fontmap);
840 root 1.257 /*pango_context_set_font_description (opengl_context, default_font);*/
841 root 1.254 #if PANGO_VERSION_CHECK (1, 15, 2)
842 root 1.249 pango_context_set_language (opengl_context, pango_language_from_string ("en"));
843 root 1.250 /*pango_context_set_base_dir (opengl_context, PANGO_DIRECTION_WEAK_LTR);*/
844 root 1.249 #endif
845 root 1.5 }
846    
847 root 1.263 char *SDL_GetError ()
848    
849 root 1.272 void SDL_braino ()
850    
851 root 1.263 int SDL_Init (U32 flags)
852    
853     int SDL_InitSubSystem (U32 flags)
854 root 1.200
855 root 1.263 void SDL_QuitSubSystem (U32 flags)
856 root 1.51
857 root 1.263 void SDL_Quit ()
858 root 1.51
859 root 1.264 int SDL_GL_SetAttribute (int attr, int value)
860    
861     int SDL_GL_GetAttribute (int attr)
862     CODE:
863     if (SDL_GL_GetAttribute (attr, &RETVAL))
864     XSRETURN_UNDEF;
865     OUTPUT:
866     RETVAL
867    
868 root 1.51 void
869 root 1.200 SDL_ListModes (int rgb, int alpha)
870 root 1.51 PPCODE:
871     {
872     SDL_Rect **m;
873    
874 root 1.200 SDL_GL_SetAttribute (SDL_GL_RED_SIZE , rgb);
875     SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgb);
876     SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE , rgb);
877     SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, alpha);
878 root 1.51
879 root 1.88 SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 15);
880 root 1.200 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE , 0);
881 root 1.85
882 root 1.200 SDL_GL_SetAttribute (SDL_GL_ACCUM_RED_SIZE , 0);
883 root 1.51 SDL_GL_SetAttribute (SDL_GL_ACCUM_GREEN_SIZE, 0);
884 root 1.200 SDL_GL_SetAttribute (SDL_GL_ACCUM_BLUE_SIZE , 0);
885 root 1.51 SDL_GL_SetAttribute (SDL_GL_ACCUM_ALPHA_SIZE, 0);
886    
887     SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
888 root 1.131 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
889 root 1.51
890     m = SDL_ListModes (0, SDL_FULLSCREEN | SDL_OPENGL);
891    
892     if (m && m != (SDL_Rect **)-1)
893     while (*m)
894     {
895 root 1.265 if ((*m)->w >= 400 && (*m)->h >= 300)
896     {
897     AV *av = newAV ();
898     av_push (av, newSViv ((*m)->w));
899     av_push (av, newSViv ((*m)->h));
900     av_push (av, newSViv (rgb));
901     av_push (av, newSViv (alpha));
902     XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
903     }
904 root 1.51
905     ++m;
906     }
907     }
908    
909     int
910 root 1.200 SDL_SetVideoMode (int w, int h, int rgb, int alpha, int fullscreen)
911 root 1.51 CODE:
912 root 1.200 {
913     SDL_EnableUNICODE (1);
914     SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
915    
916     SDL_GL_SetAttribute (SDL_GL_RED_SIZE , rgb);
917     SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgb);
918     SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE , rgb);
919     SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, alpha);
920    
921 root 1.51 RETVAL = !!SDL_SetVideoMode (
922     w, h, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)
923     );
924 root 1.200
925 root 1.103 if (RETVAL)
926     {
927 root 1.188 av_clear (texture_av);
928    
929 root 1.237 SDL_WM_SetCaption ("Deliantra MORPG Client " VERSION, "Deliantra");
930 root 1.200 #define GL_FUNC(ptr,name) gl.name = (ptr)SDL_GL_GetProcAddress ("gl" # name);
931     #include "glfunc.h"
932     #undef GL_FUNC
933 root 1.103 }
934 root 1.200 }
935 root 1.51 OUTPUT:
936     RETVAL
937    
938 root 1.53 void
939 root 1.54 SDL_GL_SwapBuffers ()
940    
941 root 1.94 char *
942     SDL_GetKeyName (int sym)
943    
944 root 1.198 int
945     SDL_GetAppState ()
946    
947 root 1.256 int
948     SDL_GetModState ()
949    
950 root 1.54 void
951 root 1.197 poll_events ()
952 root 1.53 PPCODE:
953     {
954     SDL_Event ev;
955    
956 root 1.197 SDL_PumpEvents ();
957     while (SDL_PeepEvents (&ev, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0)
958 root 1.53 {
959     HV *hv = newHV ();
960     hv_store (hv, "type", 4, newSViv (ev.type), 0);
961 root 1.70
962 root 1.53 switch (ev.type)
963     {
964     case SDL_KEYDOWN:
965     case SDL_KEYUP:
966     hv_store (hv, "state", 5, newSViv (ev.key.state), 0);
967     hv_store (hv, "sym", 3, newSViv (ev.key.keysym.sym), 0);
968 root 1.276 hv_store (hv, "mod", 3, newSViv (mod_munge (ev.key.keysym.mod)), 0);
969     hv_store (hv, "cmod", 4, newSViv (mod_munge (SDL_GetModState ())), 0); /* current mode */
970 root 1.53 hv_store (hv, "unicode", 7, newSViv (ev.key.keysym.unicode), 0);
971     break;
972    
973     case SDL_ACTIVEEVENT:
974     hv_store (hv, "gain", 4, newSViv (ev.active.gain), 0);
975     hv_store (hv, "state", 5, newSViv (ev.active.state), 0);
976     break;
977    
978     case SDL_MOUSEMOTION:
979 root 1.196 {
980     int state = ev.motion.state;
981     int x = ev.motion.x;
982     int y = ev.motion.y;
983     int xrel = ev.motion.xrel;
984     int yrel = ev.motion.yrel;
985    
986     /* do simplistic event compression */
987     while (SDL_PeepEvents (&ev, 1, SDL_PEEKEVENT, SDL_EVENTMASK (SDL_MOUSEMOTION)) > 0
988     && state == ev.motion.state)
989     {
990     xrel += ev.motion.xrel;
991     yrel += ev.motion.yrel;
992     x = ev.motion.x;
993     y = ev.motion.y;
994     SDL_PeepEvents (&ev, 1, SDL_GETEVENT, SDL_EVENTMASK (SDL_MOUSEMOTION));
995     }
996 root 1.93
997 root 1.276 hv_store (hv, "mod", 3, newSViv (mod_munge (SDL_GetModState ())), 0);
998 root 1.196 hv_store (hv, "state", 5, newSViv (state), 0);
999     hv_store (hv, "x", 1, newSViv (x), 0);
1000     hv_store (hv, "y", 1, newSViv (y), 0);
1001     hv_store (hv, "xrel", 4, newSViv (xrel), 0);
1002     hv_store (hv, "yrel", 4, newSViv (yrel), 0);
1003     }
1004 root 1.53 break;
1005    
1006     case SDL_MOUSEBUTTONDOWN:
1007     case SDL_MOUSEBUTTONUP:
1008 root 1.253 hv_store (hv, "mod", 3, newSViv (SDL_GetModState () & MOD_MASK), 0);
1009 root 1.93
1010 root 1.53 hv_store (hv, "button", 6, newSViv (ev.button.button), 0);
1011     hv_store (hv, "state", 5, newSViv (ev.button.state), 0);
1012     hv_store (hv, "x", 1, newSViv (ev.button.x), 0);
1013     hv_store (hv, "y", 1, newSViv (ev.button.y), 0);
1014 root 1.70 break;
1015 root 1.72
1016     case SDL_USEREVENT:
1017     hv_store (hv, "code", 4, newSViv (ev.user.code), 0);
1018     hv_store (hv, "data1", 5, newSViv ((IV)ev.user.data1), 0);
1019     hv_store (hv, "data2", 5, newSViv ((IV)ev.user.data2), 0);
1020     break;
1021 root 1.53 }
1022    
1023 root 1.242 XPUSHs (sv_2mortal (sv_bless (newRV_noinc ((SV *)hv), gv_stashpv ("DC::UI::Event", 1))));
1024 root 1.53 }
1025     }
1026 root 1.52
1027     int
1028 root 1.236 Mix_OpenAudio (int frequency = 44100, int format = MIX_DEFAULT_FORMAT, int channels = 2, int chunksize = 4096)
1029 root 1.56 POSTCALL:
1030     Mix_HookMusicFinished (music_finished);
1031 root 1.71 Mix_ChannelFinished (channel_finished);
1032 root 1.52
1033     void
1034 root 1.236 Mix_QuerySpec ()
1035     PPCODE:
1036     {
1037     int freq, channels;
1038     Uint16 format;
1039    
1040     if (Mix_QuerySpec (&freq, &format, &channels))
1041     {
1042     EXTEND (SP, 3);
1043     PUSHs (sv_2mortal (newSViv (freq)));
1044     PUSHs (sv_2mortal (newSViv (format)));
1045     PUSHs (sv_2mortal (newSViv (channels)));
1046     }
1047     }
1048    
1049     void
1050 root 1.52 Mix_CloseAudio ()
1051    
1052     int
1053     Mix_AllocateChannels (int numchans = -1)
1054    
1055 root 1.214 const char *
1056     Mix_GetError ()
1057    
1058 root 1.10 void
1059     lowdelay (int fd, int val = 1)
1060     CODE:
1061 root 1.179 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&val, sizeof (val));
1062 root 1.10
1063 root 1.5 void
1064 root 1.157 win32_proxy_info ()
1065     PPCODE:
1066     {
1067     #ifdef _WIN32
1068     char buffer[2048];
1069     DWORD buflen;
1070    
1071     EXTEND (SP, 3);
1072    
1073     buflen = sizeof (buffer);
1074     if (InternetQueryOption (0, INTERNET_OPTION_PROXY, (void *)buffer, &buflen))
1075     if (((INTERNET_PROXY_INFO *)buffer)->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
1076     {
1077     PUSHs (newSVpv (((INTERNET_PROXY_INFO *)buffer)->lpszProxy, 0));
1078    
1079     buflen = sizeof (buffer);
1080     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_USERNAME, (void *)buffer, &buflen))
1081     {
1082     PUSHs (newSVpv (buffer, 0));
1083    
1084     buflen = sizeof (buffer);
1085     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_PASSWORD, (void *)buffer, &buflen))
1086     PUSHs (newSVpv (buffer, 0));
1087     }
1088     }
1089     #endif
1090     }
1091    
1092 root 1.257 int
1093 root 1.13 add_font (char *file)
1094     CODE:
1095 root 1.257 RETVAL = FcConfigAppFontAddFile (0, (const FcChar8 *)file);
1096     OUTPUT:
1097     RETVAL
1098 root 1.13
1099     void
1100 root 1.23 load_image_inline (SV *image_)
1101     ALIAS:
1102     load_image_file = 1
1103     PPCODE:
1104     {
1105     STRLEN image_len;
1106     char *image = (char *)SvPVbyte (image_, image_len);
1107     SDL_Surface *surface, *surface2;
1108     SDL_PixelFormat fmt;
1109     SDL_RWops *rw = ix
1110 root 1.212 ? SDL_RWFromFile (image, "rb")
1111 root 1.23 : SDL_RWFromConstMem (image, image_len);
1112    
1113     if (!rw)
1114 root 1.41 croak ("load_image: %s", SDL_GetError ());
1115 root 1.23
1116     surface = IMG_Load_RW (rw, 1);
1117     if (!surface)
1118 root 1.41 croak ("load_image: %s", SDL_GetError ());
1119 root 1.23
1120     fmt.palette = NULL;
1121     fmt.BitsPerPixel = 32;
1122     fmt.BytesPerPixel = 4;
1123 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1124 root 1.23 fmt.Rmask = 0x000000ff;
1125     fmt.Gmask = 0x0000ff00;
1126     fmt.Bmask = 0x00ff0000;
1127     fmt.Amask = 0xff000000;
1128 root 1.49 #else
1129     fmt.Rmask = 0xff000000;
1130     fmt.Gmask = 0x00ff0000;
1131     fmt.Bmask = 0x0000ff00;
1132     fmt.Amask = 0x000000ff;
1133     #endif
1134 root 1.23 fmt.Rloss = 0;
1135     fmt.Gloss = 0;
1136     fmt.Bloss = 0;
1137     fmt.Aloss = 0;
1138     fmt.Rshift = 0;
1139     fmt.Gshift = 8;
1140     fmt.Bshift = 16;
1141     fmt.Ashift = 24;
1142     fmt.colorkey = 0;
1143     fmt.alpha = 0;
1144    
1145     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
1146    
1147 root 1.39 assert (surface2->pitch == surface2->w * 4);
1148    
1149 root 1.129 SDL_LockSurface (surface2);
1150     EXTEND (SP, 6);
1151 root 1.23 PUSHs (sv_2mortal (newSViv (surface2->w)));
1152     PUSHs (sv_2mortal (newSViv (surface2->h)));
1153     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
1154 root 1.116 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
1155 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
1156 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
1157 root 1.129 SDL_UnlockSurface (surface2);
1158 root 1.23
1159     SDL_FreeSurface (surface);
1160     SDL_FreeSurface (surface2);
1161     }
1162    
1163 root 1.25 void
1164 root 1.39 average (int x, int y, uint32_t *data)
1165     PPCODE:
1166     {
1167     uint32_t r = 0, g = 0, b = 0, a = 0;
1168    
1169     x = y = x * y;
1170    
1171     while (x--)
1172     {
1173     uint32_t p = *data++;
1174    
1175     r += (p ) & 255;
1176     g += (p >> 8) & 255;
1177     b += (p >> 16) & 255;
1178     a += (p >> 24) & 255;
1179     }
1180    
1181     EXTEND (SP, 4);
1182 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
1183     PUSHs (sv_2mortal (newSViv (g / y)));
1184     PUSHs (sv_2mortal (newSViv (b / y)));
1185     PUSHs (sv_2mortal (newSViv (a / y)));
1186 root 1.39 }
1187    
1188     void
1189 root 1.66 error (char *message)
1190     CODE:
1191 root 1.86 fprintf (stderr, "ERROR: %s\n", message);
1192 root 1.66 #ifdef _WIN32
1193 root 1.240 MessageBox (0, message, "Deliantra Client Error", MB_OK | MB_ICONERROR);
1194 root 1.66 #endif
1195    
1196     void
1197 root 1.25 fatal (char *message)
1198     CODE:
1199 root 1.86 fprintf (stderr, "FATAL: %s\n", message);
1200 root 1.50 #ifdef _WIN32
1201 root 1.240 MessageBox (0, message, "Deliantra Client Fatal Error", MB_OK | MB_ICONERROR);
1202 root 1.25 #endif
1203 root 1.112 _exit (1);
1204 root 1.111
1205     void
1206 root 1.158 _exit (int retval = 0)
1207 root 1.111 CODE:
1208 root 1.161 #ifdef WIN32
1209     ExitThread (retval); // unclean, please beam me up
1210     #else
1211 root 1.112 _exit (retval);
1212 root 1.161 #endif
1213 root 1.25
1214 root 1.193 void
1215     debug ()
1216     CODE:
1217     {
1218     #if DEBUG
1219     VALGRIND_DO_LEAK_CHECK;
1220     #endif
1221     }
1222    
1223 root 1.280 int
1224     SvREFCNT (SV *sv)
1225     CODE:
1226     RETVAL = SvREFCNT (sv);
1227     OUTPUT:
1228     RETVAL
1229    
1230 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Font
1231 root 1.61
1232 root 1.205 PROTOTYPES: DISABLE
1233    
1234 root 1.242 DC::Font
1235 root 1.70 new_from_file (SV *class, char *path, int id = 0)
1236 root 1.61 CODE:
1237     {
1238     int count;
1239 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
1240 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
1241     FcPatternDestroy (pattern);
1242     }
1243     OUTPUT:
1244     RETVAL
1245    
1246     void
1247 root 1.242 DESTROY (DC::Font self)
1248 root 1.61 CODE:
1249     pango_font_description_free (self);
1250    
1251     void
1252 root 1.242 make_default (DC::Font self)
1253 root 1.205 PROTOTYPE: $
1254 root 1.61 CODE:
1255     default_font = self;
1256    
1257 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Layout
1258 root 1.14
1259 root 1.205 PROTOTYPES: DISABLE
1260    
1261 root 1.124 void
1262 root 1.239 glyph_cache_backup ()
1263 root 1.205 PROTOTYPE:
1264 root 1.124 CODE:
1265 root 1.239 tc_backup ();
1266    
1267     void
1268     glyph_cache_restore ()
1269     PROTOTYPE:
1270     CODE:
1271     tc_restore ();
1272 root 1.124
1273 root 1.242 DC::Layout
1274 root 1.128 new (SV *class)
1275 root 1.14 CODE:
1276     New (0, RETVAL, 1, struct cf_layout);
1277 root 1.76
1278 root 1.124 RETVAL->pl = pango_layout_new (opengl_context);
1279 root 1.76 RETVAL->r = 1.;
1280     RETVAL->g = 1.;
1281     RETVAL->b = 1.;
1282     RETVAL->a = 1.;
1283     RETVAL->base_height = MIN_FONT_HEIGHT;
1284     RETVAL->font = 0;
1285 root 1.225 RETVAL->rc = rc_alloc ();
1286 root 1.76
1287 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
1288 root 1.76 layout_update_font (RETVAL);
1289 root 1.14 OUTPUT:
1290     RETVAL
1291    
1292     void
1293 root 1.242 DESTROY (DC::Layout self)
1294 root 1.14 CODE:
1295     g_object_unref (self->pl);
1296 root 1.225 rc_free (self->rc);
1297 root 1.14 Safefree (self);
1298 root 1.13
1299 root 1.8 void
1300 root 1.242 set_text (DC::Layout self, SV *text_)
1301 root 1.35 CODE:
1302     {
1303     STRLEN textlen;
1304     char *text = SvPVutf8 (text_, textlen);
1305    
1306     pango_layout_set_text (self->pl, text, textlen);
1307     }
1308    
1309     void
1310 root 1.242 set_markup (DC::Layout self, SV *text_)
1311 root 1.14 CODE:
1312 root 1.5 {
1313     STRLEN textlen;
1314     char *text = SvPVutf8 (text_, textlen);
1315 root 1.14
1316     pango_layout_set_markup (self->pl, text, textlen);
1317     }
1318    
1319 root 1.121 void
1320 root 1.242 set_shapes (DC::Layout self, ...)
1321 root 1.121 CODE:
1322     {
1323     PangoAttrList *attrs = 0;
1324     const char *text = pango_layout_get_text (self->pl);
1325     const char *pos = text;
1326 root 1.122 int arg = 4;
1327 root 1.121
1328     while (arg < items && (pos = strstr (pos, OBJ_STR)))
1329     {
1330 root 1.122 PangoRectangle inkrect, rect;
1331 root 1.121 PangoAttribute *attr;
1332    
1333 root 1.122 int x = SvIV (ST (arg - 3));
1334     int y = SvIV (ST (arg - 2));
1335 root 1.121 int w = SvIV (ST (arg - 1));
1336 root 1.122 int h = SvIV (ST (arg ));
1337 root 1.121
1338 root 1.122 inkrect.x = 0;
1339     inkrect.y = 0;
1340     inkrect.width = 0;
1341     inkrect.height = 0;
1342    
1343     rect.x = x * PANGO_SCALE;
1344     rect.y = y * PANGO_SCALE;
1345     rect.width = w * PANGO_SCALE;
1346 root 1.121 rect.height = h * PANGO_SCALE;
1347    
1348     if (!attrs)
1349     attrs = pango_layout_get_attributes (self->pl);
1350    
1351 root 1.122 attr = pango_attr_shape_new (&inkrect, &rect);
1352 root 1.121 attr->start_index = pos - text;
1353     attr->end_index = attr->start_index + sizeof (OBJ_STR) - 1;
1354     pango_attr_list_insert (attrs, attr);
1355    
1356 root 1.122 arg += 4;
1357 root 1.121 pos += sizeof (OBJ_STR) - 1;
1358     }
1359    
1360     if (attrs)
1361     pango_layout_set_attributes (self->pl, attrs);
1362     }
1363    
1364     void
1365 root 1.242 get_shapes (DC::Layout self)
1366 root 1.121 PPCODE:
1367     {
1368     PangoLayoutIter *iter = pango_layout_get_iter (self->pl);
1369    
1370     do
1371     {
1372 root 1.249 PangoLayoutRun *run = pango_layout_iter_get_run_readonly (iter);
1373 root 1.121
1374     if (run && shape_attr_p (run))
1375     {
1376     PangoRectangle extents;
1377     pango_layout_iter_get_run_extents (iter, 0, &extents);
1378    
1379 root 1.129 EXTEND (SP, 2);
1380 root 1.121 PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.x))));
1381     PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.y))));
1382     }
1383     }
1384     while (pango_layout_iter_next_run (iter));
1385    
1386     pango_layout_iter_free (iter);
1387     }
1388    
1389     int
1390 root 1.242 has_wrapped (DC::Layout self)
1391 root 1.121 CODE:
1392     {
1393     int lines = 1;
1394     const char *text = pango_layout_get_text (self->pl);
1395    
1396     while (*text)
1397     lines += *text++ == '\n';
1398    
1399     RETVAL = lines < pango_layout_get_line_count (self->pl);
1400     }
1401     OUTPUT:
1402     RETVAL
1403    
1404 root 1.46 SV *
1405 root 1.242 get_text (DC::Layout self)
1406 root 1.46 CODE:
1407 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
1408 root 1.107 sv_utf8_decode (RETVAL);
1409 root 1.46 OUTPUT:
1410     RETVAL
1411    
1412 root 1.14 void
1413 root 1.242 set_foreground (DC::Layout self, float r, float g, float b, float a = 1.)
1414 root 1.76 CODE:
1415     self->r = r;
1416     self->g = g;
1417     self->b = b;
1418     self->a = a;
1419    
1420     void
1421 root 1.242 set_font (DC::Layout self, DC::Font font = 0)
1422 root 1.61 CODE:
1423     if (self->font != font)
1424     {
1425     self->font = font;
1426     layout_update_font (self);
1427     }
1428    
1429     void
1430 root 1.242 set_height (DC::Layout self, int base_height)
1431 root 1.16 CODE:
1432 root 1.61 if (self->base_height != base_height)
1433     {
1434     self->base_height = base_height;
1435     layout_update_font (self);
1436     }
1437 root 1.16
1438     void
1439 root 1.242 set_width (DC::Layout self, int max_width = -1)
1440 root 1.14 CODE:
1441     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
1442    
1443     void
1444 root 1.242 set_indent (DC::Layout self, int indent)
1445 root 1.84 CODE:
1446     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
1447    
1448     void
1449 root 1.242 set_spacing (DC::Layout self, int spacing)
1450 root 1.84 CODE:
1451     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
1452    
1453     void
1454 root 1.242 set_ellipsise (DC::Layout self, int ellipsise)
1455 root 1.84 CODE:
1456     pango_layout_set_ellipsize (self->pl,
1457     ellipsise == 1 ? PANGO_ELLIPSIZE_START
1458     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
1459     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
1460     : PANGO_ELLIPSIZE_NONE
1461     );
1462    
1463     void
1464 root 1.242 set_single_paragraph_mode (DC::Layout self, int spm)
1465 root 1.84 CODE:
1466     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
1467    
1468     void
1469 root 1.242 size (DC::Layout self)
1470 root 1.14 PPCODE:
1471     {
1472     int w, h;
1473    
1474     layout_get_pixel_size (self, &w, &h);
1475    
1476     EXTEND (SP, 2);
1477     PUSHs (sv_2mortal (newSViv (w)));
1478     PUSHs (sv_2mortal (newSViv (h)));
1479     }
1480    
1481 root 1.17 int
1482 root 1.242 descent (DC::Layout self)
1483 root 1.122 CODE:
1484     {
1485     PangoRectangle rect;
1486 root 1.249 PangoLayoutLine *line = pango_layout_get_line_readonly (self->pl, 0);
1487 root 1.122 pango_layout_line_get_pixel_extents (line, 0, &rect);
1488     RETVAL = PANGO_DESCENT (rect);
1489     }
1490     OUTPUT:
1491     RETVAL
1492    
1493     int
1494 root 1.242 xy_to_index (DC::Layout self, int x, int y)
1495 root 1.17 CODE:
1496     {
1497     int index, trailing;
1498     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
1499 root 1.165 RETVAL = index + trailing;
1500 root 1.17 }
1501     OUTPUT:
1502     RETVAL
1503    
1504     void
1505 root 1.242 cursor_pos (DC::Layout self, int index)
1506 root 1.17 PPCODE:
1507     {
1508 root 1.251 PangoRectangle pos;
1509 root 1.252 pango_layout_get_cursor_pos (self->pl, index, &pos, 0);
1510 root 1.30
1511 root 1.17 EXTEND (SP, 3);
1512 root 1.251 PUSHs (sv_2mortal (newSViv (pos.x / PANGO_SCALE)));
1513     PUSHs (sv_2mortal (newSViv (pos.y / PANGO_SCALE)));
1514     PUSHs (sv_2mortal (newSViv (pos.height / PANGO_SCALE)));
1515 root 1.17 }
1516    
1517 root 1.14 void
1518 root 1.242 index_to_line_x (DC::Layout self, int index, int trailing = 0)
1519 root 1.165 PPCODE:
1520     {
1521     int line, x;
1522    
1523     pango_layout_index_to_line_x (self->pl, index, trailing, &line, &x);
1524 root 1.254 #if !PANGO_VERSION_CHECK (1, 17, 3)
1525 root 1.165 /* pango bug: line is between 1..numlines, not 0..numlines-1 */
1526 root 1.245 --line;
1527     #endif
1528 root 1.165 EXTEND (SP, 2);
1529 root 1.245 PUSHs (sv_2mortal (newSViv (line)));
1530 root 1.165 PUSHs (sv_2mortal (newSViv (x / PANGO_SCALE)));
1531     }
1532    
1533     void
1534 root 1.242 line_x_to_index (DC::Layout self, int line, int x)
1535 root 1.165 PPCODE:
1536     {
1537     PangoLayoutLine *lp;
1538     int index, trailing;
1539    
1540     if (line < 0)
1541     XSRETURN_EMPTY;
1542    
1543 root 1.249 if (!(lp = pango_layout_get_line_readonly (self->pl, line)))
1544 root 1.165 XSRETURN_EMPTY; /* do better */
1545    
1546 root 1.166 pango_layout_line_x_to_index (lp, x * PANGO_SCALE, &index, &trailing);
1547 root 1.165
1548     EXTEND (SP, 2);
1549     if (GIMME_V == G_SCALAR)
1550     PUSHs (sv_2mortal (newSViv (index + trailing)));
1551     else
1552     {
1553     PUSHs (sv_2mortal (newSViv (index)));
1554     PUSHs (sv_2mortal (newSViv (trailing)));
1555     }
1556     }
1557    
1558     void
1559 root 1.242 render (DC::Layout self, float x, float y, int flags = 0)
1560 root 1.225 CODE:
1561     rc_clear (self->rc);
1562 root 1.124 pango_opengl_render_layout_subpixel (
1563     self->pl,
1564 root 1.225 self->rc,
1565 root 1.124 x * PANGO_SCALE, y * PANGO_SCALE,
1566 root 1.135 self->r, self->g, self->b, self->a,
1567     flags
1568 root 1.124 );
1569 root 1.225 // we assume that context_change actually clears/frees stuff
1570     // and does not do any recomputation...
1571     pango_layout_context_changed (self->pl);
1572    
1573     void
1574 root 1.242 draw (DC::Layout self)
1575 root 1.225 CODE:
1576     {
1577     glEnable (GL_TEXTURE_2D);
1578     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1579     glEnable (GL_BLEND);
1580     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1581     GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1582     glEnable (GL_ALPHA_TEST);
1583     glAlphaFunc (GL_GREATER, 7.f / 255.f);
1584    
1585     rc_draw (self->rc);
1586    
1587     glDisable (GL_ALPHA_TEST);
1588     glDisable (GL_BLEND);
1589     glDisable (GL_TEXTURE_2D);
1590     }
1591 root 1.11
1592 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Texture
1593 root 1.11
1594 root 1.205 PROTOTYPES: ENABLE
1595    
1596 root 1.11 void
1597 root 1.203 pad (SV *data_, int ow, int oh, int nw, int nh)
1598 root 1.113 CODE:
1599     {
1600 root 1.203 if ((nw != ow || nh != oh) && SvOK (data_))
1601 root 1.113 {
1602 root 1.203 STRLEN datalen;
1603     char *data = SvPVbyte (data_, datalen);
1604     int bpp = datalen / (ow * oh);
1605     SV *result_ = sv_2mortal (newSV (nw * nh * bpp));
1606    
1607     SvPOK_only (result_);
1608     SvCUR_set (result_, nw * nh * bpp);
1609    
1610     memset (SvPVX (result_), 0, nw * nh * bpp);
1611     while (oh--)
1612     memcpy (SvPVX (result_) + oh * nw * bpp, data + oh * ow * bpp, ow * bpp);
1613 root 1.113
1614 root 1.203 sv_setsv (data_, result_);
1615 root 1.113 }
1616     }
1617    
1618     void
1619 root 1.114 draw_quad (SV *self, float x, float y, float w = 0., float h = 0.)
1620 root 1.12 PROTOTYPE: $$$;$$
1621 root 1.76 ALIAS:
1622     draw_quad_alpha = 1
1623     draw_quad_alpha_premultiplied = 2
1624 root 1.11 CODE:
1625     {
1626 root 1.12 HV *hv = (HV *)SvRV (self);
1627 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
1628     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
1629 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
1630    
1631 root 1.219 if (name <= 0)
1632     XSRETURN_EMPTY;
1633    
1634 root 1.12 if (items < 5)
1635     {
1636 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1637     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1638 root 1.12 }
1639    
1640 root 1.76 if (ix)
1641     {
1642     glEnable (GL_BLEND);
1643 root 1.103
1644     if (ix == 2)
1645     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1646     else
1647     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1648 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1649 root 1.103
1650 root 1.86 glEnable (GL_ALPHA_TEST);
1651     glAlphaFunc (GL_GREATER, 0.01f);
1652 root 1.76 }
1653    
1654 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1655 root 1.76
1656 root 1.12 glBegin (GL_QUADS);
1657 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1658     glTexCoord2f (0, t); glVertex2f (x , y + h);
1659     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1660     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1661 root 1.12 glEnd ();
1662 root 1.76
1663     if (ix)
1664 root 1.86 {
1665     glDisable (GL_ALPHA_TEST);
1666     glDisable (GL_BLEND);
1667     }
1668 root 1.11 }
1669 root 1.28
1670 root 1.293 void
1671 root 1.296 draw_fow_texture (float intensity, int hidden_tex, int name1, uint8_t *data1, float s, float t, int w, int h, float blend = 0.f, int dx = 0, int dy = 0, int name2 = 0, uint8_t *data2 = data1)
1672 root 1.293 PROTOTYPE: @
1673     CODE:
1674     {
1675     glEnable (GL_TEXTURE_2D);
1676     glEnable (GL_BLEND);
1677     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1678 root 1.294 glBindTexture (GL_TEXTURE_2D, name1);
1679 root 1.293
1680 root 1.294 glColor3f (intensity, intensity, intensity);
1681 root 1.293 glPushMatrix ();
1682     glScalef (1./3, 1./3, 1.);
1683    
1684 root 1.294 if (blend > 0.f)
1685     {
1686 root 1.296 float dx3 = dx * -3.f / w;
1687     float dy3 = dy * -3.f / h;
1688 root 1.294 GLfloat env_color[4] = { 0., 0., 0., blend };
1689    
1690     /* interpolate the two shadow textures */
1691     /* stage 0 == rgb(glcolor) + alpha(t0) */
1692     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1693    
1694     /* stage 1 == rgb(glcolor) + alpha(interpolate t0, t1, texenv) */
1695     gl.ActiveTexture (GL_TEXTURE1);
1696     glEnable (GL_TEXTURE_2D);
1697     glBindTexture (GL_TEXTURE_2D, name2);
1698     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1699    
1700     /* rgb == rgb(glcolor) */
1701     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
1702     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT);
1703     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1704    
1705     /* alpha = interpolate t0, t1 by env_alpha */
1706     glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env_color);
1707    
1708     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);
1709     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
1710     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1711    
1712     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
1713     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
1714    
1715     glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_CONSTANT);
1716     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
1717    
1718     glBegin (GL_QUADS);
1719 root 1.296 gl.MultiTexCoord2f (GL_TEXTURE0, 0, 0); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 , dy3 ); glVertex2i (0, 0);
1720     gl.MultiTexCoord2f (GL_TEXTURE0, 0, t); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 , dy3 + t); glVertex2i (0, h);
1721     gl.MultiTexCoord2f (GL_TEXTURE0, s, t); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 + s, dy3 + t); glVertex2i (w, h);
1722     gl.MultiTexCoord2f (GL_TEXTURE0, s, 0); gl.MultiTexCoord2f (GL_TEXTURE1, dx3 + s, dy3 ); glVertex2i (w, 0);
1723 root 1.294 glEnd ();
1724    
1725     glDisable (GL_TEXTURE_2D);
1726     gl.ActiveTexture (GL_TEXTURE0);
1727     }
1728     else
1729     {
1730     /* simple blending of one texture, also opengl <1.3 path */
1731     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1732 root 1.293
1733 root 1.294 glBegin (GL_QUADS);
1734 root 1.296 glTexCoord2f (0, 0); glVertex2f (0, 0);
1735     glTexCoord2f (0, t); glVertex2f (0, h);
1736     glTexCoord2f (s, t); glVertex2f (w, h);
1737     glTexCoord2f (s, 0); glVertex2f (w, 0);
1738 root 1.294 glEnd ();
1739     }
1740 root 1.293
1741 root 1.296 /* draw ?-marks or equivalent, this is very clumsy code :/ */
1742     {
1743     int x, y;
1744     int dx3 = dx * 3;
1745     int dy3 = dy * 3;
1746    
1747     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1748     glBindTexture (GL_TEXTURE_2D, hidden_tex);
1749     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1750     glTranslatef (-1., -1., 0);
1751     glBegin (GL_QUADS);
1752    
1753     for (y = 1; y < h; y += 3)
1754     {
1755     int y1 = y - dy3;
1756     int y1valid = y1 >= 0 && y1 < h;
1757    
1758     for (x = 1; x < w; x += 3)
1759     {
1760     int x1 = x - dx3;
1761     uint8_t h1 = data1 [x + y * w] == DARKNESS_ADJUST (255 - FOW_DARKNESS);
1762     uint8_t h2;
1763    
1764     if (y1valid && x1 >= 0 && x1 < w)
1765     h2 = data2 [x1 + y1 * w] == DARKNESS_ADJUST (255 - FOW_DARKNESS);
1766     else
1767     h2 = 1; /* out of range == invisible */
1768    
1769     if (h1 || h2)
1770     {
1771     float alpha = h1 == h2 ? 1.f : h1 ? 1.f - blend : blend;
1772     glColor4f (1., 1., 1., alpha);
1773    
1774     glTexCoord2f (0, 0.); glVertex2i (x , y );
1775     glTexCoord2f (0, 1.); glVertex2i (x , y + 3);
1776     glTexCoord2f (1, 1.); glVertex2i (x + 3, y + 3);
1777     glTexCoord2f (1, 0.); glVertex2i (x + 3, y );
1778     }
1779     }
1780     }
1781     }
1782    
1783     glEnd ();
1784    
1785 root 1.293 glPopMatrix ();
1786    
1787     glDisable (GL_TEXTURE_2D);
1788     glDisable (GL_BLEND);
1789     }
1790    
1791 root 1.199 IV texture_valid_2d (GLint internalformat, GLsizei w, GLsizei h, GLenum format, GLenum type)
1792     CODE:
1793     {
1794     GLint width;
1795     glTexImage2D (GL_PROXY_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, 0);
1796     glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
1797     RETVAL = width > 0;
1798     }
1799     OUTPUT:
1800     RETVAL
1801    
1802 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Map
1803 root 1.28
1804 root 1.205 PROTOTYPES: DISABLE
1805    
1806 root 1.242 DC::Map
1807 root 1.164 new (SV *class)
1808 root 1.28 CODE:
1809     New (0, RETVAL, 1, struct map);
1810 root 1.42 RETVAL->x = 0;
1811     RETVAL->y = 0;
1812 root 1.164 RETVAL->w = 0;
1813     RETVAL->h = 0;
1814 root 1.42 RETVAL->ox = 0;
1815     RETVAL->oy = 0;
1816 root 1.174 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1817     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1818 root 1.28 RETVAL->rows = 0;
1819     RETVAL->row = 0;
1820     OUTPUT:
1821     RETVAL
1822    
1823     void
1824 root 1.242 DESTROY (DC::Map self)
1825 root 1.28 CODE:
1826     {
1827 root 1.30 map_clear (self);
1828 root 1.174 Safefree (self->face2tile);
1829 root 1.111 Safefree (self->tex);
1830 root 1.29 Safefree (self);
1831     }
1832    
1833     void
1834 root 1.242 resize (DC::Map self, int map_width, int map_height)
1835 root 1.164 CODE:
1836     self->w = map_width;
1837     self->h = map_height;
1838    
1839     void
1840 root 1.242 clear (DC::Map self)
1841 root 1.30 CODE:
1842     map_clear (self);
1843    
1844     void
1845 root 1.242 set_tileid (DC::Map self, int face, int tile)
1846 root 1.29 CODE:
1847     {
1848 root 1.174 need_facenum (self, face); self->face2tile [face] = tile;
1849     need_texid (self, tile);
1850 root 1.42 }
1851    
1852     void
1853 root 1.242 set_smooth (DC::Map self, int face, int smooth, int level)
1854 root 1.176 CODE:
1855     {
1856     tileid texid;
1857     maptex *tex;
1858    
1859     if (face < 0 || face >= self->faces)
1860     return;
1861    
1862     if (smooth < 0 || smooth >= self->faces)
1863     return;
1864    
1865     texid = self->face2tile [face];
1866    
1867     if (!texid)
1868     return;
1869    
1870     tex = self->tex + texid;
1871     tex->smoothtile = self->face2tile [smooth];
1872     tex->smoothlevel = level;
1873     }
1874    
1875     void
1876 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)
1877 root 1.42 CODE:
1878     {
1879 root 1.174 need_texid (self, texid);
1880 root 1.42
1881 root 1.48 {
1882     maptex *tex = self->tex + texid;
1883 root 1.39
1884 root 1.48 tex->name = name;
1885     tex->w = w;
1886     tex->h = h;
1887     tex->s = s;
1888     tex->t = t;
1889     tex->r = r;
1890     tex->g = g;
1891     tex->b = b;
1892     tex->a = a;
1893     }
1894 root 1.95
1895     // somewhat hackish, but for textures that require it, it really
1896     // improves the look, and most others don't suffer.
1897     glBindTexture (GL_TEXTURE_2D, name);
1898 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1899     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1900     // use uglier nearest interpolation because linear suffers
1901     // from transparent color bleeding and ugly wrapping effects.
1902     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1903 root 1.29 }
1904    
1905 root 1.280 void
1906     expire_textures (DC::Map self, int texid, int count)
1907     PPCODE:
1908     for (; texid < self->texs && count; ++texid, --count)
1909     {
1910     maptex *tex = self->tex + texid;
1911    
1912     if (tex->name)
1913     {
1914     if (tex->unused)
1915     {
1916     tex->name = 0;
1917 root 1.282 tex->unused = 0;
1918 root 1.280 XPUSHs (sv_2mortal (newSViv (texid)));
1919     }
1920     else
1921     tex->unused = 1;
1922     }
1923     }
1924    
1925 root 1.42 int
1926 root 1.242 ox (DC::Map self)
1927 root 1.42 ALIAS:
1928     oy = 1
1929 root 1.101 x = 2
1930     y = 3
1931 root 1.102 w = 4
1932     h = 5
1933 root 1.42 CODE:
1934     switch (ix)
1935     {
1936     case 0: RETVAL = self->ox; break;
1937     case 1: RETVAL = self->oy; break;
1938 root 1.101 case 2: RETVAL = self->x; break;
1939     case 3: RETVAL = self->y; break;
1940 root 1.102 case 4: RETVAL = self->w; break;
1941     case 5: RETVAL = self->h; break;
1942 root 1.42 }
1943     OUTPUT:
1944     RETVAL
1945    
1946 root 1.29 void
1947 root 1.242 scroll (DC::Map self, int dx, int dy)
1948 root 1.43 CODE:
1949     {
1950 root 1.44 if (dx > 0)
1951 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
1952 root 1.44 else if (dx < 0)
1953 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
1954 root 1.44
1955     if (dy > 0)
1956 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
1957 root 1.44 else if (dy < 0)
1958 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
1959 root 1.43
1960 root 1.44 self->ox += dx; self->x += dx;
1961     self->oy += dy; self->y += dy;
1962 root 1.43
1963     while (self->y < 0)
1964     {
1965     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1966    
1967     self->rows += MAP_EXTEND_Y;
1968     self->y += MAP_EXTEND_Y;
1969     }
1970 root 1.44 }
1971 root 1.43
1972 root 1.221 SV *
1973 root 1.242 map1a_update (DC::Map self, SV *data_, int extmap)
1974 root 1.44 CODE:
1975     {
1976 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1977     uint8_t *data_end = (uint8_t *)SvEND (data_);
1978 root 1.48 mapcell *cell;
1979 root 1.221 int x, y, z, flags;
1980     AV *missing = newAV ();
1981     RETVAL = newRV_noinc ((SV *)missing);
1982 root 1.43
1983 root 1.150 while (data < data_end - 1)
1984 root 1.29 {
1985 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1986 root 1.30
1987 root 1.120 x = self->x + ((flags >> 10) & 63);
1988     y = self->y + ((flags >> 4) & 63);
1989 root 1.29
1990 root 1.48 cell = map_get_cell (self, x, y);
1991 root 1.29
1992     if (flags & 15)
1993     {
1994 root 1.142 if (!cell->darkness)
1995 root 1.29 {
1996 root 1.154 memset (cell, 0, sizeof (*cell));
1997 root 1.142 cell->darkness = 256;
1998 root 1.29 }
1999 root 1.45
2000 root 1.142 //TODO: don't trust server data to be in-range(!)
2001    
2002 root 1.141 if (flags & 8)
2003     {
2004     if (extmap)
2005     {
2006     uint8_t ext, cmd;
2007    
2008     do
2009     {
2010     ext = *data++;
2011 root 1.261 cmd = ext & 0x7f;
2012 root 1.141
2013 root 1.147 if (cmd < 4)
2014 root 1.296 cell->darkness = 255 - ext * 64 + 1; /* make sure this doesn't collide with FOW_DARKNESS */
2015 root 1.147 else if (cmd == 5) // health
2016     {
2017     cell->stat_width = 1;
2018     cell->stat_hp = *data++;
2019     }
2020     else if (cmd == 6) // monster width
2021     cell->stat_width = *data++ + 1;
2022 root 1.169 else if (cmd == 0x47)
2023 root 1.153 {
2024 root 1.261 if (*data == 1) cell->player = data [1];
2025     else if (*data == 2) cell->player = data [2] + (data [1] << 8);
2026     else if (*data == 3) cell->player = data [3] + (data [2] << 8) + (data [1] << 16);
2027     else if (*data == 4) cell->player = data [4] + (data [3] << 8) + (data [2] << 16) + (data [1] << 24);
2028 root 1.153
2029     data += *data + 1;
2030     }
2031     else if (cmd == 8) // cell flags
2032     cell->flags = *data++;
2033 root 1.144 else if (ext & 0x40) // unknown, multibyte => skip
2034     data += *data + 1;
2035 root 1.147 else
2036     data++;
2037 root 1.141 }
2038 root 1.147 while (ext & 0x80);
2039 root 1.141 }
2040     else
2041 root 1.142 cell->darkness = *data++ + 1;
2042 root 1.141 }
2043 root 1.29
2044 root 1.221 for (z = 0; z <= 2; ++z)
2045     if (flags & (4 >> z))
2046     {
2047     faceid face = (data [0] << 8) + data [1]; data += 2;
2048     need_facenum (self, face);
2049     cell->tile [z] = self->face2tile [face];
2050 root 1.29
2051 root 1.221 if (cell->tile [z])
2052     {
2053     maptex *tex = self->tex + cell->tile [z];
2054 root 1.280 tex->unused = 0;
2055 root 1.221 if (!tex->name)
2056     av_push (missing, newSViv (cell->tile [z]));
2057 root 1.29
2058 root 1.221 if (tex->smoothtile)
2059     {
2060     maptex *smooth = self->tex + tex->smoothtile;
2061 root 1.280 smooth->unused = 0;
2062 root 1.221 if (!smooth->name)
2063     av_push (missing, newSViv (tex->smoothtile));
2064     }
2065     }
2066     }
2067 root 1.29 }
2068     else
2069 root 1.267 CELL_CLEAR (cell);
2070 root 1.29 }
2071 root 1.28 }
2072 root 1.221 OUTPUT:
2073     RETVAL
2074 root 1.28
2075 root 1.40 SV *
2076 root 1.242 mapmap (DC::Map self, int x0, int y0, int w, int h)
2077 root 1.40 CODE:
2078     {
2079 root 1.55 int x1, x;
2080     int y1, y;
2081 root 1.40 int z;
2082     SV *map_sv = newSV (w * h * sizeof (uint32_t));
2083     uint32_t *map = (uint32_t *)SvPVX (map_sv);
2084    
2085     SvPOK_only (map_sv);
2086     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
2087    
2088 root 1.55 x0 += self->x; x1 = x0 + w;
2089     y0 += self->y; y1 = y0 + h;
2090 root 1.40
2091     for (y = y0; y < y1; y++)
2092     {
2093     maprow *row = 0 <= y && y < self->rows
2094     ? self->row + y
2095     : 0;
2096    
2097     for (x = x0; x < x1; x++)
2098     {
2099     int r = 32, g = 32, b = 32, a = 192;
2100    
2101     if (row && row->c0 <= x && x < row->c1)
2102     {
2103     mapcell *cell = row->col + (x - row->c0);
2104    
2105     for (z = 0; z <= 0; z++)
2106     {
2107 root 1.174 maptex tex = self->tex [cell->tile [z]];
2108     int a0 = 255 - tex.a;
2109     int a1 = tex.a;
2110    
2111     r = (r * a0 + tex.r * a1) / 255;
2112     g = (g * a0 + tex.g * a1) / 255;
2113     b = (b * a0 + tex.b * a1) / 255;
2114     a = (a * a0 + tex.a * a1) / 255;
2115 root 1.40 }
2116     }
2117    
2118     *map++ = (r )
2119     | (g << 8)
2120     | (b << 16)
2121     | (a << 24);
2122     }
2123     }
2124    
2125     RETVAL = map_sv;
2126     }
2127     OUTPUT:
2128     RETVAL
2129    
2130 root 1.221 void
2131 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)
2132 root 1.116 CODE:
2133 root 1.30 {
2134 root 1.223 int x, y, z;
2135    
2136 root 1.176 HV *smooth = (HV *)sv_2mortal ((SV *)newHV ());
2137     uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level
2138 root 1.226 static uint8_t smooth_max[256][256]; // egad, fast and wasteful on memory (64k)
2139 root 1.176 smooth_key skey;
2140 root 1.261 int pl_x, pl_y;
2141     maptex pl_tex;
2142 root 1.285 rc_t *rc = rc_alloc ();
2143     rc_t *rc_ov = rc_alloc ();
2144 root 1.223 rc_key_t key;
2145 root 1.297 rc_array_t *arr;
2146 root 1.48
2147 root 1.262 pl_tex.name = 0;
2148    
2149 pippijn 1.288 // that's current max. sorry.
2150 root 1.176 if (sw > 255) sw = 255;
2151     if (sh > 255) sh = 255;
2152    
2153     // clear key, in case of extra padding
2154     memset (&skey, 0, sizeof (skey));
2155    
2156 root 1.223 memset (&key, 0, sizeof (key));
2157     key.r = 255;
2158     key.g = 255;
2159     key.b = 255;
2160     key.a = 255;
2161     key.mode = GL_QUADS;
2162     key.format = GL_T2F_V3F;
2163 root 1.30
2164 root 1.164 mx += self->x;
2165     my += self->y;
2166    
2167 root 1.176 // first pass: determine smooth_max
2168     // rather ugly, if you ask me
2169     // could also be stored inside mapcell and updated on change
2170     memset (smooth_max, 0, sizeof (smooth_max));
2171    
2172     for (y = 0; y < sh; y++)
2173     if (0 <= y + my && y + my < self->rows)
2174     {
2175     maprow *row = self->row + (y + my);
2176    
2177     for (x = 0; x < sw; x++)
2178     if (row->c0 <= x + mx && x + mx < row->c1)
2179     {
2180     mapcell *cell = row->col + (x + mx - row->c0);
2181    
2182 root 1.177 smooth_max[x + 1][y + 1] =
2183     MAX (self->tex [cell->tile [0]].smoothlevel,
2184     MAX (self->tex [cell->tile [1]].smoothlevel,
2185     self->tex [cell->tile [2]].smoothlevel));
2186 root 1.176 }
2187     }
2188    
2189 root 1.223 glEnable (GL_BLEND);
2190     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2191     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2192    
2193 root 1.176 for (z = 0; z <= 2; z++)
2194     {
2195 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
2196 root 1.283 key.texname = -1;
2197 root 1.186
2198 root 1.176 for (y = 0; y < sh; y++)
2199     if (0 <= y + my && y + my < self->rows)
2200     {
2201     maprow *row = self->row + (y + my);
2202    
2203     for (x = 0; x < sw; x++)
2204     if (row->c0 <= x + mx && x + mx < row->c1)
2205     {
2206     mapcell *cell = row->col + (x + mx - row->c0);
2207     tileid tile = cell->tile [z];
2208    
2209     if (tile)
2210     {
2211     maptex tex = self->tex [tile];
2212 root 1.285 int px, py;
2213 root 1.176
2214 root 1.223 if (key.texname != tex.name)
2215 root 1.176 {
2216 root 1.280 self->tex [tile].unused = 0;
2217    
2218 root 1.176 if (!tex.name)
2219 root 1.285 tex = self->tex [TEXID_NOFACE]; /* missing, replace by noface */
2220 root 1.176
2221 root 1.223 key.texname = tex.name;
2222     arr = rc_array (rc, &key);
2223 root 1.176 }
2224    
2225 root 1.285 px = (x + 1) * T - tex.w;
2226     py = (y + 1) * T - tex.h;
2227    
2228 root 1.261 if (expect_false (cell->player == player) && expect_false (z == 2))
2229     {
2230     pl_x = px;
2231     pl_y = py;
2232     pl_tex = tex;
2233     continue;
2234     }
2235 root 1.219
2236 root 1.223 rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2237     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
2238     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
2239     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
2240 root 1.176
2241     // update smooth hash
2242     if (tex.smoothtile)
2243     {
2244     skey.tile = tex.smoothtile;
2245     skey.level = tex.smoothlevel;
2246    
2247     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
2248 root 1.30
2249 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
2250     // shifted +1|+1 so we always stay positive.
2251 root 1.30
2252 root 1.180 // bits is ___n cccc CCCC bbbb
2253     // n do not draw borders&corners
2254     // c draw these corners, but...
2255     // C ... not these
2256     // b draw these borders
2257    
2258     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
2259     // ┃· ·· ·┃ ━━
2260    
2261     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
2262     // ·· ·· ·┏ ┓·
2263    
2264 root 1.176 // full tile
2265     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
2266    
2267     // borders
2268 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
2269     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
2270 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
2271     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
2272    
2273     // corners
2274     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
2275     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
2276     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
2277     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
2278     }
2279     }
2280 root 1.285
2281 root 1.296 if (expect_false (z == 2) && expect_false (cell->flags))
2282 root 1.285 {
2283 root 1.296 // overlays such as the speech bubble, probably more to come
2284     if (cell->flags & 1)
2285 root 1.285 {
2286 root 1.296 rc_key_t key_ov = key;
2287     maptex tex = self->tex [TEXID_SPEECH];
2288     rc_array_t *arr;
2289     int px = x * T + T * 2 / 32;
2290     int py = y * T - T * 6 / 32;
2291    
2292     key_ov.texname = tex.name;
2293     arr = rc_array (rc_ov, &key_ov);
2294    
2295     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2296     rc_t2f_v3f (arr, 0 , tex.t, px , py + T, 0);
2297     rc_t2f_v3f (arr, tex.s, tex.t, px + T, py + T, 0);
2298     rc_t2f_v3f (arr, tex.s, 0 , px + T, py , 0);
2299 root 1.285 }
2300     }
2301 root 1.176 }
2302     }
2303 root 1.174
2304 root 1.224 rc_draw (rc);
2305     rc_clear (rc);
2306    
2307 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
2308     // this is basically counting sort
2309 root 1.176 {
2310 root 1.186 int w, b;
2311 root 1.30
2312 root 1.226 glEnable (GL_TEXTURE_2D);
2313     glBegin (GL_QUADS);
2314 root 1.186 for (w = 0; w < 256 / 32; ++w)
2315     {
2316     uint32_t smask = smooth_level [w];
2317     if (smask)
2318     for (b = 0; b < 32; ++b)
2319     if (smask & (((uint32_t)1) << b))
2320 root 1.176 {
2321 root 1.186 int level = (w << 5) | b;
2322     HE *he;
2323 root 1.153
2324 root 1.186 hv_iterinit (smooth);
2325     while ((he = hv_iternext (smooth)))
2326 root 1.153 {
2327 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
2328     IV bits = SvIVX (HeVAL (he));
2329 root 1.176
2330 root 1.186 if (!(bits & 0x1000)
2331     && skey->level == level
2332 root 1.191 && level > smooth_max [skey->x][skey->y])
2333 root 1.174 {
2334 root 1.186 maptex tex = self->tex [skey->tile];
2335     int px = (((int)skey->x) - 1) * T;
2336     int py = (((int)skey->y) - 1) * T;
2337     int border = bits & 15;
2338     int corner = (bits >> 8) & ~(bits >> 4) & 15;
2339     float dx = tex.s * .0625f; // 16 images/row
2340     float dy = tex.t * .5f ; // 2 images/column
2341    
2342 root 1.223 if (tex.name)
2343 root 1.186 {
2344 root 1.223 // this time avoiding texture state changes
2345     // save gobs of state changes.
2346     if (key.texname != tex.name)
2347     {
2348 root 1.280 self->tex [skey->tile].unused = 0;
2349    
2350 root 1.226 glEnd ();
2351     glBindTexture (GL_TEXTURE_2D, key.texname = tex.name);
2352     glBegin (GL_QUADS);
2353 root 1.223 }
2354    
2355     if (border)
2356     {
2357     float ox = border * dx;
2358    
2359 root 1.226 glTexCoord2f (ox , 0.f ); glVertex2i (px , py );
2360     glTexCoord2f (ox , dy ); glVertex2i (px , py + T);
2361     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py + T);
2362     glTexCoord2f (ox + dx, 0.f ); glVertex2i (px + T, py );
2363 root 1.223 }
2364    
2365     if (corner)
2366     {
2367     float ox = corner * dx;
2368    
2369 root 1.226 glTexCoord2f (ox , dy ); glVertex2i (px , py );
2370     glTexCoord2f (ox , dy * 2.f); glVertex2i (px , py + T);
2371     glTexCoord2f (ox + dx, dy * 2.f); glVertex2i (px + T, py + T);
2372     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py );
2373 root 1.223 }
2374 root 1.186 }
2375 root 1.174 }
2376 root 1.153 }
2377     }
2378 root 1.186 }
2379 root 1.226
2380     glEnd ();
2381     glDisable (GL_TEXTURE_2D);
2382     key.texname = -1;
2383 root 1.176 }
2384    
2385 root 1.186 hv_clear (smooth);
2386     }
2387 root 1.30
2388 root 1.261 if (pl_tex.name)
2389     {
2390     maptex tex = pl_tex;
2391 root 1.266 int px = pl_x + sdx;
2392     int py = pl_y + sdy;
2393 root 1.261
2394     key.texname = tex.name;
2395     arr = rc_array (rc, &key);
2396    
2397     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
2398     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
2399     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
2400     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
2401    
2402     rc_draw (rc);
2403     }
2404    
2405 root 1.285 rc_draw (rc_ov);
2406     rc_clear (rc_ov);
2407    
2408 root 1.152 glDisable (GL_BLEND);
2409 root 1.223 rc_free (rc);
2410 root 1.285 rc_free (rc_ov);
2411 root 1.143
2412 root 1.145 // top layer: overlays such as the health bar
2413 root 1.143 for (y = 0; y < sh; y++)
2414 root 1.164 if (0 <= y + my && y + my < self->rows)
2415 root 1.143 {
2416 root 1.164 maprow *row = self->row + (y + my);
2417 root 1.143
2418     for (x = 0; x < sw; x++)
2419 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2420 root 1.143 {
2421 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2422 root 1.143
2423 root 1.171 int px = x * T;
2424     int py = y * T;
2425 root 1.143
2426 root 1.279 if (expect_false (cell->player == player))
2427     {
2428     px += sdx;
2429     py += sdy;
2430     }
2431    
2432 root 1.143 if (cell->stat_hp)
2433     {
2434 root 1.171 int width = cell->stat_width * T;
2435 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
2436 root 1.143
2437 root 1.152 glColor3ub (0, 0, 0);
2438 root 1.151 glRectf (px + 1, py - thick - 2,
2439     px + width - 1, py);
2440 root 1.147
2441 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
2442 root 1.147 glRectf (px + 2,
2443 root 1.151 py - thick - 1,
2444     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
2445 root 1.143 }
2446     }
2447     }
2448 root 1.116 }
2449    
2450     void
2451 root 1.295 draw_magicmap (DC::Map self, int w, int h, unsigned char *data)
2452 root 1.117 CODE:
2453     {
2454     static float color[16][3] = {
2455 root 1.295 { 0.00f, 0.00f, 0.00f },
2456     { 1.00f, 1.00f, 1.00f },
2457     { 0.00f, 0.00f, 0.55f },
2458     { 1.00f, 0.00f, 0.00f },
2459    
2460     { 1.00f, 0.54f, 0.00f },
2461     { 0.11f, 0.56f, 1.00f },
2462     { 0.93f, 0.46f, 0.00f },
2463     { 0.18f, 0.54f, 0.34f },
2464    
2465     { 0.56f, 0.73f, 0.56f },
2466     { 0.80f, 0.80f, 0.80f },
2467     { 0.55f, 0.41f, 0.13f },
2468     { 0.99f, 0.77f, 0.26f },
2469    
2470     { 0.74f, 0.65f, 0.41f },
2471    
2472     { 0.00f, 1.00f, 1.00f },
2473     { 1.00f, 0.00f, 1.00f },
2474     { 1.00f, 1.00f, 0.00f },
2475 root 1.117 };
2476    
2477     int x, y;
2478    
2479     glEnable (GL_TEXTURE_2D);
2480 root 1.290 /* GL_REPLACE would be correct, as we don't need to modulate alpha,
2481     * but the nvidia driver (185.18.14) mishandles alpha textures
2482 root 1.296 * and takes the colour from god knows where instead of using
2483 root 1.290 * Cp. MODULATE results in the same colour, but slightly different
2484     * alpha, but atcually gives us the correct colour with nvidia.
2485     */
2486     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2487 root 1.117 glEnable (GL_BLEND);
2488     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2489     glBegin (GL_QUADS);
2490    
2491     for (y = 0; y < h; y++)
2492     for (x = 0; x < w; x++)
2493     {
2494     unsigned char m = data [x + y * w];
2495    
2496 root 1.118 if (m)
2497     {
2498     float *c = color [m & 15];
2499    
2500 root 1.295 float tx1 = m & 0x40 ? 0.5f : 0.f;
2501     float tx2 = tx1 + 0.5f;
2502 root 1.118
2503 root 1.290 glColor4f (c[0], c[1], c[2], 1);
2504 root 1.118 glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2505     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2506     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2507     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2508     }
2509 root 1.117 }
2510    
2511     glEnd ();
2512     glDisable (GL_BLEND);
2513     glDisable (GL_TEXTURE_2D);
2514     }
2515    
2516     void
2517 root 1.242 fow_texture (DC::Map self, int mx, int my, int sw, int sh)
2518 root 1.116 PPCODE:
2519     {
2520     int x, y;
2521 root 1.296 int sw1 = sw + 2;
2522     int sh1 = sh + 2;
2523     int sh3 = sh * 3;
2524     int sw3 = sw * 3;
2525 root 1.204 uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2526 root 1.296 SV *darkness3_sv = sv_2mortal (newSV (sw3 * sh3));
2527 root 1.204 uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2528    
2529     SvPOK_only (darkness3_sv);
2530 root 1.296 SvCUR_set (darkness3_sv, sw3 * sh3);
2531 root 1.116
2532 root 1.204 mx += self->x - 1;
2533     my += self->y - 1;
2534 root 1.116
2535 root 1.204 for (y = 0; y < sh1; y++)
2536 root 1.164 if (0 <= y + my && y + my < self->rows)
2537 root 1.116 {
2538 root 1.164 maprow *row = self->row + (y + my);
2539 root 1.116
2540 root 1.204 for (x = 0; x < sw1; x++)
2541 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2542 root 1.116 {
2543 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2544 root 1.116
2545 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2546 root 1.294 ? DARKNESS_ADJUST (255 - (cell->darkness - 1))
2547     : DARKNESS_ADJUST (255 - FOW_DARKNESS);
2548 root 1.116 }
2549     }
2550 root 1.34
2551 root 1.204 for (y = 0; y < sh; ++y)
2552     for (x = 0; x < sw; ++x)
2553     {
2554     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2555     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2556     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2557     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2558     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2559     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2560     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2561     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2562     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2563    
2564     uint8_t r11 = (d11 + d21 + d12) / 3;
2565     uint8_t r21 = d21;
2566     uint8_t r31 = (d21 + d31 + d32) / 3;
2567    
2568     uint8_t r12 = d12;
2569     uint8_t r22 = d22;
2570     uint8_t r32 = d32;
2571    
2572     uint8_t r13 = (d13 + d23 + d12) / 3;
2573     uint8_t r23 = d23;
2574     uint8_t r33 = (d23 + d33 + d32) / 3;
2575    
2576 root 1.296 darkness3 [(y * 3 ) * sw3 + (x * 3 )] = MAX (d22, r11);
2577     darkness3 [(y * 3 ) * sw3 + (x * 3 + 1)] = MAX (d22, r21);
2578     darkness3 [(y * 3 ) * sw3 + (x * 3 + 2)] = MAX (d22, r31);
2579     darkness3 [(y * 3 + 1) * sw3 + (x * 3 )] = MAX (d22, r12);
2580     darkness3 [(y * 3 + 1) * sw3 + (x * 3 + 1)] = MAX (d22, r22); /* this MUST be == d22 */
2581     darkness3 [(y * 3 + 1) * sw3 + (x * 3 + 2)] = MAX (d22, r32);
2582     darkness3 [(y * 3 + 2) * sw3 + (x * 3 )] = MAX (d22, r13);
2583     darkness3 [(y * 3 + 2) * sw3 + (x * 3 + 1)] = MAX (d22, r23);
2584     darkness3 [(y * 3 + 2) * sw3 + (x * 3 + 2)] = MAX (d22, r33);
2585 root 1.204 }
2586 root 1.201
2587 root 1.204 free (darkness1);
2588 root 1.201
2589 root 1.32 EXTEND (SP, 3);
2590 root 1.296 PUSHs (sv_2mortal (newSViv (sw3)));
2591 root 1.204 PUSHs (sv_2mortal (newSViv (sh3)));
2592     PUSHs (darkness3_sv);
2593 root 1.30 }
2594    
2595 root 1.42 SV *
2596 root 1.242 get_rect (DC::Map self, int x0, int y0, int w, int h)
2597 root 1.42 CODE:
2598     {
2599     int x, y, x1, y1;
2600     SV *data_sv = newSV (w * h * 7 + 5);
2601     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2602    
2603     *data++ = 0; /* version 0 format */
2604     *data++ = w >> 8; *data++ = w;
2605     *data++ = h >> 8; *data++ = h;
2606    
2607     // we need to do this 'cause we don't keep an absolute coord system for rows
2608 root 1.55 // TODO: treat rows as we treat columns
2609 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2610     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2611    
2612     x0 += self->x - self->ox;
2613     y0 += self->y - self->oy;
2614    
2615     x1 = x0 + w;
2616     y1 = y0 + h;
2617    
2618     for (y = y0; y < y1; y++)
2619     {
2620     maprow *row = 0 <= y && y < self->rows
2621     ? self->row + y
2622     : 0;
2623    
2624     for (x = x0; x < x1; x++)
2625     {
2626     if (row && row->c0 <= x && x < row->c1)
2627     {
2628     mapcell *cell = row->col + (x - row->c0);
2629     uint8_t flags = 0;
2630    
2631 root 1.174 if (cell->tile [0]) flags |= 1;
2632     if (cell->tile [1]) flags |= 2;
2633     if (cell->tile [2]) flags |= 4;
2634 root 1.42
2635     *data++ = flags;
2636    
2637     if (flags & 1)
2638     {
2639 root 1.174 tileid tile = cell->tile [0];
2640     *data++ = tile >> 8;
2641     *data++ = tile;
2642 root 1.42 }
2643    
2644     if (flags & 2)
2645     {
2646 root 1.174 tileid tile = cell->tile [1];
2647     *data++ = tile >> 8;
2648     *data++ = tile;
2649 root 1.42 }
2650    
2651     if (flags & 4)
2652     {
2653 root 1.174 tileid tile = cell->tile [2];
2654     *data++ = tile >> 8;
2655     *data++ = tile;
2656 root 1.42 }
2657     }
2658     else
2659     *data++ = 0;
2660     }
2661     }
2662    
2663 root 1.260 /* if size is w*h + 5 then no data has been found */
2664     if (data - (uint8_t *)SvPVX (data_sv) != w * h + 5)
2665 root 1.259 {
2666     SvPOK_only (data_sv);
2667     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2668     }
2669 root 1.260
2670     RETVAL = data_sv;
2671 root 1.42 }
2672     OUTPUT:
2673     RETVAL
2674    
2675     void
2676 root 1.259 set_rect (DC::Map self, int x0, int y0, SV *data_sv)
2677 root 1.42 PPCODE:
2678     {
2679     int x, y, z;
2680 root 1.48 int w, h;
2681 root 1.42 int x1, y1;
2682 root 1.259 STRLEN len;
2683     uint8_t *data, *end;
2684    
2685     len = SvLEN (data_sv);
2686 root 1.260 SvGROW (data_sv, len + 8); // reserve at least 7+ bytes more
2687 root 1.259 data = SvPVbyte_nolen (data_sv);
2688 root 1.260 end = data + len + 8;
2689 root 1.259
2690     if (len < 5)
2691     XSRETURN_EMPTY;
2692 root 1.42
2693     if (*data++ != 0)
2694 root 1.227 XSRETURN_EMPTY; /* version mismatch */
2695 root 1.42
2696 root 1.48 w = *data++ << 8; w |= *data++;
2697     h = *data++ << 8; h |= *data++;
2698 root 1.42
2699     // we need to do this 'cause we don't keep an absolute coord system for rows
2700 root 1.55 // TODO: treat rows as we treat columns
2701 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2702     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2703    
2704     x0 += self->x - self->ox;
2705     y0 += self->y - self->oy;
2706    
2707     x1 = x0 + w;
2708     y1 = y0 + h;
2709    
2710     for (y = y0; y < y1; y++)
2711     {
2712     maprow *row = map_get_row (self, y);
2713    
2714     for (x = x0; x < x1; x++)
2715     {
2716 root 1.259 uint8_t flags;
2717    
2718     if (data + 7 >= end)
2719     XSRETURN_EMPTY;
2720    
2721     flags = *data++;
2722 root 1.42
2723     if (flags)
2724     {
2725     mapcell *cell = row_get_cell (row, x);
2726 root 1.174 tileid tile[3] = { 0, 0, 0 };
2727 root 1.42
2728 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2729     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2730     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2731 root 1.42
2732 root 1.143 if (cell->darkness == 0)
2733 root 1.42 {
2734 root 1.260 /*cell->darkness = 0;*/
2735     EXTEND (SP, 3);
2736 root 1.42
2737     for (z = 0; z <= 2; z++)
2738     {
2739 root 1.174 tileid t = tile [z];
2740    
2741 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2742 root 1.174 {
2743 root 1.260 PUSHs (sv_2mortal (newSViv (t)));
2744 root 1.174 need_texid (self, t);
2745     }
2746 root 1.42
2747 root 1.174 cell->tile [z] = t;
2748 root 1.42 }
2749     }
2750     }
2751     }
2752     }
2753     }
2754    
2755 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::RW
2756 root 1.205
2757 root 1.242 DC::RW
2758 root 1.211 new (SV *class, SV *data_sv)
2759     CODE:
2760     {
2761     STRLEN datalen;
2762     char *data = SvPVbyte (data_sv, datalen);
2763    
2764 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2765 root 1.211 }
2766     OUTPUT:
2767     RETVAL
2768    
2769 root 1.242 DC::RW
2770 root 1.212 new_from_file (SV *class, const char *path, const char *mode = "rb")
2771     CODE:
2772     RETVAL = SDL_RWFromFile (path, mode);
2773     OUTPUT:
2774     RETVAL
2775    
2776 root 1.218 # fails on win32:
2777 root 1.241 # dc.xs(2268) : error C2059: syntax error : '('
2778 root 1.218 #void
2779 root 1.242 #close (DC::RW self)
2780 root 1.218 # CODE:
2781     # (self->(close)) (self);
2782 root 1.212
2783 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Channel
2784 root 1.212
2785     PROTOTYPES: DISABLE
2786    
2787 root 1.242 DC::Channel
2788 root 1.215 find ()
2789     CODE:
2790     {
2791     RETVAL = Mix_GroupAvailable (-1);
2792    
2793     if (RETVAL < 0)
2794     {
2795     RETVAL = Mix_GroupOldest (-1);
2796    
2797     if (RETVAL < 0)
2798     XSRETURN_UNDEF;
2799    
2800     Mix_HaltChannel (RETVAL);
2801     }
2802    
2803     Mix_UnregisterAllEffects (RETVAL);
2804     Mix_Volume (RETVAL, 128);
2805     }
2806     OUTPUT:
2807     RETVAL
2808    
2809 root 1.213 void
2810 root 1.242 halt (DC::Channel self)
2811 root 1.213 CODE:
2812     Mix_HaltChannel (self);
2813    
2814     void
2815 root 1.242 expire (DC::Channel self, int ticks = -1)
2816 root 1.213 CODE:
2817     Mix_ExpireChannel (self, ticks);
2818    
2819     void
2820 root 1.242 fade_out (DC::Channel self, int ticks = -1)
2821 root 1.213 CODE:
2822     Mix_FadeOutChannel (self, ticks);
2823    
2824 root 1.212 int
2825 root 1.242 volume (DC::Channel self, int volume)
2826 root 1.212 CODE:
2827 root 1.216 RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128));
2828 root 1.212 OUTPUT:
2829     RETVAL
2830    
2831 root 1.213 void
2832 root 1.242 unregister_all_effects (DC::Channel self)
2833 root 1.212 CODE:
2834 root 1.213 Mix_UnregisterAllEffects (self);
2835 root 1.212
2836 root 1.213 void
2837 root 1.242 set_panning (DC::Channel self, int left, int right)
2838 root 1.212 CODE:
2839 root 1.216 left = CLAMP (left , 0, 255);
2840     right = CLAMP (right, 0, 255);
2841 root 1.213 Mix_SetPanning (self, left, right);
2842 root 1.212
2843 root 1.213 void
2844 root 1.242 set_distance (DC::Channel self, int distance)
2845 root 1.212 CODE:
2846 root 1.216 Mix_SetDistance (self, CLAMP (distance, 0, 255));
2847 root 1.212
2848 root 1.213 void
2849 root 1.242 set_position (DC::Channel self, int angle, int distance)
2850 root 1.212 CODE:
2851 root 1.220
2852     void
2853 root 1.242 set_position_r (DC::Channel self, int dx, int dy, int maxdistance)
2854 root 1.220 CODE:
2855     {
2856     int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance));
2857 root 1.295 int angle = atan2f (dx, -dy) * 180.f / (float)M_PI + 360.f;
2858 root 1.216 Mix_SetPosition (self, angle, CLAMP (distance, 0, 255));
2859 root 1.220 }
2860 root 1.212
2861 root 1.213 void
2862 root 1.242 set_reverse_stereo (DC::Channel self, int flip)
2863 root 1.212 CODE:
2864 root 1.213 Mix_SetReverseStereo (self, flip);
2865 root 1.212
2866 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixChunk
2867 root 1.212
2868     PROTOTYPES: DISABLE
2869    
2870 root 1.242 DC::MixChunk
2871     new (SV *class, DC::RW rwops)
2872 root 1.52 CODE:
2873 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2874 root 1.52 OUTPUT:
2875     RETVAL
2876    
2877     void
2878 root 1.242 DESTROY (DC::MixChunk self)
2879 root 1.52 CODE:
2880     Mix_FreeChunk (self);
2881    
2882     int
2883 root 1.242 volume (DC::MixChunk self, int volume = -1)
2884 root 1.52 CODE:
2885 root 1.216 if (items > 1)
2886     volume = CLAMP (volume, 0, 128);
2887 root 1.52 RETVAL = Mix_VolumeChunk (self, volume);
2888     OUTPUT:
2889     RETVAL
2890    
2891 root 1.242 DC::Channel
2892     play (DC::MixChunk self, DC::Channel channel = -1, int loops = 0, int ticks = -1)
2893 root 1.52 CODE:
2894 root 1.215 {
2895 root 1.52 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2896 root 1.215
2897     if (RETVAL < 0)
2898     XSRETURN_UNDEF;
2899    
2900     if (channel < 0)
2901     {
2902     Mix_UnregisterAllEffects (RETVAL);
2903     Mix_Volume (RETVAL, 128);
2904     }
2905     }
2906 root 1.52 OUTPUT:
2907     RETVAL
2908    
2909 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixMusic
2910 root 1.52
2911     int
2912     volume (int volume = -1)
2913 root 1.205 PROTOTYPE: ;$
2914 root 1.52 CODE:
2915 root 1.216 if (items > 0)
2916     volume = CLAMP (volume, 0, 128);
2917 root 1.52 RETVAL = Mix_VolumeMusic (volume);
2918     OUTPUT:
2919     RETVAL
2920    
2921 root 1.213 void
2922 root 1.194 fade_out (int ms)
2923     CODE:
2924 root 1.213 Mix_FadeOutMusic (ms);
2925 root 1.194
2926 root 1.212 void
2927     halt ()
2928     CODE:
2929     Mix_HaltMusic ();
2930    
2931 root 1.242 DC::MixMusic
2932     new (SV *class, DC::RW rwops)
2933 root 1.52 CODE:
2934 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
2935 root 1.52 OUTPUT:
2936     RETVAL
2937    
2938     void
2939 root 1.242 DESTROY (DC::MixMusic self)
2940 root 1.52 CODE:
2941     Mix_FreeMusic (self);
2942    
2943     int
2944 root 1.242 play (DC::MixMusic self, int loops = -1)
2945 root 1.52 CODE:
2946     RETVAL = Mix_PlayMusic (self, loops);
2947     OUTPUT:
2948     RETVAL
2949    
2950 root 1.213 void
2951 root 1.242 fade_in_pos (DC::MixMusic self, int loops, int ms, double position)
2952 root 1.195 CODE:
2953 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
2954 root 1.195
2955 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::OpenGL
2956 root 1.54
2957 root 1.205 PROTOTYPES: ENABLE
2958    
2959 root 1.54 BOOT:
2960     {
2961 root 1.242 HV *stash = gv_stashpv ("DC::OpenGL", 1);
2962 root 1.54 static const struct {
2963     const char *name;
2964     IV iv;
2965     } *civ, const_iv[] = {
2966     # define const_iv(name) { # name, (IV)name }
2967 root 1.199 const_iv (GL_VENDOR),
2968     const_iv (GL_VERSION),
2969     const_iv (GL_EXTENSIONS),
2970 root 1.293 const_iv (GL_MAX_TEXTURE_UNITS),
2971 root 1.54 const_iv (GL_COLOR_MATERIAL),
2972     const_iv (GL_SMOOTH),
2973     const_iv (GL_FLAT),
2974 root 1.69 const_iv (GL_DITHER),
2975 root 1.54 const_iv (GL_BLEND),
2976 root 1.89 const_iv (GL_CULL_FACE),
2977 root 1.69 const_iv (GL_SCISSOR_TEST),
2978 root 1.89 const_iv (GL_DEPTH_TEST),
2979     const_iv (GL_ALPHA_TEST),
2980     const_iv (GL_NORMALIZE),
2981     const_iv (GL_RESCALE_NORMAL),
2982 root 1.119 const_iv (GL_FRONT),
2983     const_iv (GL_BACK),
2984 root 1.206 const_iv (GL_AUX0),
2985 root 1.54 const_iv (GL_AND),
2986 root 1.67 const_iv (GL_ONE),
2987     const_iv (GL_ZERO),
2988 root 1.54 const_iv (GL_SRC_ALPHA),
2989 root 1.104 const_iv (GL_DST_ALPHA),
2990 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2991 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2992 root 1.293 const_iv (GL_SRC_COLOR),
2993     const_iv (GL_DST_COLOR),
2994     const_iv (GL_ONE_MINUS_SRC_COLOR),
2995     const_iv (GL_ONE_MINUS_DST_COLOR),
2996 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2997 root 1.54 const_iv (GL_RGB),
2998     const_iv (GL_RGBA),
2999 root 1.115 const_iv (GL_RGBA4),
3000     const_iv (GL_RGBA8),
3001     const_iv (GL_RGB5_A1),
3002 root 1.54 const_iv (GL_UNSIGNED_BYTE),
3003 root 1.89 const_iv (GL_UNSIGNED_SHORT),
3004     const_iv (GL_UNSIGNED_INT),
3005 root 1.54 const_iv (GL_ALPHA),
3006 root 1.86 const_iv (GL_INTENSITY),
3007 root 1.76 const_iv (GL_LUMINANCE),
3008 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
3009 root 1.54 const_iv (GL_FLOAT),
3010     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
3011 root 1.230 const_iv (GL_COMPRESSED_ALPHA_ARB),
3012     const_iv (GL_COMPRESSED_LUMINANCE_ARB),
3013     const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB),
3014     const_iv (GL_COMPRESSED_INTENSITY_ARB),
3015     const_iv (GL_COMPRESSED_RGB_ARB),
3016     const_iv (GL_COMPRESSED_RGBA_ARB),
3017 root 1.54 const_iv (GL_COMPILE),
3018 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
3019     const_iv (GL_PROXY_TEXTURE_2D),
3020 root 1.54 const_iv (GL_TEXTURE_1D),
3021     const_iv (GL_TEXTURE_2D),
3022     const_iv (GL_TEXTURE_ENV),
3023     const_iv (GL_TEXTURE_MAG_FILTER),
3024     const_iv (GL_TEXTURE_MIN_FILTER),
3025     const_iv (GL_TEXTURE_ENV_MODE),
3026     const_iv (GL_TEXTURE_WRAP_S),
3027     const_iv (GL_TEXTURE_WRAP_T),
3028 root 1.98 const_iv (GL_REPEAT),
3029 root 1.54 const_iv (GL_CLAMP),
3030 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
3031 root 1.54 const_iv (GL_NEAREST),
3032     const_iv (GL_LINEAR),
3033 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
3034     const_iv (GL_LINEAR_MIPMAP_NEAREST),
3035     const_iv (GL_NEAREST_MIPMAP_LINEAR),
3036     const_iv (GL_LINEAR_MIPMAP_LINEAR),
3037     const_iv (GL_GENERATE_MIPMAP),
3038 root 1.54 const_iv (GL_MODULATE),
3039 root 1.69 const_iv (GL_DECAL),
3040 root 1.54 const_iv (GL_REPLACE),
3041 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
3042 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
3043     const_iv (GL_PROJECTION),
3044     const_iv (GL_MODELVIEW),
3045     const_iv (GL_COLOR_LOGIC_OP),
3046 root 1.69 const_iv (GL_SEPARABLE_2D),
3047 root 1.54 const_iv (GL_CONVOLUTION_2D),
3048     const_iv (GL_CONVOLUTION_BORDER_MODE),
3049     const_iv (GL_CONSTANT_BORDER),
3050 root 1.208 const_iv (GL_POINTS),
3051 root 1.54 const_iv (GL_LINES),
3052 root 1.138 const_iv (GL_LINE_STRIP),
3053 root 1.89 const_iv (GL_LINE_LOOP),
3054 root 1.54 const_iv (GL_QUADS),
3055 root 1.89 const_iv (GL_QUAD_STRIP),
3056     const_iv (GL_TRIANGLES),
3057     const_iv (GL_TRIANGLE_STRIP),
3058     const_iv (GL_TRIANGLE_FAN),
3059 root 1.208 const_iv (GL_POLYGON),
3060 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
3061 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
3062     const_iv (GL_LINE_SMOOTH_HINT),
3063     const_iv (GL_POLYGON_SMOOTH_HINT),
3064     const_iv (GL_GENERATE_MIPMAP_HINT),
3065 root 1.232 const_iv (GL_TEXTURE_COMPRESSION_HINT),
3066 root 1.54 const_iv (GL_FASTEST),
3067 root 1.206 const_iv (GL_DONT_CARE),
3068     const_iv (GL_NICEST),
3069 root 1.89 const_iv (GL_V2F),
3070     const_iv (GL_V3F),
3071     const_iv (GL_T2F_V3F),
3072     const_iv (GL_T2F_N3F_V3F),
3073 root 1.291 const_iv (GL_FUNC_ADD),
3074     const_iv (GL_FUNC_SUBTRACT),
3075     const_iv (GL_FUNC_REVERSE_SUBTRACT),
3076 root 1.54 # undef const_iv
3077     };
3078    
3079     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
3080     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
3081 root 1.188
3082     texture_av = newAV ();
3083     AvREAL_off (texture_av);
3084 root 1.54 }
3085    
3086 root 1.231 void
3087     disable_GL_EXT_blend_func_separate ()
3088     CODE:
3089     gl.BlendFuncSeparate = 0;
3090     gl.BlendFuncSeparateEXT = 0;
3091    
3092 root 1.291 void
3093     apple_nvidia_bug (int enable)
3094    
3095 root 1.97 char *
3096     gl_vendor ()
3097     CODE:
3098     RETVAL = (char *)glGetString (GL_VENDOR);
3099     OUTPUT:
3100     RETVAL
3101    
3102     char *
3103     gl_version ()
3104     CODE:
3105     RETVAL = (char *)glGetString (GL_VERSION);
3106     OUTPUT:
3107     RETVAL
3108    
3109     char *
3110     gl_extensions ()
3111     CODE:
3112     RETVAL = (char *)glGetString (GL_EXTENSIONS);
3113     OUTPUT:
3114     RETVAL
3115    
3116 root 1.201 const char *glGetString (GLenum pname)
3117 root 1.199
3118     GLint glGetInteger (GLenum pname)
3119     CODE:
3120     glGetIntegerv (pname, &RETVAL);
3121     OUTPUT:
3122     RETVAL
3123    
3124     GLdouble glGetDouble (GLenum pname)
3125     CODE:
3126     glGetDoublev (pname, &RETVAL);
3127     OUTPUT:
3128     RETVAL
3129    
3130 root 1.54 int glGetError ()
3131    
3132 root 1.114 void glFinish ()
3133    
3134 root 1.54 void glClear (int mask)
3135    
3136     void glClearColor (float r, float g, float b, float a = 1.0)
3137     PROTOTYPE: @
3138    
3139     void glEnable (int cap)
3140    
3141     void glDisable (int cap)
3142    
3143     void glShadeModel (int mode)
3144    
3145     void glHint (int target, int mode)
3146    
3147     void glBlendFunc (int sfactor, int dfactor)
3148    
3149 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
3150     CODE:
3151     gl_BlendFuncSeparate (sa, da, saa, daa);
3152    
3153 root 1.292 # void glBlendEquation (int se)
3154 root 1.291
3155 root 1.89 void glDepthMask (int flag)
3156    
3157 root 1.54 void glLogicOp (int opcode)
3158    
3159 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
3160    
3161 root 1.54 void glMatrixMode (int mode)
3162    
3163     void glPushMatrix ()
3164    
3165     void glPopMatrix ()
3166    
3167     void glLoadIdentity ()
3168    
3169 root 1.119 void glDrawBuffer (int buffer)
3170    
3171     void glReadBuffer (int buffer)
3172    
3173 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
3174     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
3175    
3176     # near_ and far_ are due to microsofts buggy "c" compiler
3177 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
3178 root 1.54
3179 root 1.208 PROTOTYPES: DISABLE
3180    
3181 root 1.54 void glViewport (int x, int y, int width, int height)
3182    
3183 root 1.69 void glScissor (int x, int y, int width, int height)
3184    
3185 root 1.54 void glTranslate (float x, float y, float z = 0.)
3186     CODE:
3187     glTranslatef (x, y, z);
3188    
3189 root 1.62 void glScale (float x, float y, float z = 1.)
3190 root 1.54 CODE:
3191     glScalef (x, y, z);
3192    
3193     void glRotate (float angle, float x, float y, float z)
3194     CODE:
3195     glRotatef (angle, x, y, z);
3196    
3197     void glColor (float r, float g, float b, float a = 1.0)
3198 root 1.278 PROTOTYPE: @
3199 root 1.103 ALIAS:
3200     glColor_premultiply = 1
3201 root 1.54 CODE:
3202 root 1.103 if (ix)
3203     {
3204     r *= a;
3205     g *= a;
3206     b *= a;
3207     }
3208 root 1.90 // microsoft visual "c" rounds instead of truncating...
3209 root 1.130 glColor4f (r, g, b, a);
3210 root 1.54
3211 root 1.91 void glRasterPos (float x, float y, float z = 0.)
3212     CODE:
3213     glRasterPos3f (0, 0, z);
3214     glBitmap (0, 0, 0, 0, x, y, 0);
3215    
3216 root 1.54 void glVertex (float x, float y, float z = 0.)
3217     CODE:
3218     glVertex3f (x, y, z);
3219    
3220     void glTexCoord (float s, float t)
3221     CODE:
3222     glTexCoord2f (s, t);
3223    
3224 root 1.210 void glRect (float x1, float y1, float x2, float y2)
3225     CODE:
3226     glRectf (x1, y1, x2, y2);
3227    
3228 root 1.233 void glRect_lineloop (float x1, float y1, float x2, float y2)
3229     CODE:
3230     glBegin (GL_LINE_LOOP);
3231     glVertex2f (x1, y1);
3232     glVertex2f (x2, y1);
3233     glVertex2f (x2, y2);
3234     glVertex2f (x1, y2);
3235     glEnd ();
3236    
3237 root 1.208 PROTOTYPES: ENABLE
3238    
3239     void glBegin (int mode)
3240    
3241     void glEnd ()
3242    
3243     void glPointSize (GLfloat size)
3244    
3245     void glLineWidth (GLfloat width)
3246    
3247     void glInterleavedArrays (int format, int stride, char *data)
3248    
3249     void glDrawElements (int mode, int count, int type, char *indices)
3250    
3251     # 1.2 void glDrawRangeElements (int mode, int start, int end
3252    
3253 root 1.54 void glTexEnv (int target, int pname, float param)
3254     CODE:
3255     glTexEnvf (target, pname, param);
3256    
3257     void glTexParameter (int target, int pname, float param)
3258     CODE:
3259     glTexParameterf (target, pname, param);
3260    
3261     void glBindTexture (int target, int name)
3262    
3263     void glConvolutionParameter (int target, int pname, float params)
3264     CODE:
3265 root 1.103 if (gl.ConvolutionParameterf)
3266     gl.ConvolutionParameterf (target, pname, params);
3267 root 1.54
3268     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
3269 root 1.64 CODE:
3270 root 1.103 if (gl.ConvolutionFilter2D)
3271     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
3272 root 1.54
3273 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
3274     CODE:
3275 root 1.103 if (gl.SeparableFilter2D)
3276     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
3277 root 1.69
3278 root 1.244 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data = 0)
3279 root 1.54
3280     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
3281    
3282 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
3283 root 1.68
3284 root 1.199 void glPixelZoom (float x, float y)
3285    
3286 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
3287    
3288 root 1.54 int glGenTexture ()
3289     CODE:
3290 root 1.192 RETVAL = gen_texture ();
3291 root 1.54 OUTPUT:
3292     RETVAL
3293    
3294     void glDeleteTexture (int name)
3295     CODE:
3296 root 1.192 del_texture (name);
3297    
3298 root 1.54 int glGenList ()
3299     CODE:
3300     RETVAL = glGenLists (1);
3301     OUTPUT:
3302     RETVAL
3303    
3304     void glDeleteList (int list)
3305     CODE:
3306     glDeleteLists (list, 1);
3307    
3308     void glNewList (int list, int mode = GL_COMPILE)
3309    
3310     void glEndList ()
3311    
3312     void glCallList (int list)
3313    
3314 root 1.296 void c_init ()
3315     CODE:
3316     glPixelStorei (GL_PACK_ALIGNMENT , 1);
3317     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
3318    
3319 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::UI::Base
3320 root 1.207
3321     PROTOTYPES: DISABLE
3322    
3323     void
3324 root 1.209 find_widget (SV *self, NV x, NV y)
3325 root 1.207 PPCODE:
3326     {
3327 root 1.209 if (within_widget (self, x, y))
3328     XPUSHs (self);
3329     }
3330    
3331     BOOT:
3332     {
3333 root 1.242 hover_gv = gv_fetchpv ("DC::UI::HOVER", 1, SVt_NV);
3334 root 1.209
3335 root 1.242 draw_x_gv = gv_fetchpv ("DC::UI::Base::draw_x", 1, SVt_NV);
3336     draw_y_gv = gv_fetchpv ("DC::UI::Base::draw_y", 1, SVt_NV);
3337     draw_w_gv = gv_fetchpv ("DC::UI::Base::draw_w", 1, SVt_NV);
3338     draw_h_gv = gv_fetchpv ("DC::UI::Base::draw_h", 1, SVt_NV);
3339 root 1.209 }
3340    
3341     void
3342     draw (SV *self)
3343     CODE:
3344     {
3345     HV *hv;
3346     SV **svp;
3347     NV x, y, w, h;
3348     SV *draw_x_sv = GvSV (draw_x_gv);
3349     SV *draw_y_sv = GvSV (draw_y_gv);
3350     SV *draw_w_sv = GvSV (draw_w_gv);
3351     SV *draw_h_sv = GvSV (draw_h_gv);
3352 root 1.228 double draw_x, draw_y;
3353 root 1.209
3354     if (!SvROK (self))
3355 root 1.242 croak ("DC::Base::draw: %s not a reference", SvPV_nolen (self));
3356 root 1.209
3357     hv = (HV *)SvRV (self);
3358    
3359     if (SvTYPE (hv) != SVt_PVHV)
3360 root 1.242 croak ("DC::Base::draw: %s not a hashref", SvPV_nolen (self));
3361 root 1.209
3362     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
3363     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
3364    
3365     if (!h || !w)
3366     XSRETURN_EMPTY;
3367    
3368     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
3369     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
3370    
3371     draw_x = SvNV (draw_x_sv) + x;
3372     draw_y = SvNV (draw_y_sv) + y;
3373    
3374     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
3375     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
3376     XSRETURN_EMPTY;
3377    
3378     sv_setnv (draw_x_sv, draw_x);
3379     sv_setnv (draw_y_sv, draw_y);
3380    
3381     glPushMatrix ();
3382     glTranslated (x, y, 0);
3383    
3384     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
3385     {
3386     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
3387    
3388     if (svp && SvTRUE (*svp))
3389     {
3390 root 1.228 glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f);
3391 root 1.209 glEnable (GL_BLEND);
3392     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3393     glBegin (GL_QUADS);
3394     glVertex2f (0, 0);
3395     glVertex2f (w, 0);
3396     glVertex2f (w, h);
3397     glVertex2f (0, h);
3398     glEnd ();
3399     glDisable (GL_BLEND);
3400     }
3401     }
3402     #if 0
3403 root 1.234 // draw borders, for debugging
3404     glPushMatrix ();
3405     glColor4f (1., 1., 0., 1.);
3406     glTranslatef (.5, .5, 0.);
3407     glBegin (GL_LINE_LOOP);
3408     glVertex2f (0 , 0);
3409     glVertex2f (w - 1, 0);
3410     glVertex2f (w - 1, h - 1);
3411     glVertex2f (0 , h - 1);
3412     glEnd ();
3413     glPopMatrix ();
3414 root 1.209 #endif
3415     PUSHMARK (SP);
3416     XPUSHs (self);
3417     PUTBACK;
3418     call_method ("_draw", G_VOID | G_DISCARD);
3419     SPAGAIN;
3420    
3421     glPopMatrix ();
3422    
3423     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
3424     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
3425 root 1.207 }
3426