ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.223
Committed: Sat Aug 11 11:07:08 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.222: +71 -60 lines
Log Message:
* implement a "render cache", sort of our own slow display list.

* use it when drawing the map. while this will perfectly sort
  by texture and thus give a nice speedup in itself (hardware),
  its not the actual goal.

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