ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.103
Committed: Sun Jun 4 23:05:05 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.102: +49 -22 lines
Log Message:
better gl extension management, play around with premultiplied alpha, without reaching an absolutely correct solution

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.14 New (0, RETVAL, 1, struct cf_layout);
726 root 1.76
727     RETVAL->pl = pango_layout_new (rgba ? cairo_context : ft2_context);
728     RETVAL->rgba = rgba;
729     RETVAL->r = 1.;
730     RETVAL->g = 1.;
731     RETVAL->b = 1.;
732     RETVAL->a = 1.;
733     RETVAL->base_height = MIN_FONT_HEIGHT;
734     RETVAL->font = 0;
735    
736 root 1.14 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
737 root 1.76 layout_update_font (RETVAL);
738 root 1.14 OUTPUT:
739     RETVAL
740    
741     void
742 root 1.15 DESTROY (CFClient::Layout self)
743 root 1.14 CODE:
744     g_object_unref (self->pl);
745     Safefree (self);
746 root 1.13
747 root 1.76 int
748     is_rgba (CFClient::Layout self)
749     CODE:
750     RETVAL = self->rgba;
751     OUTPUT:
752     RETVAL
753    
754 root 1.8 void
755 root 1.35 set_text (CFClient::Layout self, SV *text_)
756     CODE:
757     {
758     STRLEN textlen;
759     char *text = SvPVutf8 (text_, textlen);
760    
761     pango_layout_set_text (self->pl, text, textlen);
762     }
763    
764     void
765 root 1.15 set_markup (CFClient::Layout self, SV *text_)
766 root 1.14 CODE:
767 root 1.5 {
768     STRLEN textlen;
769     char *text = SvPVutf8 (text_, textlen);
770 root 1.14
771     pango_layout_set_markup (self->pl, text, textlen);
772     }
773    
774 root 1.46 SV *
775     get_text (CFClient::Layout self)
776     CODE:
777 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
778 root 1.46 SvUTF8_on (RETVAL);
779     OUTPUT:
780     RETVAL
781    
782 root 1.14 void
783 root 1.76 set_foreground (CFClient::Layout self, float r, float g, float b, float a = 1.)
784     CODE:
785     self->r = r;
786     self->g = g;
787     self->b = b;
788     self->a = a;
789    
790     void
791 root 1.61 set_font (CFClient::Layout self, CFClient::Font font = 0)
792     CODE:
793     if (self->font != font)
794     {
795     self->font = font;
796     layout_update_font (self);
797     }
798    
799     void
800 root 1.16 set_height (CFClient::Layout self, int base_height)
801     CODE:
802 root 1.61 if (self->base_height != base_height)
803     {
804     self->base_height = base_height;
805     layout_update_font (self);
806     }
807 root 1.16
808     void
809 root 1.15 set_width (CFClient::Layout self, int max_width = -1)
810 root 1.14 CODE:
811     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
812    
813     void
814 root 1.84 set_indent (CFClient::Layout self, int indent)
815     CODE:
816     pango_layout_set_indent (self->pl, indent * PANGO_SCALE);
817    
818     void
819     set_spacing (CFClient::Layout self, int spacing)
820     CODE:
821     pango_layout_set_spacing (self->pl, spacing * PANGO_SCALE);
822    
823     void
824     set_ellipsise (CFClient::Layout self, int ellipsise)
825     CODE:
826     pango_layout_set_ellipsize (self->pl,
827     ellipsise == 1 ? PANGO_ELLIPSIZE_START
828     : ellipsise == 2 ? PANGO_ELLIPSIZE_MIDDLE
829     : ellipsise == 3 ? PANGO_ELLIPSIZE_END
830     : PANGO_ELLIPSIZE_NONE
831     );
832    
833     void
834     set_single_paragraph_mode (CFClient::Layout self, int spm)
835     CODE:
836     pango_layout_set_single_paragraph_mode (self->pl, !!spm);
837    
838     void
839 root 1.15 size (CFClient::Layout self)
840 root 1.14 PPCODE:
841     {
842     int w, h;
843    
844     layout_get_pixel_size (self, &w, &h);
845    
846     EXTEND (SP, 2);
847     PUSHs (sv_2mortal (newSViv (w)));
848     PUSHs (sv_2mortal (newSViv (h)));
849     }
850    
851 root 1.17 int
852     xy_to_index (CFClient::Layout self, int x, int y)
853     CODE:
854     {
855     int index, trailing;
856     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
857     RETVAL = index;
858     }
859     OUTPUT:
860     RETVAL
861    
862     void
863     cursor_pos (CFClient::Layout self, int index)
864     PPCODE:
865     {
866     PangoRectangle strong_pos;
867     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
868 root 1.30
869 root 1.17 EXTEND (SP, 3);
870     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
871     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
872     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
873     }
874    
875 root 1.14 void
876 root 1.15 render (CFClient::Layout self)
877 root 1.14 PPCODE:
878     {
879 root 1.5 SV *retval;
880     int w, h;
881    
882 root 1.14 layout_get_pixel_size (self, &w, &h);
883 root 1.5
884 root 1.76 if (self->rgba)
885     {
886     cairo_surface_t *surface;
887     cairo_t *cairo;
888    
889     retval = newSV (w * h * 4);
890     SvPOK_only (retval);
891     SvCUR_set (retval, w * h * 4);
892    
893     memset (SvPVX (retval), 0, w * h * 4);
894    
895     surface = cairo_image_surface_create_for_data (
896     (void*)SvPVX (retval), CAIRO_FORMAT_ARGB32, w, h, w * 4);
897     cairo = cairo_create (surface);
898     cairo_set_source_rgba (cairo, self->r, self->g, self->b, self->a);
899    
900     pango_cairo_show_layout (cairo, self->pl);
901    
902     cairo_destroy (cairo);
903     cairo_surface_destroy (surface);
904    
905     // what a mess, and its premultiplied, too :(
906     {
907     uint32_t *p = (uint32_t *)SvPVX (retval);
908     uint32_t *e = p + w * h;
909 root 1.5
910 root 1.76 while (p < e)
911     {
912     uint32_t rgba = *p;
913     rgba = (rgba >> 24) | (rgba << 8);
914 root 1.87 #if 0
915     #ifdef _WIN32
916     {//D
917     uint8_t r = rgba >> 24;
918     uint8_t g = rgba >> 16;
919     uint8_t b = rgba >> 8;
920     uint8_t a = rgba >> 0;
921    
922     rgba = (rgba & 0xffffff00) | a;
923     }
924     #endif
925     #endif
926 root 1.76 rgba = SDL_SwapBE32 (rgba);
927     *p++ = rgba;
928     }
929     }
930    
931     EXTEND (SP, 5);
932     PUSHs (sv_2mortal (newSViv (w)));
933     PUSHs (sv_2mortal (newSViv (h)));
934     PUSHs (sv_2mortal (retval));
935     PUSHs (sv_2mortal (newSViv (GL_RGBA)));
936     PUSHs (sv_2mortal (newSViv (GL_RGBA)));
937     }
938     else
939     {
940     FT_Bitmap bitmap;
941    
942     retval = newSV (w * h);
943     SvPOK_only (retval);
944     SvCUR_set (retval, w * h);
945    
946     bitmap.rows = h;
947     bitmap.width = w;
948     bitmap.pitch = w;
949     bitmap.buffer = (unsigned char*)SvPVX (retval);
950     bitmap.num_grays = 256;
951     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
952    
953     memset (bitmap.buffer, 0, w * h);
954    
955     pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
956 root 1.1
957 root 1.76 EXTEND (SP, 5);
958     PUSHs (sv_2mortal (newSViv (w)));
959     PUSHs (sv_2mortal (newSViv (h)));
960     PUSHs (sv_2mortal (retval));
961     PUSHs (sv_2mortal (newSViv (GL_ALPHA)));
962     PUSHs (sv_2mortal (newSViv (GL_ALPHA)));
963     }
964 root 1.5 }
965 root 1.11
966 root 1.15 MODULE = CFClient PACKAGE = CFClient::Texture
967 root 1.11
968     void
969 root 1.37 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
970 root 1.12 PROTOTYPE: $$$;$$
971 root 1.76 ALIAS:
972     draw_quad_alpha = 1
973     draw_quad_alpha_premultiplied = 2
974 root 1.11 CODE:
975     {
976 root 1.12 HV *hv = (HV *)SvRV (self);
977 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
978     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
979 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
980    
981     if (items < 5)
982     {
983 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
984     h = SvNV (*hv_fetch (hv, "h", 1, 1));
985 root 1.12 }
986    
987 root 1.76 if (ix)
988     {
989     glEnable (GL_BLEND);
990 root 1.103
991     if (ix == 2)
992     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
993     else
994     gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
995     GL_ONE_MINUS_DST_ALPHA, GL_ONE);
996    
997 root 1.86 glEnable (GL_ALPHA_TEST);
998     glAlphaFunc (GL_GREATER, 0.01f);
999 root 1.76 }
1000    
1001 root 1.12 glBindTexture (GL_TEXTURE_2D, name);
1002 root 1.76
1003 root 1.12 glBegin (GL_QUADS);
1004 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
1005     glTexCoord2f (0, t); glVertex2f (x , y + h);
1006     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
1007     glTexCoord2f (s, 0); glVertex2f (x + w, y );
1008 root 1.12 glEnd ();
1009 root 1.76
1010     if (ix)
1011 root 1.86 {
1012     glDisable (GL_ALPHA_TEST);
1013     glDisable (GL_BLEND);
1014     }
1015 root 1.11 }
1016 root 1.28
1017     MODULE = CFClient PACKAGE = CFClient::Map
1018    
1019     CFClient::Map
1020     new (SV *class, int map_width, int map_height)
1021     CODE:
1022     New (0, RETVAL, 1, struct map);
1023 root 1.42 RETVAL->x = 0;
1024     RETVAL->y = 0;
1025     RETVAL->w = map_width;
1026     RETVAL->h = map_height;
1027     RETVAL->ox = 0;
1028     RETVAL->oy = 0;
1029 root 1.30 RETVAL->faces = 8192;
1030     Newz (0, RETVAL->face, RETVAL->faces, mapface);
1031 root 1.42 RETVAL->texs = 8192;
1032     Newz (0, RETVAL->tex, RETVAL->texs, maptex);
1033 root 1.28 RETVAL->rows = 0;
1034     RETVAL->row = 0;
1035     OUTPUT:
1036     RETVAL
1037    
1038     void
1039     DESTROY (CFClient::Map self)
1040     CODE:
1041     {
1042 root 1.30 map_clear (self);
1043 root 1.28 Safefree (self->face);
1044 root 1.29 Safefree (self);
1045     }
1046    
1047     void
1048 root 1.30 clear (CFClient::Map self)
1049     CODE:
1050     map_clear (self);
1051    
1052     void
1053 root 1.42 set_face (CFClient::Map self, int face, int texid)
1054 root 1.29 CODE:
1055     {
1056 root 1.42 while (self->faces <= face)
1057 root 1.28 {
1058 root 1.30 Append (mapface, self->face, self->faces, self->faces);
1059 root 1.29 self->faces *= 2;
1060     }
1061 root 1.28
1062 root 1.42 self->face [face] = texid;
1063     }
1064    
1065     void
1066     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)
1067     CODE:
1068     {
1069     while (self->texs <= texid)
1070     {
1071     Append (maptex, self->tex, self->texs, self->texs);
1072     self->texs *= 2;
1073     }
1074    
1075 root 1.48 {
1076     maptex *tex = self->tex + texid;
1077 root 1.39
1078 root 1.48 tex->name = name;
1079     tex->w = w;
1080     tex->h = h;
1081     tex->s = s;
1082     tex->t = t;
1083     tex->r = r;
1084     tex->g = g;
1085     tex->b = b;
1086     tex->a = a;
1087     }
1088 root 1.95
1089     // somewhat hackish, but for textures that require it, it really
1090     // improves the look, and most others don't suffer.
1091     glBindTexture (GL_TEXTURE_2D, name);
1092 root 1.99 //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1093     //glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1094     // use uglier nearest interpolation because linear suffers
1095     // from transparent color bleeding and ugly wrapping effects.
1096     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1097 root 1.29 }
1098    
1099 root 1.42 int
1100     ox (CFClient::Map self)
1101     ALIAS:
1102     oy = 1
1103 root 1.101 x = 2
1104     y = 3
1105 root 1.102 w = 4
1106     h = 5
1107 root 1.42 CODE:
1108     switch (ix)
1109     {
1110     case 0: RETVAL = self->ox; break;
1111     case 1: RETVAL = self->oy; break;
1112 root 1.101 case 2: RETVAL = self->x; break;
1113     case 3: RETVAL = self->y; break;
1114 root 1.102 case 4: RETVAL = self->w; break;
1115     case 5: RETVAL = self->h; break;
1116 root 1.42 }
1117     OUTPUT:
1118     RETVAL
1119    
1120 root 1.29 void
1121 root 1.43 scroll (CFClient::Map self, int dx, int dy)
1122     CODE:
1123     {
1124 root 1.44 if (dx > 0)
1125     map_blank (self, self->x, self->y, dx - 1, self->h);
1126     else if (dx < 0)
1127     map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
1128    
1129     if (dy > 0)
1130     map_blank (self, self->x, self->y, self->w, dy - 1);
1131     else if (dy < 0)
1132     map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
1133 root 1.43
1134 root 1.44 self->ox += dx; self->x += dx;
1135     self->oy += dy; self->y += dy;
1136 root 1.43
1137     while (self->y < 0)
1138     {
1139     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
1140    
1141     self->rows += MAP_EXTEND_Y;
1142     self->y += MAP_EXTEND_Y;
1143     }
1144 root 1.44 }
1145 root 1.43
1146 root 1.44 void
1147     map1a_update (CFClient::Map self, SV *data_)
1148     CODE:
1149     {
1150 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
1151     uint8_t *data_end = (uint8_t *)SvEND (data_);
1152 root 1.48 mapcell *cell;
1153     int x, y, flags;
1154 root 1.43
1155 root 1.29 while (data < data_end)
1156     {
1157 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
1158 root 1.30
1159 root 1.48 x = ((flags >> 10) & 63) + self->x;
1160     y = ((flags >> 4) & 63) + self->y;
1161 root 1.29
1162 root 1.48 cell = map_get_cell (self, x, y);
1163 root 1.29
1164     if (flags & 15)
1165     {
1166 root 1.45 if (cell->darkness < 0)
1167 root 1.29 {
1168     cell->darkness = 0;
1169     cell->face [0] = 0;
1170     cell->face [1] = 0;
1171     cell->face [2] = 0;
1172     }
1173 root 1.45
1174 root 1.29 cell->darkness = flags & 8 ? *data++ : 255;
1175    
1176 root 1.42 //TODO: don't trust server data to be in-range(!)
1177    
1178 root 1.29 if (flags & 4)
1179     {
1180 root 1.42 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
1181 root 1.29 }
1182    
1183     if (flags & 2)
1184     {
1185 root 1.42 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
1186 root 1.29 }
1187    
1188     if (flags & 1)
1189     {
1190 root 1.42 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
1191 root 1.29 }
1192     }
1193     else
1194 root 1.31 cell->darkness = -1;
1195 root 1.29 }
1196 root 1.28 }
1197    
1198 root 1.40 SV *
1199 root 1.55 mapmap (CFClient::Map self, int x0, int y0, int w, int h)
1200 root 1.40 CODE:
1201     {
1202 root 1.55 int x1, x;
1203     int y1, y;
1204 root 1.40 int z;
1205     SV *map_sv = newSV (w * h * sizeof (uint32_t));
1206     uint32_t *map = (uint32_t *)SvPVX (map_sv);
1207    
1208     SvPOK_only (map_sv);
1209     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
1210    
1211 root 1.55 x0 += self->x; x1 = x0 + w;
1212     y0 += self->y; y1 = y0 + h;
1213 root 1.40
1214     for (y = y0; y < y1; y++)
1215     {
1216     maprow *row = 0 <= y && y < self->rows
1217     ? self->row + y
1218     : 0;
1219    
1220     for (x = x0; x < x1; x++)
1221     {
1222     int r = 32, g = 32, b = 32, a = 192;
1223    
1224     if (row && row->c0 <= x && x < row->c1)
1225     {
1226     mapcell *cell = row->col + (x - row->c0);
1227    
1228     for (z = 0; z <= 0; z++)
1229     {
1230 root 1.42 mapface face = cell->face [z];
1231 root 1.40
1232     if (face)
1233     {
1234 root 1.42 maptex tex = self->tex [face];
1235 root 1.40 int a0 = 255 - tex.a;
1236     int a1 = tex.a;
1237    
1238     r = (r * a0 + tex.r * a1) / 255;
1239     g = (g * a0 + tex.g * a1) / 255;
1240     b = (b * a0 + tex.b * a1) / 255;
1241     a = (a * a0 + tex.a * a1) / 255;
1242     }
1243     }
1244     }
1245    
1246     *map++ = (r )
1247     | (g << 8)
1248     | (b << 16)
1249     | (a << 24);
1250     }
1251     }
1252    
1253     RETVAL = map_sv;
1254     }
1255     OUTPUT:
1256     RETVAL
1257    
1258 root 1.30 void
1259 root 1.38 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
1260 root 1.32 PPCODE:
1261 root 1.30 {
1262 root 1.48 int vx, vy;
1263     int x, y, z;
1264     int last_name;
1265     mapface face;
1266 root 1.32 int sw4 = (sw + 3) & ~3;
1267     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
1268 root 1.35 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
1269 root 1.48
1270 root 1.42 memset (darkness, 255, sw4 * sh);
1271 root 1.32 SvPOK_only (darkness_sv);
1272     SvCUR_set (darkness_sv, sw4 * sh);
1273    
1274 root 1.48 vx = self->x + (self->w - sw) / 2 - shift_x;
1275     vy = self->y + (self->h - sh) / 2 - shift_y;
1276 root 1.38
1277 root 1.42 /*
1278     int vx = self->vx = self->w >= sw
1279     ? self->x + (self->w - sw) / 2
1280     : MIN (self->x, MAX (self->x + self->w - sw + 1, self->vx));
1281    
1282     int vy = self->vy = self->h >= sh
1283     ? self->y + (self->h - sh) / 2
1284     : MIN (self->y, MAX (self->y + self->h - sh + 1, self->vy));
1285     */
1286 root 1.30
1287     glColor4ub (255, 255, 255, 255);
1288    
1289     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1290     glEnable (GL_BLEND);
1291     glEnable (GL_TEXTURE_2D);
1292     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1293    
1294 root 1.48 glBegin (GL_QUADS);
1295 root 1.30
1296 root 1.48 last_name = 0;
1297 root 1.30
1298     for (z = 0; z < 3; z++)
1299     for (y = 0; y < sh; y++)
1300     if (0 <= y + vy && y + vy < self->rows)
1301     {
1302     maprow *row = self->row + (y + vy);
1303    
1304     for (x = 0; x < sw; x++)
1305     if (row->c0 <= x + vx && x + vx < row->c1)
1306     {
1307     mapcell *cell = row->col + (x + vx - row->c0);
1308 root 1.32
1309     darkness[y * sw4 + x] = cell->darkness < 0
1310 root 1.33 ? 255 - FOW_DARKNESS
1311 root 1.32 : 255 - cell->darkness;
1312    
1313 root 1.48 face = cell->face [z];
1314 root 1.30
1315     if (face)
1316     {
1317 root 1.42 maptex tex = self->tex [face];
1318 root 1.30
1319     int px = (x + 1) * 32 - tex.w;
1320     int py = (y + 1) * 32 - tex.h;
1321    
1322     if (last_name != tex.name)
1323     {
1324     glEnd ();
1325     last_name = tex.name;
1326     glBindTexture (GL_TEXTURE_2D, last_name);
1327     glBegin (GL_QUADS);
1328     }
1329    
1330     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1331     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1332     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1333     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1334     }
1335     }
1336     }
1337    
1338     glEnd ();
1339 root 1.32
1340 root 1.34 glDisable (GL_TEXTURE_2D);
1341     glDisable (GL_BLEND);
1342    
1343 root 1.32 EXTEND (SP, 3);
1344     PUSHs (sv_2mortal (newSViv (sw4)));
1345     PUSHs (sv_2mortal (newSViv (sh)));
1346     PUSHs (darkness_sv);
1347 root 1.30 }
1348    
1349 root 1.42 SV *
1350     get_rect (CFClient::Map self, int x0, int y0, int w, int h)
1351     CODE:
1352     {
1353     int x, y, x1, y1;
1354     SV *data_sv = newSV (w * h * 7 + 5);
1355     uint8_t *data = (uint8_t *)SvPVX (data_sv);
1356    
1357     *data++ = 0; /* version 0 format */
1358     *data++ = w >> 8; *data++ = w;
1359     *data++ = h >> 8; *data++ = h;
1360    
1361     // we need to do this 'cause we don't keep an absolute coord system for rows
1362 root 1.55 // TODO: treat rows as we treat columns
1363 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1364     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1365    
1366     x0 += self->x - self->ox;
1367     y0 += self->y - self->oy;
1368    
1369     x1 = x0 + w;
1370     y1 = y0 + h;
1371    
1372     for (y = y0; y < y1; y++)
1373     {
1374     maprow *row = 0 <= y && y < self->rows
1375     ? self->row + y
1376     : 0;
1377    
1378     for (x = x0; x < x1; x++)
1379     {
1380     if (row && row->c0 <= x && x < row->c1)
1381     {
1382     mapcell *cell = row->col + (x - row->c0);
1383     uint8_t flags = 0;
1384    
1385     if (cell->face [0]) flags |= 1;
1386     if (cell->face [1]) flags |= 2;
1387     if (cell->face [2]) flags |= 4;
1388    
1389     *data++ = flags;
1390    
1391     if (flags & 1)
1392     {
1393     *data++ = cell->face [0] >> 8;
1394     *data++ = cell->face [0];
1395     }
1396    
1397     if (flags & 2)
1398     {
1399     *data++ = cell->face [1] >> 8;
1400     *data++ = cell->face [1];
1401     }
1402    
1403     if (flags & 4)
1404     {
1405     *data++ = cell->face [2] >> 8;
1406     *data++ = cell->face [2];
1407     }
1408     }
1409     else
1410     *data++ = 0;
1411     }
1412     }
1413    
1414     SvPOK_only (data_sv);
1415     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
1416     RETVAL = data_sv;
1417     }
1418     OUTPUT:
1419     RETVAL
1420    
1421     void
1422     set_rect (CFClient::Map self, int x0, int y0, uint8_t *data)
1423     PPCODE:
1424     {
1425     int x, y, z;
1426 root 1.48 int w, h;
1427 root 1.42 int x1, y1;
1428    
1429     if (*data++ != 0)
1430     return; /* version mismatch */
1431    
1432 root 1.48 w = *data++ << 8; w |= *data++;
1433     h = *data++ << 8; h |= *data++;
1434 root 1.42
1435     // we need to do this 'cause we don't keep an absolute coord system for rows
1436 root 1.55 // TODO: treat rows as we treat columns
1437 root 1.42 map_get_row (self, y0 + self->y - self->oy);//D
1438     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1439    
1440     x0 += self->x - self->ox;
1441     y0 += self->y - self->oy;
1442    
1443     x1 = x0 + w;
1444     y1 = y0 + h;
1445    
1446     for (y = y0; y < y1; y++)
1447     {
1448     maprow *row = map_get_row (self, y);
1449    
1450     for (x = x0; x < x1; x++)
1451     {
1452     uint8_t flags = *data++;
1453    
1454     if (flags)
1455     {
1456     mapface face[3] = { 0, 0, 0 };
1457    
1458     mapcell *cell = row_get_cell (row, x);
1459    
1460     if (flags & 1) { face[0] = *data++ << 8; face[0] |= *data++; }
1461     if (flags & 2) { face[1] = *data++ << 8; face[1] |= *data++; }
1462     if (flags & 4) { face[2] = *data++ << 8; face[2] |= *data++; }
1463    
1464     if (cell->darkness <= 0)
1465     {
1466     cell->darkness = -1;
1467    
1468     for (z = 0; z <= 2; z++)
1469     {
1470     cell->face[z] = face[z];
1471    
1472     if (face[z] && (face[z] >= self->texs || !self->tex[face [z]].name))
1473     XPUSHs (sv_2mortal (newSViv (face[z])));
1474     }
1475     }
1476     }
1477     }
1478     }
1479     }
1480    
1481 root 1.52 MODULE = CFClient PACKAGE = CFClient::MixChunk
1482    
1483     CFClient::MixChunk
1484     new_from_file (SV *class, char *path)
1485     CODE:
1486     RETVAL = Mix_LoadWAV (path);
1487     OUTPUT:
1488     RETVAL
1489    
1490     void
1491     DESTROY (CFClient::MixChunk self)
1492     CODE:
1493     Mix_FreeChunk (self);
1494    
1495     int
1496     volume (CFClient::MixChunk self, int volume = -1)
1497     CODE:
1498     RETVAL = Mix_VolumeChunk (self, volume);
1499     OUTPUT:
1500     RETVAL
1501    
1502     int
1503     play (CFClient::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
1504     CODE:
1505     RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
1506     OUTPUT:
1507     RETVAL
1508    
1509     MODULE = CFClient PACKAGE = CFClient::MixMusic
1510    
1511     int
1512     volume (int volume = -1)
1513     CODE:
1514     RETVAL = Mix_VolumeMusic (volume);
1515     OUTPUT:
1516     RETVAL
1517    
1518     CFClient::MixMusic
1519     new_from_file (SV *class, char *path)
1520     CODE:
1521     RETVAL = Mix_LoadMUS (path);
1522     OUTPUT:
1523     RETVAL
1524    
1525     void
1526     DESTROY (CFClient::MixMusic self)
1527     CODE:
1528     Mix_FreeMusic (self);
1529    
1530     int
1531     play (CFClient::MixMusic self, int loops = -1)
1532     CODE:
1533     RETVAL = Mix_PlayMusic (self, loops);
1534     OUTPUT:
1535     RETVAL
1536    
1537 root 1.54 MODULE = CFClient PACKAGE = CFClient::OpenGL
1538    
1539     BOOT:
1540     {
1541     HV *stash = gv_stashpv ("CFClient::OpenGL", 1);
1542     static const struct {
1543     const char *name;
1544     IV iv;
1545     } *civ, const_iv[] = {
1546     # define const_iv(name) { # name, (IV)name }
1547     const_iv (GL_COLOR_MATERIAL),
1548     const_iv (GL_SMOOTH),
1549     const_iv (GL_FLAT),
1550 root 1.69 const_iv (GL_DITHER),
1551 root 1.54 const_iv (GL_BLEND),
1552 root 1.89 const_iv (GL_CULL_FACE),
1553 root 1.69 const_iv (GL_SCISSOR_TEST),
1554 root 1.89 const_iv (GL_DEPTH_TEST),
1555     const_iv (GL_ALPHA_TEST),
1556     const_iv (GL_NORMALIZE),
1557     const_iv (GL_RESCALE_NORMAL),
1558 root 1.54 const_iv (GL_AND),
1559 root 1.67 const_iv (GL_ONE),
1560     const_iv (GL_ZERO),
1561 root 1.54 const_iv (GL_SRC_ALPHA),
1562 root 1.67 const_iv (GL_SRC_ALPHA_SATURATE),
1563 root 1.54 const_iv (GL_ONE_MINUS_SRC_ALPHA),
1564 root 1.67 const_iv (GL_ONE_MINUS_DST_ALPHA),
1565 root 1.54 const_iv (GL_RGB),
1566     const_iv (GL_RGBA),
1567     const_iv (GL_UNSIGNED_BYTE),
1568 root 1.89 const_iv (GL_UNSIGNED_SHORT),
1569     const_iv (GL_UNSIGNED_INT),
1570 root 1.54 const_iv (GL_ALPHA),
1571 root 1.86 const_iv (GL_INTENSITY),
1572 root 1.76 const_iv (GL_LUMINANCE),
1573 root 1.86 const_iv (GL_LUMINANCE_ALPHA),
1574 root 1.54 const_iv (GL_FLOAT),
1575     const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
1576     const_iv (GL_COMPILE),
1577     const_iv (GL_TEXTURE_1D),
1578     const_iv (GL_TEXTURE_2D),
1579     const_iv (GL_TEXTURE_ENV),
1580     const_iv (GL_TEXTURE_MAG_FILTER),
1581     const_iv (GL_TEXTURE_MIN_FILTER),
1582     const_iv (GL_TEXTURE_ENV_MODE),
1583     const_iv (GL_TEXTURE_WRAP_S),
1584     const_iv (GL_TEXTURE_WRAP_T),
1585 root 1.98 const_iv (GL_REPEAT),
1586 root 1.54 const_iv (GL_CLAMP),
1587 root 1.98 const_iv (GL_CLAMP_TO_EDGE),
1588 root 1.54 const_iv (GL_NEAREST),
1589     const_iv (GL_LINEAR),
1590 root 1.57 const_iv (GL_NEAREST_MIPMAP_NEAREST),
1591     const_iv (GL_LINEAR_MIPMAP_NEAREST),
1592     const_iv (GL_NEAREST_MIPMAP_LINEAR),
1593     const_iv (GL_LINEAR_MIPMAP_LINEAR),
1594     const_iv (GL_GENERATE_MIPMAP),
1595 root 1.54 const_iv (GL_MODULATE),
1596 root 1.69 const_iv (GL_DECAL),
1597 root 1.54 const_iv (GL_REPLACE),
1598 root 1.89 const_iv (GL_DEPTH_BUFFER_BIT),
1599 root 1.54 const_iv (GL_COLOR_BUFFER_BIT),
1600     const_iv (GL_PROJECTION),
1601     const_iv (GL_MODELVIEW),
1602     const_iv (GL_COLOR_LOGIC_OP),
1603 root 1.69 const_iv (GL_SEPARABLE_2D),
1604 root 1.54 const_iv (GL_CONVOLUTION_2D),
1605     const_iv (GL_CONVOLUTION_BORDER_MODE),
1606     const_iv (GL_CONSTANT_BORDER),
1607     const_iv (GL_LINES),
1608 root 1.89 const_iv (GL_LINE_LOOP),
1609 root 1.54 const_iv (GL_QUADS),
1610 root 1.89 const_iv (GL_QUAD_STRIP),
1611     const_iv (GL_TRIANGLES),
1612     const_iv (GL_TRIANGLE_STRIP),
1613     const_iv (GL_TRIANGLE_FAN),
1614 root 1.54 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
1615     const_iv (GL_FASTEST),
1616 root 1.89 const_iv (GL_V2F),
1617     const_iv (GL_V3F),
1618     const_iv (GL_T2F_V3F),
1619     const_iv (GL_T2F_N3F_V3F),
1620 root 1.54 # undef const_iv
1621     };
1622    
1623     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
1624     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
1625     }
1626    
1627 root 1.97 char *
1628     gl_vendor ()
1629     CODE:
1630     RETVAL = (char *)glGetString (GL_VENDOR);
1631     OUTPUT:
1632     RETVAL
1633    
1634     char *
1635     gl_version ()
1636     CODE:
1637     RETVAL = (char *)glGetString (GL_VERSION);
1638     OUTPUT:
1639     RETVAL
1640    
1641     char *
1642     gl_extensions ()
1643     CODE:
1644     RETVAL = (char *)glGetString (GL_EXTENSIONS);
1645     OUTPUT:
1646     RETVAL
1647    
1648 root 1.54 int glGetError ()
1649    
1650     void glClear (int mask)
1651    
1652     void glClearColor (float r, float g, float b, float a = 1.0)
1653     PROTOTYPE: @
1654    
1655     void glEnable (int cap)
1656    
1657     void glDisable (int cap)
1658    
1659     void glShadeModel (int mode)
1660    
1661     void glHint (int target, int mode)
1662    
1663     void glBlendFunc (int sfactor, int dfactor)
1664    
1665 root 1.103 void glBlendFuncSeparate (int sa, int da, int saa, int daa)
1666     CODE:
1667     gl_BlendFuncSeparate (sa, da, saa, daa);
1668    
1669 root 1.89 void glDepthMask (int flag)
1670    
1671 root 1.54 void glLogicOp (int opcode)
1672    
1673 root 1.68 void glColorMask (int red, int green, int blue, int alpha)
1674    
1675 root 1.54 void glMatrixMode (int mode)
1676    
1677     void glPushMatrix ()
1678    
1679     void glPopMatrix ()
1680    
1681     void glLoadIdentity ()
1682    
1683 root 1.90 # near_ and far_ are due to microsofts buggy "c" compiler
1684     void glFrustum (double left, double right, double bottom, double top, double near_, double far_)
1685    
1686     # near_ and far_ are due to microsofts buggy "c" compiler
1687 root 1.64 void glOrtho (double left, double right, double bottom, double top, double near_, double far_)
1688 root 1.54
1689     void glViewport (int x, int y, int width, int height)
1690    
1691 root 1.69 void glScissor (int x, int y, int width, int height)
1692    
1693 root 1.54 void glTranslate (float x, float y, float z = 0.)
1694     CODE:
1695     glTranslatef (x, y, z);
1696    
1697 root 1.62 void glScale (float x, float y, float z = 1.)
1698 root 1.54 CODE:
1699     glScalef (x, y, z);
1700    
1701     void glRotate (float angle, float x, float y, float z)
1702     CODE:
1703     glRotatef (angle, x, y, z);
1704    
1705     void glBegin (int mode)
1706    
1707     void glEnd ()
1708    
1709     void glColor (float r, float g, float b, float a = 1.0)
1710     PROTOTYPE: @
1711 root 1.103 ALIAS:
1712     glColor_premultiply = 1
1713 root 1.54 CODE:
1714 root 1.103 if (ix)
1715     {
1716     r *= a;
1717     g *= a;
1718     b *= a;
1719     }
1720 root 1.90 // microsoft visual "c" rounds instead of truncating...
1721 root 1.100 glColor4ub (MIN ((int)(r * 256.f), 255),
1722     MIN ((int)(g * 256.f), 255),
1723     MIN ((int)(b * 256.f), 255),
1724     MIN ((int)(a * 256.f), 255));
1725 root 1.54
1726 root 1.89 void glInterleavedArrays (int format, int stride, char *data)
1727    
1728     void glDrawElements (int mode, int count, int type, char *indices)
1729    
1730     # 1.2 void glDrawRangeElements (int mode, int start, int end
1731    
1732 root 1.91 void glRasterPos (float x, float y, float z = 0.)
1733     CODE:
1734     glRasterPos3f (0, 0, z);
1735     glBitmap (0, 0, 0, 0, x, y, 0);
1736    
1737 root 1.54 void glVertex (float x, float y, float z = 0.)
1738     CODE:
1739     glVertex3f (x, y, z);
1740    
1741     void glTexCoord (float s, float t)
1742     CODE:
1743     glTexCoord2f (s, t);
1744    
1745     void glTexEnv (int target, int pname, float param)
1746     CODE:
1747     glTexEnvf (target, pname, param);
1748    
1749     void glTexParameter (int target, int pname, float param)
1750     CODE:
1751     glTexParameterf (target, pname, param);
1752    
1753     void glBindTexture (int target, int name)
1754    
1755     void glConvolutionParameter (int target, int pname, float params)
1756     CODE:
1757 root 1.103 if (gl.ConvolutionParameterf)
1758     gl.ConvolutionParameterf (target, pname, params);
1759 root 1.54
1760     void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
1761 root 1.64 CODE:
1762 root 1.103 if (gl.ConvolutionFilter2D)
1763     gl.ConvolutionFilter2D (target, internalformat, width, height, format, type, data);
1764 root 1.54
1765 root 1.69 void glSeparableFilter2D (int target, int internalformat, int width, int height, int format, int type, char *row, char *column)
1766     CODE:
1767 root 1.103 if (gl.SeparableFilter2D)
1768     gl.SeparableFilter2D (target, internalformat, width, height, format, type, row, column);
1769 root 1.69
1770 root 1.54 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
1771    
1772     void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
1773    
1774 root 1.91 void glDrawPixels (int width, int height, int format, int type, char *pixels)
1775 root 1.68
1776     void glCopyPixels (int x, int y, int width, int height, int type = GL_COLOR)
1777    
1778 root 1.54 int glGenTexture ()
1779     CODE:
1780     {
1781     GLuint name;
1782     glGenTextures (1, &name);
1783     RETVAL = name;
1784     }
1785     OUTPUT:
1786     RETVAL
1787    
1788     void glDeleteTexture (int name)
1789     CODE:
1790     {
1791     GLuint name_ = name;
1792     glDeleteTextures (1, &name_);
1793     }
1794    
1795     int glGenList ()
1796     CODE:
1797     RETVAL = glGenLists (1);
1798     OUTPUT:
1799     RETVAL
1800    
1801     void glDeleteList (int list)
1802     CODE:
1803     glDeleteLists (list, 1);
1804    
1805     void glNewList (int list, int mode = GL_COMPILE)
1806    
1807     void glEndList ()
1808    
1809     void glCallList (int list)
1810    
1811 root 1.89