ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.322
Committed: Sun Nov 18 01:43:12 2018 UTC (5 years, 5 months ago) by root
Branch: MAIN
Changes since 1.321: +54 -34 lines
Log Message:
*** empty log message ***

File Contents

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