ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.102
Committed: Sat Jun 3 23:47:46 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.101: +4 -0 lines
Log Message:
*** empty log message ***

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