ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.224
Committed: Sat Aug 11 11:21:46 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.223: +3 -0 lines
Log Message:
need more flushes

File Contents

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