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