ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.58
Committed: Sun Apr 23 00:57:38 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.57: +5 -0 lines
Log Message:
*** empty log message ***

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