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

File Contents

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