ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.51
Committed: Wed Apr 19 20:46:44 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.50: +163 -3 lines
Log Message:
got rid of base SDL perl module

File Contents

# User Rev Content
1 root 1.48 #ifdef _WIN32
2     # include <malloc.h>
3     #endif
4    
5 root 1.1 #include "EXTERN.h"
6     #include "perl.h"
7     #include "XSUB.h"
8    
9 root 1.5 #include <string.h>
10 root 1.25 #include <stdio.h>
11 root 1.5
12 root 1.2 #include <SDL.h>
13 root 1.23 #include <SDL_image.h>
14 root 1.3 #include <SDL_opengl.h>
15 root 1.5
16 root 1.30 #include <glib/gmacros.h>
17    
18 root 1.5 #include <pango/pango.h>
19 root 1.10 #include <pango/pangofc-fontmap.h>
20 root 1.5 #include <pango/pangoft2.h>
21    
22 root 1.48 #ifndef _WIN32
23     # include <sys/types.h>
24     # include <sys/socket.h>
25     # include <netinet/in.h>
26     # include <netinet/tcp.h>
27     # include <inttypes.h>
28     #else
29     typedef unsigned char uint8_t;
30     typedef unsigned short uint16_t;
31     typedef unsigned int uint32_t;
32     typedef signed char int8_t;
33     typedef signed short int16_t;
34     typedef signed int int32_t;
35     #endif
36 root 1.28
37 root 1.29 #define FOW_DARKNESS 32
38    
39     #define MAP_EXTEND_X 32
40     #define MAP_EXTEND_Y 512
41    
42 root 1.5 static PangoContext *context;
43     static PangoFontMap *fontmap;
44 root 1.2
45 root 1.14 typedef struct cf_layout {
46     PangoLayout *pl;
47     int base_height;
48 root 1.15 } *CFClient__Layout;
49 root 1.14
50     static void
51 root 1.19 substitute_func (FcPattern *pattern, gpointer data)
52     {
53 root 1.20 FcPatternAddBool (pattern, FC_HINTING , 1);
54 root 1.35 FcPatternAddBool (pattern, FC_AUTOHINT, 0);
55 root 1.19 }
56    
57     static void
58 root 1.17 layout_update (CFClient__Layout self)
59     {
60 root 1.19 /* use a random scale factor to account for unknown descenders, 0.8 works
61     * reasonably well with bitstream vera
62     */
63 root 1.17 PangoFontDescription *font = pango_context_get_font_description (context);
64 root 1.46
65     int height = self->base_height * (PANGO_SCALE * 8 / 10);
66    
67     if (pango_font_description_get_size (font) != height)
68     {
69     pango_font_description_set_absolute_size (font, height);
70     pango_layout_context_changed (self->pl);
71     }
72 root 1.17 }
73    
74     static void
75 root 1.15 layout_get_pixel_size (CFClient__Layout self, int *w, int *h)
76 root 1.14 {
77 root 1.19 layout_update (self);
78 root 1.16
79 root 1.14 pango_layout_get_pixel_size (self->pl, w, h);
80    
81     *w = (*w + 3) & ~3;
82     if (!*w) *w = 1;
83     if (!*h) *h = 1;
84     }
85    
86 root 1.42 typedef uint16_t mapface;
87    
88 root 1.28 typedef struct {
89 root 1.30 GLint name;
90     int w, h;
91     float s, t;
92 root 1.39 uint8_t r, g, b, a;
93 root 1.42 } maptex;
94 root 1.30
95     typedef struct {
96 root 1.29 int16_t darkness;
97 root 1.42 mapface face[3];
98 root 1.28 } mapcell;
99    
100     typedef struct {
101 root 1.30 int32_t c0, c1;
102 root 1.28 mapcell *col;
103     } maprow;
104    
105     typedef struct map {
106     int x, y, w, h;
107 root 1.42 int ox, oy; /* offset to virtual global coordinate system */
108 root 1.28 int faces;
109 root 1.30 mapface *face;
110 root 1.28
111 root 1.42 int texs;
112     maptex *tex;
113    
114 root 1.48 int32_t rows;
115 root 1.28 maprow *row;
116     } *CFClient__Map;
117    
118 root 1.30 static char *
119     prepend (char *ptr, int sze, int inc)
120     {
121     char *p;
122    
123     New (0, p, sze + inc, char);
124     Zero (p, inc, char);
125     Move (ptr, p + inc, sze, char);
126     Safefree (ptr);
127    
128     return p;
129     }
130    
131     static char *
132     append (char *ptr, int sze, int inc)
133     {
134     Renew (ptr, sze + inc, char);
135     Zero (ptr + sze, inc, char);
136    
137     return ptr;
138     }
139    
140     #define Append(type,ptr,sze,inc) (ptr) = (type *)append ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
141     #define Prepend(type,ptr,sze,inc) (ptr) = (type *)prepend ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
142    
143 root 1.42 static maprow *
144     map_get_row (CFClient__Map self, int y)
145     {
146     if (0 > y)
147     {
148     int extend = - y + MAP_EXTEND_Y;
149     Prepend (maprow, self->row, self->rows, extend);
150    
151     self->rows += extend;
152     self->y += extend;
153     y += extend;
154     }
155     else if (y >= self->rows)
156     {
157     int extend = y - self->rows + MAP_EXTEND_Y;
158     Append (maprow, self->row, self->rows, extend);
159     self->rows += extend;
160     }
161    
162     return self->row + y;
163     }
164    
165     static mapcell *
166     row_get_cell (maprow *row, int x)
167     {
168     if (!row->col)
169     {
170     Newz (0, row->col, MAP_EXTEND_X, mapcell);
171     row->c0 = x - MAP_EXTEND_X / 4;
172     row->c1 = row->c0 + MAP_EXTEND_X;
173     }
174    
175     if (row->c0 > x)
176     {
177     int extend = row->c0 - x + MAP_EXTEND_X;
178     Prepend (mapcell, row->col, row->c1 - row->c0, extend);
179     row->c0 -= extend;
180     }
181     else if (x >= row->c1)
182     {
183     int extend = x - row->c1 + MAP_EXTEND_X;
184     Append (mapcell, row->col, row->c1 - row->c0, extend);
185     row->c1 += extend;
186     }
187    
188     return row->col + (x - row->c0);
189     }
190    
191     static mapcell *
192     map_get_cell (CFClient__Map self, int x, int y)
193     {
194     return row_get_cell (map_get_row (self, y), x);
195     }
196    
197 root 1.30 static void
198     map_clear (CFClient__Map self)
199     {
200     int r;
201    
202     for (r = 0; r < self->rows; r++)
203     Safefree (self->row[r].col);
204    
205     Safefree (self->row);
206    
207     self->x = 0;
208     self->y = 0;
209 root 1.42 self->ox = 0;
210     self->oy = 0;
211 root 1.30 self->row = 0;
212     self->rows = 0;
213     }
214    
215 root 1.29 static void
216     map_blank (CFClient__Map self, int x0, int y0, int w, int h)
217     {
218     int x, y;
219 root 1.48 maprow *row;
220 root 1.29
221     for (y = y0; y < y0 + h; y++)
222 root 1.30 if (y >= 0)
223     {
224     if (y >= self->rows)
225     break;
226    
227 root 1.48 row = self->row + y;
228 root 1.30
229     for (x = x0; x < x0 + w; x++)
230     if (x >= row->c0)
231     {
232     if (x >= row->c1)
233     break;
234 root 1.29
235 root 1.31 row->col[x - row->c0].darkness = -1;
236 root 1.30 }
237     }
238 root 1.29 }
239    
240 root 1.15 MODULE = CFClient PACKAGE = CFClient
241 root 1.1
242 root 1.11 PROTOTYPES: ENABLE
243    
244 root 1.5 BOOT:
245     {
246 root 1.51 HV *stash = gv_stashpv ("CFClient", 1);
247     static const struct {
248     const char *name;
249     IV iv;
250     } *civ, const_iv[] = {
251     # define const_iv(name) { # name, (IV)name }
252     const_iv (SDL_ACTIVEEVENT),
253     const_iv (SDL_KEYDOWN),
254     const_iv (SDL_KEYUP),
255     const_iv (SDL_MOUSEMOTION),
256     const_iv (SDL_MOUSEBUTTONDOWN),
257     const_iv (SDL_MOUSEBUTTONUP),
258     const_iv (SDL_JOYAXISMOTION),
259     const_iv (SDL_JOYBALLMOTION),
260     const_iv (SDL_JOYHATMOTION),
261     const_iv (SDL_JOYBUTTONDOWN),
262     const_iv (SDL_JOYBUTTONUP),
263     const_iv (SDL_QUIT),
264     const_iv (SDL_SYSWMEVENT),
265     const_iv (SDL_EVENT_RESERVEDA),
266     const_iv (SDL_EVENT_RESERVEDB),
267     const_iv (SDL_VIDEORESIZE),
268     const_iv (SDL_VIDEOEXPOSE),
269     const_iv (SDL_USEREVENT),
270     const_iv (SDLK_KP0),
271     const_iv (SDLK_KP1),
272     const_iv (SDLK_KP2),
273     const_iv (SDLK_KP3),
274     const_iv (SDLK_KP4),
275     const_iv (SDLK_KP5),
276     const_iv (SDLK_KP6),
277     const_iv (SDLK_KP7),
278     const_iv (SDLK_KP8),
279     const_iv (SDLK_KP9),
280     const_iv (SDLK_KP_PERIOD),
281     const_iv (SDLK_KP_DIVIDE),
282     const_iv (SDLK_KP_MULTIPLY),
283     const_iv (SDLK_KP_MINUS),
284     const_iv (SDLK_KP_PLUS),
285     const_iv (SDLK_KP_ENTER),
286     const_iv (SDLK_KP_EQUALS),
287     const_iv (SDLK_UP),
288     const_iv (SDLK_DOWN),
289     const_iv (SDLK_RIGHT),
290     const_iv (SDLK_LEFT),
291     const_iv (SDLK_INSERT),
292     const_iv (SDLK_HOME),
293     const_iv (SDLK_END),
294     const_iv (SDLK_PAGEUP),
295     const_iv (SDLK_PAGEDOWN),
296     const_iv (SDLK_F1),
297     const_iv (SDLK_F2),
298     const_iv (SDLK_F3),
299     const_iv (SDLK_F4),
300     const_iv (SDLK_F5),
301     const_iv (SDLK_F6),
302     const_iv (SDLK_F7),
303     const_iv (SDLK_F8),
304     const_iv (SDLK_F9),
305     const_iv (SDLK_F10),
306     const_iv (SDLK_F11),
307     const_iv (SDLK_F12),
308     const_iv (SDLK_F13),
309     const_iv (SDLK_F14),
310     const_iv (SDLK_F15),
311     const_iv (SDLK_NUMLOCK),
312     const_iv (SDLK_CAPSLOCK),
313     const_iv (SDLK_SCROLLOCK),
314     const_iv (SDLK_RSHIFT),
315     const_iv (SDLK_LSHIFT),
316     const_iv (SDLK_RCTRL),
317     const_iv (SDLK_LCTRL),
318     const_iv (SDLK_RALT),
319     const_iv (SDLK_LALT),
320     const_iv (SDLK_RMETA),
321     const_iv (SDLK_LMETA),
322     const_iv (SDLK_LSUPER),
323     const_iv (SDLK_RSUPER),
324     const_iv (SDLK_MODE),
325     const_iv (SDLK_COMPOSE),
326     const_iv (SDLK_HELP),
327     const_iv (SDLK_PRINT),
328     const_iv (SDLK_SYSREQ),
329     const_iv (SDLK_BREAK),
330     const_iv (SDLK_MENU),
331     const_iv (SDLK_POWER),
332     const_iv (SDLK_EURO),
333     const_iv (SDLK_UNDO),
334     const_iv (KMOD_NONE),
335     const_iv (KMOD_LSHIFT),
336     const_iv (KMOD_RSHIFT),
337     const_iv (KMOD_LCTRL),
338     const_iv (KMOD_RCTRL),
339     const_iv (KMOD_LALT),
340     const_iv (KMOD_RALT),
341     const_iv (KMOD_LMETA),
342     const_iv (KMOD_RMETA),
343     const_iv (KMOD_NUM),
344     const_iv (KMOD_CAPS),
345     const_iv (KMOD_MODE),
346     const_iv (KMOD_CTRL),
347     const_iv (KMOD_SHIFT),
348     const_iv (KMOD_ALT),
349     const_iv (KMOD_META)
350     # undef const_iv
351     };
352    
353     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
354     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
355    
356     fontmap = pango_ft2_font_map_new ();
357     pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, substitute_func, 0, 0);
358     context = pango_ft2_font_map_create_context ((PangoFT2FontMap *)fontmap);
359 root 1.5 }
360    
361 root 1.51 int
362     SDL_Init (U32 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO)
363    
364     void
365     SDL_Quit ()
366    
367     void
368     SDL_ListModes ()
369     PPCODE:
370     {
371     SDL_Rect **m;
372    
373     SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
374     SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
375     SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
376     SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 1);
377    
378     SDL_GL_SetAttribute (SDL_GL_ACCUM_RED_SIZE, 0);
379     SDL_GL_SetAttribute (SDL_GL_ACCUM_GREEN_SIZE, 0);
380     SDL_GL_SetAttribute (SDL_GL_ACCUM_BLUE_SIZE, 0);
381     SDL_GL_SetAttribute (SDL_GL_ACCUM_ALPHA_SIZE, 0);
382    
383     SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
384     SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 15);
385     SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 0);
386    
387     m = SDL_ListModes (0, SDL_FULLSCREEN | SDL_OPENGL);
388    
389     if (m && m != (SDL_Rect **)-1)
390     while (*m)
391     {
392     AV *av = newAV ();
393     av_push (av, newSViv ((*m)->w));
394     av_push (av, newSViv ((*m)->h));
395     XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
396    
397     ++m;
398     }
399     }
400    
401     int
402     SDL_SetVideoMode (int w, int h, int fullscreen)
403     CODE:
404     RETVAL = !!SDL_SetVideoMode (
405     w, h, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)
406     );
407     SDL_WM_SetCaption ("Crossfire+ Client " VERSION, "Crossfire+");
408     OUTPUT:
409     RETVAL
410    
411 root 1.10 void
412     lowdelay (int fd, int val = 1)
413     CODE:
414 root 1.48 #ifndef _WIN32
415 root 1.10 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
416 root 1.48 #endif
417 root 1.10
418 root 1.3 char *
419 root 1.4 gl_version ()
420     CODE:
421 root 1.5 RETVAL = (char *)glGetString (GL_VERSION);
422 root 1.4 OUTPUT:
423     RETVAL
424    
425     char *
426 root 1.3 gl_extensions ()
427     CODE:
428 root 1.5 RETVAL = (char *)glGetString (GL_EXTENSIONS);
429 root 1.3 OUTPUT:
430     RETVAL
431    
432 root 1.5 void
433 root 1.13 add_font (char *file)
434     CODE:
435     FcConfigAppFontAddFile (0, (const FcChar8 *)file); /* no idea wether this is required */
436    
437     void
438 root 1.9 set_font (char *file)
439 root 1.8 CODE:
440     {
441 root 1.9 int count;
442     FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)file, 0, 0, &count);
443 root 1.10 PangoFontDescription *font = pango_fc_font_description_from_pattern (pattern, 0);
444 root 1.9 FcPatternDestroy (pattern);
445 root 1.8 pango_context_set_font_description (context, font);
446     }
447    
448 root 1.23 void
449     load_image_inline (SV *image_)
450     ALIAS:
451     load_image_file = 1
452     PPCODE:
453     {
454     STRLEN image_len;
455     char *image = (char *)SvPVbyte (image_, image_len);
456     SDL_Surface *surface, *surface2;
457     SDL_PixelFormat fmt;
458     SDL_RWops *rw = ix
459     ? SDL_RWFromFile (image, "r")
460     : SDL_RWFromConstMem (image, image_len);
461    
462     if (!rw)
463 root 1.41 croak ("load_image: %s", SDL_GetError ());
464 root 1.23
465     surface = IMG_Load_RW (rw, 1);
466     if (!surface)
467 root 1.41 croak ("load_image: %s", SDL_GetError ());
468 root 1.23
469     fmt.palette = NULL;
470     fmt.BitsPerPixel = 32;
471     fmt.BytesPerPixel = 4;
472 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
473 root 1.23 fmt.Rmask = 0x000000ff;
474     fmt.Gmask = 0x0000ff00;
475     fmt.Bmask = 0x00ff0000;
476     fmt.Amask = 0xff000000;
477 root 1.49 #else
478     fmt.Rmask = 0xff000000;
479     fmt.Gmask = 0x00ff0000;
480     fmt.Bmask = 0x0000ff00;
481     fmt.Amask = 0x000000ff;
482     #endif
483 root 1.23 fmt.Rloss = 0;
484     fmt.Gloss = 0;
485     fmt.Bloss = 0;
486     fmt.Aloss = 0;
487     fmt.Rshift = 0;
488     fmt.Gshift = 8;
489     fmt.Bshift = 16;
490     fmt.Ashift = 24;
491     fmt.colorkey = 0;
492     fmt.alpha = 0;
493    
494     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
495    
496 root 1.39 assert (surface2->pitch == surface2->w * 4);
497    
498 root 1.23 EXTEND (SP, 5);
499     PUSHs (sv_2mortal (newSViv (surface2->w)));
500     PUSHs (sv_2mortal (newSViv (surface2->h)));
501     SDL_LockSurface (surface2);
502     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
503     SDL_UnlockSurface (surface2);
504 root 1.24 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
505 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
506 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
507 root 1.23
508     SDL_FreeSurface (surface);
509     SDL_FreeSurface (surface2);
510     }
511    
512 root 1.25 void
513 root 1.39 average (int x, int y, uint32_t *data)
514     PPCODE:
515     {
516     uint32_t r = 0, g = 0, b = 0, a = 0;
517    
518     x = y = x * y;
519    
520     while (x--)
521     {
522     uint32_t p = *data++;
523    
524     r += (p ) & 255;
525     g += (p >> 8) & 255;
526     b += (p >> 16) & 255;
527     a += (p >> 24) & 255;
528     }
529    
530     EXTEND (SP, 4);
531 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
532     PUSHs (sv_2mortal (newSViv (g / y)));
533     PUSHs (sv_2mortal (newSViv (b / y)));
534     PUSHs (sv_2mortal (newSViv (a / y)));
535 root 1.39 }
536    
537     void
538 root 1.25 fatal (char *message)
539     CODE:
540 root 1.50 #ifdef _WIN32
541 root 1.25 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
542     #else
543 root 1.40 fprintf (stderr, "FATAL: %s\n", message);
544 root 1.25 #endif
545     exit (1);
546    
547 root 1.15 MODULE = CFClient PACKAGE = CFClient::Layout
548 root 1.14
549 root 1.15 CFClient::Layout
550 root 1.14 new (SV *class, int base_height = 10)
551     CODE:
552     New (0, RETVAL, 1, struct cf_layout);
553     RETVAL->base_height = base_height;
554     RETVAL->pl = pango_layout_new (context);
555     pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
556     OUTPUT:
557     RETVAL
558    
559     void
560 root 1.15 DESTROY (CFClient::Layout self)
561 root 1.14 CODE:
562     g_object_unref (self->pl);
563     Safefree (self);
564 root 1.13
565 root 1.8 void
566 root 1.35 set_text (CFClient::Layout self, SV *text_)
567     CODE:
568     {
569     STRLEN textlen;
570     char *text = SvPVutf8 (text_, textlen);
571    
572     pango_layout_set_text (self->pl, text, textlen);
573     }
574    
575     void
576 root 1.15 set_markup (CFClient::Layout self, SV *text_)
577 root 1.14 CODE:
578 root 1.5 {
579     STRLEN textlen;
580     char *text = SvPVutf8 (text_, textlen);
581 root 1.14
582     pango_layout_set_markup (self->pl, text, textlen);
583     }
584    
585 root 1.46 SV *
586     get_text (CFClient::Layout self)
587     CODE:
588 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
589 root 1.46 SvUTF8_on (RETVAL);
590     OUTPUT:
591     RETVAL
592    
593 root 1.14 void
594 root 1.16 set_height (CFClient::Layout self, int base_height)
595     CODE:
596     self->base_height = base_height;
597    
598     void
599 root 1.15 set_width (CFClient::Layout self, int max_width = -1)
600 root 1.14 CODE:
601     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
602    
603     void
604 root 1.15 size (CFClient::Layout self)
605 root 1.14 PPCODE:
606     {
607     int w, h;
608    
609 root 1.17 layout_update (self);
610 root 1.14 layout_get_pixel_size (self, &w, &h);
611    
612     EXTEND (SP, 2);
613     PUSHs (sv_2mortal (newSViv (w)));
614     PUSHs (sv_2mortal (newSViv (h)));
615     }
616    
617 root 1.17 int
618     xy_to_index (CFClient::Layout self, int x, int y)
619     CODE:
620     {
621     int index, trailing;
622    
623     layout_update (self);
624     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
625    
626     RETVAL = index;
627     }
628     OUTPUT:
629     RETVAL
630    
631     void
632     cursor_pos (CFClient::Layout self, int index)
633     PPCODE:
634     {
635     PangoRectangle strong_pos;
636     layout_update (self);
637     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
638 root 1.30
639 root 1.17 EXTEND (SP, 3);
640     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
641     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
642     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
643     }
644    
645 root 1.14 void
646 root 1.15 render (CFClient::Layout self)
647 root 1.14 PPCODE:
648     {
649 root 1.5 SV *retval;
650     int w, h;
651     FT_Bitmap bitmap;
652    
653 root 1.17 layout_update (self);
654 root 1.14 layout_get_pixel_size (self, &w, &h);
655 root 1.5
656     retval = newSV (w * h);
657     SvPOK_only (retval);
658     SvCUR_set (retval, w * h);
659    
660     bitmap.rows = h;
661     bitmap.width = w;
662     bitmap.pitch = w;
663     bitmap.buffer = (unsigned char*)SvPVX (retval);
664     bitmap.num_grays = 256;
665     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
666    
667     memset (bitmap.buffer, 0, w * h);
668    
669 root 1.14 pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
670 root 1.1
671 root 1.5 EXTEND (SP, 3);
672     PUSHs (sv_2mortal (newSViv (w)));
673     PUSHs (sv_2mortal (newSViv (h)));
674     PUSHs (sv_2mortal (retval));
675     }
676 root 1.11
677 root 1.15 MODULE = CFClient PACKAGE = CFClient::Texture
678 root 1.11
679     void
680 root 1.37 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
681 root 1.12 PROTOTYPE: $$$;$$
682 root 1.11 CODE:
683     {
684 root 1.12 HV *hv = (HV *)SvRV (self);
685 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
686     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
687 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
688 elmex 1.36 int wrap_mode = SvIV (*hv_fetch (hv, "wrap_mode", 9, 1));
689 root 1.12
690     if (items < 5)
691     {
692 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
693     h = SvNV (*hv_fetch (hv, "h", 1, 1));
694 root 1.12 }
695    
696     glBindTexture (GL_TEXTURE_2D, name);
697 elmex 1.36 if (wrap_mode) {
698     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
699     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
700     }
701 root 1.12 glBegin (GL_QUADS);
702 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
703     glTexCoord2f (0, t); glVertex2f (x , y + h);
704     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
705     glTexCoord2f (s, 0); glVertex2f (x + w, y );
706 root 1.12 glEnd ();
707 root 1.11 }
708 root 1.28
709     MODULE = CFClient PACKAGE = CFClient::Map
710    
711     CFClient::Map
712     new (SV *class, int map_width, int map_height)
713     CODE:
714     New (0, RETVAL, 1, struct map);
715 root 1.42 RETVAL->x = 0;
716     RETVAL->y = 0;
717     RETVAL->w = map_width;
718     RETVAL->h = map_height;
719     RETVAL->ox = 0;
720     RETVAL->oy = 0;
721 root 1.30 RETVAL->faces = 8192;
722     Newz (0, RETVAL->face, RETVAL->faces, mapface);
723 root 1.42 RETVAL->texs = 8192;
724     Newz (0, RETVAL->tex, RETVAL->texs, maptex);
725 root 1.28 RETVAL->rows = 0;
726     RETVAL->row = 0;
727     OUTPUT:
728     RETVAL
729    
730     void
731     DESTROY (CFClient::Map self)
732     CODE:
733     {
734 root 1.30 map_clear (self);
735 root 1.28 Safefree (self->face);
736 root 1.29 Safefree (self);
737     }
738    
739     void
740 root 1.30 clear (CFClient::Map self)
741     CODE:
742     map_clear (self);
743    
744     void
745 root 1.42 set_face (CFClient::Map self, int face, int texid)
746 root 1.29 CODE:
747     {
748 root 1.42 while (self->faces <= face)
749 root 1.28 {
750 root 1.30 Append (mapface, self->face, self->faces, self->faces);
751 root 1.29 self->faces *= 2;
752     }
753 root 1.28
754 root 1.42 self->face [face] = texid;
755     }
756    
757     void
758     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)
759     CODE:
760     {
761     while (self->texs <= texid)
762     {
763     Append (maptex, self->tex, self->texs, self->texs);
764     self->texs *= 2;
765     }
766    
767 root 1.48 {
768     maptex *tex = self->tex + texid;
769 root 1.39
770 root 1.48 tex->name = name;
771     tex->w = w;
772     tex->h = h;
773     tex->s = s;
774     tex->t = t;
775     tex->r = r;
776     tex->g = g;
777     tex->b = b;
778     tex->a = a;
779     }
780 root 1.29 }
781    
782 root 1.42 int
783     ox (CFClient::Map self)
784     ALIAS:
785     oy = 1
786     CODE:
787     switch (ix)
788     {
789     case 0: RETVAL = self->ox; break;
790     case 1: RETVAL = self->oy; break;
791     }
792     OUTPUT:
793     RETVAL
794    
795 root 1.29 void
796 root 1.43 scroll (CFClient::Map self, int dx, int dy)
797     CODE:
798     {
799 root 1.44 if (dx > 0)
800     map_blank (self, self->x, self->y, dx - 1, self->h);
801     else if (dx < 0)
802     map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
803    
804     if (dy > 0)
805     map_blank (self, self->x, self->y, self->w, dy - 1);
806     else if (dy < 0)
807     map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
808 root 1.43
809 root 1.44 self->ox += dx; self->x += dx;
810     self->oy += dy; self->y += dy;
811 root 1.43
812     while (self->y < 0)
813     {
814     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
815    
816     self->rows += MAP_EXTEND_Y;
817     self->y += MAP_EXTEND_Y;
818     }
819 root 1.44 }
820 root 1.43
821 root 1.44 void
822     map1a_update (CFClient::Map self, SV *data_)
823     CODE:
824     {
825 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
826     uint8_t *data_end = (uint8_t *)SvEND (data_);
827 root 1.48 mapcell *cell;
828     int x, y, flags;
829 root 1.43
830 root 1.29 while (data < data_end)
831     {
832 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
833 root 1.30
834 root 1.48 x = ((flags >> 10) & 63) + self->x;
835     y = ((flags >> 4) & 63) + self->y;
836 root 1.29
837 root 1.48 cell = map_get_cell (self, x, y);
838 root 1.29
839     if (flags & 15)
840     {
841 root 1.45 if (cell->darkness < 0)
842 root 1.29 {
843     cell->darkness = 0;
844     cell->face [0] = 0;
845     cell->face [1] = 0;
846     cell->face [2] = 0;
847     }
848 root 1.45
849 root 1.29 cell->darkness = flags & 8 ? *data++ : 255;
850    
851 root 1.42 //TODO: don't trust server data to be in-range(!)
852    
853 root 1.29 if (flags & 4)
854     {
855 root 1.42 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
856 root 1.29 }
857    
858     if (flags & 2)
859     {
860 root 1.42 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
861 root 1.29 }
862    
863     if (flags & 1)
864     {
865 root 1.42 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
866 root 1.29 }
867     }
868     else
869 root 1.31 cell->darkness = -1;
870 root 1.29 }
871 root 1.28 }
872    
873 root 1.40 SV *
874     mapmap (CFClient::Map self, int w, int h)
875     CODE:
876     {
877     int x0, x1, x;
878     int y0, y1, y;
879     int z;
880     SV *map_sv = newSV (w * h * sizeof (uint32_t));
881     uint32_t *map = (uint32_t *)SvPVX (map_sv);
882    
883     SvPOK_only (map_sv);
884     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
885    
886     x0 = self->x - w / 2; x1 = x0 + w;
887     y0 = self->y - h / 2; y1 = y0 + h;
888    
889     for (y = y0; y < y1; y++)
890     {
891     maprow *row = 0 <= y && y < self->rows
892     ? self->row + y
893     : 0;
894    
895     for (x = x0; x < x1; x++)
896     {
897     int r = 32, g = 32, b = 32, a = 192;
898    
899     if (row && row->c0 <= x && x < row->c1)
900     {
901     mapcell *cell = row->col + (x - row->c0);
902    
903     for (z = 0; z <= 0; z++)
904     {
905 root 1.42 mapface face = cell->face [z];
906 root 1.40
907     if (face)
908     {
909 root 1.42 maptex tex = self->tex [face];
910 root 1.40 int a0 = 255 - tex.a;
911     int a1 = tex.a;
912    
913     r = (r * a0 + tex.r * a1) / 255;
914     g = (g * a0 + tex.g * a1) / 255;
915     b = (b * a0 + tex.b * a1) / 255;
916     a = (a * a0 + tex.a * a1) / 255;
917     }
918     }
919     }
920    
921     *map++ = (r )
922     | (g << 8)
923     | (b << 16)
924     | (a << 24);
925     }
926     }
927    
928     RETVAL = map_sv;
929     }
930     OUTPUT:
931     RETVAL
932    
933 root 1.30 void
934 root 1.38 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
935 root 1.32 PPCODE:
936 root 1.30 {
937 root 1.48 int vx, vy;
938     int x, y, z;
939     int last_name;
940     mapface face;
941 root 1.32 int sw4 = (sw + 3) & ~3;
942     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
943 root 1.35 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
944 root 1.48
945 root 1.42 memset (darkness, 255, sw4 * sh);
946 root 1.32 SvPOK_only (darkness_sv);
947     SvCUR_set (darkness_sv, sw4 * sh);
948    
949 root 1.48 vx = self->x + (self->w - sw) / 2 - shift_x;
950     vy = self->y + (self->h - sh) / 2 - shift_y;
951 root 1.38
952 root 1.42 /*
953     int vx = self->vx = self->w >= sw
954     ? self->x + (self->w - sw) / 2
955     : MIN (self->x, MAX (self->x + self->w - sw + 1, self->vx));
956    
957     int vy = self->vy = self->h >= sh
958     ? self->y + (self->h - sh) / 2
959     : MIN (self->y, MAX (self->y + self->h - sh + 1, self->vy));
960     */
961 root 1.30
962     glColor4ub (255, 255, 255, 255);
963    
964     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
965     glEnable (GL_BLEND);
966     glEnable (GL_TEXTURE_2D);
967     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
968    
969 root 1.48 glBegin (GL_QUADS);
970 root 1.30
971 root 1.48 last_name = 0;
972 root 1.30
973     for (z = 0; z < 3; z++)
974     for (y = 0; y < sh; y++)
975     if (0 <= y + vy && y + vy < self->rows)
976     {
977     maprow *row = self->row + (y + vy);
978    
979     for (x = 0; x < sw; x++)
980     if (row->c0 <= x + vx && x + vx < row->c1)
981     {
982     mapcell *cell = row->col + (x + vx - row->c0);
983 root 1.32
984     darkness[y * sw4 + x] = cell->darkness < 0
985 root 1.33 ? 255 - FOW_DARKNESS
986 root 1.32 : 255 - cell->darkness;
987    
988 root 1.48 face = cell->face [z];
989 root 1.30
990     if (face)
991     {
992 root 1.42 maptex tex = self->tex [face];
993 root 1.30
994     int px = (x + 1) * 32 - tex.w;
995     int py = (y + 1) * 32 - tex.h;
996    
997     if (last_name != tex.name)
998     {
999     glEnd ();
1000     last_name = tex.name;
1001     glBindTexture (GL_TEXTURE_2D, last_name);
1002     glBegin (GL_QUADS);
1003     }
1004    
1005     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1006     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1007     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1008     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1009     }
1010     }
1011     }
1012    
1013     glEnd ();
1014 root 1.32
1015 root 1.34 glDisable (GL_TEXTURE_2D);
1016     glDisable (GL_BLEND);
1017    
1018 root 1.32 EXTEND (SP, 3);
1019     PUSHs (sv_2mortal (newSViv (sw4)));
1020     PUSHs (sv_2mortal (newSViv (sh)));
1021     PUSHs (darkness_sv);
1022 root 1.30 }
1023    
1024 root 1.42 SV *
1025     get_rect (CFClient::Map self, int x0, int y0, int w, int h)
1026     CODE:
1027     {
1028     int x, y, x1, y1;
1029     SV *data_sv = newSV (w * h * 7 + 5);
1030     uint8_t *data = (uint8_t *)SvPVX (data_sv);
1031    
1032     *data++ = 0; /* version 0 format */
1033     *data++ = w >> 8; *data++ = w;
1034     *data++ = h >> 8; *data++ = h;
1035    
1036     // we need to do this 'cause we don't keep an absolute coord system for rows
1037     // TODO: treat rows as we treat
1038     map_get_row (self, y0 + self->y - self->oy);//D
1039     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1040    
1041     x0 += self->x - self->ox;
1042     y0 += self->y - self->oy;
1043    
1044     x1 = x0 + w;
1045     y1 = y0 + h;
1046    
1047     for (y = y0; y < y1; y++)
1048     {
1049     maprow *row = 0 <= y && y < self->rows
1050     ? self->row + y
1051     : 0;
1052    
1053     for (x = x0; x < x1; x++)
1054     {
1055     if (row && row->c0 <= x && x < row->c1)
1056     {
1057     mapcell *cell = row->col + (x - row->c0);
1058     uint8_t flags = 0;
1059    
1060     if (cell->face [0]) flags |= 1;
1061     if (cell->face [1]) flags |= 2;
1062     if (cell->face [2]) flags |= 4;
1063    
1064     *data++ = flags;
1065    
1066     if (flags & 1)
1067     {
1068     *data++ = cell->face [0] >> 8;
1069     *data++ = cell->face [0];
1070     }
1071    
1072     if (flags & 2)
1073     {
1074     *data++ = cell->face [1] >> 8;
1075     *data++ = cell->face [1];
1076     }
1077    
1078     if (flags & 4)
1079     {
1080     *data++ = cell->face [2] >> 8;
1081     *data++ = cell->face [2];
1082     }
1083     }
1084     else
1085     *data++ = 0;
1086     }
1087     }
1088    
1089     SvPOK_only (data_sv);
1090     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
1091     RETVAL = data_sv;
1092     }
1093     OUTPUT:
1094     RETVAL
1095    
1096     void
1097     set_rect (CFClient::Map self, int x0, int y0, uint8_t *data)
1098     PPCODE:
1099     {
1100     int x, y, z;
1101 root 1.48 int w, h;
1102 root 1.42 int x1, y1;
1103    
1104     if (*data++ != 0)
1105     return; /* version mismatch */
1106    
1107 root 1.48 w = *data++ << 8; w |= *data++;
1108     h = *data++ << 8; h |= *data++;
1109 root 1.42
1110     // we need to do this 'cause we don't keep an absolute coord system for rows
1111     // TODO: treat rows as we treat
1112     map_get_row (self, y0 + self->y - self->oy);//D
1113     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1114    
1115     x0 += self->x - self->ox;
1116     y0 += self->y - self->oy;
1117    
1118     x1 = x0 + w;
1119     y1 = y0 + h;
1120    
1121     for (y = y0; y < y1; y++)
1122     {
1123     maprow *row = map_get_row (self, y);
1124    
1125     for (x = x0; x < x1; x++)
1126     {
1127     uint8_t flags = *data++;
1128    
1129     if (flags)
1130     {
1131     mapface face[3] = { 0, 0, 0 };
1132    
1133     mapcell *cell = row_get_cell (row, x);
1134    
1135     if (flags & 1) { face[0] = *data++ << 8; face[0] |= *data++; }
1136     if (flags & 2) { face[1] = *data++ << 8; face[1] |= *data++; }
1137     if (flags & 4) { face[2] = *data++ << 8; face[2] |= *data++; }
1138    
1139     if (cell->darkness <= 0)
1140     {
1141     cell->darkness = -1;
1142    
1143     for (z = 0; z <= 2; z++)
1144     {
1145     cell->face[z] = face[z];
1146    
1147     if (face[z] && (face[z] >= self->texs || !self->tex[face [z]].name))
1148     XPUSHs (sv_2mortal (newSViv (face[z])));
1149     }
1150     }
1151     }
1152     }
1153     }
1154     }
1155