ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.104
Committed: Mon Jun 5 00:17:47 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.103: +4 -2 lines
Log Message:
play around some more

File Contents

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