ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.195
Committed: Sat Jul 14 12:05:52 2007 UTC (16 years, 10 months ago) by root
Branch: MAIN
Changes since 1.194: +7 -0 lines
Log Message:
greatly enhance and improve music selection algorithm and reduce database load

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