ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.296
Committed: Mon Dec 21 23:52:34 2009 UTC (14 years, 4 months ago) by root
Branch: MAIN
Changes since 1.295: +98 -77 lines
Log Message:
*** empty log message ***

File Contents

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