ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.213
Committed: Sun Jul 29 04:14:45 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.212: +29 -28 lines
Log Message:
more complete api, got rid of most retvals

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.211 Mix_OpenAudio (int frequency = 44100, int format = MIX_DEFAULT_FORMAT, int channels = 2, int chunksize = 4096)
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.10 void
821     lowdelay (int fd, int val = 1)
822     CODE:
823 root 1.179 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&val, sizeof (val));
824 root 1.10
825 root 1.5 void
826 root 1.157 win32_proxy_info ()
827     PPCODE:
828     {
829     #ifdef _WIN32
830     char buffer[2048];
831     DWORD buflen;
832    
833     EXTEND (SP, 3);
834    
835     buflen = sizeof (buffer);
836     if (InternetQueryOption (0, INTERNET_OPTION_PROXY, (void *)buffer, &buflen))
837     if (((INTERNET_PROXY_INFO *)buffer)->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
838     {
839     PUSHs (newSVpv (((INTERNET_PROXY_INFO *)buffer)->lpszProxy, 0));
840    
841     buflen = sizeof (buffer);
842     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_USERNAME, (void *)buffer, &buflen))
843     {
844     PUSHs (newSVpv (buffer, 0));
845    
846     buflen = sizeof (buffer);
847     if (InternetQueryOption (0, INTERNET_OPTION_PROXY_PASSWORD, (void *)buffer, &buflen))
848     PUSHs (newSVpv (buffer, 0));
849     }
850     }
851     #endif
852     }
853    
854     void
855 root 1.13 add_font (char *file)
856     CODE:
857 root 1.129 FcConfigAppFontAddFile (0, (const FcChar8 *)file);
858 root 1.13
859     void
860 root 1.23 load_image_inline (SV *image_)
861     ALIAS:
862     load_image_file = 1
863     PPCODE:
864     {
865     STRLEN image_len;
866     char *image = (char *)SvPVbyte (image_, image_len);
867     SDL_Surface *surface, *surface2;
868     SDL_PixelFormat fmt;
869     SDL_RWops *rw = ix
870 root 1.212 ? SDL_RWFromFile (image, "rb")
871 root 1.23 : SDL_RWFromConstMem (image, image_len);
872    
873     if (!rw)
874 root 1.41 croak ("load_image: %s", SDL_GetError ());
875 root 1.23
876     surface = IMG_Load_RW (rw, 1);
877     if (!surface)
878 root 1.41 croak ("load_image: %s", SDL_GetError ());
879 root 1.23
880     fmt.palette = NULL;
881     fmt.BitsPerPixel = 32;
882     fmt.BytesPerPixel = 4;
883 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
884 root 1.23 fmt.Rmask = 0x000000ff;
885     fmt.Gmask = 0x0000ff00;
886     fmt.Bmask = 0x00ff0000;
887     fmt.Amask = 0xff000000;
888 root 1.49 #else
889     fmt.Rmask = 0xff000000;
890     fmt.Gmask = 0x00ff0000;
891     fmt.Bmask = 0x0000ff00;
892     fmt.Amask = 0x000000ff;
893     #endif
894 root 1.23 fmt.Rloss = 0;
895     fmt.Gloss = 0;
896     fmt.Bloss = 0;
897     fmt.Aloss = 0;
898     fmt.Rshift = 0;
899     fmt.Gshift = 8;
900     fmt.Bshift = 16;
901     fmt.Ashift = 24;
902     fmt.colorkey = 0;
903     fmt.alpha = 0;
904    
905     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
906    
907 root 1.39 assert (surface2->pitch == surface2->w * 4);
908    
909 root 1.129 SDL_LockSurface (surface2);
910     EXTEND (SP, 6);
911 root 1.23 PUSHs (sv_2mortal (newSViv (surface2->w)));
912     PUSHs (sv_2mortal (newSViv (surface2->h)));
913     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
914 root 1.116 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
915 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
916 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
917 root 1.129 SDL_UnlockSurface (surface2);
918 root 1.23
919     SDL_FreeSurface (surface);
920     SDL_FreeSurface (surface2);
921     }
922    
923 root 1.25 void
924 root 1.39 average (int x, int y, uint32_t *data)
925     PPCODE:
926     {
927     uint32_t r = 0, g = 0, b = 0, a = 0;
928    
929     x = y = x * y;
930    
931     while (x--)
932     {
933     uint32_t p = *data++;
934    
935     r += (p ) & 255;
936     g += (p >> 8) & 255;
937     b += (p >> 16) & 255;
938     a += (p >> 24) & 255;
939     }
940    
941     EXTEND (SP, 4);
942 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
943     PUSHs (sv_2mortal (newSViv (g / y)));
944     PUSHs (sv_2mortal (newSViv (b / y)));
945     PUSHs (sv_2mortal (newSViv (a / y)));
946 root 1.39 }
947    
948     void
949 root 1.66 error (char *message)
950     CODE:
951 root 1.86 fprintf (stderr, "ERROR: %s\n", message);
952 root 1.66 #ifdef _WIN32
953 root 1.86 MessageBox (0, message, "Crossfire+ Error", MB_OK | MB_ICONERROR);
954 root 1.66 #endif
955    
956     void
957 root 1.25 fatal (char *message)
958     CODE:
959 root 1.86 fprintf (stderr, "FATAL: %s\n", message);
960 root 1.50 #ifdef _WIN32
961 root 1.86 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR);
962 root 1.25 #endif
963 root 1.112 _exit (1);
964 root 1.111
965     void
966 root 1.158 _exit (int retval = 0)
967 root 1.111 CODE:
968 root 1.161 #ifdef WIN32
969     ExitThread (retval); // unclean, please beam me up
970     #else
971 root 1.112 _exit (retval);
972 root 1.161 #endif
973 root 1.25
974 root 1.193 void
975     debug ()
976     CODE:
977     {
978     #if DEBUG
979     VALGRIND_DO_LEAK_CHECK;
980     #endif
981     }
982    
983 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Font
984 root 1.61
985 root 1.205 PROTOTYPES: DISABLE
986    
987 root 1.133 CFPlus::Font
988 root 1.70 new_from_file (SV *class, char *path, int id = 0)
989 root 1.61 CODE:
990     {
991     int count;
992 root 1.70 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, id, 0, &count);
993 root 1.61 RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
994     FcPatternDestroy (pattern);
995     }
996     OUTPUT:
997     RETVAL
998    
999     void
1000 root 1.133 DESTROY (CFPlus::Font self)
1001 root 1.61 CODE:
1002     pango_font_description_free (self);
1003    
1004     void
1005 root 1.133 make_default (CFPlus::Font self)
1006 root 1.205 PROTOTYPE: $
1007 root 1.61 CODE:
1008     default_font = self;
1009    
1010 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Layout
1011 root 1.14
1012 root 1.205 PROTOTYPES: DISABLE
1013    
1014 root 1.124 void
1015 root 1.129 reset_glyph_cache ()
1016 root 1.205 PROTOTYPE:
1017 root 1.124 CODE:
1018     tc_clear ();
1019    
1020 root 1.133 CFPlus::Layout
1021 root 1.128 new (SV *class)
1022 root 1.14 CODE:
1023     New (0, RETVAL, 1, struct cf_layout);
1024 root 1.76
1025 root 1.124 RETVAL->pl = pango_layout_new (opengl_context);
1026 root 1.76 RETVAL->r = 1.;
1027     RETVAL->g = 1.;
1028     RETVAL->b = 1.;
1029     RETVAL->a = 1.;
1030     RETVAL->base_height = MIN_FONT_HEIGHT;
1031     RETVAL->font = 0;
1032    
1033 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
1034 root 1.76 layout_update_font (RETVAL);
1035 root 1.14 OUTPUT:
1036     RETVAL
1037    
1038     void
1039 root 1.133 DESTROY (CFPlus::Layout self)
1040 root 1.14 CODE:
1041     g_object_unref (self->pl);
1042     Safefree (self);
1043 root 1.13
1044 root 1.8 void
1045 root 1.133 set_text (CFPlus::Layout self, SV *text_)
1046 root 1.35 CODE:
1047     {
1048     STRLEN textlen;
1049     char *text = SvPVutf8 (text_, textlen);
1050    
1051     pango_layout_set_text (self->pl, text, textlen);
1052     }
1053    
1054     void
1055 root 1.133 set_markup (CFPlus::Layout self, SV *text_)
1056 root 1.14 CODE:
1057 root 1.5 {
1058     STRLEN textlen;
1059     char *text = SvPVutf8 (text_, textlen);
1060 root 1.14
1061     pango_layout_set_markup (self->pl, text, textlen);
1062     }
1063    
1064 root 1.121 void
1065 root 1.133 set_shapes (CFPlus::Layout self, ...)
1066 root 1.121 CODE:
1067     {
1068     PangoAttrList *attrs = 0;
1069     const char *text = pango_layout_get_text (self->pl);
1070     const char *pos = text;
1071 root 1.122 int arg = 4;
1072 root 1.121
1073     while (arg < items && (pos = strstr (pos, OBJ_STR)))
1074     {
1075 root 1.122 PangoRectangle inkrect, rect;
1076 root 1.121 PangoAttribute *attr;
1077    
1078 root 1.122 int x = SvIV (ST (arg - 3));
1079     int y = SvIV (ST (arg - 2));
1080 root 1.121 int w = SvIV (ST (arg - 1));
1081 root 1.122 int h = SvIV (ST (arg ));
1082 root 1.121
1083 root 1.122 inkrect.x = 0;
1084     inkrect.y = 0;
1085     inkrect.width = 0;
1086     inkrect.height = 0;
1087    
1088     rect.x = x * PANGO_SCALE;
1089     rect.y = y * PANGO_SCALE;
1090     rect.width = w * PANGO_SCALE;
1091 root 1.121 rect.height = h * PANGO_SCALE;
1092    
1093     if (!attrs)
1094     attrs = pango_layout_get_attributes (self->pl);
1095    
1096 root 1.122 attr = pango_attr_shape_new (&inkrect, &rect);
1097 root 1.121 attr->start_index = pos - text;
1098     attr->end_index = attr->start_index + sizeof (OBJ_STR) - 1;
1099     pango_attr_list_insert (attrs, attr);
1100    
1101 root 1.122 arg += 4;
1102 root 1.121 pos += sizeof (OBJ_STR) - 1;
1103     }
1104    
1105     if (attrs)
1106     pango_layout_set_attributes (self->pl, attrs);
1107     }
1108    
1109     void
1110 root 1.133 get_shapes (CFPlus::Layout self)
1111 root 1.121 PPCODE:
1112     {
1113     PangoLayoutIter *iter = pango_layout_get_iter (self->pl);
1114    
1115     do
1116     {
1117     PangoLayoutRun *run = pango_layout_iter_get_run (iter);
1118    
1119     if (run && shape_attr_p (run))
1120     {
1121     PangoRectangle extents;
1122     pango_layout_iter_get_run_extents (iter, 0, &extents);
1123    
1124 root 1.129 EXTEND (SP, 2);
1125 root 1.121 PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.x))));
1126     PUSHs (sv_2mortal (newSViv (PANGO_PIXELS (extents.y))));
1127     }
1128     }
1129     while (pango_layout_iter_next_run (iter));
1130    
1131     pango_layout_iter_free (iter);
1132     }
1133    
1134     int
1135 root 1.133 has_wrapped (CFPlus::Layout self)
1136 root 1.121 CODE:
1137     {
1138     int lines = 1;
1139     const char *text = pango_layout_get_text (self->pl);
1140    
1141     while (*text)
1142     lines += *text++ == '\n';
1143    
1144     RETVAL = lines < pango_layout_get_line_count (self->pl);
1145     }
1146     OUTPUT:
1147     RETVAL
1148    
1149 root 1.46 SV *
1150 root 1.133 get_text (CFPlus::Layout self)
1151 root 1.46 CODE:
1152 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
1153 root 1.107 sv_utf8_decode (RETVAL);
1154 root 1.46 OUTPUT:
1155     RETVAL
1156    
1157 root 1.14 void
1158 root 1.133 set_foreground (CFPlus::Layout self, float r, float g, float b, float a = 1.)
1159 root 1.76 CODE:
1160     self->r = r;
1161     self->g = g;
1162     self->b = b;
1163     self->a = a;
1164    
1165     void
1166 root 1.133 set_font (CFPlus::Layout self, CFPlus::Font font = 0)
1167 root 1.61 CODE:
1168     if (self->font != font)
1169     {
1170     self->font = font;
1171     layout_update_font (self);
1172     }
1173    
1174     void
1175 root 1.133 set_height (CFPlus::Layout self, int base_height)
1176 root 1.16 CODE:
1177 root 1.61 if (self->base_height != base_height)
1178     {
1179     self->base_height = base_height;
1180     layout_update_font (self);
1181     }
1182 root 1.16
1183     void
1184 root 1.133 set_width (CFPlus::Layout self, int max_width = -1)
1185 root 1.14 CODE:
1186     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
1187    
1188     void
1189 root 1.133 set_indent (CFPlus::Layout self, int indent)
1190 root 1.84 CODE:
1191     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
1192    
1193     void
1194 root 1.133 set_spacing (CFPlus::Layout self, int spacing)
1195 root 1.84 CODE:
1196     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
1197    
1198     void
1199 root 1.133 set_ellipsise (CFPlus::Layout self, int ellipsise)
1200 root 1.84 CODE:
1201     pango_layout_set_ellipsize (self->pl,
1202     ellipsise == 1 ? PANGO_ELLIPSIZE_START
1203     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
1204     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
1205     : PANGO_ELLIPSIZE_NONE
1206     );
1207    
1208     void
1209 root 1.133 set_single_paragraph_mode (CFPlus::Layout self, int spm)
1210 root 1.84 CODE:
1211     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
1212    
1213     void
1214 root 1.133 size (CFPlus::Layout self)
1215 root 1.14 PPCODE:
1216     {
1217     int w, h;
1218    
1219     layout_get_pixel_size (self, &w, &h);
1220    
1221     EXTEND (SP, 2);
1222     PUSHs (sv_2mortal (newSViv (w)));
1223     PUSHs (sv_2mortal (newSViv (h)));
1224     }
1225    
1226 root 1.17 int
1227 root 1.133 descent (CFPlus::Layout self)
1228 root 1.122 CODE:
1229     {
1230     PangoRectangle rect;
1231     PangoLayoutLine *line = pango_layout_get_line (self->pl, 0);
1232     pango_layout_line_get_pixel_extents (line, 0, &rect);
1233     RETVAL = PANGO_DESCENT (rect);
1234     }
1235     OUTPUT:
1236     RETVAL
1237    
1238     int
1239 root 1.133 xy_to_index (CFPlus::Layout self, int x, int y)
1240 root 1.17 CODE:
1241     {
1242     int index, trailing;
1243     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
1244 root 1.165 RETVAL = index + trailing;
1245 root 1.17 }
1246     OUTPUT:
1247     RETVAL
1248    
1249     void
1250 root 1.133 cursor_pos (CFPlus::Layout self, int index)
1251 root 1.17 PPCODE:
1252     {
1253     PangoRectangle strong_pos;
1254     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
1255 root 1.30
1256 root 1.17 EXTEND (SP, 3);
1257     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
1258     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
1259     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
1260     }
1261    
1262 root 1.14 void
1263 root 1.165 index_to_line_x (CFPlus::Layout self, int index, int trailing = 0)
1264     PPCODE:
1265     {
1266     int line, x;
1267    
1268     pango_layout_index_to_line_x (self->pl, index, trailing, &line, &x);
1269     /* pango bug: line is between 1..numlines, not 0..numlines-1 */
1270    
1271     EXTEND (SP, 2);
1272     PUSHs (sv_2mortal (newSViv (line - 1)));
1273     PUSHs (sv_2mortal (newSViv (x / PANGO_SCALE)));
1274     }
1275    
1276     void
1277     line_x_to_index (CFPlus::Layout self, int line, int x)
1278     PPCODE:
1279     {
1280     PangoLayoutLine *lp;
1281     int index, trailing;
1282    
1283     if (line < 0)
1284     XSRETURN_EMPTY;
1285    
1286     if (!(lp = pango_layout_get_line (self->pl, line)))
1287     XSRETURN_EMPTY; /* do better */
1288    
1289 root 1.166 pango_layout_line_x_to_index (lp, x * PANGO_SCALE, &index, &trailing);
1290 root 1.165
1291     EXTEND (SP, 2);
1292     if (GIMME_V == G_SCALAR)
1293     PUSHs (sv_2mortal (newSViv (index + trailing)));
1294     else
1295     {
1296     PUSHs (sv_2mortal (newSViv (index)));
1297     PUSHs (sv_2mortal (newSViv (trailing)));
1298     }
1299     }
1300    
1301     void
1302 root 1.135 render (CFPlus::Layout self, float x, float y, int flags = 0)
1303 root 1.14 PPCODE:
1304 root 1.124 pango_opengl_render_layout_subpixel (
1305     self->pl,
1306     x * PANGO_SCALE, y * PANGO_SCALE,
1307 root 1.135 self->r, self->g, self->b, self->a,
1308     flags
1309 root 1.124 );
1310 root 1.11
1311 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Texture
1312 root 1.11
1313 root 1.205 PROTOTYPES: ENABLE
1314    
1315 root 1.199 int minpot (int n)
1316    
1317 root 1.11 void
1318 root 1.203 pad (SV *data_, int ow, int oh, int nw, int nh)
1319 root 1.113 CODE:
1320     {
1321 root 1.203 if ((nw != ow || nh != oh) && SvOK (data_))
1322 root 1.113 {
1323 root 1.203 STRLEN datalen;
1324     char *data = SvPVbyte (data_, datalen);
1325     int bpp = datalen / (ow * oh);
1326     SV *result_ = sv_2mortal (newSV (nw * nh * bpp));
1327    
1328     SvPOK_only (result_);
1329     SvCUR_set (result_, nw * nh * bpp);
1330    
1331     memset (SvPVX (result_), 0, nw * nh * bpp);
1332     while (oh--)
1333     memcpy (SvPVX (result_) + oh * nw * bpp, data + oh * ow * bpp, ow * bpp);
1334 root 1.113
1335 root 1.203 sv_setsv (data_, result_);
1336 root 1.113 }
1337     }
1338    
1339     void
1340 root 1.114 draw_quad (SV *self, float x, float y, float w = 0., float h = 0.)
1341 root 1.12 PROTOTYPE: $$$;$$
1342 root 1.76 ALIAS:
1343     draw_quad_alpha = 1
1344     draw_quad_alpha_premultiplied = 2
1345 root 1.11 CODE:
1346     {
1347 root 1.12 HV *hv = (HV *)SvRV (self);
1348 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
1349     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
1350 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
1351    
1352     if (items < 5)
1353     {
1354 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1355     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1356 root 1.12 }
1357    
1358 root 1.76 if (ix)
1359     {
1360     glEnable (GL_BLEND);
1361 root 1.103
1362     if (ix == 2)
1363     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1364     else
1365     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1366 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1367 root 1.103
1368 root 1.86 glEnable (GL_ALPHA_TEST);
1369     glAlphaFunc (GL_GREATER, 0.01f);
1370 root 1.76 }
1371    
1372 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1373 root 1.76
1374 root 1.12 glBegin (GL_QUADS);
1375 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1376     glTexCoord2f (0, t); glVertex2f (x , y + h);
1377     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1378     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1379 root 1.12 glEnd ();
1380 root 1.76
1381     if (ix)
1382 root 1.86 {
1383     glDisable (GL_ALPHA_TEST);
1384     glDisable (GL_BLEND);
1385     }
1386 root 1.11 }
1387 root 1.28
1388 root 1.199 IV texture_valid_2d (GLint internalformat, GLsizei w, GLsizei h, GLenum format, GLenum type)
1389     CODE:
1390     {
1391     GLint width;
1392     glTexImage2D (GL_PROXY_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, 0);
1393     glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
1394     RETVAL = width > 0;
1395     }
1396     OUTPUT:
1397     RETVAL
1398    
1399 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Map
1400 root 1.28
1401 root 1.205 PROTOTYPES: DISABLE
1402    
1403 root 1.133 CFPlus::Map
1404 root 1.164 new (SV *class)
1405 root 1.28 CODE:
1406     New (0, RETVAL, 1, struct map);
1407 root 1.42 RETVAL->x = 0;
1408     RETVAL->y = 0;
1409 root 1.164 RETVAL->w = 0;
1410     RETVAL->h = 0;
1411 root 1.42 RETVAL->ox = 0;
1412     RETVAL->oy = 0;
1413 root 1.174 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1414     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1415 root 1.28 RETVAL->rows = 0;
1416     RETVAL->row = 0;
1417     OUTPUT:
1418     RETVAL
1419    
1420     void
1421 root 1.133 DESTROY (CFPlus::Map self)
1422 root 1.28 CODE:
1423     {
1424 root 1.30 map_clear (self);
1425 root 1.174 Safefree (self->face2tile);
1426 root 1.111 Safefree (self->tex);
1427 root 1.29 Safefree (self);
1428     }
1429    
1430     void
1431 root 1.164 resize (CFPlus::Map self, int map_width, int map_height)
1432     CODE:
1433     self->w = map_width;
1434     self->h = map_height;
1435    
1436     void
1437 root 1.133 clear (CFPlus::Map self)
1438 root 1.30 CODE:
1439     map_clear (self);
1440    
1441     void
1442 root 1.174 set_tileid (CFPlus::Map self, int face, int tile)
1443 root 1.29 CODE:
1444     {
1445 root 1.174 need_facenum (self, face); self->face2tile [face] = tile;
1446     need_texid (self, tile);
1447 root 1.42 }
1448    
1449     void
1450 root 1.176 set_smooth (CFPlus::Map self, int face, int smooth, int level)
1451     CODE:
1452     {
1453     tileid texid;
1454     maptex *tex;
1455    
1456     if (face < 0 || face >= self->faces)
1457     return;
1458    
1459     if (smooth < 0 || smooth >= self->faces)
1460     return;
1461    
1462     texid = self->face2tile [face];
1463    
1464     if (!texid)
1465     return;
1466    
1467     tex = self->tex + texid;
1468     tex->smoothtile = self->face2tile [smooth];
1469     tex->smoothlevel = level;
1470     }
1471    
1472     void
1473 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)
1474 root 1.42 CODE:
1475     {
1476 root 1.174 need_texid (self, texid);
1477 root 1.42
1478 root 1.48 {
1479     maptex *tex = self->tex + texid;
1480 root 1.39
1481 root 1.48 tex->name = name;
1482     tex->w = w;
1483     tex->h = h;
1484     tex->s = s;
1485     tex->t = t;
1486     tex->r = r;
1487     tex->g = g;
1488     tex->b = b;
1489     tex->a = a;
1490     }
1491 root 1.95
1492     // somewhat hackish, but for textures that require it, it really
1493     // improves the look, and most others don't suffer.
1494     glBindTexture (GL_TEXTURE_2D, name);
1495 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1496     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1497     // use uglier nearest interpolation because linear suffers
1498     // from transparent color bleeding and ugly wrapping effects.
1499     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1500 root 1.29 }
1501    
1502 root 1.42 int
1503 root 1.133 ox (CFPlus::Map self)
1504 root 1.42 ALIAS:
1505     oy = 1
1506 root 1.101 x = 2
1507     y = 3
1508 root 1.102 w = 4
1509     h = 5
1510 root 1.42 CODE:
1511     switch (ix)
1512     {
1513     case 0: RETVAL = self->ox; break;
1514     case 1: RETVAL = self->oy; break;
1515 root 1.101 case 2: RETVAL = self->x; break;
1516     case 3: RETVAL = self->y; break;
1517 root 1.102 case 4: RETVAL = self->w; break;
1518     case 5: RETVAL = self->h; break;
1519 root 1.42 }
1520     OUTPUT:
1521     RETVAL
1522    
1523 root 1.29 void
1524 root 1.133 scroll (CFPlus::Map self, int dx, int dy)
1525 root 1.43 CODE:
1526     {
1527 root 1.44 if (dx > 0)
1528 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
1529 root 1.44 else if (dx < 0)
1530 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
1531 root 1.44
1532     if (dy > 0)
1533 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
1534 root 1.44 else if (dy < 0)
1535 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
1536 root 1.43
1537 root 1.44 self->ox += dx; self->x += dx;
1538     self->oy += dy; self->y += dy;
1539 root 1.43
1540     while (self->y < 0)
1541     {
1542     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1543    
1544     self->rows += MAP_EXTEND_Y;
1545     self->y += MAP_EXTEND_Y;
1546     }
1547 root 1.44 }
1548 root 1.43
1549 root 1.44 void
1550 root 1.141 map1a_update (CFPlus::Map self, SV *data_, int extmap)
1551 root 1.44 CODE:
1552     {
1553 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1554     uint8_t *data_end = (uint8_t *)SvEND (data_);
1555 root 1.48 mapcell *cell;
1556     int x, y, flags;
1557 root 1.43
1558 root 1.150 while (data < data_end - 1)
1559 root 1.29 {
1560 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1561 root 1.30
1562 root 1.120 x = self->x + ((flags >> 10) & 63);
1563     y = self->y + ((flags >> 4) & 63);
1564 root 1.29
1565 root 1.48 cell = map_get_cell (self, x, y);
1566 root 1.29
1567     if (flags & 15)
1568     {
1569 root 1.142 if (!cell->darkness)
1570 root 1.29 {
1571 root 1.154 memset (cell, 0, sizeof (*cell));
1572 root 1.142 cell->darkness = 256;
1573 root 1.29 }
1574 root 1.45
1575 root 1.142 //TODO: don't trust server data to be in-range(!)
1576    
1577 root 1.141 if (flags & 8)
1578     {
1579     if (extmap)
1580     {
1581     uint8_t ext, cmd;
1582    
1583     do
1584     {
1585     ext = *data++;
1586 root 1.144 cmd = ext & 0x3f;
1587 root 1.141
1588 root 1.147 if (cmd < 4)
1589 root 1.142 cell->darkness = 255 - ext * 64 + 1;
1590 root 1.147 else if (cmd == 5) // health
1591     {
1592     cell->stat_width = 1;
1593     cell->stat_hp = *data++;
1594     }
1595     else if (cmd == 6) // monster width
1596     cell->stat_width = *data++ + 1;
1597 root 1.169 else if (cmd == 0x47)
1598 root 1.153 {
1599 root 1.182 if (*data == 4)
1600     ; // decode player count
1601 root 1.153
1602     data += *data + 1;
1603     }
1604     else if (cmd == 8) // cell flags
1605     cell->flags = *data++;
1606 root 1.144 else if (ext & 0x40) // unknown, multibyte => skip
1607     data += *data + 1;
1608 root 1.147 else
1609     data++;
1610 root 1.141 }
1611 root 1.147 while (ext & 0x80);
1612 root 1.141 }
1613     else
1614 root 1.142 cell->darkness = *data++ + 1;
1615 root 1.141 }
1616 root 1.29
1617     if (flags & 4)
1618     {
1619 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1620     need_facenum (self, face);
1621     cell->tile [0] = self->face2tile [face];
1622 root 1.29 }
1623    
1624     if (flags & 2)
1625     {
1626 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1627     need_facenum (self, face);
1628     cell->tile [1] = self->face2tile [face];
1629 root 1.29 }
1630    
1631     if (flags & 1)
1632     {
1633 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1634     need_facenum (self, face);
1635     cell->tile [2] = self->face2tile [face];
1636 root 1.29 }
1637     }
1638     else
1639 root 1.155 cell->darkness = 0;
1640 root 1.29 }
1641 root 1.28 }
1642    
1643 root 1.40 SV *
1644 root 1.133 mapmap (CFPlus::Map self, int x0, int y0, int w, int h)
1645 root 1.40 CODE:
1646     {
1647 root 1.55 int x1, x;
1648     int y1, y;
1649 root 1.40 int z;
1650     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1651     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1652    
1653     SvPOK_only (map_sv);
1654     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1655    
1656 root 1.55 x0 += self->x; x1 = x0 + w;
1657     y0 += self->y; y1 = y0 + h;
1658 root 1.40
1659     for (y = y0; y < y1; y++)
1660     {
1661     maprow *row = 0 <= y && y < self->rows
1662     ? self->row + y
1663     : 0;
1664    
1665     for (x = x0; x < x1; x++)
1666     {
1667     int r = 32, g = 32, b = 32, a = 192;
1668    
1669     if (row && row->c0 <= x && x < row->c1)
1670     {
1671     mapcell *cell = row->col + (x - row->c0);
1672    
1673     for (z = 0; z <= 0; z++)
1674     {
1675 root 1.174 maptex tex = self->tex [cell->tile [z]];
1676     int a0 = 255 - tex.a;
1677     int a1 = tex.a;
1678    
1679     r = (r * a0 + tex.r * a1) / 255;
1680     g = (g * a0 + tex.g * a1) / 255;
1681     b = (b * a0 + tex.b * a1) / 255;
1682     a = (a * a0 + tex.a * a1) / 255;
1683 root 1.40 }
1684     }
1685    
1686     *map++ = (r )
1687     | (g << 8)
1688     | (b << 16)
1689     | (a << 24);
1690     }
1691     }
1692    
1693     RETVAL = map_sv;
1694     }
1695     OUTPUT:
1696     RETVAL
1697    
1698 root 1.30 void
1699 root 1.171 draw (CFPlus::Map self, int mx, int my, int sw, int sh, int T)
1700 root 1.116 CODE:
1701 root 1.30 {
1702 root 1.176 HV *smooth = (HV *)sv_2mortal ((SV *)newHV ());
1703     uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level
1704 root 1.178 static uint8_t smooth_max[256][256]; // egad, fats and wasteful on memory (64k)
1705 root 1.176 smooth_key skey;
1706 root 1.48 int x, y, z;
1707     int last_name;
1708    
1709 root 1.176 // thats current max. sorry.
1710     if (sw > 255) sw = 255;
1711     if (sh > 255) sh = 255;
1712    
1713     // clear key, in case of extra padding
1714     memset (&skey, 0, sizeof (skey));
1715    
1716 root 1.30 glColor4ub (255, 255, 255, 255);
1717    
1718 root 1.117 glEnable (GL_BLEND);
1719 root 1.30 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1720     glEnable (GL_TEXTURE_2D);
1721     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1722    
1723 root 1.48 glBegin (GL_QUADS);
1724 root 1.30
1725 root 1.48 last_name = 0;
1726 root 1.30
1727 root 1.164 mx += self->x;
1728     my += self->y;
1729    
1730 root 1.176 // first pass: determine smooth_max
1731     // rather ugly, if you ask me
1732     // could also be stored inside mapcell and updated on change
1733     memset (smooth_max, 0, sizeof (smooth_max));
1734    
1735     for (y = 0; y < sh; y++)
1736     if (0 <= y + my && y + my < self->rows)
1737     {
1738     maprow *row = self->row + (y + my);
1739    
1740     for (x = 0; x < sw; x++)
1741     if (row->c0 <= x + mx && x + mx < row->c1)
1742     {
1743     mapcell *cell = row->col + (x + mx - row->c0);
1744    
1745 root 1.177 smooth_max[x + 1][y + 1] =
1746     MAX (self->tex [cell->tile [0]].smoothlevel,
1747     MAX (self->tex [cell->tile [1]].smoothlevel,
1748     self->tex [cell->tile [2]].smoothlevel));
1749 root 1.176 }
1750     }
1751    
1752     for (z = 0; z <= 2; z++)
1753     {
1754 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
1755    
1756 root 1.176 for (y = 0; y < sh; y++)
1757     if (0 <= y + my && y + my < self->rows)
1758     {
1759     maprow *row = self->row + (y + my);
1760    
1761     for (x = 0; x < sw; x++)
1762     if (row->c0 <= x + mx && x + mx < row->c1)
1763     {
1764     mapcell *cell = row->col + (x + mx - row->c0);
1765     tileid tile = cell->tile [z];
1766    
1767     if (tile)
1768     {
1769     maptex tex = self->tex [tile];
1770     int px = (x + 1) * T - tex.w;
1771     int py = (y + 1) * T - tex.h;
1772    
1773     // suppressing texture state switches here
1774     // is only moderately effective, but worth the extra effort
1775     if (last_name != tex.name)
1776     {
1777     if (!tex.name)
1778     tex = self->tex [2]; /* missing, replace by noface */
1779    
1780     glEnd ();
1781     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1782     glBegin (GL_QUADS);
1783     }
1784    
1785     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1786     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1787     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1788     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1789    
1790     if (cell->flags && z == 2)
1791     {
1792     if (cell->flags & 1)
1793     {
1794     maptex tex = self->tex [1];
1795     int px = x * T + T * 2 / 32;
1796     int py = y * T - T * 6 / 32;
1797    
1798     glEnd ();
1799     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1800     glBegin (GL_QUADS);
1801    
1802     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1803     glTexCoord2f (0 , tex.t); glVertex2f (px , py + T);
1804     glTexCoord2f (tex.s, tex.t); glVertex2f (px + T, py + T);
1805     glTexCoord2f (tex.s, 0 ); glVertex2f (px + T, py );
1806     }
1807     }
1808    
1809     // update smooth hash
1810     if (tex.smoothtile)
1811     {
1812     skey.tile = tex.smoothtile;
1813     skey.level = tex.smoothlevel;
1814    
1815     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
1816 root 1.30
1817 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
1818     // shifted +1|+1 so we always stay positive.
1819 root 1.30
1820 root 1.180 // bits is ___n cccc CCCC bbbb
1821     // n do not draw borders&corners
1822     // c draw these corners, but...
1823     // C ... not these
1824     // b draw these borders
1825    
1826     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
1827     // ┃· ·· ·┃ ━━
1828    
1829     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
1830     // ·· ·· ·┏ ┓·
1831    
1832 root 1.176 // full tile
1833     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
1834    
1835     // borders
1836 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
1837     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
1838 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
1839     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
1840    
1841     // corners
1842     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
1843     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
1844     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
1845     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
1846     }
1847     }
1848     }
1849     }
1850 root 1.174
1851 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
1852     // this is basically counting sort
1853 root 1.176 {
1854 root 1.186 int w, b;
1855 root 1.30
1856 root 1.186 for (w = 0; w < 256 / 32; ++w)
1857     {
1858     uint32_t smask = smooth_level [w];
1859     if (smask)
1860     for (b = 0; b < 32; ++b)
1861     if (smask & (((uint32_t)1) << b))
1862 root 1.176 {
1863 root 1.186 int level = (w << 5) | b;
1864     HE *he;
1865 root 1.153
1866 root 1.186 hv_iterinit (smooth);
1867     while ((he = hv_iternext (smooth)))
1868 root 1.153 {
1869 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
1870     IV bits = SvIVX (HeVAL (he));
1871 root 1.176
1872 root 1.186 if (!(bits & 0x1000)
1873     && skey->level == level
1874 root 1.191 && level > smooth_max [skey->x][skey->y])
1875 root 1.174 {
1876 root 1.186 maptex tex = self->tex [skey->tile];
1877     int px = (((int)skey->x) - 1) * T;
1878     int py = (((int)skey->y) - 1) * T;
1879     int border = bits & 15;
1880     int corner = (bits >> 8) & ~(bits >> 4) & 15;
1881     float dx = tex.s * .0625f; // 16 images/row
1882     float dy = tex.t * .5f ; // 2 images/column
1883    
1884     // this time naively avoiding texture state changes
1885     // save gobs of state changes.
1886     if (last_name != tex.name)
1887     {
1888     if (!tex.name)
1889     continue; // smoothing not yet available
1890    
1891     glEnd ();
1892     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1893     glBegin (GL_QUADS);
1894     }
1895    
1896     if (border)
1897     {
1898     float ox = border * dx;
1899    
1900     glTexCoord2f (ox , 0.f ); glVertex2f (px , py );
1901     glTexCoord2f (ox , dy ); glVertex2f (px , py + T);
1902     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py + T);
1903     glTexCoord2f (ox + dx, 0.f ); glVertex2f (px + T, py );
1904     }
1905    
1906     if (corner)
1907     {
1908     float ox = corner * dx;
1909    
1910     glTexCoord2f (ox , dy ); glVertex2f (px , py );
1911     glTexCoord2f (ox , dy * 2.f); glVertex2f (px , py + T);
1912     glTexCoord2f (ox + dx, dy * 2.f); glVertex2f (px + T, py + T);
1913     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py );
1914     }
1915 root 1.174 }
1916 root 1.153 }
1917     }
1918 root 1.186 }
1919 root 1.176 }
1920    
1921 root 1.186 hv_clear (smooth);
1922     }
1923 root 1.30
1924     glEnd ();
1925 root 1.32
1926 root 1.34 glDisable (GL_TEXTURE_2D);
1927 root 1.152 glDisable (GL_BLEND);
1928 root 1.143
1929 root 1.145 // top layer: overlays such as the health bar
1930 root 1.143 for (y = 0; y < sh; y++)
1931 root 1.164 if (0 <= y + my && y + my < self->rows)
1932 root 1.143 {
1933 root 1.164 maprow *row = self->row + (y + my);
1934 root 1.143
1935     for (x = 0; x < sw; x++)
1936 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
1937 root 1.143 {
1938 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
1939 root 1.143
1940 root 1.171 int px = x * T;
1941     int py = y * T;
1942 root 1.143
1943     if (cell->stat_hp)
1944     {
1945 root 1.171 int width = cell->stat_width * T;
1946 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
1947 root 1.143
1948 root 1.152 glColor3ub (0, 0, 0);
1949 root 1.151 glRectf (px + 1, py - thick - 2,
1950     px + width - 1, py);
1951 root 1.147
1952 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
1953 root 1.147 glRectf (px + 2,
1954 root 1.151 py - thick - 1,
1955     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
1956 root 1.143 }
1957     }
1958     }
1959 root 1.116 }
1960    
1961     void
1962 root 1.133 draw_magicmap (CFPlus::Map self, int dx, int dy, int w, int h, unsigned char *data)
1963 root 1.117 CODE:
1964     {
1965     static float color[16][3] = {
1966 root 1.123 { 0.00F, 0.00F, 0.00F },
1967     { 1.00F, 1.00F, 1.00F },
1968     { 0.00F, 0.00F, 0.55F },
1969     { 1.00F, 0.00F, 0.00F },
1970    
1971     { 1.00F, 0.54F, 0.00F },
1972     { 0.11F, 0.56F, 1.00F },
1973     { 0.93F, 0.46F, 0.00F },
1974     { 0.18F, 0.54F, 0.34F },
1975    
1976     { 0.56F, 0.73F, 0.56F },
1977     { 0.80F, 0.80F, 0.80F },
1978     { 0.55F, 0.41F, 0.13F },
1979     { 0.99F, 0.77F, 0.26F },
1980    
1981     { 0.74F, 0.65F, 0.41F },
1982    
1983     { 0.00F, 1.00F, 1.00F },
1984     { 1.00F, 0.00F, 1.00F },
1985     { 1.00F, 1.00F, 0.00F },
1986 root 1.117 };
1987    
1988     int x, y;
1989    
1990     glEnable (GL_TEXTURE_2D);
1991     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1992     glEnable (GL_BLEND);
1993     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1994     glBegin (GL_QUADS);
1995    
1996     for (y = 0; y < h; y++)
1997     for (x = 0; x < w; x++)
1998     {
1999     unsigned char m = data [x + y * w];
2000    
2001 root 1.118 if (m)
2002     {
2003     float *c = color [m & 15];
2004    
2005     float tx1 = m & 0x40 ? 0.5 : 0.;
2006     float tx2 = tx1 + 0.5;
2007    
2008     glColor4f (c[0], c[1], c[2], 0.75);
2009     glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2010     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2011     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2012     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2013     }
2014 root 1.117 }
2015    
2016     glEnd ();
2017     glDisable (GL_BLEND);
2018     glDisable (GL_TEXTURE_2D);
2019     }
2020    
2021     void
2022 root 1.204 fow_texture (CFPlus::Map self, int mx, int my, int sw, int sh)
2023 root 1.116 PPCODE:
2024     {
2025     int x, y;
2026 root 1.204 int sw1 = sw + 2;
2027     int sh1 = sh + 2;
2028     int sh3 = sh * 3;
2029     int sw34 = (sw * 3 + 3) & ~3;
2030     uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2031     SV *darkness3_sv = sv_2mortal (newSV (sw34 * sh3));
2032     uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2033    
2034     SvPOK_only (darkness3_sv);
2035     SvCUR_set (darkness3_sv, sw34 * sh3);
2036 root 1.116
2037 root 1.204 mx += self->x - 1;
2038     my += self->y - 1;
2039 root 1.116
2040 root 1.204 memset (darkness1, 255, sw1 * sh1);
2041    
2042     for (y = 0; y < sh1; y++)
2043 root 1.164 if (0 <= y + my && y + my < self->rows)
2044 root 1.116 {
2045 root 1.164 maprow *row = self->row + (y + my);
2046 root 1.116
2047 root 1.204 for (x = 0; x < sw1; x++)
2048 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2049 root 1.116 {
2050 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2051 root 1.116
2052 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2053 root 1.143 ? 255 - (cell->darkness - 1)
2054 root 1.142 : 255 - FOW_DARKNESS;
2055 root 1.116 }
2056     }
2057 root 1.34
2058 root 1.204 for (y = 0; y < sh; ++y)
2059     for (x = 0; x < sw; ++x)
2060     {
2061     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2062     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2063     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2064     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2065     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2066     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2067     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2068     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2069     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2070    
2071     uint8_t r11 = (d11 + d21 + d12) / 3;
2072     uint8_t r21 = d21;
2073     uint8_t r31 = (d21 + d31 + d32) / 3;
2074    
2075     uint8_t r12 = d12;
2076     uint8_t r22 = d22;
2077     uint8_t r32 = d32;
2078    
2079     uint8_t r13 = (d13 + d23 + d12) / 3;
2080     uint8_t r23 = d23;
2081     uint8_t r33 = (d23 + d33 + d32) / 3;
2082    
2083     darkness3 [(y * 3 ) * sw34 + (x * 3 )] = MAX (d22, r11);
2084     darkness3 [(y * 3 ) * sw34 + (x * 3 + 1)] = MAX (d22, r21);
2085     darkness3 [(y * 3 ) * sw34 + (x * 3 + 2)] = MAX (d22, r31);
2086     darkness3 [(y * 3 + 1) * sw34 + (x * 3 )] = MAX (d22, r12);
2087     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 1)] = MAX (d22, r22);
2088     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 2)] = MAX (d22, r32);
2089     darkness3 [(y * 3 + 2) * sw34 + (x * 3 )] = MAX (d22, r13);
2090     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 1)] = MAX (d22, r23);
2091     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 2)] = MAX (d22, r33);
2092     }
2093 root 1.201
2094 root 1.204 free (darkness1);
2095 root 1.201
2096 root 1.32 EXTEND (SP, 3);
2097 root 1.204 PUSHs (sv_2mortal (newSViv (sw34)));
2098     PUSHs (sv_2mortal (newSViv (sh3)));
2099     PUSHs (darkness3_sv);
2100 root 1.30 }
2101    
2102 root 1.42 SV *
2103 root 1.133 get_rect (CFPlus::Map self, int x0, int y0, int w, int h)
2104 root 1.42 CODE:
2105     {
2106     int x, y, x1, y1;
2107     SV *data_sv = newSV (w * h * 7 + 5);
2108     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2109    
2110     *data++ = 0; /* version 0 format */
2111     *data++ = w >> 8; *data++ = w;
2112     *data++ = h >> 8; *data++ = h;
2113    
2114     // we need to do this 'cause we don't keep an absolute coord system for rows
2115 root 1.55 // TODO: treat rows as we treat columns
2116 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2117     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2118    
2119     x0 += self->x - self->ox;
2120     y0 += self->y - self->oy;
2121    
2122     x1 = x0 + w;
2123     y1 = y0 + h;
2124    
2125     for (y = y0; y < y1; y++)
2126     {
2127     maprow *row = 0 <= y && y < self->rows
2128     ? self->row + y
2129     : 0;
2130    
2131     for (x = x0; x < x1; x++)
2132     {
2133     if (row && row->c0 <= x && x < row->c1)
2134     {
2135     mapcell *cell = row->col + (x - row->c0);
2136     uint8_t flags = 0;
2137    
2138 root 1.174 if (cell->tile [0]) flags |= 1;
2139     if (cell->tile [1]) flags |= 2;
2140     if (cell->tile [2]) flags |= 4;
2141 root 1.42
2142     *data++ = flags;
2143    
2144     if (flags & 1)
2145     {
2146 root 1.174 tileid tile = cell->tile [0];
2147     *data++ = tile >> 8;
2148     *data++ = tile;
2149 root 1.42 }
2150    
2151     if (flags & 2)
2152     {
2153 root 1.174 tileid tile = cell->tile [1];
2154     *data++ = tile >> 8;
2155     *data++ = tile;
2156 root 1.42 }
2157    
2158     if (flags & 4)
2159     {
2160 root 1.174 tileid tile = cell->tile [2];
2161     *data++ = tile >> 8;
2162     *data++ = tile;
2163 root 1.42 }
2164     }
2165     else
2166     *data++ = 0;
2167     }
2168     }
2169    
2170     SvPOK_only (data_sv);
2171     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2172     RETVAL = data_sv;
2173     }
2174     OUTPUT:
2175     RETVAL
2176    
2177     void
2178 root 1.133 set_rect (CFPlus::Map self, int x0, int y0, uint8_t *data)
2179 root 1.42 PPCODE:
2180     {
2181     int x, y, z;
2182 root 1.48 int w, h;
2183 root 1.42 int x1, y1;
2184    
2185     if (*data++ != 0)
2186     return; /* version mismatch */
2187    
2188 root 1.48 w = *data++ << 8; w |= *data++;
2189     h = *data++ << 8; h |= *data++;
2190 root 1.42
2191     // we need to do this 'cause we don't keep an absolute coord system for rows
2192 root 1.55 // TODO: treat rows as we treat columns
2193 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2194     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2195    
2196     x0 += self->x - self->ox;
2197     y0 += self->y - self->oy;
2198    
2199     x1 = x0 + w;
2200     y1 = y0 + h;
2201    
2202     for (y = y0; y < y1; y++)
2203     {
2204     maprow *row = map_get_row (self, y);
2205    
2206     for (x = x0; x < x1; x++)
2207     {
2208     uint8_t flags = *data++;
2209    
2210     if (flags)
2211     {
2212     mapcell *cell = row_get_cell (row, x);
2213 root 1.174 tileid tile[3] = { 0, 0, 0 };
2214 root 1.42
2215 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2216     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2217     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2218 root 1.42
2219 root 1.143 if (cell->darkness == 0)
2220 root 1.42 {
2221 root 1.142 cell->darkness = 0;
2222 root 1.42
2223     for (z = 0; z <= 2; z++)
2224     {
2225 root 1.174 tileid t = tile [z];
2226    
2227 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2228 root 1.174 {
2229     XPUSHs (sv_2mortal (newSViv (t)));
2230     need_texid (self, t);
2231     }
2232 root 1.42
2233 root 1.174 cell->tile [z] = t;
2234 root 1.42 }
2235     }
2236     }
2237     }
2238     }
2239     }
2240    
2241 root 1.212 MODULE = CFPlus PACKAGE = CFPlus::RW
2242 root 1.205
2243 root 1.212 CFPlus::RW
2244 root 1.211 new (SV *class, SV *data_sv)
2245     CODE:
2246     {
2247     STRLEN datalen;
2248     char *data = SvPVbyte (data_sv, datalen);
2249    
2250 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2251 root 1.211 }
2252     OUTPUT:
2253     RETVAL
2254    
2255 root 1.212 CFPlus::RW
2256     new_from_file (SV *class, const char *path, const char *mode = "rb")
2257     CODE:
2258     RETVAL = SDL_RWFromFile (path, mode);
2259     OUTPUT:
2260     RETVAL
2261    
2262     void
2263     close (CFPlus::RW self)
2264     CODE:
2265     SDL_RWclose (self);
2266    
2267     MODULE = CFPlus PACKAGE = CFPlus::Channel
2268    
2269     PROTOTYPES: DISABLE
2270    
2271 root 1.213 void
2272     halt (CFPlus::Channel self)
2273     CODE:
2274     Mix_HaltChannel (self);
2275    
2276     void
2277     expire (CFPlus::Channel self, int ticks = -1)
2278     CODE:
2279     Mix_ExpireChannel (self, ticks);
2280    
2281     void
2282     fade_out (CFPlus::Channel self, int ticks = -1)
2283     CODE:
2284     Mix_FadeOutChannel (self, ticks);
2285    
2286 root 1.212 int
2287     volume (CFPlus::Channel self, int volume)
2288     CODE:
2289     RETVAL = Mix_Volume (self, volume);
2290     OUTPUT:
2291     RETVAL
2292    
2293 root 1.213 void
2294 root 1.212 unregister_all_effects (CFPlus::Channel self)
2295     CODE:
2296 root 1.213 Mix_UnregisterAllEffects (self);
2297 root 1.212
2298 root 1.213 void
2299 root 1.212 set_panning (CFPlus::Channel self, int left, int right)
2300     CODE:
2301 root 1.213 Mix_SetPanning (self, left, right);
2302 root 1.212
2303 root 1.213 void
2304 root 1.212 set_distance (CFPlus::Channel self, int distance)
2305     CODE:
2306 root 1.213 Mix_SetDistance (self, distance);
2307 root 1.212
2308 root 1.213 void
2309 root 1.212 set_position (CFPlus::Channel self, int angle, int distance)
2310     CODE:
2311 root 1.213 Mix_SetPosition (self, angle, distance);
2312 root 1.212
2313 root 1.213 void
2314 root 1.212 set_reverse_stereo (CFPlus::Channel self, int flip)
2315     CODE:
2316 root 1.213 Mix_SetReverseStereo (self, flip);
2317 root 1.212
2318     MODULE = CFPlus PACKAGE = CFPlus::MixChunk
2319    
2320     PROTOTYPES: DISABLE
2321    
2322 root 1.211 CFPlus::MixChunk
2323 root 1.212 new (SV *class, CFPlus::RW rwops)
2324 root 1.52 CODE:
2325 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2326 root 1.52 OUTPUT:
2327     RETVAL
2328    
2329     void
2330 root 1.133 DESTROY (CFPlus::MixChunk self)
2331 root 1.52 CODE:
2332     Mix_FreeChunk (self);
2333    
2334     int
2335 root 1.133 volume (CFPlus::MixChunk self, int volume = -1)
2336 root 1.52 CODE:
2337     RETVAL = Mix_VolumeChunk (self, volume);
2338     OUTPUT:
2339     RETVAL
2340    
2341 root 1.212 CFPlus::Channel
2342 root 1.133 play (CFPlus::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
2343 root 1.52 CODE:
2344     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2345 root 1.212 Mix_UnregisterAllEffects (RETVAL);
2346 root 1.52 OUTPUT:
2347     RETVAL
2348    
2349 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixMusic
2350 root 1.52
2351     int
2352     volume (int volume = -1)
2353 root 1.205 PROTOTYPE: ;$
2354 root 1.52 CODE:
2355     RETVAL = Mix_VolumeMusic (volume);
2356     OUTPUT:
2357     RETVAL
2358    
2359 root 1.213 void
2360 root 1.194 fade_out (int ms)
2361     CODE:
2362 root 1.213 Mix_FadeOutMusic (ms);
2363 root 1.194
2364 root 1.212 void
2365     halt ()
2366     CODE:
2367     Mix_HaltMusic ();
2368    
2369 root 1.133 CFPlus::MixMusic
2370 root 1.212 new (SV *class, CFPlus::RW rwops)
2371 root 1.52 CODE:
2372 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
2373 root 1.52 OUTPUT:
2374     RETVAL
2375    
2376     void
2377 root 1.133 DESTROY (CFPlus::MixMusic self)
2378 root 1.52 CODE:
2379     Mix_FreeMusic (self);
2380    
2381     int
2382 root 1.133 play (CFPlus::MixMusic self, int loops = -1)
2383 root 1.52 CODE:
2384     RETVAL = Mix_PlayMusic (self, loops);
2385     OUTPUT:
2386     RETVAL
2387    
2388 root 1.213 void
2389 root 1.195 fade_in_pos (CFPlus::MixMusic self, int loops, int ms, double position)
2390     CODE:
2391 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
2392 root 1.195
2393 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::OpenGL
2394 root 1.54
2395 root 1.205 PROTOTYPES: ENABLE
2396    
2397 root 1.54 BOOT:
2398     {
2399 root 1.133 HV *stash = gv_stashpv ("CFPlus::OpenGL", 1);
2400 root 1.54 static const struct {
2401     const char *name;
2402     IV iv;
2403     } *civ, const_iv[] = {
2404     # define const_iv(name) { # name, (IV)name }
2405 root 1.199 const_iv (GL_VENDOR),
2406     const_iv (GL_VERSION),
2407     const_iv (GL_EXTENSIONS),
2408 root 1.54 const_iv (GL_COLOR_MATERIAL),
2409     const_iv (GL_SMOOTH),
2410     const_iv (GL_FLAT),
2411 root 1.69 const_iv (GL_DITHER),
2412 root 1.54 const_iv (GL_BLEND),
2413 root 1.89 const_iv (GL_CULL_FACE),
2414 root 1.69 const_iv (GL_SCISSOR_TEST),
2415 root 1.89 const_iv (GL_DEPTH_TEST),
2416     const_iv (GL_ALPHA_TEST),
2417     const_iv (GL_NORMALIZE),
2418     const_iv (GL_RESCALE_NORMAL),
2419 root 1.119 const_iv (GL_FRONT),
2420     const_iv (GL_BACK),
2421 root 1.206 const_iv (GL_AUX0),
2422 root 1.54 const_iv (GL_AND),
2423 root 1.67 const_iv (GL_ONE),
2424     const_iv (GL_ZERO),
2425 root 1.54 const_iv (GL_SRC_ALPHA),
2426 root 1.104 const_iv (GL_DST_ALPHA),
2427 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2428 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2429 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2430 root 1.54 const_iv (GL_RGB),
2431     const_iv (GL_RGBA),
2432 root 1.115 const_iv (GL_RGBA4),
2433     const_iv (GL_RGBA8),
2434     const_iv (GL_RGB5_A1),
2435 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2436 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2437     const_iv (GL_UNSIGNED_INT),
2438 root 1.54 const_iv (GL_ALPHA),
2439 root 1.86 const_iv (GL_INTENSITY),
2440 root 1.76 const_iv (GL_LUMINANCE),
2441 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2442 root 1.54 const_iv (GL_FLOAT),
2443     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2444     const_iv (GL_COMPILE),
2445 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
2446     const_iv (GL_PROXY_TEXTURE_2D),
2447 root 1.54 const_iv (GL_TEXTURE_1D),
2448     const_iv (GL_TEXTURE_2D),
2449     const_iv (GL_TEXTURE_ENV),
2450     const_iv (GL_TEXTURE_MAG_FILTER),
2451     const_iv (GL_TEXTURE_MIN_FILTER),
2452     const_iv (GL_TEXTURE_ENV_MODE),
2453     const_iv (GL_TEXTURE_WRAP_S),
2454     const_iv (GL_TEXTURE_WRAP_T),
2455 root 1.98 const_iv (GL_REPEAT),
2456 root 1.54 const_iv (GL_CLAMP),
2457 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2458 root 1.54 const_iv (GL_NEAREST),
2459     const_iv (GL_LINEAR),
2460 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2461     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2462     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2463     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2464     const_iv (GL_GENERATE_MIPMAP),
2465 root 1.54 const_iv (GL_MODULATE),
2466 root 1.69 const_iv (GL_DECAL),
2467 root 1.54 const_iv (GL_REPLACE),
2468 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2469 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2470     const_iv (GL_PROJECTION),
2471     const_iv (GL_MODELVIEW),
2472     const_iv (GL_COLOR_LOGIC_OP),
2473 root 1.69 const_iv (GL_SEPARABLE_2D),
2474 root 1.54 const_iv (GL_CONVOLUTION_2D),
2475     const_iv (GL_CONVOLUTION_BORDER_MODE),
2476     const_iv (GL_CONSTANT_BORDER),
2477 root 1.208 const_iv (GL_POINTS),
2478 root 1.54 const_iv (GL_LINES),
2479 root 1.138 const_iv (GL_LINE_STRIP),
2480 root 1.89 const_iv (GL_LINE_LOOP),
2481 root 1.54 const_iv (GL_QUADS),
2482 root 1.89 const_iv (GL_QUAD_STRIP),
2483     const_iv (GL_TRIANGLES),
2484     const_iv (GL_TRIANGLE_STRIP),
2485     const_iv (GL_TRIANGLE_FAN),
2486 root 1.208 const_iv (GL_POLYGON),
2487 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2488 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
2489     const_iv (GL_LINE_SMOOTH_HINT),
2490     const_iv (GL_POLYGON_SMOOTH_HINT),
2491     const_iv (GL_GENERATE_MIPMAP_HINT),
2492 root 1.54 const_iv (GL_FASTEST),
2493 root 1.206 const_iv (GL_DONT_CARE),
2494     const_iv (GL_NICEST),
2495 root 1.89 const_iv (GL_V2F),
2496     const_iv (GL_V3F),
2497     const_iv (GL_T2F_V3F),
2498     const_iv (GL_T2F_N3F_V3F),
2499 root 1.54 # undef const_iv
2500     };
2501    
2502     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2503     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2504 root 1.188
2505     texture_av = newAV ();
2506     AvREAL_off (texture_av);
2507 root 1.54 }
2508    
2509 root 1.97 char *
2510     gl_vendor ()
2511     CODE:
2512     RETVAL = (char *)glGetString (GL_VENDOR);
2513     OUTPUT:
2514     RETVAL
2515    
2516     char *
2517     gl_version ()
2518     CODE:
2519     RETVAL = (char *)glGetString (GL_VERSION);
2520     OUTPUT:
2521     RETVAL
2522    
2523     char *
2524     gl_extensions ()
2525     CODE:
2526     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2527     OUTPUT:
2528     RETVAL
2529    
2530 root 1.201 const char *glGetString (GLenum pname)
2531 root 1.199
2532     GLint glGetInteger (GLenum pname)
2533     CODE:
2534     glGetIntegerv (pname, &RETVAL);
2535     OUTPUT:
2536     RETVAL
2537    
2538     GLdouble glGetDouble (GLenum pname)
2539     CODE:
2540     glGetDoublev (pname, &RETVAL);
2541     OUTPUT:
2542     RETVAL
2543    
2544 root 1.54 int glGetError ()
2545    
2546 root 1.114 void glFinish ()
2547    
2548 root 1.54 void glClear (int mask)
2549    
2550     void glClearColor (float r, float g, float b, float a = 1.0)
2551     PROTOTYPE: @
2552    
2553     void glEnable (int cap)
2554    
2555     void glDisable (int cap)
2556    
2557     void glShadeModel (int mode)
2558    
2559     void glHint (int target, int mode)
2560    
2561     void glBlendFunc (int sfactor, int dfactor)
2562    
2563 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
2564     CODE:
2565     gl_BlendFuncSeparate (sa, da, saa, daa);
2566    
2567 root 1.89 void glDepthMask (int flag)
2568    
2569 root 1.54 void glLogicOp (int opcode)
2570    
2571 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
2572    
2573 root 1.54 void glMatrixMode (int mode)
2574    
2575     void glPushMatrix ()
2576    
2577     void glPopMatrix ()
2578    
2579     void glLoadIdentity ()
2580    
2581 root 1.119 void glDrawBuffer (int buffer)
2582    
2583     void glReadBuffer (int buffer)
2584    
2585 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
2586     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
2587    
2588     # near_ and far_ are due to microsofts buggy "c" compiler
2589 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
2590 root 1.54
2591 root 1.208 PROTOTYPES: DISABLE
2592    
2593 root 1.54 void glViewport (int x, int y, int width, int height)
2594    
2595 root 1.69 void glScissor (int x, int y, int width, int height)
2596    
2597 root 1.54 void glTranslate (float x, float y, float z = 0.)
2598     CODE:
2599     glTranslatef (x, y, z);
2600    
2601 root 1.62 void glScale (float x, float y, float z = 1.)
2602 root 1.54 CODE:
2603     glScalef (x, y, z);
2604    
2605     void glRotate (float angle, float x, float y, float z)
2606     CODE:
2607     glRotatef (angle, x, y, z);
2608    
2609     void glColor (float r, float g, float b, float a = 1.0)
2610 root 1.103 ALIAS:
2611     glColor_premultiply = 1
2612 root 1.54 CODE:
2613 root 1.103 if (ix)
2614     {
2615     r *= a;
2616     g *= a;
2617     b *= a;
2618     }
2619 root 1.90 // microsoft visual "c" rounds instead of truncating...
2620 root 1.130 glColor4f (r, g, b, a);
2621 root 1.54
2622 root 1.91 void glRasterPos (float x, float y, float z = 0.)
2623     CODE:
2624     glRasterPos3f (0, 0, z);
2625     glBitmap (0, 0, 0, 0, x, y, 0);
2626    
2627 root 1.54 void glVertex (float x, float y, float z = 0.)
2628     CODE:
2629     glVertex3f (x, y, z);
2630    
2631     void glTexCoord (float s, float t)
2632     CODE:
2633     glTexCoord2f (s, t);
2634    
2635 root 1.210 void glRect (float x1, float y1, float x2, float y2)
2636     CODE:
2637     glRectf (x1, y1, x2, y2);
2638    
2639 root 1.208 PROTOTYPES: ENABLE
2640    
2641     void glBegin (int mode)
2642    
2643     void glEnd ()
2644    
2645     void glPointSize (GLfloat size)
2646    
2647     void glLineWidth (GLfloat width)
2648    
2649     void glInterleavedArrays (int format, int stride, char *data)
2650    
2651     void glDrawElements (int mode, int count, int type, char *indices)
2652    
2653     # 1.2 void glDrawRangeElements (int mode, int start, int end
2654    
2655 root 1.54 void glTexEnv (int target, int pname, float param)
2656     CODE:
2657     glTexEnvf (target, pname, param);
2658    
2659     void glTexParameter (int target, int pname, float param)
2660     CODE:
2661     glTexParameterf (target, pname, param);
2662    
2663     void glBindTexture (int target, int name)
2664    
2665     void glConvolutionParameter (int target, int pname, float params)
2666     CODE:
2667 root 1.103 if (gl.ConvolutionParameterf)
2668     gl.ConvolutionParameterf (target, pname, params);
2669 root 1.54
2670     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
2671 root 1.64 CODE:
2672 root 1.103 if (gl.ConvolutionFilter2D)
2673     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
2674 root 1.54
2675 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
2676     CODE:
2677 root 1.103 if (gl.SeparableFilter2D)
2678     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
2679 root 1.69
2680 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
2681    
2682     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
2683    
2684 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
2685 root 1.68
2686 root 1.199 void glPixelZoom (float x, float y)
2687    
2688 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
2689    
2690 root 1.54 int glGenTexture ()
2691     CODE:
2692 root 1.192 RETVAL = gen_texture ();
2693 root 1.54 OUTPUT:
2694     RETVAL
2695    
2696     void glDeleteTexture (int name)
2697     CODE:
2698 root 1.192 del_texture (name);
2699    
2700 root 1.54 int glGenList ()
2701     CODE:
2702     RETVAL = glGenLists (1);
2703     OUTPUT:
2704     RETVAL
2705    
2706     void glDeleteList (int list)
2707     CODE:
2708     glDeleteLists (list, 1);
2709    
2710     void glNewList (int list, int mode = GL_COMPILE)
2711    
2712     void glEndList ()
2713    
2714     void glCallList (int list)
2715    
2716 root 1.207 MODULE = CFPlus PACKAGE = CFPlus::UI::Base
2717    
2718     PROTOTYPES: DISABLE
2719    
2720     void
2721 root 1.209 find_widget (SV *self, NV x, NV y)
2722 root 1.207 PPCODE:
2723     {
2724 root 1.209 if (within_widget (self, x, y))
2725     XPUSHs (self);
2726     }
2727    
2728     BOOT:
2729     {
2730     hover_gv = gv_fetchpv ("CFPlus::UI::HOVER", 1, SVt_NV);
2731    
2732     draw_x_gv = gv_fetchpv ("CFPlus::UI::Base::draw_x", 1, SVt_NV);
2733     draw_y_gv = gv_fetchpv ("CFPlus::UI::Base::draw_y", 1, SVt_NV);
2734     draw_w_gv = gv_fetchpv ("CFPlus::UI::Base::draw_w", 1, SVt_NV);
2735     draw_h_gv = gv_fetchpv ("CFPlus::UI::Base::draw_h", 1, SVt_NV);
2736     }
2737    
2738     void
2739     draw (SV *self)
2740     CODE:
2741     {
2742     HV *hv;
2743     SV **svp;
2744     NV x, y, w, h;
2745     SV *draw_x_sv = GvSV (draw_x_gv);
2746     SV *draw_y_sv = GvSV (draw_y_gv);
2747     SV *draw_w_sv = GvSV (draw_w_gv);
2748     SV *draw_h_sv = GvSV (draw_h_gv);
2749     SV *hover;
2750     double draw_x, draw_y, draw_w, draw_h;
2751    
2752     if (!SvROK (self))
2753     croak ("CFPlus::Base::draw: %s not a reference", SvPV_nolen (self));
2754    
2755     hv = (HV *)SvRV (self);
2756    
2757     if (SvTYPE (hv) != SVt_PVHV)
2758     croak ("CFPlus::Base::draw: %s not a hashref", SvPV_nolen (self));
2759    
2760     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
2761     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
2762    
2763     if (!h || !w)
2764     XSRETURN_EMPTY;
2765    
2766     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
2767     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
2768    
2769     draw_x = SvNV (draw_x_sv) + x;
2770     draw_y = SvNV (draw_y_sv) + y;
2771    
2772     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
2773     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
2774     XSRETURN_EMPTY;
2775    
2776     sv_setnv (draw_x_sv, draw_x);
2777     sv_setnv (draw_y_sv, draw_y);
2778    
2779     glPushMatrix ();
2780     glTranslated (x, y, 0);
2781    
2782     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
2783     {
2784     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
2785    
2786     if (svp && SvTRUE (*svp))
2787     {
2788     glColor4f (1*0.2f, 0.8*0.2f, 0.5*0.2f, 0.2f);
2789     glEnable (GL_BLEND);
2790     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
2791     glBegin (GL_QUADS);
2792     glVertex2f (0, 0);
2793     glVertex2f (w, 0);
2794     glVertex2f (w, h);
2795     glVertex2f (0, h);
2796     glEnd ();
2797     glDisable (GL_BLEND);
2798     }
2799     }
2800     #if 0
2801     if ($ENV{CFPLUS_DEBUG} & 1) {
2802     glPushMatrix;
2803     glColor 1, 1, 0, 1;
2804     glTranslate 0.375, 0.375;
2805     glBegin GL_LINE_LOOP;
2806     glVertex 0 , 0;
2807     glVertex $self->{w} - 1, 0;
2808     glVertex $self->{w} - 1, $self->{h} - 1;
2809     glVertex 0 , $self->{h} - 1;
2810     glEnd;
2811     glPopMatrix;
2812     #CFPlus::UI::Label->new (w => $self->{w}, h => $self->{h}, text => $self, fontsize => 0)->_draw;
2813     }
2814     #endif
2815     PUSHMARK (SP);
2816     XPUSHs (self);
2817     PUTBACK;
2818     call_method ("_draw", G_VOID | G_DISCARD);
2819     SPAGAIN;
2820    
2821     glPopMatrix ();
2822    
2823     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
2824     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
2825 root 1.207 }
2826