ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.62
Committed: Mon Apr 24 02:41:47 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.61: +1 -1 lines
Log Message:
implmenet map scale - now fully playability at 640x480

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