ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.246
Committed: Fri Dec 28 15:06:02 2007 UTC (16 years, 4 months ago) by root
Branch: MAIN
Changes since 1.245: +0 -2 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 #if !PANGO_VERSION_CHECK (1, 17. 3)
1323 root 1.165 /* pango bug: line is between 1..numlines, not 0..numlines-1 */
1324 root 1.245 --line;
1325     #endif
1326 root 1.165 EXTEND (SP, 2);
1327 root 1.245 PUSHs (sv_2mortal (newSViv (line)));
1328 root 1.165 PUSHs (sv_2mortal (newSViv (x / PANGO_SCALE)));
1329     }
1330    
1331     void
1332 root 1.242 line_x_to_index (DC::Layout self, int line, int x)
1333 root 1.165 PPCODE:
1334     {
1335     PangoLayoutLine *lp;
1336     int index, trailing;
1337    
1338     if (line < 0)
1339     XSRETURN_EMPTY;
1340    
1341     if (!(lp = pango_layout_get_line (self->pl, line)))
1342     XSRETURN_EMPTY; /* do better */
1343    
1344 root 1.166 pango_layout_line_x_to_index (lp, x * PANGO_SCALE, &index, &trailing);
1345 root 1.165
1346     EXTEND (SP, 2);
1347     if (GIMME_V == G_SCALAR)
1348     PUSHs (sv_2mortal (newSViv (index + trailing)));
1349     else
1350     {
1351     PUSHs (sv_2mortal (newSViv (index)));
1352     PUSHs (sv_2mortal (newSViv (trailing)));
1353     }
1354     }
1355    
1356     void
1357 root 1.242 render (DC::Layout self, float x, float y, int flags = 0)
1358 root 1.225 CODE:
1359     rc_clear (self->rc);
1360 root 1.124 pango_opengl_render_layout_subpixel (
1361     self->pl,
1362 root 1.225 self->rc,
1363 root 1.124 x * PANGO_SCALE, y * PANGO_SCALE,
1364 root 1.135 self->r, self->g, self->b, self->a,
1365     flags
1366 root 1.124 );
1367 root 1.225 // we assume that context_change actually clears/frees stuff
1368     // and does not do any recomputation...
1369     pango_layout_context_changed (self->pl);
1370    
1371     void
1372 root 1.242 draw (DC::Layout self)
1373 root 1.225 CODE:
1374     {
1375     glEnable (GL_TEXTURE_2D);
1376     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1377     glEnable (GL_BLEND);
1378     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1379     GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1380     glEnable (GL_ALPHA_TEST);
1381     glAlphaFunc (GL_GREATER, 7.f / 255.f);
1382    
1383     rc_draw (self->rc);
1384    
1385     glDisable (GL_ALPHA_TEST);
1386     glDisable (GL_BLEND);
1387     glDisable (GL_TEXTURE_2D);
1388     }
1389 root 1.11
1390 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Texture
1391 root 1.11
1392 root 1.205 PROTOTYPES: ENABLE
1393    
1394 root 1.11 void
1395 root 1.203 pad (SV *data_, int ow, int oh, int nw, int nh)
1396 root 1.113 CODE:
1397     {
1398 root 1.203 if ((nw != ow || nh != oh) && SvOK (data_))
1399 root 1.113 {
1400 root 1.203 STRLEN datalen;
1401     char *data = SvPVbyte (data_, datalen);
1402     int bpp = datalen / (ow * oh);
1403     SV *result_ = sv_2mortal (newSV (nw * nh * bpp));
1404    
1405     SvPOK_only (result_);
1406     SvCUR_set (result_, nw * nh * bpp);
1407    
1408     memset (SvPVX (result_), 0, nw * nh * bpp);
1409     while (oh--)
1410     memcpy (SvPVX (result_) + oh * nw * bpp, data + oh * ow * bpp, ow * bpp);
1411 root 1.113
1412 root 1.203 sv_setsv (data_, result_);
1413 root 1.113 }
1414     }
1415    
1416     void
1417 root 1.114 draw_quad (SV *self, float x, float y, float w = 0., float h = 0.)
1418 root 1.12 PROTOTYPE: $$$;$$
1419 root 1.76 ALIAS:
1420     draw_quad_alpha = 1
1421     draw_quad_alpha_premultiplied = 2
1422 root 1.11 CODE:
1423     {
1424 root 1.12 HV *hv = (HV *)SvRV (self);
1425 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
1426     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
1427 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
1428    
1429 root 1.219 if (name <= 0)
1430     XSRETURN_EMPTY;
1431    
1432 root 1.12 if (items < 5)
1433     {
1434 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1435     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1436 root 1.12 }
1437    
1438 root 1.76 if (ix)
1439     {
1440     glEnable (GL_BLEND);
1441 root 1.103
1442     if (ix == 2)
1443     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1444     else
1445     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1446 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1447 root 1.103
1448 root 1.86 glEnable (GL_ALPHA_TEST);
1449     glAlphaFunc (GL_GREATER, 0.01f);
1450 root 1.76 }
1451    
1452 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1453 root 1.76
1454 root 1.12 glBegin (GL_QUADS);
1455 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1456     glTexCoord2f (0, t); glVertex2f (x , y + h);
1457     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1458     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1459 root 1.12 glEnd ();
1460 root 1.76
1461     if (ix)
1462 root 1.86 {
1463     glDisable (GL_ALPHA_TEST);
1464     glDisable (GL_BLEND);
1465     }
1466 root 1.11 }
1467 root 1.28
1468 root 1.199 IV texture_valid_2d (GLint internalformat, GLsizei w, GLsizei h, GLenum format, GLenum type)
1469     CODE:
1470     {
1471     GLint width;
1472     glTexImage2D (GL_PROXY_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, 0);
1473     glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
1474     RETVAL = width > 0;
1475     }
1476     OUTPUT:
1477     RETVAL
1478    
1479 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Map
1480 root 1.28
1481 root 1.205 PROTOTYPES: DISABLE
1482    
1483 root 1.242 DC::Map
1484 root 1.164 new (SV *class)
1485 root 1.28 CODE:
1486     New (0, RETVAL, 1, struct map);
1487 root 1.42 RETVAL->x = 0;
1488     RETVAL->y = 0;
1489 root 1.164 RETVAL->w = 0;
1490     RETVAL->h = 0;
1491 root 1.42 RETVAL->ox = 0;
1492     RETVAL->oy = 0;
1493 root 1.174 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1494     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1495 root 1.28 RETVAL->rows = 0;
1496     RETVAL->row = 0;
1497     OUTPUT:
1498     RETVAL
1499    
1500     void
1501 root 1.242 DESTROY (DC::Map self)
1502 root 1.28 CODE:
1503     {
1504 root 1.30 map_clear (self);
1505 root 1.174 Safefree (self->face2tile);
1506 root 1.111 Safefree (self->tex);
1507 root 1.29 Safefree (self);
1508     }
1509    
1510     void
1511 root 1.242 resize (DC::Map self, int map_width, int map_height)
1512 root 1.164 CODE:
1513     self->w = map_width;
1514     self->h = map_height;
1515    
1516     void
1517 root 1.242 clear (DC::Map self)
1518 root 1.30 CODE:
1519     map_clear (self);
1520    
1521     void
1522 root 1.242 set_tileid (DC::Map self, int face, int tile)
1523 root 1.29 CODE:
1524     {
1525 root 1.174 need_facenum (self, face); self->face2tile [face] = tile;
1526     need_texid (self, tile);
1527 root 1.42 }
1528    
1529     void
1530 root 1.242 set_smooth (DC::Map self, int face, int smooth, int level)
1531 root 1.176 CODE:
1532     {
1533     tileid texid;
1534     maptex *tex;
1535    
1536     if (face < 0 || face >= self->faces)
1537     return;
1538    
1539     if (smooth < 0 || smooth >= self->faces)
1540     return;
1541    
1542     texid = self->face2tile [face];
1543    
1544     if (!texid)
1545     return;
1546    
1547     tex = self->tex + texid;
1548     tex->smoothtile = self->face2tile [smooth];
1549     tex->smoothlevel = level;
1550     }
1551    
1552     void
1553 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)
1554 root 1.42 CODE:
1555     {
1556 root 1.174 need_texid (self, texid);
1557 root 1.42
1558 root 1.48 {
1559     maptex *tex = self->tex + texid;
1560 root 1.39
1561 root 1.48 tex->name = name;
1562     tex->w = w;
1563     tex->h = h;
1564     tex->s = s;
1565     tex->t = t;
1566     tex->r = r;
1567     tex->g = g;
1568     tex->b = b;
1569     tex->a = a;
1570     }
1571 root 1.95
1572     // somewhat hackish, but for textures that require it, it really
1573     // improves the look, and most others don't suffer.
1574     glBindTexture (GL_TEXTURE_2D, name);
1575 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1576     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1577     // use uglier nearest interpolation because linear suffers
1578     // from transparent color bleeding and ugly wrapping effects.
1579     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1580 root 1.29 }
1581    
1582 root 1.42 int
1583 root 1.242 ox (DC::Map self)
1584 root 1.42 ALIAS:
1585     oy = 1
1586 root 1.101 x = 2
1587     y = 3
1588 root 1.102 w = 4
1589     h = 5
1590 root 1.42 CODE:
1591     switch (ix)
1592     {
1593     case 0: RETVAL = self->ox; break;
1594     case 1: RETVAL = self->oy; break;
1595 root 1.101 case 2: RETVAL = self->x; break;
1596     case 3: RETVAL = self->y; break;
1597 root 1.102 case 4: RETVAL = self->w; break;
1598     case 5: RETVAL = self->h; break;
1599 root 1.42 }
1600     OUTPUT:
1601     RETVAL
1602    
1603 root 1.29 void
1604 root 1.242 scroll (DC::Map self, int dx, int dy)
1605 root 1.43 CODE:
1606     {
1607 root 1.44 if (dx > 0)
1608 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
1609 root 1.44 else if (dx < 0)
1610 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
1611 root 1.44
1612     if (dy > 0)
1613 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
1614 root 1.44 else if (dy < 0)
1615 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
1616 root 1.43
1617 root 1.44 self->ox += dx; self->x += dx;
1618     self->oy += dy; self->y += dy;
1619 root 1.43
1620     while (self->y < 0)
1621     {
1622     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1623    
1624     self->rows += MAP_EXTEND_Y;
1625     self->y += MAP_EXTEND_Y;
1626     }
1627 root 1.44 }
1628 root 1.43
1629 root 1.221 SV *
1630 root 1.242 map1a_update (DC::Map self, SV *data_, int extmap)
1631 root 1.44 CODE:
1632     {
1633 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1634     uint8_t *data_end = (uint8_t *)SvEND (data_);
1635 root 1.48 mapcell *cell;
1636 root 1.221 int x, y, z, flags;
1637     AV *missing = newAV ();
1638     RETVAL = newRV_noinc ((SV *)missing);
1639 root 1.43
1640 root 1.150 while (data < data_end - 1)
1641 root 1.29 {
1642 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1643 root 1.30
1644 root 1.120 x = self->x + ((flags >> 10) & 63);
1645     y = self->y + ((flags >> 4) & 63);
1646 root 1.29
1647 root 1.48 cell = map_get_cell (self, x, y);
1648 root 1.29
1649     if (flags & 15)
1650     {
1651 root 1.142 if (!cell->darkness)
1652 root 1.29 {
1653 root 1.154 memset (cell, 0, sizeof (*cell));
1654 root 1.142 cell->darkness = 256;
1655 root 1.29 }
1656 root 1.45
1657 root 1.142 //TODO: don't trust server data to be in-range(!)
1658    
1659 root 1.141 if (flags & 8)
1660     {
1661     if (extmap)
1662     {
1663     uint8_t ext, cmd;
1664    
1665     do
1666     {
1667     ext = *data++;
1668 root 1.144 cmd = ext & 0x3f;
1669 root 1.141
1670 root 1.147 if (cmd < 4)
1671 root 1.142 cell->darkness = 255 - ext * 64 + 1;
1672 root 1.147 else if (cmd == 5) // health
1673     {
1674     cell->stat_width = 1;
1675     cell->stat_hp = *data++;
1676     }
1677     else if (cmd == 6) // monster width
1678     cell->stat_width = *data++ + 1;
1679 root 1.169 else if (cmd == 0x47)
1680 root 1.153 {
1681 root 1.182 if (*data == 4)
1682     ; // decode player count
1683 root 1.153
1684     data += *data + 1;
1685     }
1686     else if (cmd == 8) // cell flags
1687     cell->flags = *data++;
1688 root 1.144 else if (ext & 0x40) // unknown, multibyte => skip
1689     data += *data + 1;
1690 root 1.147 else
1691     data++;
1692 root 1.141 }
1693 root 1.147 while (ext & 0x80);
1694 root 1.141 }
1695     else
1696 root 1.142 cell->darkness = *data++ + 1;
1697 root 1.141 }
1698 root 1.29
1699 root 1.221 for (z = 0; z <= 2; ++z)
1700     if (flags & (4 >> z))
1701     {
1702     faceid face = (data [0] << 8) + data [1]; data += 2;
1703     need_facenum (self, face);
1704     cell->tile [z] = self->face2tile [face];
1705 root 1.29
1706 root 1.221 if (cell->tile [z])
1707     {
1708     maptex *tex = self->tex + cell->tile [z];
1709     if (!tex->name)
1710     av_push (missing, newSViv (cell->tile [z]));
1711 root 1.29
1712 root 1.221 if (tex->smoothtile)
1713     {
1714     maptex *smooth = self->tex + tex->smoothtile;
1715     if (!smooth->name)
1716     av_push (missing, newSViv (tex->smoothtile));
1717     }
1718     }
1719     }
1720 root 1.29 }
1721     else
1722 root 1.155 cell->darkness = 0;
1723 root 1.29 }
1724 root 1.28 }
1725 root 1.221 OUTPUT:
1726     RETVAL
1727 root 1.28
1728 root 1.40 SV *
1729 root 1.242 mapmap (DC::Map self, int x0, int y0, int w, int h)
1730 root 1.40 CODE:
1731     {
1732 root 1.55 int x1, x;
1733     int y1, y;
1734 root 1.40 int z;
1735     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1736     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1737    
1738     SvPOK_only (map_sv);
1739     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1740    
1741 root 1.55 x0 += self->x; x1 = x0 + w;
1742     y0 += self->y; y1 = y0 + h;
1743 root 1.40
1744     for (y = y0; y < y1; y++)
1745     {
1746     maprow *row = 0 <= y && y < self->rows
1747     ? self->row + y
1748     : 0;
1749    
1750     for (x = x0; x < x1; x++)
1751     {
1752     int r = 32, g = 32, b = 32, a = 192;
1753    
1754     if (row && row->c0 <= x && x < row->c1)
1755     {
1756     mapcell *cell = row->col + (x - row->c0);
1757    
1758     for (z = 0; z <= 0; z++)
1759     {
1760 root 1.174 maptex tex = self->tex [cell->tile [z]];
1761     int a0 = 255 - tex.a;
1762     int a1 = tex.a;
1763    
1764     r = (r * a0 + tex.r * a1) / 255;
1765     g = (g * a0 + tex.g * a1) / 255;
1766     b = (b * a0 + tex.b * a1) / 255;
1767     a = (a * a0 + tex.a * a1) / 255;
1768 root 1.40 }
1769     }
1770    
1771     *map++ = (r )
1772     | (g << 8)
1773     | (b << 16)
1774     | (a << 24);
1775     }
1776     }
1777    
1778     RETVAL = map_sv;
1779     }
1780     OUTPUT:
1781     RETVAL
1782    
1783 root 1.221 void
1784 root 1.242 draw (DC::Map self, int mx, int my, int sw, int sh, int T)
1785 root 1.116 CODE:
1786 root 1.30 {
1787 root 1.223 int x, y, z;
1788    
1789 root 1.176 HV *smooth = (HV *)sv_2mortal ((SV *)newHV ());
1790     uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level
1791 root 1.226 static uint8_t smooth_max[256][256]; // egad, fast and wasteful on memory (64k)
1792 root 1.176 smooth_key skey;
1793 root 1.223
1794     rc_t *rc = rc_alloc ();
1795     rc_key_t key;
1796     rc_array_t *arr;
1797 root 1.48
1798 root 1.176 // thats current max. sorry.
1799     if (sw > 255) sw = 255;
1800     if (sh > 255) sh = 255;
1801    
1802     // clear key, in case of extra padding
1803     memset (&skey, 0, sizeof (skey));
1804    
1805 root 1.223 memset (&key, 0, sizeof (key));
1806     key.r = 255;
1807     key.g = 255;
1808     key.b = 255;
1809     key.a = 255;
1810     key.mode = GL_QUADS;
1811     key.format = GL_T2F_V3F;
1812     key.texname = -1;
1813 root 1.30
1814 root 1.164 mx += self->x;
1815     my += self->y;
1816    
1817 root 1.176 // first pass: determine smooth_max
1818     // rather ugly, if you ask me
1819     // could also be stored inside mapcell and updated on change
1820     memset (smooth_max, 0, sizeof (smooth_max));
1821    
1822     for (y = 0; y < sh; y++)
1823     if (0 <= y + my && y + my < self->rows)
1824     {
1825     maprow *row = self->row + (y + my);
1826    
1827     for (x = 0; x < sw; x++)
1828     if (row->c0 <= x + mx && x + mx < row->c1)
1829     {
1830     mapcell *cell = row->col + (x + mx - row->c0);
1831    
1832 root 1.177 smooth_max[x + 1][y + 1] =
1833     MAX (self->tex [cell->tile [0]].smoothlevel,
1834     MAX (self->tex [cell->tile [1]].smoothlevel,
1835     self->tex [cell->tile [2]].smoothlevel));
1836 root 1.176 }
1837     }
1838    
1839 root 1.223 glEnable (GL_BLEND);
1840     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1841     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1842    
1843 root 1.176 for (z = 0; z <= 2; z++)
1844     {
1845 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
1846    
1847 root 1.176 for (y = 0; y < sh; y++)
1848     if (0 <= y + my && y + my < self->rows)
1849     {
1850     maprow *row = self->row + (y + my);
1851    
1852     for (x = 0; x < sw; x++)
1853     if (row->c0 <= x + mx && x + mx < row->c1)
1854     {
1855     mapcell *cell = row->col + (x + mx - row->c0);
1856     tileid tile = cell->tile [z];
1857    
1858     if (tile)
1859     {
1860     maptex tex = self->tex [tile];
1861 root 1.219 int px, py;
1862 root 1.176
1863 root 1.223 if (key.texname != tex.name)
1864 root 1.176 {
1865     if (!tex.name)
1866 root 1.221 tex = self->tex [2]; /* missing, replace by noface */
1867 root 1.176
1868 root 1.223 key.texname = tex.name;
1869     arr = rc_array (rc, &key);
1870 root 1.176 }
1871    
1872 root 1.219 px = (x + 1) * T - tex.w;
1873     py = (y + 1) * T - tex.h;
1874    
1875 root 1.223 rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
1876     rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0);
1877     rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0);
1878     rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0);
1879 root 1.176
1880     if (cell->flags && z == 2)
1881     {
1882 root 1.223 // overlays such as the speech bubble, probably more to come
1883 root 1.176 if (cell->flags & 1)
1884     {
1885     maptex tex = self->tex [1];
1886     int px = x * T + T * 2 / 32;
1887     int py = y * T - T * 6 / 32;
1888    
1889 root 1.223 if (tex.name)
1890     {
1891     if (key.texname != tex.name)
1892     {
1893     key.texname = tex.name;
1894     arr = rc_array (rc, &key);
1895     }
1896    
1897     rc_t2f_v3f (arr, 0 , 0 , px , py , 0);
1898     rc_t2f_v3f (arr, 0 , tex.t, px , py + T, 0);
1899     rc_t2f_v3f (arr, tex.s, tex.t, px + T, py + T, 0);
1900     rc_t2f_v3f (arr, tex.s, 0 , px + T, py , 0);
1901     }
1902 root 1.176 }
1903     }
1904    
1905     // update smooth hash
1906     if (tex.smoothtile)
1907     {
1908     skey.tile = tex.smoothtile;
1909     skey.level = tex.smoothlevel;
1910    
1911     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
1912 root 1.30
1913 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
1914     // shifted +1|+1 so we always stay positive.
1915 root 1.30
1916 root 1.180 // bits is ___n cccc CCCC bbbb
1917     // n do not draw borders&corners
1918     // c draw these corners, but...
1919     // C ... not these
1920     // b draw these borders
1921    
1922     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
1923     // ┃· ·· ·┃ ━━
1924    
1925     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
1926     // ·· ·· ·┏ ┓·
1927    
1928 root 1.176 // full tile
1929     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
1930    
1931     // borders
1932 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
1933     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
1934 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
1935     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
1936    
1937     // corners
1938     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
1939     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
1940     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
1941     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
1942     }
1943     }
1944     }
1945     }
1946 root 1.174
1947 root 1.224 rc_draw (rc);
1948     rc_clear (rc);
1949    
1950 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
1951     // this is basically counting sort
1952 root 1.176 {
1953 root 1.186 int w, b;
1954 root 1.30
1955 root 1.226 glEnable (GL_TEXTURE_2D);
1956     glBegin (GL_QUADS);
1957 root 1.186 for (w = 0; w < 256 / 32; ++w)
1958     {
1959     uint32_t smask = smooth_level [w];
1960     if (smask)
1961     for (b = 0; b < 32; ++b)
1962     if (smask & (((uint32_t)1) << b))
1963 root 1.176 {
1964 root 1.186 int level = (w << 5) | b;
1965     HE *he;
1966 root 1.153
1967 root 1.186 hv_iterinit (smooth);
1968     while ((he = hv_iternext (smooth)))
1969 root 1.153 {
1970 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
1971     IV bits = SvIVX (HeVAL (he));
1972 root 1.176
1973 root 1.186 if (!(bits & 0x1000)
1974     && skey->level == level
1975 root 1.191 && level > smooth_max [skey->x][skey->y])
1976 root 1.174 {
1977 root 1.186 maptex tex = self->tex [skey->tile];
1978     int px = (((int)skey->x) - 1) * T;
1979     int py = (((int)skey->y) - 1) * T;
1980     int border = bits & 15;
1981     int corner = (bits >> 8) & ~(bits >> 4) & 15;
1982     float dx = tex.s * .0625f; // 16 images/row
1983     float dy = tex.t * .5f ; // 2 images/column
1984    
1985 root 1.223 if (tex.name)
1986 root 1.186 {
1987 root 1.223 // this time avoiding texture state changes
1988     // save gobs of state changes.
1989     if (key.texname != tex.name)
1990     {
1991 root 1.226 glEnd ();
1992     glBindTexture (GL_TEXTURE_2D, key.texname = tex.name);
1993     glBegin (GL_QUADS);
1994 root 1.223 }
1995    
1996     if (border)
1997     {
1998     float ox = border * dx;
1999    
2000 root 1.226 glTexCoord2f (ox , 0.f ); glVertex2i (px , py );
2001     glTexCoord2f (ox , dy ); glVertex2i (px , py + T);
2002     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py + T);
2003     glTexCoord2f (ox + dx, 0.f ); glVertex2i (px + T, py );
2004 root 1.223 }
2005    
2006     if (corner)
2007     {
2008     float ox = corner * dx;
2009    
2010 root 1.226 glTexCoord2f (ox , dy ); glVertex2i (px , py );
2011     glTexCoord2f (ox , dy * 2.f); glVertex2i (px , py + T);
2012     glTexCoord2f (ox + dx, dy * 2.f); glVertex2i (px + T, py + T);
2013     glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py );
2014 root 1.223 }
2015 root 1.186 }
2016 root 1.174 }
2017 root 1.153 }
2018     }
2019 root 1.186 }
2020 root 1.226
2021     glEnd ();
2022     glDisable (GL_TEXTURE_2D);
2023     key.texname = -1;
2024 root 1.176 }
2025    
2026 root 1.186 hv_clear (smooth);
2027     }
2028 root 1.30
2029 root 1.152 glDisable (GL_BLEND);
2030 root 1.223 rc_free (rc);
2031 root 1.143
2032 root 1.145 // top layer: overlays such as the health bar
2033 root 1.143 for (y = 0; y < sh; y++)
2034 root 1.164 if (0 <= y + my && y + my < self->rows)
2035 root 1.143 {
2036 root 1.164 maprow *row = self->row + (y + my);
2037 root 1.143
2038     for (x = 0; x < sw; x++)
2039 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2040 root 1.143 {
2041 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2042 root 1.143
2043 root 1.171 int px = x * T;
2044     int py = y * T;
2045 root 1.143
2046     if (cell->stat_hp)
2047     {
2048 root 1.171 int width = cell->stat_width * T;
2049 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
2050 root 1.143
2051 root 1.152 glColor3ub (0, 0, 0);
2052 root 1.151 glRectf (px + 1, py - thick - 2,
2053     px + width - 1, py);
2054 root 1.147
2055 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
2056 root 1.147 glRectf (px + 2,
2057 root 1.151 py - thick - 1,
2058     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
2059 root 1.143 }
2060     }
2061     }
2062 root 1.116 }
2063    
2064     void
2065 root 1.242 draw_magicmap (DC::Map self, int dx, int dy, int w, int h, unsigned char *data)
2066 root 1.117 CODE:
2067     {
2068     static float color[16][3] = {
2069 root 1.123 { 0.00F, 0.00F, 0.00F },
2070     { 1.00F, 1.00F, 1.00F },
2071     { 0.00F, 0.00F, 0.55F },
2072     { 1.00F, 0.00F, 0.00F },
2073    
2074     { 1.00F, 0.54F, 0.00F },
2075     { 0.11F, 0.56F, 1.00F },
2076     { 0.93F, 0.46F, 0.00F },
2077     { 0.18F, 0.54F, 0.34F },
2078    
2079     { 0.56F, 0.73F, 0.56F },
2080     { 0.80F, 0.80F, 0.80F },
2081     { 0.55F, 0.41F, 0.13F },
2082     { 0.99F, 0.77F, 0.26F },
2083    
2084     { 0.74F, 0.65F, 0.41F },
2085    
2086     { 0.00F, 1.00F, 1.00F },
2087     { 1.00F, 0.00F, 1.00F },
2088     { 1.00F, 1.00F, 0.00F },
2089 root 1.117 };
2090    
2091     int x, y;
2092    
2093     glEnable (GL_TEXTURE_2D);
2094     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2095     glEnable (GL_BLEND);
2096     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2097     glBegin (GL_QUADS);
2098    
2099     for (y = 0; y < h; y++)
2100     for (x = 0; x < w; x++)
2101     {
2102     unsigned char m = data [x + y * w];
2103    
2104 root 1.118 if (m)
2105     {
2106     float *c = color [m & 15];
2107    
2108     float tx1 = m & 0x40 ? 0.5 : 0.;
2109     float tx2 = tx1 + 0.5;
2110    
2111     glColor4f (c[0], c[1], c[2], 0.75);
2112     glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2113     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2114     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2115     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2116     }
2117 root 1.117 }
2118    
2119     glEnd ();
2120     glDisable (GL_BLEND);
2121     glDisable (GL_TEXTURE_2D);
2122     }
2123    
2124     void
2125 root 1.242 fow_texture (DC::Map self, int mx, int my, int sw, int sh)
2126 root 1.116 PPCODE:
2127     {
2128     int x, y;
2129 root 1.204 int sw1 = sw + 2;
2130     int sh1 = sh + 2;
2131     int sh3 = sh * 3;
2132     int sw34 = (sw * 3 + 3) & ~3;
2133     uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2134     SV *darkness3_sv = sv_2mortal (newSV (sw34 * sh3));
2135     uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2136    
2137     SvPOK_only (darkness3_sv);
2138     SvCUR_set (darkness3_sv, sw34 * sh3);
2139 root 1.116
2140 root 1.204 mx += self->x - 1;
2141     my += self->y - 1;
2142 root 1.116
2143 root 1.204 memset (darkness1, 255, sw1 * sh1);
2144    
2145     for (y = 0; y < sh1; y++)
2146 root 1.164 if (0 <= y + my && y + my < self->rows)
2147 root 1.116 {
2148 root 1.164 maprow *row = self->row + (y + my);
2149 root 1.116
2150 root 1.204 for (x = 0; x < sw1; x++)
2151 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2152 root 1.116 {
2153 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2154 root 1.116
2155 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2156 root 1.143 ? 255 - (cell->darkness - 1)
2157 root 1.142 : 255 - FOW_DARKNESS;
2158 root 1.116 }
2159     }
2160 root 1.34
2161 root 1.204 for (y = 0; y < sh; ++y)
2162     for (x = 0; x < sw; ++x)
2163     {
2164     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2165     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2166     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2167     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2168     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2169     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2170     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2171     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2172     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2173    
2174     uint8_t r11 = (d11 + d21 + d12) / 3;
2175     uint8_t r21 = d21;
2176     uint8_t r31 = (d21 + d31 + d32) / 3;
2177    
2178     uint8_t r12 = d12;
2179     uint8_t r22 = d22;
2180     uint8_t r32 = d32;
2181    
2182     uint8_t r13 = (d13 + d23 + d12) / 3;
2183     uint8_t r23 = d23;
2184     uint8_t r33 = (d23 + d33 + d32) / 3;
2185    
2186     darkness3 [(y * 3 ) * sw34 + (x * 3 )] = MAX (d22, r11);
2187     darkness3 [(y * 3 ) * sw34 + (x * 3 + 1)] = MAX (d22, r21);
2188     darkness3 [(y * 3 ) * sw34 + (x * 3 + 2)] = MAX (d22, r31);
2189     darkness3 [(y * 3 + 1) * sw34 + (x * 3 )] = MAX (d22, r12);
2190     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 1)] = MAX (d22, r22);
2191     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 2)] = MAX (d22, r32);
2192     darkness3 [(y * 3 + 2) * sw34 + (x * 3 )] = MAX (d22, r13);
2193     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 1)] = MAX (d22, r23);
2194     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 2)] = MAX (d22, r33);
2195     }
2196 root 1.201
2197 root 1.204 free (darkness1);
2198 root 1.201
2199 root 1.32 EXTEND (SP, 3);
2200 root 1.204 PUSHs (sv_2mortal (newSViv (sw34)));
2201     PUSHs (sv_2mortal (newSViv (sh3)));
2202     PUSHs (darkness3_sv);
2203 root 1.30 }
2204    
2205 root 1.42 SV *
2206 root 1.242 get_rect (DC::Map self, int x0, int y0, int w, int h)
2207 root 1.42 CODE:
2208     {
2209     int x, y, x1, y1;
2210     SV *data_sv = newSV (w * h * 7 + 5);
2211     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2212    
2213     *data++ = 0; /* version 0 format */
2214     *data++ = w >> 8; *data++ = w;
2215     *data++ = h >> 8; *data++ = h;
2216    
2217     // we need to do this 'cause we don't keep an absolute coord system for rows
2218 root 1.55 // TODO: treat rows as we treat columns
2219 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2220     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2221    
2222     x0 += self->x - self->ox;
2223     y0 += self->y - self->oy;
2224    
2225     x1 = x0 + w;
2226     y1 = y0 + h;
2227    
2228     for (y = y0; y < y1; y++)
2229     {
2230     maprow *row = 0 <= y && y < self->rows
2231     ? self->row + y
2232     : 0;
2233    
2234     for (x = x0; x < x1; x++)
2235     {
2236     if (row && row->c0 <= x && x < row->c1)
2237     {
2238     mapcell *cell = row->col + (x - row->c0);
2239     uint8_t flags = 0;
2240    
2241 root 1.174 if (cell->tile [0]) flags |= 1;
2242     if (cell->tile [1]) flags |= 2;
2243     if (cell->tile [2]) flags |= 4;
2244 root 1.42
2245     *data++ = flags;
2246    
2247     if (flags & 1)
2248     {
2249 root 1.174 tileid tile = cell->tile [0];
2250     *data++ = tile >> 8;
2251     *data++ = tile;
2252 root 1.42 }
2253    
2254     if (flags & 2)
2255     {
2256 root 1.174 tileid tile = cell->tile [1];
2257     *data++ = tile >> 8;
2258     *data++ = tile;
2259 root 1.42 }
2260    
2261     if (flags & 4)
2262     {
2263 root 1.174 tileid tile = cell->tile [2];
2264     *data++ = tile >> 8;
2265     *data++ = tile;
2266 root 1.42 }
2267     }
2268     else
2269     *data++ = 0;
2270     }
2271     }
2272    
2273     SvPOK_only (data_sv);
2274     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2275     RETVAL = data_sv;
2276     }
2277     OUTPUT:
2278     RETVAL
2279    
2280     void
2281 root 1.242 set_rect (DC::Map self, int x0, int y0, uint8_t *data)
2282 root 1.42 PPCODE:
2283     {
2284     int x, y, z;
2285 root 1.48 int w, h;
2286 root 1.42 int x1, y1;
2287    
2288     if (*data++ != 0)
2289 root 1.227 XSRETURN_EMPTY; /* version mismatch */
2290 root 1.42
2291 root 1.48 w = *data++ << 8; w |= *data++;
2292     h = *data++ << 8; h |= *data++;
2293 root 1.42
2294     // we need to do this 'cause we don't keep an absolute coord system for rows
2295 root 1.55 // TODO: treat rows as we treat columns
2296 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2297     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2298    
2299     x0 += self->x - self->ox;
2300     y0 += self->y - self->oy;
2301    
2302     x1 = x0 + w;
2303     y1 = y0 + h;
2304    
2305     for (y = y0; y < y1; y++)
2306     {
2307     maprow *row = map_get_row (self, y);
2308    
2309     for (x = x0; x < x1; x++)
2310     {
2311     uint8_t flags = *data++;
2312    
2313     if (flags)
2314     {
2315     mapcell *cell = row_get_cell (row, x);
2316 root 1.174 tileid tile[3] = { 0, 0, 0 };
2317 root 1.42
2318 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2319     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2320     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2321 root 1.42
2322 root 1.143 if (cell->darkness == 0)
2323 root 1.42 {
2324 root 1.142 cell->darkness = 0;
2325 root 1.42
2326     for (z = 0; z <= 2; z++)
2327     {
2328 root 1.174 tileid t = tile [z];
2329    
2330 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2331 root 1.174 {
2332     XPUSHs (sv_2mortal (newSViv (t)));
2333     need_texid (self, t);
2334     }
2335 root 1.42
2336 root 1.174 cell->tile [z] = t;
2337 root 1.42 }
2338     }
2339     }
2340     }
2341     }
2342     }
2343    
2344 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::RW
2345 root 1.205
2346 root 1.242 DC::RW
2347 root 1.211 new (SV *class, SV *data_sv)
2348     CODE:
2349     {
2350     STRLEN datalen;
2351     char *data = SvPVbyte (data_sv, datalen);
2352    
2353 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2354 root 1.211 }
2355     OUTPUT:
2356     RETVAL
2357    
2358 root 1.242 DC::RW
2359 root 1.212 new_from_file (SV *class, const char *path, const char *mode = "rb")
2360     CODE:
2361     RETVAL = SDL_RWFromFile (path, mode);
2362     OUTPUT:
2363     RETVAL
2364    
2365 root 1.218 # fails on win32:
2366 root 1.241 # dc.xs(2268) : error C2059: syntax error : '('
2367 root 1.218 #void
2368 root 1.242 #close (DC::RW self)
2369 root 1.218 # CODE:
2370     # (self->(close)) (self);
2371 root 1.212
2372 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::Channel
2373 root 1.212
2374     PROTOTYPES: DISABLE
2375    
2376 root 1.242 DC::Channel
2377 root 1.215 find ()
2378     CODE:
2379     {
2380     RETVAL = Mix_GroupAvailable (-1);
2381    
2382     if (RETVAL < 0)
2383     {
2384     RETVAL = Mix_GroupOldest (-1);
2385    
2386     if (RETVAL < 0)
2387     XSRETURN_UNDEF;
2388    
2389     Mix_HaltChannel (RETVAL);
2390     }
2391    
2392     Mix_UnregisterAllEffects (RETVAL);
2393     Mix_Volume (RETVAL, 128);
2394     }
2395     OUTPUT:
2396     RETVAL
2397    
2398 root 1.213 void
2399 root 1.242 halt (DC::Channel self)
2400 root 1.213 CODE:
2401     Mix_HaltChannel (self);
2402    
2403     void
2404 root 1.242 expire (DC::Channel self, int ticks = -1)
2405 root 1.213 CODE:
2406     Mix_ExpireChannel (self, ticks);
2407    
2408     void
2409 root 1.242 fade_out (DC::Channel self, int ticks = -1)
2410 root 1.213 CODE:
2411     Mix_FadeOutChannel (self, ticks);
2412    
2413 root 1.212 int
2414 root 1.242 volume (DC::Channel self, int volume)
2415 root 1.212 CODE:
2416 root 1.216 RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128));
2417 root 1.212 OUTPUT:
2418     RETVAL
2419    
2420 root 1.213 void
2421 root 1.242 unregister_all_effects (DC::Channel self)
2422 root 1.212 CODE:
2423 root 1.213 Mix_UnregisterAllEffects (self);
2424 root 1.212
2425 root 1.213 void
2426 root 1.242 set_panning (DC::Channel self, int left, int right)
2427 root 1.212 CODE:
2428 root 1.216 left = CLAMP (left , 0, 255);
2429     right = CLAMP (right, 0, 255);
2430 root 1.213 Mix_SetPanning (self, left, right);
2431 root 1.212
2432 root 1.213 void
2433 root 1.242 set_distance (DC::Channel self, int distance)
2434 root 1.212 CODE:
2435 root 1.216 Mix_SetDistance (self, CLAMP (distance, 0, 255));
2436 root 1.212
2437 root 1.213 void
2438 root 1.242 set_position (DC::Channel self, int angle, int distance)
2439 root 1.212 CODE:
2440 root 1.220
2441     void
2442 root 1.242 set_position_r (DC::Channel self, int dx, int dy, int maxdistance)
2443 root 1.220 CODE:
2444     {
2445     int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance));
2446     int angle = 360 + (int)roundf (atan2f (dx, -dy) * 180.f / (float)M_PI);
2447 root 1.216 Mix_SetPosition (self, angle, CLAMP (distance, 0, 255));
2448 root 1.220 }
2449 root 1.212
2450 root 1.213 void
2451 root 1.242 set_reverse_stereo (DC::Channel self, int flip)
2452 root 1.212 CODE:
2453 root 1.213 Mix_SetReverseStereo (self, flip);
2454 root 1.212
2455 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixChunk
2456 root 1.212
2457     PROTOTYPES: DISABLE
2458    
2459 root 1.242 DC::MixChunk
2460     new (SV *class, DC::RW rwops)
2461 root 1.52 CODE:
2462 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2463 root 1.52 OUTPUT:
2464     RETVAL
2465    
2466     void
2467 root 1.242 DESTROY (DC::MixChunk self)
2468 root 1.52 CODE:
2469     Mix_FreeChunk (self);
2470    
2471     int
2472 root 1.242 volume (DC::MixChunk self, int volume = -1)
2473 root 1.52 CODE:
2474 root 1.216 if (items > 1)
2475     volume = CLAMP (volume, 0, 128);
2476 root 1.52 RETVAL = Mix_VolumeChunk (self, volume);
2477     OUTPUT:
2478     RETVAL
2479    
2480 root 1.242 DC::Channel
2481     play (DC::MixChunk self, DC::Channel channel = -1, int loops = 0, int ticks = -1)
2482 root 1.52 CODE:
2483 root 1.215 {
2484 root 1.52 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2485 root 1.215
2486     if (RETVAL < 0)
2487     XSRETURN_UNDEF;
2488    
2489     if (channel < 0)
2490     {
2491     Mix_UnregisterAllEffects (RETVAL);
2492     Mix_Volume (RETVAL, 128);
2493     }
2494     }
2495 root 1.52 OUTPUT:
2496     RETVAL
2497    
2498 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::MixMusic
2499 root 1.52
2500     int
2501     volume (int volume = -1)
2502 root 1.205 PROTOTYPE: ;$
2503 root 1.52 CODE:
2504 root 1.216 if (items > 0)
2505     volume = CLAMP (volume, 0, 128);
2506 root 1.52 RETVAL = Mix_VolumeMusic (volume);
2507     OUTPUT:
2508     RETVAL
2509    
2510 root 1.213 void
2511 root 1.194 fade_out (int ms)
2512     CODE:
2513 root 1.213 Mix_FadeOutMusic (ms);
2514 root 1.194
2515 root 1.212 void
2516     halt ()
2517     CODE:
2518     Mix_HaltMusic ();
2519    
2520 root 1.242 DC::MixMusic
2521     new (SV *class, DC::RW rwops)
2522 root 1.52 CODE:
2523 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
2524 root 1.52 OUTPUT:
2525     RETVAL
2526    
2527     void
2528 root 1.242 DESTROY (DC::MixMusic self)
2529 root 1.52 CODE:
2530     Mix_FreeMusic (self);
2531    
2532     int
2533 root 1.242 play (DC::MixMusic self, int loops = -1)
2534 root 1.52 CODE:
2535     RETVAL = Mix_PlayMusic (self, loops);
2536     OUTPUT:
2537     RETVAL
2538    
2539 root 1.213 void
2540 root 1.242 fade_in_pos (DC::MixMusic self, int loops, int ms, double position)
2541 root 1.195 CODE:
2542 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
2543 root 1.195
2544 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::OpenGL
2545 root 1.54
2546 root 1.205 PROTOTYPES: ENABLE
2547    
2548 root 1.54 BOOT:
2549     {
2550 root 1.242 HV *stash = gv_stashpv ("DC::OpenGL", 1);
2551 root 1.54 static const struct {
2552     const char *name;
2553     IV iv;
2554     } *civ, const_iv[] = {
2555     # define const_iv(name) { # name, (IV)name }
2556 root 1.199 const_iv (GL_VENDOR),
2557     const_iv (GL_VERSION),
2558     const_iv (GL_EXTENSIONS),
2559 root 1.54 const_iv (GL_COLOR_MATERIAL),
2560     const_iv (GL_SMOOTH),
2561     const_iv (GL_FLAT),
2562 root 1.69 const_iv (GL_DITHER),
2563 root 1.54 const_iv (GL_BLEND),
2564 root 1.89 const_iv (GL_CULL_FACE),
2565 root 1.69 const_iv (GL_SCISSOR_TEST),
2566 root 1.89 const_iv (GL_DEPTH_TEST),
2567     const_iv (GL_ALPHA_TEST),
2568     const_iv (GL_NORMALIZE),
2569     const_iv (GL_RESCALE_NORMAL),
2570 root 1.119 const_iv (GL_FRONT),
2571     const_iv (GL_BACK),
2572 root 1.206 const_iv (GL_AUX0),
2573 root 1.54 const_iv (GL_AND),
2574 root 1.67 const_iv (GL_ONE),
2575     const_iv (GL_ZERO),
2576 root 1.54 const_iv (GL_SRC_ALPHA),
2577 root 1.104 const_iv (GL_DST_ALPHA),
2578 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2579 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2580 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2581 root 1.54 const_iv (GL_RGB),
2582     const_iv (GL_RGBA),
2583 root 1.115 const_iv (GL_RGBA4),
2584     const_iv (GL_RGBA8),
2585     const_iv (GL_RGB5_A1),
2586 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2587 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2588     const_iv (GL_UNSIGNED_INT),
2589 root 1.54 const_iv (GL_ALPHA),
2590 root 1.86 const_iv (GL_INTENSITY),
2591 root 1.76 const_iv (GL_LUMINANCE),
2592 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2593 root 1.54 const_iv (GL_FLOAT),
2594     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2595 root 1.230 const_iv (GL_COMPRESSED_ALPHA_ARB),
2596     const_iv (GL_COMPRESSED_LUMINANCE_ARB),
2597     const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB),
2598     const_iv (GL_COMPRESSED_INTENSITY_ARB),
2599     const_iv (GL_COMPRESSED_RGB_ARB),
2600     const_iv (GL_COMPRESSED_RGBA_ARB),
2601 root 1.54 const_iv (GL_COMPILE),
2602 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
2603     const_iv (GL_PROXY_TEXTURE_2D),
2604 root 1.54 const_iv (GL_TEXTURE_1D),
2605     const_iv (GL_TEXTURE_2D),
2606     const_iv (GL_TEXTURE_ENV),
2607     const_iv (GL_TEXTURE_MAG_FILTER),
2608     const_iv (GL_TEXTURE_MIN_FILTER),
2609     const_iv (GL_TEXTURE_ENV_MODE),
2610     const_iv (GL_TEXTURE_WRAP_S),
2611     const_iv (GL_TEXTURE_WRAP_T),
2612 root 1.98 const_iv (GL_REPEAT),
2613 root 1.54 const_iv (GL_CLAMP),
2614 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2615 root 1.54 const_iv (GL_NEAREST),
2616     const_iv (GL_LINEAR),
2617 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2618     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2619     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2620     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2621     const_iv (GL_GENERATE_MIPMAP),
2622 root 1.54 const_iv (GL_MODULATE),
2623 root 1.69 const_iv (GL_DECAL),
2624 root 1.54 const_iv (GL_REPLACE),
2625 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2626 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2627     const_iv (GL_PROJECTION),
2628     const_iv (GL_MODELVIEW),
2629     const_iv (GL_COLOR_LOGIC_OP),
2630 root 1.69 const_iv (GL_SEPARABLE_2D),
2631 root 1.54 const_iv (GL_CONVOLUTION_2D),
2632     const_iv (GL_CONVOLUTION_BORDER_MODE),
2633     const_iv (GL_CONSTANT_BORDER),
2634 root 1.208 const_iv (GL_POINTS),
2635 root 1.54 const_iv (GL_LINES),
2636 root 1.138 const_iv (GL_LINE_STRIP),
2637 root 1.89 const_iv (GL_LINE_LOOP),
2638 root 1.54 const_iv (GL_QUADS),
2639 root 1.89 const_iv (GL_QUAD_STRIP),
2640     const_iv (GL_TRIANGLES),
2641     const_iv (GL_TRIANGLE_STRIP),
2642     const_iv (GL_TRIANGLE_FAN),
2643 root 1.208 const_iv (GL_POLYGON),
2644 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2645 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
2646     const_iv (GL_LINE_SMOOTH_HINT),
2647     const_iv (GL_POLYGON_SMOOTH_HINT),
2648     const_iv (GL_GENERATE_MIPMAP_HINT),
2649 root 1.232 const_iv (GL_TEXTURE_COMPRESSION_HINT),
2650 root 1.54 const_iv (GL_FASTEST),
2651 root 1.206 const_iv (GL_DONT_CARE),
2652     const_iv (GL_NICEST),
2653 root 1.89 const_iv (GL_V2F),
2654     const_iv (GL_V3F),
2655     const_iv (GL_T2F_V3F),
2656     const_iv (GL_T2F_N3F_V3F),
2657 root 1.54 # undef const_iv
2658     };
2659    
2660     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2661     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2662 root 1.188
2663     texture_av = newAV ();
2664     AvREAL_off (texture_av);
2665 root 1.54 }
2666    
2667 root 1.231 void
2668     disable_GL_EXT_blend_func_separate ()
2669     CODE:
2670     gl.BlendFuncSeparate = 0;
2671     gl.BlendFuncSeparateEXT = 0;
2672    
2673 root 1.97 char *
2674     gl_vendor ()
2675     CODE:
2676     RETVAL = (char *)glGetString (GL_VENDOR);
2677     OUTPUT:
2678     RETVAL
2679    
2680     char *
2681     gl_version ()
2682     CODE:
2683     RETVAL = (char *)glGetString (GL_VERSION);
2684     OUTPUT:
2685     RETVAL
2686    
2687     char *
2688     gl_extensions ()
2689     CODE:
2690     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2691     OUTPUT:
2692     RETVAL
2693    
2694 root 1.201 const char *glGetString (GLenum pname)
2695 root 1.199
2696     GLint glGetInteger (GLenum pname)
2697     CODE:
2698     glGetIntegerv (pname, &RETVAL);
2699     OUTPUT:
2700     RETVAL
2701    
2702     GLdouble glGetDouble (GLenum pname)
2703     CODE:
2704     glGetDoublev (pname, &RETVAL);
2705     OUTPUT:
2706     RETVAL
2707    
2708 root 1.54 int glGetError ()
2709    
2710 root 1.114 void glFinish ()
2711    
2712 root 1.54 void glClear (int mask)
2713    
2714     void glClearColor (float r, float g, float b, float a = 1.0)
2715     PROTOTYPE: @
2716    
2717     void glEnable (int cap)
2718    
2719     void glDisable (int cap)
2720    
2721     void glShadeModel (int mode)
2722    
2723     void glHint (int target, int mode)
2724    
2725     void glBlendFunc (int sfactor, int dfactor)
2726    
2727 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
2728     CODE:
2729     gl_BlendFuncSeparate (sa, da, saa, daa);
2730    
2731 root 1.89 void glDepthMask (int flag)
2732    
2733 root 1.54 void glLogicOp (int opcode)
2734    
2735 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
2736    
2737 root 1.54 void glMatrixMode (int mode)
2738    
2739     void glPushMatrix ()
2740    
2741     void glPopMatrix ()
2742    
2743     void glLoadIdentity ()
2744    
2745 root 1.119 void glDrawBuffer (int buffer)
2746    
2747     void glReadBuffer (int buffer)
2748    
2749 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
2750     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
2751    
2752     # near_ and far_ are due to microsofts buggy "c" compiler
2753 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
2754 root 1.54
2755 root 1.208 PROTOTYPES: DISABLE
2756    
2757 root 1.54 void glViewport (int x, int y, int width, int height)
2758    
2759 root 1.69 void glScissor (int x, int y, int width, int height)
2760    
2761 root 1.54 void glTranslate (float x, float y, float z = 0.)
2762     CODE:
2763     glTranslatef (x, y, z);
2764    
2765 root 1.62 void glScale (float x, float y, float z = 1.)
2766 root 1.54 CODE:
2767     glScalef (x, y, z);
2768    
2769     void glRotate (float angle, float x, float y, float z)
2770     CODE:
2771     glRotatef (angle, x, y, z);
2772    
2773     void glColor (float r, float g, float b, float a = 1.0)
2774 root 1.103 ALIAS:
2775     glColor_premultiply = 1
2776 root 1.54 CODE:
2777 root 1.103 if (ix)
2778     {
2779     r *= a;
2780     g *= a;
2781     b *= a;
2782     }
2783 root 1.90 // microsoft visual "c" rounds instead of truncating...
2784 root 1.130 glColor4f (r, g, b, a);
2785 root 1.54
2786 root 1.91 void glRasterPos (float x, float y, float z = 0.)
2787     CODE:
2788     glRasterPos3f (0, 0, z);
2789     glBitmap (0, 0, 0, 0, x, y, 0);
2790    
2791 root 1.54 void glVertex (float x, float y, float z = 0.)
2792     CODE:
2793     glVertex3f (x, y, z);
2794    
2795     void glTexCoord (float s, float t)
2796     CODE:
2797     glTexCoord2f (s, t);
2798    
2799 root 1.210 void glRect (float x1, float y1, float x2, float y2)
2800     CODE:
2801     glRectf (x1, y1, x2, y2);
2802    
2803 root 1.233 void glRect_lineloop (float x1, float y1, float x2, float y2)
2804     CODE:
2805     glBegin (GL_LINE_LOOP);
2806     glVertex2f (x1, y1);
2807     glVertex2f (x2, y1);
2808     glVertex2f (x2, y2);
2809     glVertex2f (x1, y2);
2810     glEnd ();
2811    
2812 root 1.208 PROTOTYPES: ENABLE
2813    
2814     void glBegin (int mode)
2815    
2816     void glEnd ()
2817    
2818     void glPointSize (GLfloat size)
2819    
2820     void glLineWidth (GLfloat width)
2821    
2822     void glInterleavedArrays (int format, int stride, char *data)
2823    
2824     void glDrawElements (int mode, int count, int type, char *indices)
2825    
2826     # 1.2 void glDrawRangeElements (int mode, int start, int end
2827    
2828 root 1.54 void glTexEnv (int target, int pname, float param)
2829     CODE:
2830     glTexEnvf (target, pname, param);
2831    
2832     void glTexParameter (int target, int pname, float param)
2833     CODE:
2834     glTexParameterf (target, pname, param);
2835    
2836     void glBindTexture (int target, int name)
2837    
2838     void glConvolutionParameter (int target, int pname, float params)
2839     CODE:
2840 root 1.103 if (gl.ConvolutionParameterf)
2841     gl.ConvolutionParameterf (target, pname, params);
2842 root 1.54
2843     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
2844 root 1.64 CODE:
2845 root 1.103 if (gl.ConvolutionFilter2D)
2846     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
2847 root 1.54
2848 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
2849     CODE:
2850 root 1.103 if (gl.SeparableFilter2D)
2851     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
2852 root 1.69
2853 root 1.244 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data = 0)
2854 root 1.54
2855     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
2856    
2857 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
2858 root 1.68
2859 root 1.199 void glPixelZoom (float x, float y)
2860    
2861 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
2862    
2863 root 1.54 int glGenTexture ()
2864     CODE:
2865 root 1.192 RETVAL = gen_texture ();
2866 root 1.54 OUTPUT:
2867     RETVAL
2868    
2869     void glDeleteTexture (int name)
2870     CODE:
2871 root 1.192 del_texture (name);
2872    
2873 root 1.54 int glGenList ()
2874     CODE:
2875     RETVAL = glGenLists (1);
2876     OUTPUT:
2877     RETVAL
2878    
2879     void glDeleteList (int list)
2880     CODE:
2881     glDeleteLists (list, 1);
2882    
2883     void glNewList (int list, int mode = GL_COMPILE)
2884    
2885     void glEndList ()
2886    
2887     void glCallList (int list)
2888    
2889 root 1.242 MODULE = Deliantra::Client PACKAGE = DC::UI::Base
2890 root 1.207
2891     PROTOTYPES: DISABLE
2892    
2893     void
2894 root 1.209 find_widget (SV *self, NV x, NV y)
2895 root 1.207 PPCODE:
2896     {
2897 root 1.209 if (within_widget (self, x, y))
2898     XPUSHs (self);
2899     }
2900    
2901     BOOT:
2902     {
2903 root 1.242 hover_gv = gv_fetchpv ("DC::UI::HOVER", 1, SVt_NV);
2904 root 1.209
2905 root 1.242 draw_x_gv = gv_fetchpv ("DC::UI::Base::draw_x", 1, SVt_NV);
2906     draw_y_gv = gv_fetchpv ("DC::UI::Base::draw_y", 1, SVt_NV);
2907     draw_w_gv = gv_fetchpv ("DC::UI::Base::draw_w", 1, SVt_NV);
2908     draw_h_gv = gv_fetchpv ("DC::UI::Base::draw_h", 1, SVt_NV);
2909 root 1.209 }
2910    
2911     void
2912     draw (SV *self)
2913     CODE:
2914     {
2915     HV *hv;
2916     SV **svp;
2917     NV x, y, w, h;
2918     SV *draw_x_sv = GvSV (draw_x_gv);
2919     SV *draw_y_sv = GvSV (draw_y_gv);
2920     SV *draw_w_sv = GvSV (draw_w_gv);
2921     SV *draw_h_sv = GvSV (draw_h_gv);
2922 root 1.228 double draw_x, draw_y;
2923 root 1.209
2924     if (!SvROK (self))
2925 root 1.242 croak ("DC::Base::draw: %s not a reference", SvPV_nolen (self));
2926 root 1.209
2927     hv = (HV *)SvRV (self);
2928    
2929     if (SvTYPE (hv) != SVt_PVHV)
2930 root 1.242 croak ("DC::Base::draw: %s not a hashref", SvPV_nolen (self));
2931 root 1.209
2932     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
2933     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
2934    
2935     if (!h || !w)
2936     XSRETURN_EMPTY;
2937    
2938     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
2939     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
2940    
2941     draw_x = SvNV (draw_x_sv) + x;
2942     draw_y = SvNV (draw_y_sv) + y;
2943    
2944     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
2945     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
2946     XSRETURN_EMPTY;
2947    
2948     sv_setnv (draw_x_sv, draw_x);
2949     sv_setnv (draw_y_sv, draw_y);
2950    
2951     glPushMatrix ();
2952     glTranslated (x, y, 0);
2953    
2954     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
2955     {
2956     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
2957    
2958     if (svp && SvTRUE (*svp))
2959     {
2960 root 1.228 glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f);
2961 root 1.209 glEnable (GL_BLEND);
2962     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
2963     glBegin (GL_QUADS);
2964     glVertex2f (0, 0);
2965     glVertex2f (w, 0);
2966     glVertex2f (w, h);
2967     glVertex2f (0, h);
2968     glEnd ();
2969     glDisable (GL_BLEND);
2970     }
2971     }
2972     #if 0
2973 root 1.234 // draw borders, for debugging
2974     glPushMatrix ();
2975     glColor4f (1., 1., 0., 1.);
2976     glTranslatef (.5, .5, 0.);
2977     glBegin (GL_LINE_LOOP);
2978     glVertex2f (0 , 0);
2979     glVertex2f (w - 1, 0);
2980     glVertex2f (w - 1, h - 1);
2981     glVertex2f (0 , h - 1);
2982     glEnd ();
2983     glPopMatrix ();
2984 root 1.209 #endif
2985     PUSHMARK (SP);
2986     XPUSHs (self);
2987     PUTBACK;
2988     call_method ("_draw", G_VOID | G_DISCARD);
2989     SPAGAIN;
2990    
2991     glPopMatrix ();
2992    
2993     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
2994     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
2995 root 1.207 }
2996