ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.221
Committed: Fri Aug 10 04:02:13 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.220: +28 -33 lines
Log Message:
- detect missing tiles or faces in map1a
- delay map drawing a tiny bit when some faces are missing, in the
  hope of being able to fetch them from the database.
- do not rate-limit refreshes to 60hz
- do refresh in an idle handler
- poll events independently from refresh

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