ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.204
Committed: Thu Jul 19 14:54:50 2007 UTC (16 years, 9 months ago) by root
Branch: MAIN
Changes since 1.203: +57 -44 lines
Log Message:
- remove fow smoothing option, its now
  mandatory.
- change the map smoothing algorithm to be
  a bit harder, more edgy, but more true
  to reality.

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.203 pad (SV *data_, int ow, int oh, int nw, int nh)
1264 root 1.113 CODE:
1265     {
1266 root 1.203 if ((nw != ow || nh != oh) && SvOK (data_))
1267 root 1.113 {
1268 root 1.203 STRLEN datalen;
1269     char *data = SvPVbyte (data_, datalen);
1270     int bpp = datalen / (ow * oh);
1271     SV *result_ = sv_2mortal (newSV (nw * nh * bpp));
1272    
1273     SvPOK_only (result_);
1274     SvCUR_set (result_, nw * nh * bpp);
1275    
1276     memset (SvPVX (result_), 0, nw * nh * bpp);
1277     while (oh--)
1278     memcpy (SvPVX (result_) + oh * nw * bpp, data + oh * ow * bpp, ow * bpp);
1279 root 1.113
1280 root 1.203 sv_setsv (data_, result_);
1281 root 1.113 }
1282     }
1283    
1284     void
1285 root 1.114 draw_quad (SV *self, float x, float y, float w = 0., float h = 0.)
1286 root 1.12 PROTOTYPE: $$$;$$
1287 root 1.76 ALIAS:
1288     draw_quad_alpha = 1
1289     draw_quad_alpha_premultiplied = 2
1290 root 1.11 CODE:
1291     {
1292 root 1.12 HV *hv = (HV *)SvRV (self);
1293 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
1294     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
1295 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
1296    
1297     if (items < 5)
1298     {
1299 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
1300     h = SvNV (*hv_fetch (hv, "h", 1, 1));
1301 root 1.12 }
1302    
1303 root 1.76 if (ix)
1304     {
1305     glEnable (GL_BLEND);
1306 root 1.103
1307     if (ix == 2)
1308     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1309     else
1310     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1311 root 1.104 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
1312 root 1.103
1313 root 1.86 glEnable (GL_ALPHA_TEST);
1314     glAlphaFunc (GL_GREATER, 0.01f);
1315 root 1.76 }
1316    
1317 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1318 root 1.76
1319 root 1.12 glBegin (GL_QUADS);
1320 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1321     glTexCoord2f (0, t); glVertex2f (x , y + h);
1322     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1323     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1324 root 1.12 glEnd ();
1325 root 1.76
1326     if (ix)
1327 root 1.86 {
1328     glDisable (GL_ALPHA_TEST);
1329     glDisable (GL_BLEND);
1330     }
1331 root 1.11 }
1332 root 1.28
1333 root 1.199 IV texture_valid_2d (GLint internalformat, GLsizei w, GLsizei h, GLenum format, GLenum type)
1334     CODE:
1335     {
1336     GLint width;
1337     glTexImage2D (GL_PROXY_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, 0);
1338     glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
1339     RETVAL = width > 0;
1340     }
1341     OUTPUT:
1342     RETVAL
1343    
1344 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::Map
1345 root 1.28
1346 root 1.133 CFPlus::Map
1347 root 1.164 new (SV *class)
1348 root 1.28 CODE:
1349     New (0, RETVAL, 1, struct map);
1350 root 1.42 RETVAL->x = 0;
1351     RETVAL->y = 0;
1352 root 1.164 RETVAL->w = 0;
1353     RETVAL->h = 0;
1354 root 1.42 RETVAL->ox = 0;
1355     RETVAL->oy = 0;
1356 root 1.174 RETVAL->faces = 8192; Newz (0, RETVAL->face2tile, RETVAL->faces, tileid);
1357     RETVAL->texs = 8192; Newz (0, RETVAL->tex , RETVAL->texs , maptex);
1358 root 1.28 RETVAL->rows = 0;
1359     RETVAL->row = 0;
1360     OUTPUT:
1361     RETVAL
1362    
1363     void
1364 root 1.133 DESTROY (CFPlus::Map self)
1365 root 1.28 CODE:
1366     {
1367 root 1.30 map_clear (self);
1368 root 1.174 Safefree (self->face2tile);
1369 root 1.111 Safefree (self->tex);
1370 root 1.29 Safefree (self);
1371     }
1372    
1373     void
1374 root 1.164 resize (CFPlus::Map self, int map_width, int map_height)
1375     CODE:
1376     self->w = map_width;
1377     self->h = map_height;
1378    
1379     void
1380 root 1.133 clear (CFPlus::Map self)
1381 root 1.30 CODE:
1382     map_clear (self);
1383    
1384     void
1385 root 1.174 set_tileid (CFPlus::Map self, int face, int tile)
1386 root 1.29 CODE:
1387     {
1388 root 1.174 need_facenum (self, face); self->face2tile [face] = tile;
1389     need_texid (self, tile);
1390 root 1.42 }
1391    
1392     void
1393 root 1.176 set_smooth (CFPlus::Map self, int face, int smooth, int level)
1394     CODE:
1395     {
1396     tileid texid;
1397     maptex *tex;
1398    
1399     if (face < 0 || face >= self->faces)
1400     return;
1401    
1402     if (smooth < 0 || smooth >= self->faces)
1403     return;
1404    
1405     texid = self->face2tile [face];
1406    
1407     if (!texid)
1408     return;
1409    
1410     tex = self->tex + texid;
1411     tex->smoothtile = self->face2tile [smooth];
1412     tex->smoothlevel = level;
1413     }
1414    
1415     void
1416 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)
1417 root 1.42 CODE:
1418     {
1419 root 1.174 need_texid (self, texid);
1420 root 1.42
1421 root 1.48 {
1422     maptex *tex = self->tex + texid;
1423 root 1.39
1424 root 1.48 tex->name = name;
1425     tex->w = w;
1426     tex->h = h;
1427     tex->s = s;
1428     tex->t = t;
1429     tex->r = r;
1430     tex->g = g;
1431     tex->b = b;
1432     tex->a = a;
1433     }
1434 root 1.95
1435     // somewhat hackish, but for textures that require it, it really
1436     // improves the look, and most others don't suffer.
1437     glBindTexture (GL_TEXTURE_2D, name);
1438 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1439     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1440     // use uglier nearest interpolation because linear suffers
1441     // from transparent color bleeding and ugly wrapping effects.
1442     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1443 root 1.29 }
1444    
1445 root 1.42 int
1446 root 1.133 ox (CFPlus::Map self)
1447 root 1.42 ALIAS:
1448     oy = 1
1449 root 1.101 x = 2
1450     y = 3
1451 root 1.102 w = 4
1452     h = 5
1453 root 1.42 CODE:
1454     switch (ix)
1455     {
1456     case 0: RETVAL = self->ox; break;
1457     case 1: RETVAL = self->oy; break;
1458 root 1.101 case 2: RETVAL = self->x; break;
1459     case 3: RETVAL = self->y; break;
1460 root 1.102 case 4: RETVAL = self->w; break;
1461     case 5: RETVAL = self->h; break;
1462 root 1.42 }
1463     OUTPUT:
1464     RETVAL
1465    
1466 root 1.29 void
1467 root 1.133 scroll (CFPlus::Map self, int dx, int dy)
1468 root 1.43 CODE:
1469     {
1470 root 1.44 if (dx > 0)
1471 root 1.154 map_blank (self, self->x, self->y, dx, self->h);
1472 root 1.44 else if (dx < 0)
1473 root 1.187 map_blank (self, self->x + self->w + dx, self->y, -dx, self->h);
1474 root 1.44
1475     if (dy > 0)
1476 root 1.154 map_blank (self, self->x, self->y, self->w, dy);
1477 root 1.44 else if (dy < 0)
1478 root 1.187 map_blank (self, self->x, self->y + self->h + dy, self->w, -dy);
1479 root 1.43
1480 root 1.44 self->ox += dx; self->x += dx;
1481     self->oy += dy; self->y += dy;
1482 root 1.43
1483     while (self->y < 0)
1484     {
1485     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1486    
1487     self->rows += MAP_EXTEND_Y;
1488     self->y += MAP_EXTEND_Y;
1489     }
1490 root 1.44 }
1491 root 1.43
1492 root 1.44 void
1493 root 1.141 map1a_update (CFPlus::Map self, SV *data_, int extmap)
1494 root 1.44 CODE:
1495     {
1496 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1497     uint8_t *data_end = (uint8_t *)SvEND (data_);
1498 root 1.48 mapcell *cell;
1499     int x, y, flags;
1500 root 1.43
1501 root 1.150 while (data < data_end - 1)
1502 root 1.29 {
1503 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1504 root 1.30
1505 root 1.120 x = self->x + ((flags >> 10) & 63);
1506     y = self->y + ((flags >> 4) & 63);
1507 root 1.29
1508 root 1.48 cell = map_get_cell (self, x, y);
1509 root 1.29
1510     if (flags & 15)
1511     {
1512 root 1.142 if (!cell->darkness)
1513 root 1.29 {
1514 root 1.154 memset (cell, 0, sizeof (*cell));
1515 root 1.142 cell->darkness = 256;
1516 root 1.29 }
1517 root 1.45
1518 root 1.142 //TODO: don't trust server data to be in-range(!)
1519    
1520 root 1.141 if (flags & 8)
1521     {
1522     if (extmap)
1523     {
1524     uint8_t ext, cmd;
1525    
1526     do
1527     {
1528     ext = *data++;
1529 root 1.144 cmd = ext & 0x3f;
1530 root 1.141
1531 root 1.147 if (cmd < 4)
1532 root 1.142 cell->darkness = 255 - ext * 64 + 1;
1533 root 1.147 else if (cmd == 5) // health
1534     {
1535     cell->stat_width = 1;
1536     cell->stat_hp = *data++;
1537     }
1538     else if (cmd == 6) // monster width
1539     cell->stat_width = *data++ + 1;
1540 root 1.169 else if (cmd == 0x47)
1541 root 1.153 {
1542 root 1.182 if (*data == 4)
1543     ; // decode player count
1544 root 1.153
1545     data += *data + 1;
1546     }
1547     else if (cmd == 8) // cell flags
1548     cell->flags = *data++;
1549 root 1.144 else if (ext & 0x40) // unknown, multibyte => skip
1550     data += *data + 1;
1551 root 1.147 else
1552     data++;
1553 root 1.141 }
1554 root 1.147 while (ext & 0x80);
1555 root 1.141 }
1556     else
1557 root 1.142 cell->darkness = *data++ + 1;
1558 root 1.141 }
1559 root 1.29
1560     if (flags & 4)
1561     {
1562 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1563     need_facenum (self, face);
1564     cell->tile [0] = self->face2tile [face];
1565 root 1.29 }
1566    
1567     if (flags & 2)
1568     {
1569 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1570     need_facenum (self, face);
1571     cell->tile [1] = self->face2tile [face];
1572 root 1.29 }
1573    
1574     if (flags & 1)
1575     {
1576 root 1.174 faceid face = (data [0] << 8) + data [1]; data += 2;
1577     need_facenum (self, face);
1578     cell->tile [2] = self->face2tile [face];
1579 root 1.29 }
1580     }
1581     else
1582 root 1.155 cell->darkness = 0;
1583 root 1.29 }
1584 root 1.28 }
1585    
1586 root 1.40 SV *
1587 root 1.133 mapmap (CFPlus::Map self, int x0, int y0, int w, int h)
1588 root 1.40 CODE:
1589     {
1590 root 1.55 int x1, x;
1591     int y1, y;
1592 root 1.40 int z;
1593     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1594     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1595    
1596     SvPOK_only (map_sv);
1597     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1598    
1599 root 1.55 x0 += self->x; x1 = x0 + w;
1600     y0 += self->y; y1 = y0 + h;
1601 root 1.40
1602     for (y = y0; y < y1; y++)
1603     {
1604     maprow *row = 0 <= y && y < self->rows
1605     ? self->row + y
1606     : 0;
1607    
1608     for (x = x0; x < x1; x++)
1609     {
1610     int r = 32, g = 32, b = 32, a = 192;
1611    
1612     if (row && row->c0 <= x && x < row->c1)
1613     {
1614     mapcell *cell = row->col + (x - row->c0);
1615    
1616     for (z = 0; z <= 0; z++)
1617     {
1618 root 1.174 maptex tex = self->tex [cell->tile [z]];
1619     int a0 = 255 - tex.a;
1620     int a1 = tex.a;
1621    
1622     r = (r * a0 + tex.r * a1) / 255;
1623     g = (g * a0 + tex.g * a1) / 255;
1624     b = (b * a0 + tex.b * a1) / 255;
1625     a = (a * a0 + tex.a * a1) / 255;
1626 root 1.40 }
1627     }
1628    
1629     *map++ = (r )
1630     | (g << 8)
1631     | (b << 16)
1632     | (a << 24);
1633     }
1634     }
1635    
1636     RETVAL = map_sv;
1637     }
1638     OUTPUT:
1639     RETVAL
1640    
1641 root 1.30 void
1642 root 1.171 draw (CFPlus::Map self, int mx, int my, int sw, int sh, int T)
1643 root 1.116 CODE:
1644 root 1.30 {
1645 root 1.176 HV *smooth = (HV *)sv_2mortal ((SV *)newHV ());
1646     uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level
1647 root 1.178 static uint8_t smooth_max[256][256]; // egad, fats and wasteful on memory (64k)
1648 root 1.176 smooth_key skey;
1649 root 1.48 int x, y, z;
1650     int last_name;
1651    
1652 root 1.176 // thats current max. sorry.
1653     if (sw > 255) sw = 255;
1654     if (sh > 255) sh = 255;
1655    
1656     // clear key, in case of extra padding
1657     memset (&skey, 0, sizeof (skey));
1658    
1659 root 1.30 glColor4ub (255, 255, 255, 255);
1660    
1661 root 1.117 glEnable (GL_BLEND);
1662 root 1.30 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1663     glEnable (GL_TEXTURE_2D);
1664     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1665    
1666 root 1.48 glBegin (GL_QUADS);
1667 root 1.30
1668 root 1.48 last_name = 0;
1669 root 1.30
1670 root 1.164 mx += self->x;
1671     my += self->y;
1672    
1673 root 1.176 // first pass: determine smooth_max
1674     // rather ugly, if you ask me
1675     // could also be stored inside mapcell and updated on change
1676     memset (smooth_max, 0, sizeof (smooth_max));
1677    
1678     for (y = 0; y < sh; y++)
1679     if (0 <= y + my && y + my < self->rows)
1680     {
1681     maprow *row = self->row + (y + my);
1682    
1683     for (x = 0; x < sw; x++)
1684     if (row->c0 <= x + mx && x + mx < row->c1)
1685     {
1686     mapcell *cell = row->col + (x + mx - row->c0);
1687    
1688 root 1.177 smooth_max[x + 1][y + 1] =
1689     MAX (self->tex [cell->tile [0]].smoothlevel,
1690     MAX (self->tex [cell->tile [1]].smoothlevel,
1691     self->tex [cell->tile [2]].smoothlevel));
1692 root 1.176 }
1693     }
1694    
1695     for (z = 0; z <= 2; z++)
1696     {
1697 root 1.186 memset (smooth_level, 0, sizeof (smooth_level));
1698    
1699 root 1.176 for (y = 0; y < sh; y++)
1700     if (0 <= y + my && y + my < self->rows)
1701     {
1702     maprow *row = self->row + (y + my);
1703    
1704     for (x = 0; x < sw; x++)
1705     if (row->c0 <= x + mx && x + mx < row->c1)
1706     {
1707     mapcell *cell = row->col + (x + mx - row->c0);
1708     tileid tile = cell->tile [z];
1709    
1710     if (tile)
1711     {
1712     maptex tex = self->tex [tile];
1713     int px = (x + 1) * T - tex.w;
1714     int py = (y + 1) * T - tex.h;
1715    
1716     // suppressing texture state switches here
1717     // is only moderately effective, but worth the extra effort
1718     if (last_name != tex.name)
1719     {
1720     if (!tex.name)
1721     tex = self->tex [2]; /* missing, replace by noface */
1722    
1723     glEnd ();
1724     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1725     glBegin (GL_QUADS);
1726     }
1727    
1728     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1729     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1730     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1731     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1732    
1733     if (cell->flags && z == 2)
1734     {
1735     if (cell->flags & 1)
1736     {
1737     maptex tex = self->tex [1];
1738     int px = x * T + T * 2 / 32;
1739     int py = y * T - T * 6 / 32;
1740    
1741     glEnd ();
1742     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1743     glBegin (GL_QUADS);
1744    
1745     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1746     glTexCoord2f (0 , tex.t); glVertex2f (px , py + T);
1747     glTexCoord2f (tex.s, tex.t); glVertex2f (px + T, py + T);
1748     glTexCoord2f (tex.s, 0 ); glVertex2f (px + T, py );
1749     }
1750     }
1751    
1752     // update smooth hash
1753     if (tex.smoothtile)
1754     {
1755     skey.tile = tex.smoothtile;
1756     skey.level = tex.smoothlevel;
1757    
1758     smooth_level [tex.smoothlevel >> 5] |= ((uint32_t)1) << (tex.smoothlevel & 31);
1759 root 1.30
1760 root 1.176 // add bits to current tile and all neighbours. skey.x|y is
1761     // shifted +1|+1 so we always stay positive.
1762 root 1.30
1763 root 1.180 // bits is ___n cccc CCCC bbbb
1764     // n do not draw borders&corners
1765     // c draw these corners, but...
1766     // C ... not these
1767     // b draw these borders
1768    
1769     // borders: 1 ┃· 2 ━━ 4 ·┃ 8 ··
1770     // ┃· ·· ·┃ ━━
1771    
1772     // corners: 1 ┛· 2 ·┗ 4 ·· 8 ··
1773     // ·· ·· ·┏ ┓·
1774    
1775 root 1.176 // full tile
1776     skey.x = x + 1; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x1000);
1777    
1778     // borders
1779 root 1.180 skey.x = x + 2; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0091);
1780     skey.x = x + 1; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0032);
1781 root 1.176 skey.x = x ; skey.y = y + 1; smooth_or_bits (smooth, &skey, 0x0064);
1782     skey.x = x + 1; skey.y = y ; smooth_or_bits (smooth, &skey, 0x00c8);
1783    
1784     // corners
1785     skey.x = x + 2; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0100);
1786     skey.x = x ; skey.y = y + 2; smooth_or_bits (smooth, &skey, 0x0200);
1787     skey.x = x ; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0400);
1788     skey.x = x + 2; skey.y = y ; smooth_or_bits (smooth, &skey, 0x0800);
1789     }
1790     }
1791     }
1792     }
1793 root 1.174
1794 root 1.186 // go through all smoothlevels, lowest to highest, then draw.
1795     // this is basically counting sort
1796 root 1.176 {
1797 root 1.186 int w, b;
1798 root 1.30
1799 root 1.186 for (w = 0; w < 256 / 32; ++w)
1800     {
1801     uint32_t smask = smooth_level [w];
1802     if (smask)
1803     for (b = 0; b < 32; ++b)
1804     if (smask & (((uint32_t)1) << b))
1805 root 1.176 {
1806 root 1.186 int level = (w << 5) | b;
1807     HE *he;
1808 root 1.153
1809 root 1.186 hv_iterinit (smooth);
1810     while ((he = hv_iternext (smooth)))
1811 root 1.153 {
1812 root 1.186 smooth_key *skey = (smooth_key *)HeKEY (he);
1813     IV bits = SvIVX (HeVAL (he));
1814 root 1.176
1815 root 1.186 if (!(bits & 0x1000)
1816     && skey->level == level
1817 root 1.191 && level > smooth_max [skey->x][skey->y])
1818 root 1.174 {
1819 root 1.186 maptex tex = self->tex [skey->tile];
1820     int px = (((int)skey->x) - 1) * T;
1821     int py = (((int)skey->y) - 1) * T;
1822     int border = bits & 15;
1823     int corner = (bits >> 8) & ~(bits >> 4) & 15;
1824     float dx = tex.s * .0625f; // 16 images/row
1825     float dy = tex.t * .5f ; // 2 images/column
1826    
1827     // this time naively avoiding texture state changes
1828     // save gobs of state changes.
1829     if (last_name != tex.name)
1830     {
1831     if (!tex.name)
1832     continue; // smoothing not yet available
1833    
1834     glEnd ();
1835     glBindTexture (GL_TEXTURE_2D, last_name = tex.name);
1836     glBegin (GL_QUADS);
1837     }
1838    
1839     if (border)
1840     {
1841     float ox = border * dx;
1842    
1843     glTexCoord2f (ox , 0.f ); glVertex2f (px , py );
1844     glTexCoord2f (ox , dy ); glVertex2f (px , py + T);
1845     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py + T);
1846     glTexCoord2f (ox + dx, 0.f ); glVertex2f (px + T, py );
1847     }
1848    
1849     if (corner)
1850     {
1851     float ox = corner * dx;
1852    
1853     glTexCoord2f (ox , dy ); glVertex2f (px , py );
1854     glTexCoord2f (ox , dy * 2.f); glVertex2f (px , py + T);
1855     glTexCoord2f (ox + dx, dy * 2.f); glVertex2f (px + T, py + T);
1856     glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py );
1857     }
1858 root 1.174 }
1859 root 1.153 }
1860     }
1861 root 1.186 }
1862 root 1.176 }
1863    
1864 root 1.186 hv_clear (smooth);
1865     }
1866 root 1.30
1867     glEnd ();
1868 root 1.32
1869 root 1.34 glDisable (GL_TEXTURE_2D);
1870 root 1.152 glDisable (GL_BLEND);
1871 root 1.143
1872 root 1.145 // top layer: overlays such as the health bar
1873 root 1.143 for (y = 0; y < sh; y++)
1874 root 1.164 if (0 <= y + my && y + my < self->rows)
1875 root 1.143 {
1876 root 1.164 maprow *row = self->row + (y + my);
1877 root 1.143
1878     for (x = 0; x < sw; x++)
1879 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
1880 root 1.143 {
1881 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
1882 root 1.143
1883 root 1.171 int px = x * T;
1884     int py = y * T;
1885 root 1.143
1886     if (cell->stat_hp)
1887     {
1888 root 1.171 int width = cell->stat_width * T;
1889 root 1.174 int thick = (sh * T / 32 + 27) / 28 + 1 + cell->stat_width;
1890 root 1.143
1891 root 1.152 glColor3ub (0, 0, 0);
1892 root 1.151 glRectf (px + 1, py - thick - 2,
1893     px + width - 1, py);
1894 root 1.147
1895 root 1.152 glColor3ub (cell->stat_hp, 255 - cell->stat_hp, 0);
1896 root 1.147 glRectf (px + 2,
1897 root 1.151 py - thick - 1,
1898     px + width - 2 - cell->stat_hp * (width - 4) / 255, py - 1);
1899 root 1.143 }
1900     }
1901     }
1902 root 1.116 }
1903    
1904     void
1905 root 1.133 draw_magicmap (CFPlus::Map self, int dx, int dy, int w, int h, unsigned char *data)
1906 root 1.117 CODE:
1907     {
1908     static float color[16][3] = {
1909 root 1.123 { 0.00F, 0.00F, 0.00F },
1910     { 1.00F, 1.00F, 1.00F },
1911     { 0.00F, 0.00F, 0.55F },
1912     { 1.00F, 0.00F, 0.00F },
1913    
1914     { 1.00F, 0.54F, 0.00F },
1915     { 0.11F, 0.56F, 1.00F },
1916     { 0.93F, 0.46F, 0.00F },
1917     { 0.18F, 0.54F, 0.34F },
1918    
1919     { 0.56F, 0.73F, 0.56F },
1920     { 0.80F, 0.80F, 0.80F },
1921     { 0.55F, 0.41F, 0.13F },
1922     { 0.99F, 0.77F, 0.26F },
1923    
1924     { 0.74F, 0.65F, 0.41F },
1925    
1926     { 0.00F, 1.00F, 1.00F },
1927     { 1.00F, 0.00F, 1.00F },
1928     { 1.00F, 1.00F, 0.00F },
1929 root 1.117 };
1930    
1931     int x, y;
1932    
1933     glEnable (GL_TEXTURE_2D);
1934     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1935     glEnable (GL_BLEND);
1936     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1937     glBegin (GL_QUADS);
1938    
1939     for (y = 0; y < h; y++)
1940     for (x = 0; x < w; x++)
1941     {
1942     unsigned char m = data [x + y * w];
1943    
1944 root 1.118 if (m)
1945     {
1946     float *c = color [m & 15];
1947    
1948     float tx1 = m & 0x40 ? 0.5 : 0.;
1949     float tx2 = tx1 + 0.5;
1950    
1951     glColor4f (c[0], c[1], c[2], 0.75);
1952     glTexCoord2f (tx1, 0.); glVertex2i (x , y );
1953     glTexCoord2f (tx1, 1.); glVertex2i (x , y + 1);
1954     glTexCoord2f (tx2, 1.); glVertex2i (x + 1, y + 1);
1955     glTexCoord2f (tx2, 0.); glVertex2i (x + 1, y );
1956     }
1957 root 1.117 }
1958    
1959     glEnd ();
1960     glDisable (GL_BLEND);
1961     glDisable (GL_TEXTURE_2D);
1962     }
1963    
1964     void
1965 root 1.204 fow_texture (CFPlus::Map self, int mx, int my, int sw, int sh)
1966 root 1.116 PPCODE:
1967     {
1968     int x, y;
1969 root 1.204 int sw1 = sw + 2;
1970     int sh1 = sh + 2;
1971     int sh3 = sh * 3;
1972     int sw34 = (sw * 3 + 3) & ~3;
1973     uint8_t *darkness1 = (uint8_t *)malloc (sw1 * sh1);
1974     SV *darkness3_sv = sv_2mortal (newSV (sw34 * sh3));
1975     uint8_t *darkness3 = (uint8_t *)SvPVX (darkness3_sv);
1976    
1977     SvPOK_only (darkness3_sv);
1978     SvCUR_set (darkness3_sv, sw34 * sh3);
1979 root 1.116
1980 root 1.204 mx += self->x - 1;
1981     my += self->y - 1;
1982 root 1.116
1983 root 1.204 memset (darkness1, 255, sw1 * sh1);
1984    
1985     for (y = 0; y < sh1; y++)
1986 root 1.164 if (0 <= y + my && y + my < self->rows)
1987 root 1.116 {
1988 root 1.164 maprow *row = self->row + (y + my);
1989 root 1.116
1990 root 1.204 for (x = 0; x < sw1; x++)
1991 root 1.164 if (row->c0 <= x + mx && x + mx < row->c1)
1992 root 1.116 {
1993 root 1.164 mapcell *cell = row->col + (x + mx - row->c0);
1994 root 1.116
1995 root 1.204 darkness1 [y * sw1 + x] = cell->darkness
1996 root 1.143 ? 255 - (cell->darkness - 1)
1997 root 1.142 : 255 - FOW_DARKNESS;
1998 root 1.116 }
1999     }
2000 root 1.34
2001 root 1.204 for (y = 0; y < sh; ++y)
2002     for (x = 0; x < sw; ++x)
2003     {
2004     uint8_t d11 = darkness1 [(y ) * sw1 + x ];
2005     uint8_t d21 = darkness1 [(y ) * sw1 + x + 1];
2006     uint8_t d31 = darkness1 [(y ) * sw1 + x + 2];
2007     uint8_t d12 = darkness1 [(y + 1) * sw1 + x ];
2008     uint8_t d22 = darkness1 [(y + 1) * sw1 + x + 1];
2009     uint8_t d32 = darkness1 [(y + 1) * sw1 + x + 2];
2010     uint8_t d13 = darkness1 [(y + 2) * sw1 + x ];
2011     uint8_t d23 = darkness1 [(y + 2) * sw1 + x + 1];
2012     uint8_t d33 = darkness1 [(y + 2) * sw1 + x + 2];
2013    
2014     uint8_t r11 = (d11 + d21 + d12) / 3;
2015     uint8_t r21 = d21;
2016     uint8_t r31 = (d21 + d31 + d32) / 3;
2017    
2018     uint8_t r12 = d12;
2019     uint8_t r22 = d22;
2020     uint8_t r32 = d32;
2021    
2022     uint8_t r13 = (d13 + d23 + d12) / 3;
2023     uint8_t r23 = d23;
2024     uint8_t r33 = (d23 + d33 + d32) / 3;
2025    
2026     darkness3 [(y * 3 ) * sw34 + (x * 3 )] = MAX (d22, r11);
2027     darkness3 [(y * 3 ) * sw34 + (x * 3 + 1)] = MAX (d22, r21);
2028     darkness3 [(y * 3 ) * sw34 + (x * 3 + 2)] = MAX (d22, r31);
2029     darkness3 [(y * 3 + 1) * sw34 + (x * 3 )] = MAX (d22, r12);
2030     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 1)] = MAX (d22, r22);
2031     darkness3 [(y * 3 + 1) * sw34 + (x * 3 + 2)] = MAX (d22, r32);
2032     darkness3 [(y * 3 + 2) * sw34 + (x * 3 )] = MAX (d22, r13);
2033     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 1)] = MAX (d22, r23);
2034     darkness3 [(y * 3 + 2) * sw34 + (x * 3 + 2)] = MAX (d22, r33);
2035     }
2036 root 1.201
2037 root 1.204 free (darkness1);
2038 root 1.201
2039 root 1.32 EXTEND (SP, 3);
2040 root 1.204 PUSHs (sv_2mortal (newSViv (sw34)));
2041     PUSHs (sv_2mortal (newSViv (sh3)));
2042     PUSHs (darkness3_sv);
2043 root 1.30 }
2044    
2045 root 1.42 SV *
2046 root 1.133 get_rect (CFPlus::Map self, int x0, int y0, int w, int h)
2047 root 1.42 CODE:
2048     {
2049     int x, y, x1, y1;
2050     SV *data_sv = newSV (w * h * 7 + 5);
2051     uint8_t *data = (uint8_t *)SvPVX (data_sv);
2052    
2053     *data++ = 0; /* version 0 format */
2054     *data++ = w >> 8; *data++ = w;
2055     *data++ = h >> 8; *data++ = h;
2056    
2057     // we need to do this 'cause we don't keep an absolute coord system for rows
2058 root 1.55 // TODO: treat rows as we treat columns
2059 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2060     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2061    
2062     x0 += self->x - self->ox;
2063     y0 += self->y - self->oy;
2064    
2065     x1 = x0 + w;
2066     y1 = y0 + h;
2067    
2068     for (y = y0; y < y1; y++)
2069     {
2070     maprow *row = 0 <= y && y < self->rows
2071     ? self->row + y
2072     : 0;
2073    
2074     for (x = x0; x < x1; x++)
2075     {
2076     if (row && row->c0 <= x && x < row->c1)
2077     {
2078     mapcell *cell = row->col + (x - row->c0);
2079     uint8_t flags = 0;
2080    
2081 root 1.174 if (cell->tile [0]) flags |= 1;
2082     if (cell->tile [1]) flags |= 2;
2083     if (cell->tile [2]) flags |= 4;
2084 root 1.42
2085     *data++ = flags;
2086    
2087     if (flags & 1)
2088     {
2089 root 1.174 tileid tile = cell->tile [0];
2090     *data++ = tile >> 8;
2091     *data++ = tile;
2092 root 1.42 }
2093    
2094     if (flags & 2)
2095     {
2096 root 1.174 tileid tile = cell->tile [1];
2097     *data++ = tile >> 8;
2098     *data++ = tile;
2099 root 1.42 }
2100    
2101     if (flags & 4)
2102     {
2103 root 1.174 tileid tile = cell->tile [2];
2104     *data++ = tile >> 8;
2105     *data++ = tile;
2106 root 1.42 }
2107     }
2108     else
2109     *data++ = 0;
2110     }
2111     }
2112    
2113     SvPOK_only (data_sv);
2114     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
2115     RETVAL = data_sv;
2116     }
2117     OUTPUT:
2118     RETVAL
2119    
2120     void
2121 root 1.133 set_rect (CFPlus::Map self, int x0, int y0, uint8_t *data)
2122 root 1.42 PPCODE:
2123     {
2124     int x, y, z;
2125 root 1.48 int w, h;
2126 root 1.42 int x1, y1;
2127    
2128     if (*data++ != 0)
2129     return; /* version mismatch */
2130    
2131 root 1.48 w = *data++ << 8; w |= *data++;
2132     h = *data++ << 8; h |= *data++;
2133 root 1.42
2134     // we need to do this 'cause we don't keep an absolute coord system for rows
2135 root 1.55 // TODO: treat rows as we treat columns
2136 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
2137     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
2138    
2139     x0 += self->x - self->ox;
2140     y0 += self->y - self->oy;
2141    
2142     x1 = x0 + w;
2143     y1 = y0 + h;
2144    
2145     for (y = y0; y < y1; y++)
2146     {
2147     maprow *row = map_get_row (self, y);
2148    
2149     for (x = x0; x < x1; x++)
2150     {
2151     uint8_t flags = *data++;
2152    
2153     if (flags)
2154     {
2155     mapcell *cell = row_get_cell (row, x);
2156 root 1.174 tileid tile[3] = { 0, 0, 0 };
2157 root 1.42
2158 root 1.174 if (flags & 1) { tile[0] = *data++ << 8; tile[0] |= *data++; }
2159     if (flags & 2) { tile[1] = *data++ << 8; tile[1] |= *data++; }
2160     if (flags & 4) { tile[2] = *data++ << 8; tile[2] |= *data++; }
2161 root 1.42
2162 root 1.143 if (cell->darkness == 0)
2163 root 1.42 {
2164 root 1.142 cell->darkness = 0;
2165 root 1.42
2166     for (z = 0; z <= 2; z++)
2167     {
2168 root 1.174 tileid t = tile [z];
2169    
2170 root 1.175 if (t >= self->texs || (t && !self->tex [t].name))
2171 root 1.174 {
2172     XPUSHs (sv_2mortal (newSViv (t)));
2173     need_texid (self, t);
2174     }
2175 root 1.42
2176 root 1.174 cell->tile [z] = t;
2177 root 1.42 }
2178     }
2179     }
2180     }
2181     }
2182     }
2183    
2184 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixChunk
2185 root 1.52
2186 root 1.133 CFPlus::MixChunk
2187 root 1.52 new_from_file (SV *class, char *path)
2188     CODE:
2189     RETVAL = Mix_LoadWAV (path);
2190     OUTPUT:
2191     RETVAL
2192    
2193     void
2194 root 1.133 DESTROY (CFPlus::MixChunk self)
2195 root 1.52 CODE:
2196     Mix_FreeChunk (self);
2197    
2198     int
2199 root 1.133 volume (CFPlus::MixChunk self, int volume = -1)
2200 root 1.52 CODE:
2201     RETVAL = Mix_VolumeChunk (self, volume);
2202     OUTPUT:
2203     RETVAL
2204    
2205     int
2206 root 1.133 play (CFPlus::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
2207 root 1.52 CODE:
2208     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
2209     OUTPUT:
2210     RETVAL
2211    
2212 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::MixMusic
2213 root 1.52
2214     int
2215     volume (int volume = -1)
2216     CODE:
2217     RETVAL = Mix_VolumeMusic (volume);
2218     OUTPUT:
2219     RETVAL
2220    
2221 root 1.194 int
2222     fade_out (int ms)
2223     CODE:
2224     RETVAL = Mix_FadeOutMusic (ms);
2225     OUTPUT:
2226     RETVAL
2227    
2228 root 1.133 CFPlus::MixMusic
2229 root 1.52 new_from_file (SV *class, char *path)
2230     CODE:
2231     RETVAL = Mix_LoadMUS (path);
2232     OUTPUT:
2233     RETVAL
2234    
2235     void
2236 root 1.133 DESTROY (CFPlus::MixMusic self)
2237 root 1.52 CODE:
2238     Mix_FreeMusic (self);
2239    
2240     int
2241 root 1.133 play (CFPlus::MixMusic self, int loops = -1)
2242 root 1.52 CODE:
2243     RETVAL = Mix_PlayMusic (self, loops);
2244     OUTPUT:
2245     RETVAL
2246    
2247 root 1.195 int
2248     fade_in_pos (CFPlus::MixMusic self, int loops, int ms, double position)
2249     CODE:
2250     RETVAL = Mix_FadeInMusicPos (self, loops, ms, position);
2251     OUTPUT:
2252     RETVAL
2253    
2254 root 1.133 MODULE = CFPlus PACKAGE = CFPlus::OpenGL
2255 root 1.54
2256     BOOT:
2257     {
2258 root 1.133 HV *stash = gv_stashpv ("CFPlus::OpenGL", 1);
2259 root 1.54 static const struct {
2260     const char *name;
2261     IV iv;
2262     } *civ, const_iv[] = {
2263     # define const_iv(name) { # name, (IV)name }
2264 root 1.199 const_iv (GL_VENDOR),
2265     const_iv (GL_VERSION),
2266     const_iv (GL_EXTENSIONS),
2267 root 1.54 const_iv (GL_COLOR_MATERIAL),
2268     const_iv (GL_SMOOTH),
2269     const_iv (GL_FLAT),
2270 root 1.69 const_iv (GL_DITHER),
2271 root 1.54 const_iv (GL_BLEND),
2272 root 1.89 const_iv (GL_CULL_FACE),
2273 root 1.69 const_iv (GL_SCISSOR_TEST),
2274 root 1.89 const_iv (GL_DEPTH_TEST),
2275     const_iv (GL_ALPHA_TEST),
2276     const_iv (GL_NORMALIZE),
2277     const_iv (GL_RESCALE_NORMAL),
2278 root 1.119 const_iv (GL_FRONT),
2279     const_iv (GL_BACK),
2280 root 1.54 const_iv (GL_AND),
2281 root 1.67 const_iv (GL_ONE),
2282     const_iv (GL_ZERO),
2283 root 1.54 const_iv (GL_SRC_ALPHA),
2284 root 1.104 const_iv (GL_DST_ALPHA),
2285 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
2286 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
2287 root 1.104 const_iv (GL_SRC_ALPHA_SATURATE),
2288 root 1.54 const_iv (GL_RGB),
2289     const_iv (GL_RGBA),
2290 root 1.115 const_iv (GL_RGBA4),
2291     const_iv (GL_RGBA8),
2292     const_iv (GL_RGB5_A1),
2293 root 1.54 const_iv (GL_UNSIGNED_BYTE),
2294 root 1.89 const_iv (GL_UNSIGNED_SHORT),
2295     const_iv (GL_UNSIGNED_INT),
2296 root 1.54 const_iv (GL_ALPHA),
2297 root 1.86 const_iv (GL_INTENSITY),
2298 root 1.76 const_iv (GL_LUMINANCE),
2299 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
2300 root 1.54 const_iv (GL_FLOAT),
2301     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
2302     const_iv (GL_COMPILE),
2303 root 1.199 const_iv (GL_PROXY_TEXTURE_1D),
2304     const_iv (GL_PROXY_TEXTURE_2D),
2305 root 1.54 const_iv (GL_TEXTURE_1D),
2306     const_iv (GL_TEXTURE_2D),
2307     const_iv (GL_TEXTURE_ENV),
2308     const_iv (GL_TEXTURE_MAG_FILTER),
2309     const_iv (GL_TEXTURE_MIN_FILTER),
2310     const_iv (GL_TEXTURE_ENV_MODE),
2311     const_iv (GL_TEXTURE_WRAP_S),
2312     const_iv (GL_TEXTURE_WRAP_T),
2313 root 1.98 const_iv (GL_REPEAT),
2314 root 1.54 const_iv (GL_CLAMP),
2315 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
2316 root 1.54 const_iv (GL_NEAREST),
2317     const_iv (GL_LINEAR),
2318 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
2319     const_iv (GL_LINEAR_MIPMAP_NEAREST),
2320     const_iv (GL_NEAREST_MIPMAP_LINEAR),
2321     const_iv (GL_LINEAR_MIPMAP_LINEAR),
2322     const_iv (GL_GENERATE_MIPMAP),
2323 root 1.54 const_iv (GL_MODULATE),
2324 root 1.69 const_iv (GL_DECAL),
2325 root 1.54 const_iv (GL_REPLACE),
2326 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
2327 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
2328     const_iv (GL_PROJECTION),
2329     const_iv (GL_MODELVIEW),
2330     const_iv (GL_COLOR_LOGIC_OP),
2331 root 1.69 const_iv (GL_SEPARABLE_2D),
2332 root 1.54 const_iv (GL_CONVOLUTION_2D),
2333     const_iv (GL_CONVOLUTION_BORDER_MODE),
2334     const_iv (GL_CONSTANT_BORDER),
2335     const_iv (GL_LINES),
2336 root 1.138 const_iv (GL_LINE_STRIP),
2337 root 1.89 const_iv (GL_LINE_LOOP),
2338 root 1.54 const_iv (GL_QUADS),
2339 root 1.89 const_iv (GL_QUAD_STRIP),
2340     const_iv (GL_TRIANGLES),
2341     const_iv (GL_TRIANGLE_STRIP),
2342     const_iv (GL_TRIANGLE_FAN),
2343 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
2344     const_iv (GL_FASTEST),
2345 root 1.89 const_iv (GL_V2F),
2346     const_iv (GL_V3F),
2347     const_iv (GL_T2F_V3F),
2348     const_iv (GL_T2F_N3F_V3F),
2349 root 1.54 # undef const_iv
2350     };
2351    
2352     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
2353     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
2354 root 1.188
2355     texture_av = newAV ();
2356     AvREAL_off (texture_av);
2357 root 1.54 }
2358    
2359 root 1.97 char *
2360     gl_vendor ()
2361     CODE:
2362     RETVAL = (char *)glGetString (GL_VENDOR);
2363     OUTPUT:
2364     RETVAL
2365    
2366     char *
2367     gl_version ()
2368     CODE:
2369     RETVAL = (char *)glGetString (GL_VERSION);
2370     OUTPUT:
2371     RETVAL
2372    
2373     char *
2374     gl_extensions ()
2375     CODE:
2376     RETVAL = (char *)glGetString (GL_EXTENSIONS);
2377     OUTPUT:
2378     RETVAL
2379    
2380 root 1.201 const char *glGetString (GLenum pname)
2381 root 1.199
2382     GLint glGetInteger (GLenum pname)
2383     CODE:
2384     glGetIntegerv (pname, &RETVAL);
2385     OUTPUT:
2386     RETVAL
2387    
2388     GLdouble glGetDouble (GLenum pname)
2389     CODE:
2390     glGetDoublev (pname, &RETVAL);
2391     OUTPUT:
2392     RETVAL
2393    
2394 root 1.54 int glGetError ()
2395    
2396 root 1.114 void glFinish ()
2397    
2398 root 1.54 void glClear (int mask)
2399    
2400     void glClearColor (float r, float g, float b, float a = 1.0)
2401     PROTOTYPE: @
2402    
2403     void glEnable (int cap)
2404    
2405     void glDisable (int cap)
2406    
2407     void glShadeModel (int mode)
2408    
2409     void glHint (int target, int mode)
2410    
2411     void glBlendFunc (int sfactor, int dfactor)
2412    
2413 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
2414     CODE:
2415     gl_BlendFuncSeparate (sa, da, saa, daa);
2416    
2417 root 1.89 void glDepthMask (int flag)
2418    
2419 root 1.54 void glLogicOp (int opcode)
2420    
2421 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
2422    
2423 root 1.54 void glMatrixMode (int mode)
2424    
2425     void glPushMatrix ()
2426    
2427     void glPopMatrix ()
2428    
2429     void glLoadIdentity ()
2430    
2431 root 1.119 void glDrawBuffer (int buffer)
2432    
2433     void glReadBuffer (int buffer)
2434    
2435 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
2436     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
2437    
2438     # near_ and far_ are due to microsofts buggy "c" compiler
2439 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
2440 root 1.54
2441     void glViewport (int x, int y, int width, int height)
2442    
2443 root 1.69 void glScissor (int x, int y, int width, int height)
2444    
2445 root 1.54 void glTranslate (float x, float y, float z = 0.)
2446     CODE:
2447     glTranslatef (x, y, z);
2448    
2449 root 1.62 void glScale (float x, float y, float z = 1.)
2450 root 1.54 CODE:
2451     glScalef (x, y, z);
2452    
2453     void glRotate (float angle, float x, float y, float z)
2454     CODE:
2455     glRotatef (angle, x, y, z);
2456    
2457     void glBegin (int mode)
2458    
2459     void glEnd ()
2460    
2461     void glColor (float r, float g, float b, float a = 1.0)
2462     PROTOTYPE: @
2463 root 1.103 ALIAS:
2464     glColor_premultiply = 1
2465 root 1.54 CODE:
2466 root 1.103 if (ix)
2467     {
2468     r *= a;
2469     g *= a;
2470     b *= a;
2471     }
2472 root 1.90 // microsoft visual "c" rounds instead of truncating...
2473 root 1.130 glColor4f (r, g, b, a);
2474 root 1.54
2475 root 1.89 void glInterleavedArrays (int format, int stride, char *data)
2476    
2477     void glDrawElements (int mode, int count, int type, char *indices)
2478    
2479     # 1.2 void glDrawRangeElements (int mode, int start, int end
2480    
2481 root 1.91 void glRasterPos (float x, float y, float z = 0.)
2482     CODE:
2483     glRasterPos3f (0, 0, z);
2484     glBitmap (0, 0, 0, 0, x, y, 0);
2485    
2486 root 1.54 void glVertex (float x, float y, float z = 0.)
2487     CODE:
2488     glVertex3f (x, y, z);
2489    
2490     void glTexCoord (float s, float t)
2491     CODE:
2492     glTexCoord2f (s, t);
2493    
2494     void glTexEnv (int target, int pname, float param)
2495     CODE:
2496     glTexEnvf (target, pname, param);
2497    
2498     void glTexParameter (int target, int pname, float param)
2499     CODE:
2500     glTexParameterf (target, pname, param);
2501    
2502     void glBindTexture (int target, int name)
2503    
2504     void glConvolutionParameter (int target, int pname, float params)
2505     CODE:
2506 root 1.103 if (gl.ConvolutionParameterf)
2507     gl.ConvolutionParameterf (target, pname, params);
2508 root 1.54
2509     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
2510 root 1.64 CODE:
2511 root 1.103 if (gl.ConvolutionFilter2D)
2512     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
2513 root 1.54
2514 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
2515     CODE:
2516 root 1.103 if (gl.SeparableFilter2D)
2517     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
2518 root 1.69
2519 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
2520    
2521     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
2522    
2523 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
2524 root 1.68
2525 root 1.199 void glPixelZoom (float x, float y)
2526    
2527 root 1.68 void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
2528    
2529 root 1.54 int glGenTexture ()
2530     CODE:
2531 root 1.192 RETVAL = gen_texture ();
2532 root 1.54 OUTPUT:
2533     RETVAL
2534    
2535     void glDeleteTexture (int name)
2536     CODE:
2537 root 1.192 del_texture (name);
2538    
2539 root 1.54 int glGenList ()
2540     CODE:
2541     RETVAL = glGenLists (1);
2542     OUTPUT:
2543     RETVAL
2544    
2545     void glDeleteList (int list)
2546     CODE:
2547     glDeleteLists (list, 1);
2548    
2549     void glNewList (int list, int mode = GL_COMPILE)
2550    
2551     void glEndList ()
2552    
2553     void glCallList (int list)
2554