ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.327
Committed: Sun Nov 18 12:01:50 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.326: +64 -85 lines
Log Message:
more pointless c++ification

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