ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.200
Committed: Tue Jul 17 16:02:13 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.199: +35 -23 lines
Log Message:
support non-32bpp displays and non-alpha displays with lower quality (hopefully)

File Contents

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