ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.75
Committed: Mon May 8 18:28:40 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.74: +2 -1 lines
Log Message:
*** empty log message ***

File Contents

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