ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.299
Committed: Tue Dec 22 01:37:41 2009 UTC (14 years, 4 months ago) by root
Branch: MAIN
Changes since 1.298: +4 -1 lines
Log Message:
bugfixes, also support ARB_multitexturing for low-end apple intel

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