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