ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.220
Committed: Thu Aug 9 11:02:08 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.219: +8 -0 lines
Log Message:
implement set_positon_r and use it

File Contents

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