ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.64
Committed: Mon Apr 24 08:11:31 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.63: +21 -2 lines
Log Message:
fully support opengl1.1 at link time now

File Contents

# User Rev Content
1 root 1.48 #ifdef _WIN32
2     # include <malloc.h>
3     #endif
4    
5 root 1.1 #include "EXTERN.h"
6     #include "perl.h"
7     #include "XSUB.h"
8    
9 root 1.5 #include <string.h>
10 root 1.25 #include <stdio.h>
11 root 1.5
12 root 1.2 #include <SDL.h>
13 root 1.23 #include <SDL_image.h>
14 root 1.52 #include <SDL_mixer.h>
15 root 1.3 #include <SDL_opengl.h>
16 root 1.5
17 root 1.30 #include <glib/gmacros.h>
18    
19 root 1.5 #include <pango/pango.h>
20 root 1.10 #include <pango/pangofc-fontmap.h>
21 root 1.5 #include <pango/pangoft2.h>
22    
23 root 1.48 #ifndef _WIN32
24     # include <sys/types.h>
25     # include <sys/socket.h>
26     # include <netinet/in.h>
27     # include <netinet/tcp.h>
28     # include <inttypes.h>
29     #else
30     typedef unsigned char uint8_t;
31     typedef unsigned short uint16_t;
32     typedef unsigned int uint32_t;
33     typedef signed char int8_t;
34     typedef signed short int16_t;
35     typedef signed int int32_t;
36     #endif
37 root 1.28
38 root 1.57 #include "glext.h"
39    
40 root 1.29 #define FOW_DARKNESS 32
41    
42     #define MAP_EXTEND_X 32
43     #define MAP_EXTEND_Y 512
44    
45 root 1.63 #define MIN_FONT_HEIGHT 10
46 root 1.58
47 root 1.64 #define GL_CALL(type,func,args) \
48     { \
49     static int init_; \
50     static type fptr_; \
51     \
52     if (!init_) \
53     { \
54     init_ = 1; \
55     fptr_ = (type)SDL_GL_GetProcAddress (# func); \
56     } \
57     \
58     if (fptr_) \
59     fptr_ args; \
60     }
61    
62 root 1.52 typedef Mix_Chunk *CFClient__MixChunk;
63     typedef Mix_Music *CFClient__MixMusic;
64    
65 root 1.61 typedef PangoFontDescription *CFClient__Font;
66 root 1.2
67 root 1.14 typedef struct cf_layout {
68     PangoLayout *pl;
69     int base_height;
70 root 1.61 CFClient__Font font;
71 root 1.15 } *CFClient__Layout;
72 root 1.14
73 root 1.61 static CFClient__Font default_font;
74     static PangoContext *context;
75     static PangoFontMap *fontmap;
76    
77 root 1.14 static void
78 root 1.19 substitute_func (FcPattern *pattern, gpointer data)
79     {
80 root 1.20 FcPatternAddBool (pattern, FC_HINTING , 1);
81 root 1.35 FcPatternAddBool (pattern, FC_AUTOHINT, 0);
82 root 1.19 }
83    
84     static void
85 root 1.61 layout_update_font (CFClient__Layout self)
86 root 1.17 {
87 root 1.19 /* use a random scale factor to account for unknown descenders, 0.8 works
88     * reasonably well with bitstream vera
89     */
90 root 1.61 PangoFontDescription *font = self->font ? self->font : default_font;
91 root 1.46
92 root 1.61 pango_font_description_set_absolute_size (font,
93     MAX (MIN_FONT_HEIGHT, self->base_height) * (PANGO_SCALE * 8 / 10));
94 root 1.58
95 root 1.61 pango_layout_set_font_description (self->pl, font);
96 root 1.17 }
97    
98     static void
99 root 1.15 layout_get_pixel_size (CFClient__Layout self, int *w, int *h)
100 root 1.14 {
101     pango_layout_get_pixel_size (self->pl, w, h);
102    
103     *w = (*w + 3) & ~3;
104     if (!*w) *w = 1;
105     if (!*h) *h = 1;
106     }
107    
108 root 1.42 typedef uint16_t mapface;
109    
110 root 1.28 typedef struct {
111 root 1.30 GLint name;
112     int w, h;
113     float s, t;
114 root 1.39 uint8_t r, g, b, a;
115 root 1.42 } maptex;
116 root 1.30
117     typedef struct {
118 root 1.29 int16_t darkness;
119 root 1.42 mapface face[3];
120 root 1.28 } mapcell;
121    
122     typedef struct {
123 root 1.30 int32_t c0, c1;
124 root 1.28 mapcell *col;
125     } maprow;
126    
127     typedef struct map {
128     int x, y, w, h;
129 root 1.42 int ox, oy; /* offset to virtual global coordinate system */
130 root 1.28 int faces;
131 root 1.30 mapface *face;
132 root 1.28
133 root 1.42 int texs;
134     maptex *tex;
135    
136 root 1.48 int32_t rows;
137 root 1.28 maprow *row;
138     } *CFClient__Map;
139    
140 root 1.30 static char *
141     prepend (char *ptr, int sze, int inc)
142     {
143     char *p;
144    
145     New (0, p, sze + inc, char);
146     Zero (p, inc, char);
147     Move (ptr, p + inc, sze, char);
148     Safefree (ptr);
149    
150     return p;
151     }
152    
153     static char *
154     append (char *ptr, int sze, int inc)
155     {
156     Renew (ptr, sze + inc, char);
157     Zero (ptr + sze, inc, char);
158    
159     return ptr;
160     }
161    
162     #define Append(type,ptr,sze,inc) (ptr) = (type *)append ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
163     #define Prepend(type,ptr,sze,inc) (ptr) = (type *)prepend ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
164    
165 root 1.42 static maprow *
166     map_get_row (CFClient__Map self, int y)
167     {
168     if (0 > y)
169     {
170     int extend = - y + MAP_EXTEND_Y;
171     Prepend (maprow, self->row, self->rows, extend);
172    
173     self->rows += extend;
174     self->y += extend;
175     y += extend;
176     }
177     else if (y >= self->rows)
178     {
179     int extend = y - self->rows + MAP_EXTEND_Y;
180     Append (maprow, self->row, self->rows, extend);
181     self->rows += extend;
182     }
183    
184     return self->row + y;
185     }
186    
187     static mapcell *
188     row_get_cell (maprow *row, int x)
189     {
190     if (!row->col)
191     {
192     Newz (0, row->col, MAP_EXTEND_X, mapcell);
193     row->c0 = x - MAP_EXTEND_X / 4;
194     row->c1 = row->c0 + MAP_EXTEND_X;
195     }
196    
197     if (row->c0 > x)
198     {
199     int extend = row->c0 - x + MAP_EXTEND_X;
200     Prepend (mapcell, row->col, row->c1 - row->c0, extend);
201     row->c0 -= extend;
202     }
203     else if (x >= row->c1)
204     {
205     int extend = x - row->c1 + MAP_EXTEND_X;
206     Append (mapcell, row->col, row->c1 - row->c0, extend);
207     row->c1 += extend;
208     }
209    
210     return row->col + (x - row->c0);
211     }
212    
213     static mapcell *
214     map_get_cell (CFClient__Map self, int x, int y)
215     {
216     return row_get_cell (map_get_row (self, y), x);
217     }
218    
219 root 1.30 static void
220     map_clear (CFClient__Map self)
221     {
222     int r;
223    
224     for (r = 0; r < self->rows; r++)
225     Safefree (self->row[r].col);
226    
227     Safefree (self->row);
228    
229     self->x = 0;
230     self->y = 0;
231 root 1.42 self->ox = 0;
232     self->oy = 0;
233 root 1.30 self->row = 0;
234     self->rows = 0;
235     }
236    
237 root 1.29 static void
238     map_blank (CFClient__Map self, int x0, int y0, int w, int h)
239     {
240     int x, y;
241 root 1.48 maprow *row;
242 root 1.29
243     for (y = y0; y < y0 + h; y++)
244 root 1.30 if (y >= 0)
245     {
246     if (y >= self->rows)
247     break;
248    
249 root 1.48 row = self->row + y;
250 root 1.30
251     for (x = x0; x < x0 + w; x++)
252     if (x >= row->c0)
253     {
254     if (x >= row->c1)
255     break;
256 root 1.29
257 root 1.31 row->col[x - row->c0].darkness = -1;
258 root 1.30 }
259     }
260 root 1.29 }
261    
262 root 1.56 static void
263     music_finished ()
264     {
265     SDL_UserEvent ev;
266    
267     ev.type = SDL_USEREVENT;
268     ev.code = 0;
269     ev.data1 = 0;
270     ev.data2 = 0;
271    
272 root 1.57 SDL_PushEvent ((SDL_Event *)&ev);
273 root 1.56 }
274    
275 root 1.15 MODULE = CFClient PACKAGE = CFClient
276 root 1.1
277 root 1.11 PROTOTYPES: ENABLE
278    
279 root 1.5 BOOT:
280     {
281 root 1.51 HV *stash = gv_stashpv ("CFClient", 1);
282     static const struct {
283     const char *name;
284     IV iv;
285     } *civ, const_iv[] = {
286     # define const_iv(name) { # name, (IV)name }
287     const_iv (SDL_ACTIVEEVENT),
288     const_iv (SDL_KEYDOWN),
289     const_iv (SDL_KEYUP),
290     const_iv (SDL_MOUSEMOTION),
291     const_iv (SDL_MOUSEBUTTONDOWN),
292     const_iv (SDL_MOUSEBUTTONUP),
293     const_iv (SDL_JOYAXISMOTION),
294     const_iv (SDL_JOYBALLMOTION),
295     const_iv (SDL_JOYHATMOTION),
296     const_iv (SDL_JOYBUTTONDOWN),
297     const_iv (SDL_JOYBUTTONUP),
298     const_iv (SDL_QUIT),
299     const_iv (SDL_SYSWMEVENT),
300     const_iv (SDL_EVENT_RESERVEDA),
301     const_iv (SDL_EVENT_RESERVEDB),
302     const_iv (SDL_VIDEORESIZE),
303     const_iv (SDL_VIDEOEXPOSE),
304     const_iv (SDL_USEREVENT),
305     const_iv (SDLK_KP0),
306     const_iv (SDLK_KP1),
307     const_iv (SDLK_KP2),
308     const_iv (SDLK_KP3),
309     const_iv (SDLK_KP4),
310     const_iv (SDLK_KP5),
311     const_iv (SDLK_KP6),
312     const_iv (SDLK_KP7),
313     const_iv (SDLK_KP8),
314     const_iv (SDLK_KP9),
315     const_iv (SDLK_KP_PERIOD),
316     const_iv (SDLK_KP_DIVIDE),
317     const_iv (SDLK_KP_MULTIPLY),
318     const_iv (SDLK_KP_MINUS),
319     const_iv (SDLK_KP_PLUS),
320     const_iv (SDLK_KP_ENTER),
321     const_iv (SDLK_KP_EQUALS),
322     const_iv (SDLK_UP),
323     const_iv (SDLK_DOWN),
324     const_iv (SDLK_RIGHT),
325     const_iv (SDLK_LEFT),
326     const_iv (SDLK_INSERT),
327     const_iv (SDLK_HOME),
328     const_iv (SDLK_END),
329     const_iv (SDLK_PAGEUP),
330     const_iv (SDLK_PAGEDOWN),
331     const_iv (SDLK_F1),
332     const_iv (SDLK_F2),
333     const_iv (SDLK_F3),
334     const_iv (SDLK_F4),
335     const_iv (SDLK_F5),
336     const_iv (SDLK_F6),
337     const_iv (SDLK_F7),
338     const_iv (SDLK_F8),
339     const_iv (SDLK_F9),
340     const_iv (SDLK_F10),
341     const_iv (SDLK_F11),
342     const_iv (SDLK_F12),
343     const_iv (SDLK_F13),
344     const_iv (SDLK_F14),
345     const_iv (SDLK_F15),
346     const_iv (SDLK_NUMLOCK),
347     const_iv (SDLK_CAPSLOCK),
348     const_iv (SDLK_SCROLLOCK),
349     const_iv (SDLK_RSHIFT),
350     const_iv (SDLK_LSHIFT),
351     const_iv (SDLK_RCTRL),
352     const_iv (SDLK_LCTRL),
353     const_iv (SDLK_RALT),
354     const_iv (SDLK_LALT),
355     const_iv (SDLK_RMETA),
356     const_iv (SDLK_LMETA),
357     const_iv (SDLK_LSUPER),
358     const_iv (SDLK_RSUPER),
359     const_iv (SDLK_MODE),
360     const_iv (SDLK_COMPOSE),
361     const_iv (SDLK_HELP),
362     const_iv (SDLK_PRINT),
363     const_iv (SDLK_SYSREQ),
364     const_iv (SDLK_BREAK),
365     const_iv (SDLK_MENU),
366     const_iv (SDLK_POWER),
367     const_iv (SDLK_EURO),
368     const_iv (SDLK_UNDO),
369     const_iv (KMOD_NONE),
370     const_iv (KMOD_LSHIFT),
371     const_iv (KMOD_RSHIFT),
372     const_iv (KMOD_LCTRL),
373     const_iv (KMOD_RCTRL),
374     const_iv (KMOD_LALT),
375     const_iv (KMOD_RALT),
376     const_iv (KMOD_LMETA),
377     const_iv (KMOD_RMETA),
378     const_iv (KMOD_NUM),
379     const_iv (KMOD_CAPS),
380     const_iv (KMOD_MODE),
381     const_iv (KMOD_CTRL),
382     const_iv (KMOD_SHIFT),
383     const_iv (KMOD_ALT),
384     const_iv (KMOD_META)
385     # undef const_iv
386     };
387    
388     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
389     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
390    
391     fontmap = pango_ft2_font_map_new ();
392     pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, substitute_func, 0, 0);
393     context = pango_ft2_font_map_create_context ((PangoFT2FontMap *)fontmap);
394 root 1.5 }
395    
396 root 1.51 int
397     SDL_Init (U32 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO)
398    
399     void
400     SDL_Quit ()
401    
402     void
403     SDL_ListModes ()
404     PPCODE:
405     {
406     SDL_Rect **m;
407    
408     SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
409     SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
410     SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
411     SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 1);
412    
413     SDL_GL_SetAttribute (SDL_GL_ACCUM_RED_SIZE, 0);
414     SDL_GL_SetAttribute (SDL_GL_ACCUM_GREEN_SIZE, 0);
415     SDL_GL_SetAttribute (SDL_GL_ACCUM_BLUE_SIZE, 0);
416     SDL_GL_SetAttribute (SDL_GL_ACCUM_ALPHA_SIZE, 0);
417    
418     SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
419     SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 15);
420     SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 0);
421    
422 root 1.53 SDL_EnableUNICODE (1);
423     SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
424    
425 root 1.51 m = SDL_ListModes (0, SDL_FULLSCREEN | SDL_OPENGL);
426    
427     if (m && m != (SDL_Rect **)-1)
428     while (*m)
429     {
430     AV *av = newAV ();
431     av_push (av, newSViv ((*m)->w));
432     av_push (av, newSViv ((*m)->h));
433     XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
434    
435     ++m;
436     }
437     }
438    
439     int
440     SDL_SetVideoMode (int w, int h, int fullscreen)
441     CODE:
442     RETVAL = !!SDL_SetVideoMode (
443     w, h, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)
444     );
445     SDL_WM_SetCaption ("Crossfire+ Client " VERSION, "Crossfire+");
446     OUTPUT:
447     RETVAL
448    
449 root 1.53 void
450 root 1.54 SDL_GL_SwapBuffers ()
451    
452     void
453 root 1.53 SDL_PollEvent ()
454     PPCODE:
455     {
456     SDL_Event ev;
457    
458     while (SDL_PollEvent (&ev))
459     {
460     HV *hv = newHV ();
461     hv_store (hv, "type", 4, newSViv (ev.type), 0);
462     switch (ev.type)
463     {
464     case SDL_KEYDOWN:
465     case SDL_KEYUP:
466     hv_store (hv, "state", 5, newSViv (ev.key.state), 0);
467     hv_store (hv, "sym", 3, newSViv (ev.key.keysym.sym), 0);
468     hv_store (hv, "mod", 3, newSViv (ev.key.keysym.mod), 0);
469     hv_store (hv, "unicode", 7, newSViv (ev.key.keysym.unicode), 0);
470     break;
471    
472     case SDL_ACTIVEEVENT:
473     hv_store (hv, "gain", 4, newSViv (ev.active.gain), 0);
474     hv_store (hv, "state", 5, newSViv (ev.active.state), 0);
475     break;
476    
477     case SDL_MOUSEMOTION:
478     hv_store (hv, "state", 5, newSViv (ev.motion.state), 0);
479     hv_store (hv, "x", 1, newSViv (ev.motion.x), 0);
480     hv_store (hv, "y", 1, newSViv (ev.motion.y), 0);
481     hv_store (hv, "xrel", 4, newSViv (ev.motion.xrel), 0);
482     hv_store (hv, "yrel", 4, newSViv (ev.motion.yrel), 0);
483     break;
484    
485     case SDL_MOUSEBUTTONDOWN:
486     case SDL_MOUSEBUTTONUP:
487     hv_store (hv, "button", 6, newSViv (ev.button.button), 0);
488     hv_store (hv, "state", 5, newSViv (ev.button.state), 0);
489     hv_store (hv, "x", 1, newSViv (ev.button.x), 0);
490     hv_store (hv, "y", 1, newSViv (ev.button.y), 0);
491     }
492    
493     XPUSHs (sv_2mortal (newRV_noinc ((SV *)hv)));
494     }
495     }
496 root 1.52
497     int
498     Mix_OpenAudio (int frequency = 22050, int format = MIX_DEFAULT_FORMAT, int channels = 1, int chunksize = 512)
499 root 1.56 POSTCALL:
500     Mix_HookMusicFinished (music_finished);
501 root 1.52
502     void
503     Mix_CloseAudio ()
504    
505     int
506     Mix_AllocateChannels (int numchans = -1)
507    
508 root 1.10 void
509     lowdelay (int fd, int val = 1)
510     CODE:
511 root 1.48 #ifndef _WIN32
512 root 1.10 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
513 root 1.48 #endif
514 root 1.10
515 root 1.3 char *
516 root 1.4 gl_version ()
517     CODE:
518 root 1.5 RETVAL = (char *)glGetString (GL_VERSION);
519 root 1.4 OUTPUT:
520     RETVAL
521    
522     char *
523 root 1.3 gl_extensions ()
524     CODE:
525 root 1.5 RETVAL = (char *)glGetString (GL_EXTENSIONS);
526 root 1.3 OUTPUT:
527     RETVAL
528    
529 root 1.5 void
530 root 1.13 add_font (char *file)
531     CODE:
532     FcConfigAppFontAddFile (0, (const FcChar8 *)file); /* no idea wether this is required */
533    
534     void
535 root 1.23 load_image_inline (SV *image_)
536     ALIAS:
537     load_image_file = 1
538     PPCODE:
539     {
540     STRLEN image_len;
541     char *image = (char *)SvPVbyte (image_, image_len);
542     SDL_Surface *surface, *surface2;
543     SDL_PixelFormat fmt;
544     SDL_RWops *rw = ix
545     ? SDL_RWFromFile (image, "r")
546     : SDL_RWFromConstMem (image, image_len);
547    
548     if (!rw)
549 root 1.41 croak ("load_image: %s", SDL_GetError ());
550 root 1.23
551     surface = IMG_Load_RW (rw, 1);
552     if (!surface)
553 root 1.41 croak ("load_image: %s", SDL_GetError ());
554 root 1.23
555     fmt.palette = NULL;
556     fmt.BitsPerPixel = 32;
557     fmt.BytesPerPixel = 4;
558 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
559 root 1.23 fmt.Rmask = 0x000000ff;
560     fmt.Gmask = 0x0000ff00;
561     fmt.Bmask = 0x00ff0000;
562     fmt.Amask = 0xff000000;
563 root 1.49 #else
564     fmt.Rmask = 0xff000000;
565     fmt.Gmask = 0x00ff0000;
566     fmt.Bmask = 0x0000ff00;
567     fmt.Amask = 0x000000ff;
568     #endif
569 root 1.23 fmt.Rloss = 0;
570     fmt.Gloss = 0;
571     fmt.Bloss = 0;
572     fmt.Aloss = 0;
573     fmt.Rshift = 0;
574     fmt.Gshift = 8;
575     fmt.Bshift = 16;
576     fmt.Ashift = 24;
577     fmt.colorkey = 0;
578     fmt.alpha = 0;
579    
580     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
581    
582 root 1.39 assert (surface2->pitch == surface2->w * 4);
583    
584 root 1.23 EXTEND (SP, 5);
585     PUSHs (sv_2mortal (newSViv (surface2->w)));
586     PUSHs (sv_2mortal (newSViv (surface2->h)));
587     SDL_LockSurface (surface2);
588     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
589     SDL_UnlockSurface (surface2);
590 root 1.24 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
591 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
592 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
593 root 1.23
594     SDL_FreeSurface (surface);
595     SDL_FreeSurface (surface2);
596     }
597    
598 root 1.25 void
599 root 1.39 average (int x, int y, uint32_t *data)
600     PPCODE:
601     {
602     uint32_t r = 0, g = 0, b = 0, a = 0;
603    
604     x = y = x * y;
605    
606     while (x--)
607     {
608     uint32_t p = *data++;
609    
610     r += (p ) & 255;
611     g += (p >> 8) & 255;
612     b += (p >> 16) & 255;
613     a += (p >> 24) & 255;
614     }
615    
616     EXTEND (SP, 4);
617 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
618     PUSHs (sv_2mortal (newSViv (g / y)));
619     PUSHs (sv_2mortal (newSViv (b / y)));
620     PUSHs (sv_2mortal (newSViv (a / y)));
621 root 1.39 }
622    
623     void
624 root 1.25 fatal (char *message)
625     CODE:
626 root 1.50 #ifdef _WIN32
627 root 1.25 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
628     #else
629 root 1.40 fprintf (stderr, "FATAL: %s\n", message);
630 root 1.25 #endif
631     exit (1);
632    
633 root 1.61 MODULE = CFClient PACKAGE = CFClient::Font
634    
635     CFClient::Font
636     new_from_file (SV *class, char *path)
637     CODE:
638     {
639     int count;
640     FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)path, 0, 0, &count);
641     RETVAL = pango_fc_font_description_from_pattern (pattern, 0);
642     FcPatternDestroy (pattern);
643     }
644     OUTPUT:
645     RETVAL
646    
647     void
648     DESTROY (CFClient::Font self)
649     CODE:
650     pango_font_description_free (self);
651    
652     void
653     make_default (CFClient::Font self)
654     CODE:
655     default_font = self;
656    
657 root 1.15 MODULE = CFClient PACKAGE = CFClient::Layout
658 root 1.14
659 root 1.15 CFClient::Layout
660 root 1.61 new (SV *class, int base_height = MIN_FONT_HEIGHT)
661 root 1.14 CODE:
662     New (0, RETVAL, 1, struct cf_layout);
663 root 1.61 RETVAL->pl = pango_layout_new (context);
664 root 1.14 RETVAL->base_height = base_height;
665 root 1.61 RETVAL->font = 0;
666 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
667 root 1.61 pango_layout_set_font_description (RETVAL->pl, default_font);
668 root 1.14 OUTPUT:
669     RETVAL
670    
671     void
672 root 1.15 DESTROY (CFClient::Layout self)
673 root 1.14 CODE:
674     g_object_unref (self->pl);
675     Safefree (self);
676 root 1.13
677 root 1.8 void
678 root 1.35 set_text (CFClient::Layout self, SV *text_)
679     CODE:
680     {
681     STRLEN textlen;
682     char *text = SvPVutf8 (text_, textlen);
683    
684     pango_layout_set_text (self->pl, text, textlen);
685     }
686    
687     void
688 root 1.15 set_markup (CFClient::Layout self, SV *text_)
689 root 1.14 CODE:
690 root 1.5 {
691     STRLEN textlen;
692     char *text = SvPVutf8 (text_, textlen);
693 root 1.14
694     pango_layout_set_markup (self->pl, text, textlen);
695     }
696    
697 root 1.46 SV *
698     get_text (CFClient::Layout self)
699     CODE:
700 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
701 root 1.46 SvUTF8_on (RETVAL);
702     OUTPUT:
703     RETVAL
704    
705 root 1.14 void
706 root 1.61 set_font (CFClient::Layout self, CFClient::Font font = 0)
707     CODE:
708     if (self->font != font)
709     {
710     self->font = font;
711     layout_update_font (self);
712     }
713    
714     void
715 root 1.16 set_height (CFClient::Layout self, int base_height)
716     CODE:
717 root 1.61 if (self->base_height != base_height)
718     {
719     self->base_height = base_height;
720     layout_update_font (self);
721     }
722 root 1.16
723     void
724 root 1.15 set_width (CFClient::Layout self, int max_width = -1)
725 root 1.14 CODE:
726     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
727    
728     void
729 root 1.15 size (CFClient::Layout self)
730 root 1.14 PPCODE:
731     {
732     int w, h;
733    
734     layout_get_pixel_size (self, &w, &h);
735    
736     EXTEND (SP, 2);
737     PUSHs (sv_2mortal (newSViv (w)));
738     PUSHs (sv_2mortal (newSViv (h)));
739     }
740    
741 root 1.17 int
742     xy_to_index (CFClient::Layout self, int x, int y)
743     CODE:
744     {
745     int index, trailing;
746     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
747     RETVAL = index;
748     }
749     OUTPUT:
750     RETVAL
751    
752     void
753     cursor_pos (CFClient::Layout self, int index)
754     PPCODE:
755     {
756     PangoRectangle strong_pos;
757     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
758 root 1.30
759 root 1.17 EXTEND (SP, 3);
760     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
761     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
762     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
763     }
764    
765 root 1.14 void
766 root 1.15 render (CFClient::Layout self)
767 root 1.14 PPCODE:
768     {
769 root 1.5 SV *retval;
770     int w, h;
771     FT_Bitmap bitmap;
772    
773 root 1.14 layout_get_pixel_size (self, &w, &h);
774 root 1.5
775     retval = newSV (w * h);
776     SvPOK_only (retval);
777     SvCUR_set (retval, w * h);
778    
779     bitmap.rows = h;
780     bitmap.width = w;
781     bitmap.pitch = w;
782     bitmap.buffer = (unsigned char*)SvPVX (retval);
783     bitmap.num_grays = 256;
784     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
785    
786     memset (bitmap.buffer, 0, w * h);
787    
788 root 1.14 pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
789 root 1.1
790 root 1.5 EXTEND (SP, 3);
791     PUSHs (sv_2mortal (newSViv (w)));
792     PUSHs (sv_2mortal (newSViv (h)));
793     PUSHs (sv_2mortal (retval));
794     }
795 root 1.11
796 root 1.15 MODULE = CFClient PACKAGE = CFClient::Texture
797 root 1.11
798     void
799 root 1.37 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
800 root 1.12 PROTOTYPE: $$$;$$
801 root 1.11 CODE:
802     {
803 root 1.12 HV *hv = (HV *)SvRV (self);
804 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
805     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
806 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
807 elmex 1.36 int wrap_mode = SvIV (*hv_fetch (hv, "wrap_mode", 9, 1));
808 root 1.12
809     if (items < 5)
810     {
811 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
812     h = SvNV (*hv_fetch (hv, "h", 1, 1));
813 root 1.12 }
814    
815     glBindTexture (GL_TEXTURE_2D, name);
816 elmex 1.36 if (wrap_mode) {
817     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
818     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
819     }
820 root 1.12 glBegin (GL_QUADS);
821 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
822     glTexCoord2f (0, t); glVertex2f (x , y + h);
823     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
824     glTexCoord2f (s, 0); glVertex2f (x + w, y );
825 root 1.12 glEnd ();
826 root 1.11 }
827 root 1.28
828     MODULE = CFClient PACKAGE = CFClient::Map
829    
830     CFClient::Map
831     new (SV *class, int map_width, int map_height)
832     CODE:
833     New (0, RETVAL, 1, struct map);
834 root 1.42 RETVAL->x = 0;
835     RETVAL->y = 0;
836     RETVAL->w = map_width;
837     RETVAL->h = map_height;
838     RETVAL->ox = 0;
839     RETVAL->oy = 0;
840 root 1.30 RETVAL->faces = 8192;
841     Newz (0, RETVAL->face, RETVAL->faces, mapface);
842 root 1.42 RETVAL->texs = 8192;
843     Newz (0, RETVAL->tex, RETVAL->texs, maptex);
844 root 1.28 RETVAL->rows = 0;
845     RETVAL->row = 0;
846     OUTPUT:
847     RETVAL
848    
849     void
850     DESTROY (CFClient::Map self)
851     CODE:
852     {
853 root 1.30 map_clear (self);
854 root 1.28 Safefree (self->face);
855 root 1.29 Safefree (self);
856     }
857    
858     void
859 root 1.30 clear (CFClient::Map self)
860     CODE:
861     map_clear (self);
862    
863     void
864 root 1.42 set_face (CFClient::Map self, int face, int texid)
865 root 1.29 CODE:
866     {
867 root 1.42 while (self->faces <= face)
868 root 1.28 {
869 root 1.30 Append (mapface, self->face, self->faces, self->faces);
870 root 1.29 self->faces *= 2;
871     }
872 root 1.28
873 root 1.42 self->face [face] = texid;
874     }
875    
876     void
877     set_texture (CFClient::Map self, int texid, int name, int w, int h, float s, float t, int r, int g, int b, int a)
878     CODE:
879     {
880     while (self->texs <= texid)
881     {
882     Append (maptex, self->tex, self->texs, self->texs);
883     self->texs *= 2;
884     }
885    
886 root 1.48 {
887     maptex *tex = self->tex + texid;
888 root 1.39
889 root 1.48 tex->name = name;
890     tex->w = w;
891     tex->h = h;
892     tex->s = s;
893     tex->t = t;
894     tex->r = r;
895     tex->g = g;
896     tex->b = b;
897     tex->a = a;
898     }
899 root 1.29 }
900    
901 root 1.42 int
902     ox (CFClient::Map self)
903     ALIAS:
904     oy = 1
905     CODE:
906     switch (ix)
907     {
908     case 0: RETVAL = self->ox; break;
909     case 1: RETVAL = self->oy; break;
910     }
911     OUTPUT:
912     RETVAL
913    
914 root 1.29 void
915 root 1.43 scroll (CFClient::Map self, int dx, int dy)
916     CODE:
917     {
918 root 1.44 if (dx > 0)
919     map_blank (self, self->x, self->y, dx - 1, self->h);
920     else if (dx < 0)
921     map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
922    
923     if (dy > 0)
924     map_blank (self, self->x, self->y, self->w, dy - 1);
925     else if (dy < 0)
926     map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
927 root 1.43
928 root 1.44 self->ox += dx; self->x += dx;
929     self->oy += dy; self->y += dy;
930 root 1.43
931     while (self->y < 0)
932     {
933     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
934    
935     self->rows += MAP_EXTEND_Y;
936     self->y += MAP_EXTEND_Y;
937     }
938 root 1.44 }
939 root 1.43
940 root 1.44 void
941     map1a_update (CFClient::Map self, SV *data_)
942     CODE:
943     {
944 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
945     uint8_t *data_end = (uint8_t *)SvEND (data_);
946 root 1.48 mapcell *cell;
947     int x, y, flags;
948 root 1.43
949 root 1.29 while (data < data_end)
950     {
951 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
952 root 1.30
953 root 1.48 x = ((flags >> 10) & 63) + self->x;
954     y = ((flags >> 4) & 63) + self->y;
955 root 1.29
956 root 1.48 cell = map_get_cell (self, x, y);
957 root 1.29
958     if (flags & 15)
959     {
960 root 1.45 if (cell->darkness < 0)
961 root 1.29 {
962     cell->darkness = 0;
963     cell->face [0] = 0;
964     cell->face [1] = 0;
965     cell->face [2] = 0;
966     }
967 root 1.45
968 root 1.29 cell->darkness = flags & 8 ? *data++ : 255;
969    
970 root 1.42 //TODO: don't trust server data to be in-range(!)
971    
972 root 1.29 if (flags & 4)
973     {
974 root 1.42 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
975 root 1.29 }
976    
977     if (flags & 2)
978     {
979 root 1.42 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
980 root 1.29 }
981    
982     if (flags & 1)
983     {
984 root 1.42 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
985 root 1.29 }
986     }
987     else
988 root 1.31 cell->darkness = -1;
989 root 1.29 }
990 root 1.28 }
991    
992 root 1.40 SV *
993 root 1.55 mapmap (CFClient::Map self, int x0, int y0, int w, int h)
994 root 1.40 CODE:
995     {
996 root 1.55 int x1, x;
997     int y1, y;
998 root 1.40 int z;
999     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1000     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1001    
1002     SvPOK_only (map_sv);
1003     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1004    
1005 root 1.55 x0 += self->x; x1 = x0 + w;
1006     y0 += self->y; y1 = y0 + h;
1007 root 1.40
1008     for (y = y0; y < y1; y++)
1009     {
1010     maprow *row = 0 <= y && y < self->rows
1011     ? self->row + y
1012     : 0;
1013    
1014     for (x = x0; x < x1; x++)
1015     {
1016     int r = 32, g = 32, b = 32, a = 192;
1017    
1018     if (row && row->c0 <= x && x < row->c1)
1019     {
1020     mapcell *cell = row->col + (x - row->c0);
1021    
1022     for (z = 0; z <= 0; z++)
1023     {
1024 root 1.42 mapface face = cell->face [z];
1025 root 1.40
1026     if (face)
1027     {
1028 root 1.42 maptex tex = self->tex [face];
1029 root 1.40 int a0 = 255 - tex.a;
1030     int a1 = tex.a;
1031    
1032     r = (r * a0 + tex.r * a1) / 255;
1033     g = (g * a0 + tex.g * a1) / 255;
1034     b = (b * a0 + tex.b * a1) / 255;
1035     a = (a * a0 + tex.a * a1) / 255;
1036     }
1037     }
1038     }
1039    
1040     *map++ = (r )
1041     | (g << 8)
1042     | (b << 16)
1043     | (a << 24);
1044     }
1045     }
1046    
1047     RETVAL = map_sv;
1048     }
1049     OUTPUT:
1050     RETVAL
1051    
1052 root 1.30 void
1053 root 1.38 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
1054 root 1.32 PPCODE:
1055 root 1.30 {
1056 root 1.48 int vx, vy;
1057     int x, y, z;
1058     int last_name;
1059     mapface face;
1060 root 1.32 int sw4 = (sw + 3) & ~3;
1061     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
1062 root 1.35 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
1063 root 1.48
1064 root 1.42 memset (darkness, 255, sw4 * sh);
1065 root 1.32 SvPOK_only (darkness_sv);
1066     SvCUR_set (darkness_sv, sw4 * sh);
1067    
1068 root 1.48 vx = self->x + (self->w - sw) / 2 - shift_x;
1069     vy = self->y + (self->h - sh) / 2 - shift_y;
1070 root 1.38
1071 root 1.42 /*
1072     int vx = self->vx = self->w >= sw
1073     ? self->x + (self->w - sw) / 2
1074     : MIN (self->x, MAX (self->x + self->w - sw + 1, self->vx));
1075    
1076     int vy = self->vy = self->h >= sh
1077     ? self->y + (self->h - sh) / 2
1078     : MIN (self->y, MAX (self->y + self->h - sh + 1, self->vy));
1079     */
1080 root 1.30
1081     glColor4ub (255, 255, 255, 255);
1082    
1083     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1084     glEnable (GL_BLEND);
1085     glEnable (GL_TEXTURE_2D);
1086     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1087    
1088 root 1.48 glBegin (GL_QUADS);
1089 root 1.30
1090 root 1.48 last_name = 0;
1091 root 1.30
1092     for (z = 0; z < 3; z++)
1093     for (y = 0; y < sh; y++)
1094     if (0 <= y + vy && y + vy < self->rows)
1095     {
1096     maprow *row = self->row + (y + vy);
1097    
1098     for (x = 0; x < sw; x++)
1099     if (row->c0 <= x + vx && x + vx < row->c1)
1100     {
1101     mapcell *cell = row->col + (x + vx - row->c0);
1102 root 1.32
1103     darkness[y * sw4 + x] = cell->darkness < 0
1104 root 1.33 ? 255 - FOW_DARKNESS
1105 root 1.32 : 255 - cell->darkness;
1106    
1107 root 1.48 face = cell->face [z];
1108 root 1.30
1109     if (face)
1110     {
1111 root 1.42 maptex tex = self->tex [face];
1112 root 1.30
1113     int px = (x + 1) * 32 - tex.w;
1114     int py = (y + 1) * 32 - tex.h;
1115    
1116     if (last_name != tex.name)
1117     {
1118     glEnd ();
1119     last_name = tex.name;
1120     glBindTexture (GL_TEXTURE_2D, last_name);
1121     glBegin (GL_QUADS);
1122     }
1123    
1124     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1125     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1126     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1127     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1128     }
1129     }
1130     }
1131    
1132     glEnd ();
1133 root 1.32
1134 root 1.34 glDisable (GL_TEXTURE_2D);
1135     glDisable (GL_BLEND);
1136    
1137 root 1.32 EXTEND (SP, 3);
1138     PUSHs (sv_2mortal (newSViv (sw4)));
1139     PUSHs (sv_2mortal (newSViv (sh)));
1140     PUSHs (darkness_sv);
1141 root 1.30 }
1142    
1143 root 1.42 SV *
1144     get_rect (CFClient::Map self, int x0, int y0, int w, int h)
1145     CODE:
1146     {
1147     int x, y, x1, y1;
1148     SV *data_sv = newSV (w * h * 7 + 5);
1149     uint8_t *data = (uint8_t *)SvPVX (data_sv);
1150    
1151     *data++ = 0; /* version 0 format */
1152     *data++ = w >> 8; *data++ = w;
1153     *data++ = h >> 8; *data++ = h;
1154    
1155     // we need to do this 'cause we don't keep an absolute coord system for rows
1156 root 1.55 // TODO: treat rows as we treat columns
1157 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1158     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1159    
1160     x0 += self->x - self->ox;
1161     y0 += self->y - self->oy;
1162    
1163     x1 = x0 + w;
1164     y1 = y0 + h;
1165    
1166     for (y = y0; y < y1; y++)
1167     {
1168     maprow *row = 0 <= y && y < self->rows
1169     ? self->row + y
1170     : 0;
1171    
1172     for (x = x0; x < x1; x++)
1173     {
1174     if (row && row->c0 <= x && x < row->c1)
1175     {
1176     mapcell *cell = row->col + (x - row->c0);
1177     uint8_t flags = 0;
1178    
1179     if (cell->face [0]) flags |= 1;
1180     if (cell->face [1]) flags |= 2;
1181     if (cell->face [2]) flags |= 4;
1182    
1183     *data++ = flags;
1184    
1185     if (flags & 1)
1186     {
1187     *data++ = cell->face [0] >> 8;
1188     *data++ = cell->face [0];
1189     }
1190    
1191     if (flags & 2)
1192     {
1193     *data++ = cell->face [1] >> 8;
1194     *data++ = cell->face [1];
1195     }
1196    
1197     if (flags & 4)
1198     {
1199     *data++ = cell->face [2] >> 8;
1200     *data++ = cell->face [2];
1201     }
1202     }
1203     else
1204     *data++ = 0;
1205     }
1206     }
1207    
1208     SvPOK_only (data_sv);
1209     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
1210     RETVAL = data_sv;
1211     }
1212     OUTPUT:
1213     RETVAL
1214    
1215     void
1216     set_rect (CFClient::Map self, int x0, int y0, uint8_t *data)
1217     PPCODE:
1218     {
1219     int x, y, z;
1220 root 1.48 int w, h;
1221 root 1.42 int x1, y1;
1222    
1223     if (*data++ != 0)
1224     return; /* version mismatch */
1225    
1226 root 1.48 w = *data++ << 8; w |= *data++;
1227     h = *data++ << 8; h |= *data++;
1228 root 1.42
1229     // we need to do this 'cause we don't keep an absolute coord system for rows
1230 root 1.55 // TODO: treat rows as we treat columns
1231 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1232     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1233    
1234     x0 += self->x - self->ox;
1235     y0 += self->y - self->oy;
1236    
1237     x1 = x0 + w;
1238     y1 = y0 + h;
1239    
1240     for (y = y0; y < y1; y++)
1241     {
1242     maprow *row = map_get_row (self, y);
1243    
1244     for (x = x0; x < x1; x++)
1245     {
1246     uint8_t flags = *data++;
1247    
1248     if (flags)
1249     {
1250     mapface face[3] = { 0, 0, 0 };
1251    
1252     mapcell *cell = row_get_cell (row, x);
1253    
1254     if (flags & 1) { face[0] = *data++ << 8; face[0] |= *data++; }
1255     if (flags & 2) { face[1] = *data++ << 8; face[1] |= *data++; }
1256     if (flags & 4) { face[2] = *data++ << 8; face[2] |= *data++; }
1257    
1258     if (cell->darkness <= 0)
1259     {
1260     cell->darkness = -1;
1261    
1262     for (z = 0; z <= 2; z++)
1263     {
1264     cell->face[z] = face[z];
1265    
1266     if (face[z] && (face[z] >= self->texs || !self->tex[face [z]].name))
1267     XPUSHs (sv_2mortal (newSViv (face[z])));
1268     }
1269     }
1270     }
1271     }
1272     }
1273     }
1274    
1275 root 1.52 MODULE = CFClient PACKAGE = CFClient::MixChunk
1276    
1277     CFClient::MixChunk
1278     new_from_file (SV *class, char *path)
1279     CODE:
1280     RETVAL = Mix_LoadWAV (path);
1281     OUTPUT:
1282     RETVAL
1283    
1284     void
1285     DESTROY (CFClient::MixChunk self)
1286     CODE:
1287     Mix_FreeChunk (self);
1288    
1289     int
1290     volume (CFClient::MixChunk self, int volume = -1)
1291     CODE:
1292     RETVAL = Mix_VolumeChunk (self, volume);
1293     OUTPUT:
1294     RETVAL
1295    
1296     int
1297     play (CFClient::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
1298     CODE:
1299     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
1300     OUTPUT:
1301     RETVAL
1302    
1303     MODULE = CFClient PACKAGE = CFClient::MixMusic
1304    
1305     int
1306     volume (int volume = -1)
1307     CODE:
1308     RETVAL = Mix_VolumeMusic (volume);
1309     OUTPUT:
1310     RETVAL
1311    
1312     CFClient::MixMusic
1313     new_from_file (SV *class, char *path)
1314     CODE:
1315     RETVAL = Mix_LoadMUS (path);
1316     OUTPUT:
1317     RETVAL
1318    
1319     void
1320     DESTROY (CFClient::MixMusic self)
1321     CODE:
1322     Mix_FreeMusic (self);
1323    
1324     int
1325     play (CFClient::MixMusic self, int loops = -1)
1326     CODE:
1327     RETVAL = Mix_PlayMusic (self, loops);
1328     OUTPUT:
1329     RETVAL
1330    
1331 root 1.54 MODULE = CFClient PACKAGE = CFClient::OpenGL
1332    
1333     BOOT:
1334     {
1335     HV *stash = gv_stashpv ("CFClient::OpenGL", 1);
1336     static const struct {
1337     const char *name;
1338     IV iv;
1339     } *civ, const_iv[] = {
1340     # define const_iv(name) { # name, (IV)name }
1341     const_iv (GL_COLOR_MATERIAL),
1342     const_iv (GL_SMOOTH),
1343     const_iv (GL_FLAT),
1344     const_iv (GL_BLEND),
1345     const_iv (GL_AND),
1346     const_iv (GL_SRC_ALPHA),
1347     const_iv (GL_ONE_MINUS_SRC_ALPHA),
1348     const_iv (GL_RGB),
1349     const_iv (GL_RGBA),
1350     const_iv (GL_UNSIGNED_BYTE),
1351     const_iv (GL_ALPHA4),
1352     const_iv (GL_ALPHA),
1353     const_iv (GL_FLOAT),
1354     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
1355     const_iv (GL_COMPILE),
1356     const_iv (GL_TEXTURE_1D),
1357     const_iv (GL_TEXTURE_2D),
1358     const_iv (GL_TEXTURE_ENV),
1359     const_iv (GL_TEXTURE_MAG_FILTER),
1360     const_iv (GL_TEXTURE_MIN_FILTER),
1361     const_iv (GL_TEXTURE_ENV_MODE),
1362     const_iv (GL_TEXTURE_WRAP_S),
1363     const_iv (GL_TEXTURE_WRAP_T),
1364     const_iv (GL_CLAMP),
1365     const_iv (GL_REPEAT),
1366     const_iv (GL_NEAREST),
1367     const_iv (GL_LINEAR),
1368 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
1369     const_iv (GL_LINEAR_MIPMAP_NEAREST),
1370     const_iv (GL_NEAREST_MIPMAP_LINEAR),
1371     const_iv (GL_LINEAR_MIPMAP_LINEAR),
1372     const_iv (GL_GENERATE_MIPMAP),
1373     const_iv (GL_LINEAR),
1374 root 1.54 const_iv (GL_MODULATE),
1375     const_iv (GL_REPLACE),
1376     const_iv (GL_COLOR_BUFFER_BIT),
1377     const_iv (GL_PROJECTION),
1378     const_iv (GL_MODELVIEW),
1379     const_iv (GL_COLOR_LOGIC_OP),
1380     const_iv (GL_CONVOLUTION_2D),
1381     const_iv (GL_CONVOLUTION_BORDER_MODE),
1382     const_iv (GL_CONSTANT_BORDER),
1383     const_iv (GL_LINES),
1384     const_iv (GL_QUADS),
1385 root 1.55 const_iv (GL_LINE_LOOP),
1386 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
1387     const_iv (GL_FASTEST),
1388     # undef const_iv
1389     };
1390    
1391     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
1392     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
1393     }
1394    
1395     int glGetError ()
1396    
1397     void glClear (int mask)
1398    
1399     void glClearColor (float r, float g, float b, float a = 1.0)
1400     PROTOTYPE: @
1401    
1402     void glEnable (int cap)
1403    
1404     void glDisable (int cap)
1405    
1406     void glShadeModel (int mode)
1407    
1408     void glHint (int target, int mode)
1409    
1410     void glBlendFunc (int sfactor, int dfactor)
1411    
1412     void glLogicOp (int opcode)
1413    
1414     void glMatrixMode (int mode)
1415    
1416     void glPushMatrix ()
1417    
1418     void glPopMatrix ()
1419    
1420     void glLoadIdentity ()
1421    
1422 root 1.64 # near and far are due to microsofts buggy c compiler
1423     void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
1424 root 1.54
1425     void glViewport (int x, int y, int width, int height)
1426    
1427     void glTranslate (float x, float y, float z = 0.)
1428     CODE:
1429     glTranslatef (x, y, z);
1430    
1431 root 1.62 void glScale (float x, float y, float z = 1.)
1432 root 1.54 CODE:
1433     glScalef (x, y, z);
1434    
1435     void glRotate (float angle, float x, float y, float z)
1436     CODE:
1437     glRotatef (angle, x, y, z);
1438    
1439     void glBegin (int mode)
1440    
1441     void glEnd ()
1442    
1443     void glColor (float r, float g, float b, float a = 1.0)
1444     PROTOTYPE: @
1445     CODE:
1446     glColor4f (r, g, b, a);
1447    
1448     void glVertex (float x, float y, float z = 0.)
1449     CODE:
1450     glVertex3f (x, y, z);
1451    
1452     void glTexCoord (float s, float t)
1453     CODE:
1454     glTexCoord2f (s, t);
1455    
1456     void glTexEnv (int target, int pname, float param)
1457     CODE:
1458     glTexEnvf (target, pname, param);
1459    
1460     void glTexParameter (int target, int pname, float param)
1461     CODE:
1462     glTexParameterf (target, pname, param);
1463    
1464     void glBindTexture (int target, int name)
1465    
1466     void glConvolutionParameter (int target, int pname, float params)
1467     CODE:
1468 root 1.64 GL_CALL (PFNGLCONVOLUTIONPARAMETERFEXTPROC, glConvolutionParameterf, (target, pname, params));
1469 root 1.54
1470     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
1471 root 1.64 CODE:
1472     GL_CALL (PFNGLCONVOLUTIONFILTER2DEXTPROC, glConvolutionFilter2D,
1473     (target, internalformat, width, height, format, type, data));
1474 root 1.54
1475     void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
1476    
1477     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
1478    
1479     int glGenTexture ()
1480     CODE:
1481     {
1482     GLuint name;
1483     glGenTextures (1, &name);
1484     RETVAL = name;
1485     }
1486     OUTPUT:
1487     RETVAL
1488    
1489     void glDeleteTexture (int name)
1490     CODE:
1491     {
1492     GLuint name_ = name;
1493     glDeleteTextures (1, &name_);
1494     }
1495    
1496     int glGenList ()
1497     CODE:
1498     RETVAL = glGenLists (1);
1499     OUTPUT:
1500     RETVAL
1501    
1502     void glDeleteList (int list)
1503     CODE:
1504     glDeleteLists (list, 1);
1505    
1506     void glNewList (int list, int mode = GL_COMPILE)
1507    
1508     void glEndList ()
1509    
1510     void glCallList (int list)
1511