ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.202
Committed: Tue Jul 17 18:34:24 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.201: +1 -0 lines
Log Message:
*** empty log message ***

File Contents

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