ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.214
Committed: Sun Jul 29 18:56:02 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.213: +3 -0 lines
Log Message:
put music and other resources into the database, now that we can play form memory

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.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     if (items < 5)
1356     {
1357 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1358     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1359 root 1.12 }
1360    
1361 root 1.76 if (ix)
1362     {
1363     glEnable (GL_BLEND);
1364 root 1.103
1365     if (ix == 2)
1366     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1367     else
1368     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1369 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1370 root 1.103
1371 root 1.86 glEnable (GL_ALPHA_TEST);
1372     glAlphaFunc (GL_GREATER, 0.01f);
1373 root 1.76 }
1374    
1375 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1376 root 1.76
1377 root 1.12 glBegin (GL_QUADS);
1378 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1379     glTexCoord2f (0, t); glVertex2f (x , y + h);
1380     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1381     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1382 root 1.12 glEnd ();
1383 root 1.76
1384     if (ix)
1385 root 1.86 {
1386     glDisable (GL_ALPHA_TEST);
1387     glDisable (GL_BLEND);
1388     }
1389 root 1.11 }
1390 root 1.28
1391 root 1.199 IV texture_valid_2d (GLint internalformat, GLsizei w, GLsizei h, GLenum format, GLenum type)
1392     CODE:
1393     {
1394     GLint width;
1395     glTexImage2D (GL_PROXY_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, 0);
1396     glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
1397     RETVAL = width > 0;
1398     }
1399     OUTPUT:
1400     RETVAL
1401    
1402 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Map
1403 root 1.28
1404 root 1.205 PROTOTYPES: DISABLE
1405    
1406 root 1.133 CFPlus::Map
1407 root 1.164 new (SV *class)
1408 root 1.28 CODE:
1409     New (0, RETVAL, 1, struct map);
1410 root 1.42 RETVAL->x = 0;
1411     RETVAL->y = 0;
1412 root 1.164 RETVAL->w = 0;
1413     RETVAL->h = 0;
1414 root 1.42 RETVAL->ox = 0;
1415     RETVAL->oy = 0;
1416 root 1.174 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1417     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1418 root 1.28 RETVAL->rows = 0;
1419     RETVAL->row = 0;
1420     OUTPUT:
1421     RETVAL
1422    
1423     void
1424 root 1.133 DESTROY (CFPlus::Map self)
1425 root 1.28 CODE:
1426     {
1427 root 1.30 map_clear (self);
1428 root 1.174 Safefree (self->face2tile);
1429 root 1.111 Safefree (self->tex);
1430 root 1.29 Safefree (self);
1431     }
1432    
1433     void
1434 root 1.164 resize (CFPlus::Map self, int map_width, int map_height)
1435     CODE:
1436     self->w = map_width;
1437     self->h = map_height;
1438    
1439     void
1440 root 1.133 clear (CFPlus::Map self)
1441 root 1.30 CODE:
1442     map_clear (self);
1443    
1444     void
1445 root 1.174 set_tileid (CFPlus::Map self, int face, int tile)
1446 root 1.29 CODE:
1447     {
1448 root 1.174 need_facenum (self, face); self->face2tile [face] = tile;
1449     need_texid (self, tile);
1450 root 1.42 }
1451    
1452     void
1453 root 1.176 set_smooth (CFPlus::Map self, int face, int smooth, int level)
1454     CODE:
1455     {
1456     tileid texid;
1457     maptex *tex;
1458    
1459     if (face < 0 || face >= self->faces)
1460     return;
1461    
1462     if (smooth < 0 || smooth >= self->faces)
1463     return;
1464    
1465     texid = self->face2tile [face];
1466    
1467     if (!texid)
1468     return;
1469    
1470     tex = self->tex + texid;
1471     tex->smoothtile = self->face2tile [smooth];
1472     tex->smoothlevel = level;
1473     }
1474    
1475     void
1476 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)
1477 root 1.42 CODE:
1478     {
1479 root 1.174 need_texid (self, texid);
1480 root 1.42
1481 root 1.48 {
1482     maptex *tex = self->tex + texid;
1483 root 1.39
1484 root 1.48 tex->name = name;
1485     tex->w = w;
1486     tex->h = h;
1487     tex->s = s;
1488     tex->t = t;
1489     tex->r = r;
1490     tex->g = g;
1491     tex->b = b;
1492     tex->a = a;
1493     }
1494 root 1.95
1495     // somewhat hackish, but for textures that require it, it really
1496     // improves the look, and most others don't suffer.
1497     glBindTexture (GL_TEXTURE_2D, name);
1498 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1499     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1500     // use uglier nearest interpolation because linear suffers
1501     // from transparent color bleeding and ugly wrapping effects.
1502     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1503 root 1.29 }
1504    
1505 root 1.42 int
1506 root 1.133 ox (CFPlus::Map self)
1507 root 1.42 ALIAS:
1508     oy = 1
1509 root 1.101 x = 2
1510     y = 3
1511 root 1.102 w = 4
1512     h = 5
1513 root 1.42 CODE:
1514     switch (ix)
1515     {
1516     case 0: RETVAL = self->ox; break;
1517     case 1: RETVAL = self->oy; break;
1518 root 1.101 case 2: RETVAL = self->x; break;
1519     case 3: RETVAL = self->y; break;
1520 root 1.102 case 4: RETVAL = self->w; break;
1521     case 5: RETVAL = self->h; break;
1522 root 1.42 }
1523     OUTPUT:
1524     RETVAL
1525    
1526 root 1.29 void
1527 root 1.133 scroll (CFPlus::Map self, int dx, int dy)
1528 root 1.43 CODE:
1529     {
1530 root 1.44 if (dx > 0)
1531 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
1532 root 1.44 else if (dx < 0)
1533 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
1534 root 1.44
1535     if (dy > 0)
1536 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
1537 root 1.44 else if (dy < 0)
1538 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
1539 root 1.43
1540 root 1.44 self->ox += dx; self->x += dx;
1541     self->oy += dy; self->y += dy;
1542 root 1.43
1543     while (self->y < 0)
1544     {
1545     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1546    
1547     self->rows += MAP_EXTEND_Y;
1548     self->y += MAP_EXTEND_Y;
1549     }
1550 root 1.44 }
1551 root 1.43
1552 root 1.44 void
1553 root 1.141 map1a_update (CFPlus::Map self, SV *data_, int extmap)
1554 root 1.44 CODE:
1555     {
1556 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1557     uint8_t *data_end = (uint8_t *)SvEND (data_);
1558 root 1.48 mapcell *cell;
1559     int x, y, flags;
1560 root 1.43
1561 root 1.150 while (data < data_end - 1)
1562 root 1.29 {
1563 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1564 root 1.30
1565 root 1.120 x = self->x + ((flags >> 10) & 63);
1566     y = self->y + ((flags >> 4) & 63);
1567 root 1.29
1568 root 1.48 cell = map_get_cell (self, x, y);
1569 root 1.29
1570     if (flags & 15)
1571     {
1572 root 1.142 if (!cell->darkness)
1573 root 1.29 {
1574 root 1.154 memset (cell, 0, sizeof (*cell));
1575 root 1.142 cell->darkness = 256;
1576 root 1.29 }
1577 root 1.45
1578 root 1.142 //TODO: don't trust server data to be in-range(!)
1579    
1580 root 1.141 if (flags & 8)
1581     {
1582     if (extmap)
1583     {
1584     uint8_t ext, cmd;
1585    
1586     do
1587     {
1588     ext = *data++;
1589 root 1.144 cmd = ext & 0x3f;
1590 root 1.141
1591 root 1.147 if (cmd < 4)
1592 root 1.142 cell->darkness = 255 - ext * 64 + 1;
1593 root 1.147 else if (cmd == 5) // health
1594     {
1595     cell->stat_width = 1;
1596     cell->stat_hp = *data++;
1597     }
1598     else if (cmd == 6) // monster width
1599     cell->stat_width = *data++ + 1;
1600 root 1.169 else if (cmd == 0x47)
1601 root 1.153 {
1602 root 1.182 if (*data == 4)
1603     ; // decode player count
1604 root 1.153
1605     data += *data + 1;
1606     }
1607     else if (cmd == 8) // cell flags
1608     cell->flags = *data++;
1609 root 1.144 else if (ext & 0x40) // unknown, multibyte => skip
1610     data += *data + 1;
1611 root 1.147 else
1612     data++;
1613 root 1.141 }
1614 root 1.147 while (ext & 0x80);
1615 root 1.141 }
1616     else
1617 root 1.142 cell->darkness = *data++ + 1;
1618 root 1.141 }
1619 root 1.29
1620     if (flags & 4)
1621     {
1622 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1623     need_facenum (self, face);
1624     cell->tile [0] = self->face2tile [face];
1625 root 1.29 }
1626    
1627     if (flags & 2)
1628     {
1629 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1630     need_facenum (self, face);
1631     cell->tile [1] = self->face2tile [face];
1632 root 1.29 }
1633    
1634     if (flags & 1)
1635     {
1636 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1637     need_facenum (self, face);
1638     cell->tile [2] = self->face2tile [face];
1639 root 1.29 }
1640     }
1641     else
1642 root 1.155 cell->darkness = 0;
1643 root 1.29 }
1644 root 1.28 }
1645    
1646 root 1.40 SV *
1647 root 1.133 mapmap (CFPlus::Map self, int x0, int y0, int w, int h)
1648 root 1.40 CODE:
1649     {
1650 root 1.55 int x1, x;
1651     int y1, y;
1652 root 1.40 int z;
1653     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1654     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1655    
1656     SvPOK_only (map_sv);
1657     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1658    
1659 root 1.55 x0 += self->x; x1 = x0 + w;
1660     y0 += self->y; y1 = y0 + h;
1661 root 1.40
1662     for (y = y0; y < y1; y++)
1663     {
1664     maprow *row = 0 <= y && y < self->rows
1665     ? self->row + y
1666     : 0;
1667    
1668     for (x = x0; x < x1; x++)
1669     {
1670     int r = 32, g = 32, b = 32, a = 192;
1671    
1672     if (row && row->c0 <= x && x < row->c1)
1673     {
1674     mapcell *cell = row->col + (x - row->c0);
1675    
1676     for (z = 0; z <= 0; z++)
1677     {
1678 root 1.174 maptex tex = self->tex [cell->tile [z]];
1679     int a0 = 255 - tex.a;
1680     int a1 = tex.a;
1681    
1682     r = (r * a0 + tex.r * a1) / 255;
1683     g = (g * a0 + tex.g * a1) / 255;
1684     b = (b * a0 + tex.b * a1) / 255;
1685     a = (a * a0 + tex.a * a1) / 255;
1686 root 1.40 }
1687     }
1688    
1689     *map++ = (r )
1690     | (g << 8)
1691     | (b << 16)
1692     | (a << 24);
1693     }
1694     }
1695    
1696     RETVAL = map_sv;
1697     }
1698     OUTPUT:
1699     RETVAL
1700    
1701 root 1.30 void
1702 root 1.171 draw (CFPlus::Map self, int mx, int my, int sw, int sh, int T)
1703 root 1.116 CODE:
1704 root 1.30 {
1705 root 1.176 HV *smooth = (HV *)sv_2mortal ((SV *)newHV ());
1706     uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level
1707 root 1.178 static uint8_t smooth_max[256][256]; // egad, fats and wasteful on memory (64k)
1708 root 1.176 smooth_key skey;
1709 root 1.48 int x, y, z;
1710     int last_name;
1711    
1712 root 1.176 // thats current max. sorry.
1713     if (sw > 255) sw = 255;
1714     if (sh > 255) sh = 255;
1715    
1716     // clear key, in case of extra padding
1717     memset (&skey, 0, sizeof (skey));
1718    
1719 root 1.30 glColor4ub (255, 255, 255, 255);
1720    
1721 root 1.117 glEnable (GL_BLEND);
1722 root 1.30 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1723     glEnable (GL_TEXTURE_2D);
1724     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1725    
1726 root 1.48 glBegin (GL_QUADS);
1727 root 1.30
1728 root 1.48 last_name = 0;
1729 root 1.30
1730 root 1.164 mx += self->x;
1731     my += self->y;
1732    
1733 root 1.176 // first pass: determine smooth_max
1734     // rather ugly, if you ask me
1735     // could also be stored inside mapcell and updated on change
1736     memset (smooth_max, 0, sizeof (smooth_max));
1737    
1738     for (y = 0; y < sh; y++)
1739     if (0 <= y + my && y + my < self->rows)
1740     {
1741     maprow *row = self->row + (y + my);
1742    
1743     for (x = 0; x < sw; x++)
1744     if (row->c0 <= x + mx && x + mx < row->c1)
1745     {
1746     mapcell *cell = row->col + (x + mx - row->c0);
1747    
1748 root 1.177 smooth_max[x + 1][y + 1] =
1749     MAX (self->tex [cell->tile [0]].smoothlevel,
1750     MAX (self->tex [cell->tile [1]].smoothlevel,
1751     self->tex [cell->tile [2]].smoothlevel));
1752 root 1.176 }
1753     }
1754    
1755     for (z = 0; z <= 2; z++)
1756     {
1757 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
1758    
1759 root 1.176 for (y = 0; y < sh; y++)
1760     if (0 <= y + my && y + my < self->rows)
1761     {
1762     maprow *row = self->row + (y + my);
1763    
1764     for (x = 0; x < sw; x++)
1765     if (row->c0 <= x + mx && x + mx < row->c1)
1766     {
1767     mapcell *cell = row->col + (x + mx - row->c0);
1768     tileid tile = cell->tile [z];
1769    
1770     if (tile)
1771     {
1772     maptex tex = self->tex [tile];
1773     int px = (x + 1) * T - tex.w;
1774     int py = (y + 1) * T - tex.h;
1775    
1776     // suppressing texture state switches here
1777     // is only moderately effective, but worth the extra effort
1778     if (last_name != tex.name)
1779     {
1780     if (!tex.name)
1781     tex = self->tex [2]; /* missing, replace by noface */
1782    
1783     glEnd ();
1784     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1785     glBegin (GL_QUADS);
1786     }
1787    
1788     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1789     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1790     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1791     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1792    
1793     if (cell->flags && z == 2)
1794     {
1795     if (cell->flags & 1)
1796     {
1797     maptex tex = self->tex [1];
1798     int px = x * T + T * 2 / 32;
1799     int py = y * T - T * 6 / 32;
1800    
1801     glEnd ();
1802     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1803     glBegin (GL_QUADS);
1804    
1805     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1806     glTexCoord2f (0 , tex.t); glVertex2f (px , py + T);
1807     glTexCoord2f (tex.s, tex.t); glVertex2f (px + T, py + T);
1808     glTexCoord2f (tex.s, 0 ); glVertex2f (px + T, py );
1809     }
1810     }
1811    
1812     // update smooth hash
1813     if (tex.smoothtile)
1814     {
1815     skey.tile = tex.smoothtile;
1816     skey.level = tex.smoothlevel;
1817    
1818     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
1819 root 1.30
1820 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
1821     // shifted +1|+1 so we always stay positive.
1822 root 1.30
1823 root 1.180 // bits is ___n cccc CCCC bbbb
1824     // n do not draw borders&corners
1825     // c draw these corners, but...
1826     // C ... not these
1827     // b draw these borders
1828    
1829     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
1830     // ┃· ·· ·┃ ━━
1831    
1832     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
1833     // ·· ·· ·┏ ┓·
1834    
1835 root 1.176 // full tile
1836     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
1837    
1838     // borders
1839 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
1840     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
1841 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
1842     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
1843    
1844     // corners
1845     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
1846     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
1847     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
1848     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
1849     }
1850     }
1851     }
1852     }
1853 root 1.174
1854 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
1855     // this is basically counting sort
1856 root 1.176 {
1857 root 1.186 int w, b;
1858 root 1.30
1859 root 1.186 for (w = 0; w < 256 / 32; ++w)
1860     {
1861     uint32_t smask = smooth_level [w];
1862     if (smask)
1863     for (b = 0; b < 32; ++b)
1864     if (smask & (((uint32_t)1) << b))
1865 root 1.176 {
1866 root 1.186 int level = (w << 5) | b;
1867     HE *he;
1868 root 1.153
1869 root 1.186 hv_iterinit (smooth);
1870     while ((he = hv_iternext (smooth)))
1871 root 1.153 {
1872 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
1873     IV bits = SvIVX (HeVAL (he));
1874 root 1.176
1875 root 1.186 if (!(bits & 0x1000)
1876     && skey->level == level
1877 root 1.191 && level > smooth_max [skey->x][skey->y])
1878 root 1.174 {
1879 root 1.186 maptex tex = self->tex [skey->tile];
1880     int px = (((int)skey->x) - 1) * T;
1881     int py = (((int)skey->y) - 1) * T;
1882     int border = bits & 15;
1883     int corner = (bits >> 8) & ~(bits >> 4) & 15;
1884     float dx = tex.s * .0625f; // 16 images/row
1885     float dy = tex.t * .5f ; // 2 images/column
1886    
1887     // this time naively avoiding texture state changes
1888     // save gobs of state changes.
1889     if (last_name != tex.name)
1890     {
1891     if (!tex.name)
1892     continue; // smoothing not yet available
1893    
1894     glEnd ();
1895     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1896     glBegin (GL_QUADS);
1897     }
1898    
1899     if (border)
1900     {
1901     float ox = border * dx;
1902    
1903     glTexCoord2f (ox , 0.f ); glVertex2f (px , py );
1904     glTexCoord2f (ox , dy ); glVertex2f (px , py + T);
1905     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py + T);
1906     glTexCoord2f (ox + dx, 0.f ); glVertex2f (px + T, py );
1907     }
1908    
1909     if (corner)
1910     {
1911     float ox = corner * dx;
1912    
1913     glTexCoord2f (ox , dy ); glVertex2f (px , py );
1914     glTexCoord2f (ox , dy * 2.f); glVertex2f (px , py + T);
1915     glTexCoord2f (ox + dx, dy * 2.f); glVertex2f (px + T, py + T);
1916     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py );
1917     }
1918 root 1.174 }
1919 root 1.153 }
1920     }
1921 root 1.186 }
1922 root 1.176 }
1923    
1924 root 1.186 hv_clear (smooth);
1925     }
1926 root 1.30
1927     glEnd ();
1928 root 1.32
1929 root 1.34 glDisable (GL_TEXTURE_2D);
1930 root 1.152 glDisable (GL_BLEND);
1931 root 1.143
1932 root 1.145 // top layer: overlays such as the health bar
1933 root 1.143 for (y = 0; y < sh; y++)
1934 root 1.164 if (0 <= y + my && y + my < self->rows)
1935 root 1.143 {
1936 root 1.164 maprow *row = self->row + (y + my);
1937 root 1.143
1938     for (x = 0; x < sw; x++)
1939 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
1940 root 1.143 {
1941 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
1942 root 1.143
1943 root 1.171 int px = x * T;
1944     int py = y * T;
1945 root 1.143
1946     if (cell->stat_hp)
1947     {
1948 root 1.171 int width = cell->stat_width * T;
1949 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
1950 root 1.143
1951 root 1.152 glColor3ub (0, 0, 0);
1952 root 1.151 glRectf (px + 1, py - thick - 2,
1953     px + width - 1, py);
1954 root 1.147
1955 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
1956 root 1.147 glRectf (px + 2,
1957 root 1.151 py - thick - 1,
1958     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
1959 root 1.143 }
1960     }
1961     }
1962 root 1.116 }
1963    
1964     void
1965 root 1.133 draw_magicmap (CFPlus::Map self, int dx, int dy, int w, int h, unsigned char *data)
1966 root 1.117 CODE:
1967     {
1968     static float color[16][3] = {
1969 root 1.123 { 0.00F, 0.00F, 0.00F },
1970     { 1.00F, 1.00F, 1.00F },
1971     { 0.00F, 0.00F, 0.55F },
1972     { 1.00F, 0.00F, 0.00F },
1973    
1974     { 1.00F, 0.54F, 0.00F },
1975     { 0.11F, 0.56F, 1.00F },
1976     { 0.93F, 0.46F, 0.00F },
1977     { 0.18F, 0.54F, 0.34F },
1978    
1979     { 0.56F, 0.73F, 0.56F },
1980     { 0.80F, 0.80F, 0.80F },
1981     { 0.55F, 0.41F, 0.13F },
1982     { 0.99F, 0.77F, 0.26F },
1983    
1984     { 0.74F, 0.65F, 0.41F },
1985    
1986     { 0.00F, 1.00F, 1.00F },
1987     { 1.00F, 0.00F, 1.00F },
1988     { 1.00F, 1.00F, 0.00F },
1989 root 1.117 };
1990    
1991     int x, y;
1992    
1993     glEnable (GL_TEXTURE_2D);
1994     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1995     glEnable (GL_BLEND);
1996     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1997     glBegin (GL_QUADS);
1998    
1999     for (y = 0; y < h; y++)
2000     for (x = 0; x < w; x++)
2001     {
2002     unsigned char m = data [x + y * w];
2003    
2004 root 1.118 if (m)
2005     {
2006     float *c = color [m & 15];
2007    
2008     float tx1 = m & 0x40 ? 0.5 : 0.;
2009     float tx2 = tx1 + 0.5;
2010    
2011     glColor4f (c[0], c[1], c[2], 0.75);
2012     glTexCoord2f (tx1, 0.); glVertex2i (x , y );
2013     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
2014     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
2015     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
2016     }
2017 root 1.117 }
2018    
2019     glEnd ();
2020     glDisable (GL_BLEND);
2021     glDisable (GL_TEXTURE_2D);
2022     }
2023    
2024     void
2025 root 1.204 fow_texture (CFPlus::Map self, int mx, int my, int sw, int sh)
2026 root 1.116 PPCODE:
2027     {
2028     int x, y;
2029 root 1.204 int sw1 = sw + 2;
2030     int sh1 = sh + 2;
2031     int sh3 = sh * 3;
2032     int sw34 = (sw * 3 + 3) & ~3;
2033     uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
2034     SV *darkness3_sv = sv_2mortal (newSV (sw34 * sh3));
2035     uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
2036    
2037     SvPOK_only (darkness3_sv);
2038     SvCUR_set (darkness3_sv, sw34 * sh3);
2039 root 1.116
2040 root 1.204 mx += self->x - 1;
2041     my += self->y - 1;
2042 root 1.116
2043 root 1.204 memset (darkness1, 255, sw1 * sh1);
2044    
2045     for (y = 0; y < sh1; y++)
2046 root 1.164 if (0 <= y + my && y + my < self->rows)
2047 root 1.116 {
2048 root 1.164 maprow *row = self->row + (y + my);
2049 root 1.116
2050 root 1.204 for (x = 0; x < sw1; x++)
2051 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
2052 root 1.116 {
2053 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
2054 root 1.116
2055 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
2056 root 1.143 ? 255 - (cell->darkness - 1)
2057 root 1.142 : 255 - FOW_DARKNESS;
2058 root 1.116 }
2059     }
2060 root 1.34
2061 root 1.204 for (y = 0; y < sh; ++y)
2062     for (x = 0; x < sw; ++x)
2063     {
2064     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2065     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2066     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2067     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2068     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2069     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2070     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2071     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2072     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2073    
2074     uint8_t r11 = (d11 + d21 + d12) / 3;
2075     uint8_t r21 = d21;
2076     uint8_t r31 = (d21 + d31 + d32) / 3;
2077    
2078     uint8_t r12 = d12;
2079     uint8_t r22 = d22;
2080     uint8_t r32 = d32;
2081    
2082     uint8_t r13 = (d13 + d23 + d12) / 3;
2083     uint8_t r23 = d23;
2084     uint8_t r33 = (d23 + d33 + d32) / 3;
2085    
2086     darkness3 [(y * 3 ) * sw34 + (x * 3 )] = MAX (d22, r11);
2087     darkness3 [(y * 3 ) * sw34 + (x * 3 + 1)] = MAX (d22, r21);
2088     darkness3 [(y * 3 ) * sw34 + (x * 3 + 2)] = MAX (d22, r31);
2089     darkness3 [(y * 3 + 1) * sw34 + (x * 3 )] = MAX (d22, r12);
2090     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 1)] = MAX (d22, r22);
2091     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 2)] = MAX (d22, r32);
2092     darkness3 [(y * 3 + 2) * sw34 + (x * 3 )] = MAX (d22, r13);
2093     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 1)] = MAX (d22, r23);
2094     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 2)] = MAX (d22, r33);
2095     }
2096 root 1.201
2097 root 1.204 free (darkness1);
2098 root 1.201
2099 root 1.32 EXTEND (SP, 3);
2100 root 1.204 PUSHs (sv_2mortal (newSViv (sw34)));
2101     PUSHs (sv_2mortal (newSViv (sh3)));
2102     PUSHs (darkness3_sv);
2103 root 1.30 }
2104    
2105 root 1.42 SV *
2106 root 1.133 get_rect (CFPlus::Map self, int x0, int y0, int w, int h)
2107 root 1.42 CODE:
2108     {
2109     int x, y, x1, y1;
2110     SV *data_sv = newSV (w * h * 7 + 5);
2111     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2112    
2113     *data++ = 0; /* version 0 format */
2114     *data++ = w >> 8; *data++ = w;
2115     *data++ = h >> 8; *data++ = h;
2116    
2117     // we need to do this 'cause we don't keep an absolute coord system for rows
2118 root 1.55 // TODO: treat rows as we treat columns
2119 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2120     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2121    
2122     x0 += self->x - self->ox;
2123     y0 += self->y - self->oy;
2124    
2125     x1 = x0 + w;
2126     y1 = y0 + h;
2127    
2128     for (y = y0; y < y1; y++)
2129     {
2130     maprow *row = 0 <= y && y < self->rows
2131     ? self->row + y
2132     : 0;
2133    
2134     for (x = x0; x < x1; x++)
2135     {
2136     if (row && row->c0 <= x && x < row->c1)
2137     {
2138     mapcell *cell = row->col + (x - row->c0);
2139     uint8_t flags = 0;
2140    
2141 root 1.174 if (cell->tile [0]) flags |= 1;
2142     if (cell->tile [1]) flags |= 2;
2143     if (cell->tile [2]) flags |= 4;
2144 root 1.42
2145     *data++ = flags;
2146    
2147     if (flags & 1)
2148     {
2149 root 1.174 tileid tile = cell->tile [0];
2150     *data++ = tile >> 8;
2151     *data++ = tile;
2152 root 1.42 }
2153    
2154     if (flags & 2)
2155     {
2156 root 1.174 tileid tile = cell->tile [1];
2157     *data++ = tile >> 8;
2158     *data++ = tile;
2159 root 1.42 }
2160    
2161     if (flags & 4)
2162     {
2163 root 1.174 tileid tile = cell->tile [2];
2164     *data++ = tile >> 8;
2165     *data++ = tile;
2166 root 1.42 }
2167     }
2168     else
2169     *data++ = 0;
2170     }
2171     }
2172    
2173     SvPOK_only (data_sv);
2174     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2175     RETVAL = data_sv;
2176     }
2177     OUTPUT:
2178     RETVAL
2179    
2180     void
2181 root 1.133 set_rect (CFPlus::Map self, int x0, int y0, uint8_t *data)
2182 root 1.42 PPCODE:
2183     {
2184     int x, y, z;
2185 root 1.48 int w, h;
2186 root 1.42 int x1, y1;
2187    
2188     if (*data++ != 0)
2189     return; /* version mismatch */
2190    
2191 root 1.48 w = *data++ << 8; w |= *data++;
2192     h = *data++ << 8; h |= *data++;
2193 root 1.42
2194     // we need to do this 'cause we don't keep an absolute coord system for rows
2195 root 1.55 // TODO: treat rows as we treat columns
2196 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2197     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2198    
2199     x0 += self->x - self->ox;
2200     y0 += self->y - self->oy;
2201    
2202     x1 = x0 + w;
2203     y1 = y0 + h;
2204    
2205     for (y = y0; y < y1; y++)
2206     {
2207     maprow *row = map_get_row (self, y);
2208    
2209     for (x = x0; x < x1; x++)
2210     {
2211     uint8_t flags = *data++;
2212    
2213     if (flags)
2214     {
2215     mapcell *cell = row_get_cell (row, x);
2216 root 1.174 tileid tile[3] = { 0, 0, 0 };
2217 root 1.42
2218 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2219     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2220     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2221 root 1.42
2222 root 1.143 if (cell->darkness == 0)
2223 root 1.42 {
2224 root 1.142 cell->darkness = 0;
2225 root 1.42
2226     for (z = 0; z <= 2; z++)
2227     {
2228 root 1.174 tileid t = tile [z];
2229    
2230 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2231 root 1.174 {
2232     XPUSHs (sv_2mortal (newSViv (t)));
2233     need_texid (self, t);
2234     }
2235 root 1.42
2236 root 1.174 cell->tile [z] = t;
2237 root 1.42 }
2238     }
2239     }
2240     }
2241     }
2242     }
2243    
2244 root 1.212 MODULE = CFPlus PACKAGE = CFPlus::RW
2245 root 1.205
2246 root 1.212 CFPlus::RW
2247 root 1.211 new (SV *class, SV *data_sv)
2248     CODE:
2249     {
2250     STRLEN datalen;
2251     char *data = SvPVbyte (data_sv, datalen);
2252    
2253 root 1.212 RETVAL = SDL_RWFromConstMem (data, datalen);
2254 root 1.211 }
2255     OUTPUT:
2256     RETVAL
2257    
2258 root 1.212 CFPlus::RW
2259     new_from_file (SV *class, const char *path, const char *mode = "rb")
2260     CODE:
2261     RETVAL = SDL_RWFromFile (path, mode);
2262     OUTPUT:
2263     RETVAL
2264    
2265     void
2266     close (CFPlus::RW self)
2267     CODE:
2268     SDL_RWclose (self);
2269    
2270     MODULE = CFPlus PACKAGE = CFPlus::Channel
2271    
2272     PROTOTYPES: DISABLE
2273    
2274 root 1.213 void
2275     halt (CFPlus::Channel self)
2276     CODE:
2277     Mix_HaltChannel (self);
2278    
2279     void
2280     expire (CFPlus::Channel self, int ticks = -1)
2281     CODE:
2282     Mix_ExpireChannel (self, ticks);
2283    
2284     void
2285     fade_out (CFPlus::Channel self, int ticks = -1)
2286     CODE:
2287     Mix_FadeOutChannel (self, ticks);
2288    
2289 root 1.212 int
2290     volume (CFPlus::Channel self, int volume)
2291     CODE:
2292     RETVAL = Mix_Volume (self, volume);
2293     OUTPUT:
2294     RETVAL
2295    
2296 root 1.213 void
2297 root 1.212 unregister_all_effects (CFPlus::Channel self)
2298     CODE:
2299 root 1.213 Mix_UnregisterAllEffects (self);
2300 root 1.212
2301 root 1.213 void
2302 root 1.212 set_panning (CFPlus::Channel self, int left, int right)
2303     CODE:
2304 root 1.213 Mix_SetPanning (self, left, right);
2305 root 1.212
2306 root 1.213 void
2307 root 1.212 set_distance (CFPlus::Channel self, int distance)
2308     CODE:
2309 root 1.213 Mix_SetDistance (self, distance);
2310 root 1.212
2311 root 1.213 void
2312 root 1.212 set_position (CFPlus::Channel self, int angle, int distance)
2313     CODE:
2314 root 1.213 Mix_SetPosition (self, angle, distance);
2315 root 1.212
2316 root 1.213 void
2317 root 1.212 set_reverse_stereo (CFPlus::Channel self, int flip)
2318     CODE:
2319 root 1.213 Mix_SetReverseStereo (self, flip);
2320 root 1.212
2321     MODULE = CFPlus PACKAGE = CFPlus::MixChunk
2322    
2323     PROTOTYPES: DISABLE
2324    
2325 root 1.211 CFPlus::MixChunk
2326 root 1.212 new (SV *class, CFPlus::RW rwops)
2327 root 1.52 CODE:
2328 root 1.212 RETVAL = Mix_LoadWAV_RW (rwops, 1);
2329 root 1.52 OUTPUT:
2330     RETVAL
2331    
2332     void
2333 root 1.133 DESTROY (CFPlus::MixChunk self)
2334 root 1.52 CODE:
2335     Mix_FreeChunk (self);
2336    
2337     int
2338 root 1.133 volume (CFPlus::MixChunk self, int volume = -1)
2339 root 1.52 CODE:
2340     RETVAL = Mix_VolumeChunk (self, volume);
2341     OUTPUT:
2342     RETVAL
2343    
2344 root 1.212 CFPlus::Channel
2345 root 1.133 play (CFPlus::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
2346 root 1.52 CODE:
2347     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2348 root 1.212 Mix_UnregisterAllEffects (RETVAL);
2349 root 1.52 OUTPUT:
2350     RETVAL
2351    
2352 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixMusic
2353 root 1.52
2354     int
2355     volume (int volume = -1)
2356 root 1.205 PROTOTYPE: ;$
2357 root 1.52 CODE:
2358     RETVAL = Mix_VolumeMusic (volume);
2359     OUTPUT:
2360     RETVAL
2361    
2362 root 1.213 void
2363 root 1.194 fade_out (int ms)
2364     CODE:
2365 root 1.213 Mix_FadeOutMusic (ms);
2366 root 1.194
2367 root 1.212 void
2368     halt ()
2369     CODE:
2370     Mix_HaltMusic ();
2371    
2372 root 1.133 CFPlus::MixMusic
2373 root 1.212 new (SV *class, CFPlus::RW rwops)
2374 root 1.52 CODE:
2375 root 1.212 RETVAL = Mix_LoadMUS_RW (rwops);
2376 root 1.52 OUTPUT:
2377     RETVAL
2378    
2379     void
2380 root 1.133 DESTROY (CFPlus::MixMusic self)
2381 root 1.52 CODE:
2382     Mix_FreeMusic (self);
2383    
2384     int
2385 root 1.133 play (CFPlus::MixMusic self, int loops = -1)
2386 root 1.52 CODE:
2387     RETVAL = Mix_PlayMusic (self, loops);
2388     OUTPUT:
2389     RETVAL
2390    
2391 root 1.213 void
2392 root 1.195 fade_in_pos (CFPlus::MixMusic self, int loops, int ms, double position)
2393     CODE:
2394 root 1.213 Mix_FadeInMusicPos (self, loops, ms, position);
2395 root 1.195
2396 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::OpenGL
2397 root 1.54
2398 root 1.205 PROTOTYPES: ENABLE
2399    
2400 root 1.54 BOOT:
2401     {
2402 root 1.133 HV *stash = gv_stashpv ("CFPlus::OpenGL", 1);
2403 root 1.54 static const struct {
2404     const char *name;
2405     IV iv;
2406     } *civ, const_iv[] = {
2407     # define const_iv(name) { # name, (IV)name }
2408 root 1.199 const_iv (GL_VENDOR),
2409     const_iv (GL_VERSION),
2410     const_iv (GL_EXTENSIONS),
2411 root 1.54 const_iv (GL_COLOR_MATERIAL),
2412     const_iv (GL_SMOOTH),
2413     const_iv (GL_FLAT),
2414 root 1.69 const_iv (GL_DITHER),
2415 root 1.54 const_iv (GL_BLEND),
2416 root 1.89 const_iv (GL_CULL_FACE),
2417 root 1.69 const_iv (GL_SCISSOR_TEST),
2418 root 1.89 const_iv (GL_DEPTH_TEST),
2419     const_iv (GL_ALPHA_TEST),
2420     const_iv (GL_NORMALIZE),
2421     const_iv (GL_RESCALE_NORMAL),
2422 root 1.119 const_iv (GL_FRONT),
2423     const_iv (GL_BACK),
2424 root 1.206 const_iv (GL_AUX0),
2425 root 1.54 const_iv (GL_AND),
2426 root 1.67 const_iv (GL_ONE),
2427     const_iv (GL_ZERO),
2428 root 1.54 const_iv (GL_SRC_ALPHA),
2429 root 1.104 const_iv (GL_DST_ALPHA),
2430 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2431 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2432 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2433 root 1.54 const_iv (GL_RGB),
2434     const_iv (GL_RGBA),
2435 root 1.115 const_iv (GL_RGBA4),
2436     const_iv (GL_RGBA8),
2437     const_iv (GL_RGB5_A1),
2438 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2439 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2440     const_iv (GL_UNSIGNED_INT),
2441 root 1.54 const_iv (GL_ALPHA),
2442 root 1.86 const_iv (GL_INTENSITY),
2443 root 1.76 const_iv (GL_LUMINANCE),
2444 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2445 root 1.54 const_iv (GL_FLOAT),
2446     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2447     const_iv (GL_COMPILE),
2448 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
2449     const_iv (GL_PROXY_TEXTURE_2D),
2450 root 1.54 const_iv (GL_TEXTURE_1D),
2451     const_iv (GL_TEXTURE_2D),
2452     const_iv (GL_TEXTURE_ENV),
2453     const_iv (GL_TEXTURE_MAG_FILTER),
2454     const_iv (GL_TEXTURE_MIN_FILTER),
2455     const_iv (GL_TEXTURE_ENV_MODE),
2456     const_iv (GL_TEXTURE_WRAP_S),
2457     const_iv (GL_TEXTURE_WRAP_T),
2458 root 1.98 const_iv (GL_REPEAT),
2459 root 1.54 const_iv (GL_CLAMP),
2460 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2461 root 1.54 const_iv (GL_NEAREST),
2462     const_iv (GL_LINEAR),
2463 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2464     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2465     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2466     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2467     const_iv (GL_GENERATE_MIPMAP),
2468 root 1.54 const_iv (GL_MODULATE),
2469 root 1.69 const_iv (GL_DECAL),
2470 root 1.54 const_iv (GL_REPLACE),
2471 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2472 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2473     const_iv (GL_PROJECTION),
2474     const_iv (GL_MODELVIEW),
2475     const_iv (GL_COLOR_LOGIC_OP),
2476 root 1.69 const_iv (GL_SEPARABLE_2D),
2477 root 1.54 const_iv (GL_CONVOLUTION_2D),
2478     const_iv (GL_CONVOLUTION_BORDER_MODE),
2479     const_iv (GL_CONSTANT_BORDER),
2480 root 1.208 const_iv (GL_POINTS),
2481 root 1.54 const_iv (GL_LINES),
2482 root 1.138 const_iv (GL_LINE_STRIP),
2483 root 1.89 const_iv (GL_LINE_LOOP),
2484 root 1.54 const_iv (GL_QUADS),
2485 root 1.89 const_iv (GL_QUAD_STRIP),
2486     const_iv (GL_TRIANGLES),
2487     const_iv (GL_TRIANGLE_STRIP),
2488     const_iv (GL_TRIANGLE_FAN),
2489 root 1.208 const_iv (GL_POLYGON),
2490 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2491 root 1.206 const_iv (GL_POINT_SMOOTH_HINT),
2492     const_iv (GL_LINE_SMOOTH_HINT),
2493     const_iv (GL_POLYGON_SMOOTH_HINT),
2494     const_iv (GL_GENERATE_MIPMAP_HINT),
2495 root 1.54 const_iv (GL_FASTEST),
2496 root 1.206 const_iv (GL_DONT_CARE),
2497     const_iv (GL_NICEST),
2498 root 1.89 const_iv (GL_V2F),
2499     const_iv (GL_V3F),
2500     const_iv (GL_T2F_V3F),
2501     const_iv (GL_T2F_N3F_V3F),
2502 root 1.54 # undef const_iv
2503     };
2504    
2505     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2506     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2507 root 1.188
2508     texture_av = newAV ();
2509     AvREAL_off (texture_av);
2510 root 1.54 }
2511    
2512 root 1.97 char *
2513     gl_vendor ()
2514     CODE:
2515     RETVAL = (char *)glGetString (GL_VENDOR);
2516     OUTPUT:
2517     RETVAL
2518    
2519     char *
2520     gl_version ()
2521     CODE:
2522     RETVAL = (char *)glGetString (GL_VERSION);
2523     OUTPUT:
2524     RETVAL
2525    
2526     char *
2527     gl_extensions ()
2528     CODE:
2529     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2530     OUTPUT:
2531     RETVAL
2532    
2533 root 1.201 const char *glGetString (GLenum pname)
2534 root 1.199
2535     GLint glGetInteger (GLenum pname)
2536     CODE:
2537     glGetIntegerv (pname, &RETVAL);
2538     OUTPUT:
2539     RETVAL
2540    
2541     GLdouble glGetDouble (GLenum pname)
2542     CODE:
2543     glGetDoublev (pname, &RETVAL);
2544     OUTPUT:
2545     RETVAL
2546    
2547 root 1.54 int glGetError ()
2548    
2549 root 1.114 void glFinish ()
2550    
2551 root 1.54 void glClear (int mask)
2552    
2553     void glClearColor (float r, float g, float b, float a = 1.0)
2554     PROTOTYPE: @
2555    
2556     void glEnable (int cap)
2557    
2558     void glDisable (int cap)
2559    
2560     void glShadeModel (int mode)
2561    
2562     void glHint (int target, int mode)
2563    
2564     void glBlendFunc (int sfactor, int dfactor)
2565    
2566 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
2567     CODE:
2568     gl_BlendFuncSeparate (sa, da, saa, daa);
2569    
2570 root 1.89 void glDepthMask (int flag)
2571    
2572 root 1.54 void glLogicOp (int opcode)
2573    
2574 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
2575    
2576 root 1.54 void glMatrixMode (int mode)
2577    
2578     void glPushMatrix ()
2579    
2580     void glPopMatrix ()
2581    
2582     void glLoadIdentity ()
2583    
2584 root 1.119 void glDrawBuffer (int buffer)
2585    
2586     void glReadBuffer (int buffer)
2587    
2588 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
2589     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
2590    
2591     # near_ and far_ are due to microsofts buggy "c" compiler
2592 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
2593 root 1.54
2594 root 1.208 PROTOTYPES: DISABLE
2595    
2596 root 1.54 void glViewport (int x, int y, int width, int height)
2597    
2598 root 1.69 void glScissor (int x, int y, int width, int height)
2599    
2600 root 1.54 void glTranslate (float x, float y, float z = 0.)
2601     CODE:
2602     glTranslatef (x, y, z);
2603    
2604 root 1.62 void glScale (float x, float y, float z = 1.)
2605 root 1.54 CODE:
2606     glScalef (x, y, z);
2607    
2608     void glRotate (float angle, float x, float y, float z)
2609     CODE:
2610     glRotatef (angle, x, y, z);
2611    
2612     void glColor (float r, float g, float b, float a = 1.0)
2613 root 1.103 ALIAS:
2614     glColor_premultiply = 1
2615 root 1.54 CODE:
2616 root 1.103 if (ix)
2617     {
2618     r *= a;
2619     g *= a;
2620     b *= a;
2621     }
2622 root 1.90 // microsoft visual "c" rounds instead of truncating...
2623 root 1.130 glColor4f (r, g, b, a);
2624 root 1.54
2625 root 1.91 void glRasterPos (float x, float y, float z = 0.)
2626     CODE:
2627     glRasterPos3f (0, 0, z);
2628     glBitmap (0, 0, 0, 0, x, y, 0);
2629    
2630 root 1.54 void glVertex (float x, float y, float z = 0.)
2631     CODE:
2632     glVertex3f (x, y, z);
2633    
2634     void glTexCoord (float s, float t)
2635     CODE:
2636     glTexCoord2f (s, t);
2637    
2638 root 1.210 void glRect (float x1, float y1, float x2, float y2)
2639     CODE:
2640     glRectf (x1, y1, x2, y2);
2641    
2642 root 1.208 PROTOTYPES: ENABLE
2643    
2644     void glBegin (int mode)
2645    
2646     void glEnd ()
2647    
2648     void glPointSize (GLfloat size)
2649    
2650     void glLineWidth (GLfloat width)
2651    
2652     void glInterleavedArrays (int format, int stride, char *data)
2653    
2654     void glDrawElements (int mode, int count, int type, char *indices)
2655    
2656     # 1.2 void glDrawRangeElements (int mode, int start, int end
2657    
2658 root 1.54 void glTexEnv (int target, int pname, float param)
2659     CODE:
2660     glTexEnvf (target, pname, param);
2661    
2662     void glTexParameter (int target, int pname, float param)
2663     CODE:
2664     glTexParameterf (target, pname, param);
2665    
2666     void glBindTexture (int target, int name)
2667    
2668     void glConvolutionParameter (int target, int pname, float params)
2669     CODE:
2670 root 1.103 if (gl.ConvolutionParameterf)
2671     gl.ConvolutionParameterf (target, pname, params);
2672 root 1.54
2673     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
2674 root 1.64 CODE:
2675 root 1.103 if (gl.ConvolutionFilter2D)
2676     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
2677 root 1.54
2678 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
2679     CODE:
2680 root 1.103 if (gl.SeparableFilter2D)
2681     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
2682 root 1.69
2683 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
2684    
2685     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
2686    
2687 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
2688 root 1.68
2689 root 1.199 void glPixelZoom (float x, float y)
2690    
2691 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
2692    
2693 root 1.54 int glGenTexture ()
2694     CODE:
2695 root 1.192 RETVAL = gen_texture ();
2696 root 1.54 OUTPUT:
2697     RETVAL
2698    
2699     void glDeleteTexture (int name)
2700     CODE:
2701 root 1.192 del_texture (name);
2702    
2703 root 1.54 int glGenList ()
2704     CODE:
2705     RETVAL = glGenLists (1);
2706     OUTPUT:
2707     RETVAL
2708    
2709     void glDeleteList (int list)
2710     CODE:
2711     glDeleteLists (list, 1);
2712    
2713     void glNewList (int list, int mode = GL_COMPILE)
2714    
2715     void glEndList ()
2716    
2717     void glCallList (int list)
2718    
2719 root 1.207 MODULE = CFPlus PACKAGE = CFPlus::UI::Base
2720    
2721     PROTOTYPES: DISABLE
2722    
2723     void
2724 root 1.209 find_widget (SV *self, NV x, NV y)
2725 root 1.207 PPCODE:
2726     {
2727 root 1.209 if (within_widget (self, x, y))
2728     XPUSHs (self);
2729     }
2730    
2731     BOOT:
2732     {
2733     hover_gv = gv_fetchpv ("CFPlus::UI::HOVER", 1, SVt_NV);
2734    
2735     draw_x_gv = gv_fetchpv ("CFPlus::UI::Base::draw_x", 1, SVt_NV);
2736     draw_y_gv = gv_fetchpv ("CFPlus::UI::Base::draw_y", 1, SVt_NV);
2737     draw_w_gv = gv_fetchpv ("CFPlus::UI::Base::draw_w", 1, SVt_NV);
2738     draw_h_gv = gv_fetchpv ("CFPlus::UI::Base::draw_h", 1, SVt_NV);
2739     }
2740    
2741     void
2742     draw (SV *self)
2743     CODE:
2744     {
2745     HV *hv;
2746     SV **svp;
2747     NV x, y, w, h;
2748     SV *draw_x_sv = GvSV (draw_x_gv);
2749     SV *draw_y_sv = GvSV (draw_y_gv);
2750     SV *draw_w_sv = GvSV (draw_w_gv);
2751     SV *draw_h_sv = GvSV (draw_h_gv);
2752     SV *hover;
2753     double draw_x, draw_y, draw_w, draw_h;
2754    
2755     if (!SvROK (self))
2756     croak ("CFPlus::Base::draw: %s not a reference", SvPV_nolen (self));
2757    
2758     hv = (HV *)SvRV (self);
2759    
2760     if (SvTYPE (hv) != SVt_PVHV)
2761     croak ("CFPlus::Base::draw: %s not a hashref", SvPV_nolen (self));
2762    
2763     svp = hv_fetch (hv, "w", 1, 0); w = svp ? SvNV (*svp) : 0.;
2764     svp = hv_fetch (hv, "h", 1, 0); h = svp ? SvNV (*svp) : 0.;
2765    
2766     if (!h || !w)
2767     XSRETURN_EMPTY;
2768    
2769     svp = hv_fetch (hv, "x", 1, 0); x = svp ? SvNV (*svp) : 0.;
2770     svp = hv_fetch (hv, "y", 1, 0); y = svp ? SvNV (*svp) : 0.;
2771    
2772     draw_x = SvNV (draw_x_sv) + x;
2773     draw_y = SvNV (draw_y_sv) + y;
2774    
2775     if (draw_x + w < 0 || draw_x >= SvNV (draw_w_sv)
2776     || draw_y + h < 0 || draw_y >= SvNV (draw_h_sv))
2777     XSRETURN_EMPTY;
2778    
2779     sv_setnv (draw_x_sv, draw_x);
2780     sv_setnv (draw_y_sv, draw_y);
2781    
2782     glPushMatrix ();
2783     glTranslated (x, y, 0);
2784    
2785     if (SvROK (GvSV (hover_gv)) && SvRV (GvSV (hover_gv)) == (SV *)hv)
2786     {
2787     svp = hv_fetch (hv, "can_hover", sizeof ("can_hover") - 1, 0);
2788    
2789     if (svp && SvTRUE (*svp))
2790     {
2791     glColor4f (1*0.2f, 0.8*0.2f, 0.5*0.2f, 0.2f);
2792     glEnable (GL_BLEND);
2793     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
2794     glBegin (GL_QUADS);
2795     glVertex2f (0, 0);
2796     glVertex2f (w, 0);
2797     glVertex2f (w, h);
2798     glVertex2f (0, h);
2799     glEnd ();
2800     glDisable (GL_BLEND);
2801     }
2802     }
2803     #if 0
2804     if ($ENV{CFPLUS_DEBUG} & 1) {
2805     glPushMatrix;
2806     glColor 1, 1, 0, 1;
2807     glTranslate 0.375, 0.375;
2808     glBegin GL_LINE_LOOP;
2809     glVertex 0 , 0;
2810     glVertex $self->{w} - 1, 0;
2811     glVertex $self->{w} - 1, $self->{h} - 1;
2812     glVertex 0 , $self->{h} - 1;
2813     glEnd;
2814     glPopMatrix;
2815     #CFPlus::UI::Label->new (w => $self->{w}, h => $self->{h}, text => $self, fontsize => 0)->_draw;
2816     }
2817     #endif
2818     PUSHMARK (SP);
2819     XPUSHs (self);
2820     PUTBACK;
2821     call_method ("_draw", G_VOID | G_DISCARD);
2822     SPAGAIN;
2823    
2824     glPopMatrix ();
2825    
2826     draw_x = draw_x - x; sv_setnv (draw_x_sv, draw_x);
2827     draw_y = draw_y - y; sv_setnv (draw_y_sv, draw_y);
2828 root 1.207 }
2829