ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.245
Committed: Fri Dec 28 15:05:20 2007 UTC (16 years, 4 months ago) by root
Branch: MAIN
Changes since 1.244: +5 -1 lines
Log Message:
why does fucking pango team fix fucking bugs silently :)

File Contents

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