ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.192
Committed: Fri Apr 27 21:27:51 2007 UTC (17 years ago) by root
Branch: MAIN
CVS Tags: rel-0_98
Changes since 1.191: +29 -18 lines
Log Message:
even more changes to texture management - screw those completely broken drivers, but cater for the leaking ones

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