ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.71
Committed: Fri May 5 19:05:47 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.70: +14 -0 lines
Log Message:
better mode management, experimental 'end of channel' event for sound

File Contents

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