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