ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.259
Committed: Tue May 20 02:47:21 2008 UTC (15 years, 11 months ago) by root
Branch: MAIN
Changes since 1.258: +28 -5 lines
Log Message:
*** empty log message ***

File Contents

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