ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.209
Committed: Sat Jul 21 22:54:52 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.208: +105 -3 lines
Log Message:
rewrote ->draw in speed, making it ~40% faster, but it doesn't really show much except in profile output

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