ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.50
Committed: Wed Apr 19 00:47:34 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.49: +1 -1 lines
Log Message:
*** empty log message ***

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     fontmap = pango_ft2_font_map_new ();
247 root 1.19 pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, substitute_func, 0, 0);
248 root 1.8 context = pango_ft2_font_map_create_context ((PangoFT2FontMap *)fontmap);
249 root 1.5 }
250    
251 root 1.10 void
252     lowdelay (int fd, int val = 1)
253     CODE:
254 root 1.48 #ifndef _WIN32
255 root 1.10 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
256 root 1.48 #endif
257 root 1.10
258 root 1.3 char *
259 root 1.4 gl_version ()
260     CODE:
261 root 1.5 RETVAL = (char *)glGetString (GL_VERSION);
262 root 1.4 OUTPUT:
263     RETVAL
264    
265     char *
266 root 1.3 gl_extensions ()
267     CODE:
268 root 1.5 RETVAL = (char *)glGetString (GL_EXTENSIONS);
269 root 1.3 OUTPUT:
270     RETVAL
271    
272 root 1.5 void
273 root 1.13 add_font (char *file)
274     CODE:
275     FcConfigAppFontAddFile (0, (const FcChar8 *)file); /* no idea wether this is required */
276    
277     void
278 root 1.9 set_font (char *file)
279 root 1.8 CODE:
280     {
281 root 1.9 int count;
282     FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)file, 0, 0, &count);
283 root 1.10 PangoFontDescription *font = pango_fc_font_description_from_pattern (pattern, 0);
284 root 1.9 FcPatternDestroy (pattern);
285 root 1.8 pango_context_set_font_description (context, font);
286     }
287    
288 root 1.23 void
289     load_image_inline (SV *image_)
290     ALIAS:
291     load_image_file = 1
292     PPCODE:
293     {
294     STRLEN image_len;
295     char *image = (char *)SvPVbyte (image_, image_len);
296     SDL_Surface *surface, *surface2;
297     SDL_PixelFormat fmt;
298     SDL_RWops *rw = ix
299     ? SDL_RWFromFile (image, "r")
300     : SDL_RWFromConstMem (image, image_len);
301    
302     if (!rw)
303 root 1.41 croak ("load_image: %s", SDL_GetError ());
304 root 1.23
305     surface = IMG_Load_RW (rw, 1);
306     if (!surface)
307 root 1.41 croak ("load_image: %s", SDL_GetError ());
308 root 1.23
309     fmt.palette = NULL;
310     fmt.BitsPerPixel = 32;
311     fmt.BytesPerPixel = 4;
312 root 1.49 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
313 root 1.23 fmt.Rmask = 0x000000ff;
314     fmt.Gmask = 0x0000ff00;
315     fmt.Bmask = 0x00ff0000;
316     fmt.Amask = 0xff000000;
317 root 1.49 #else
318     fmt.Rmask = 0xff000000;
319     fmt.Gmask = 0x00ff0000;
320     fmt.Bmask = 0x0000ff00;
321     fmt.Amask = 0x000000ff;
322     #endif
323 root 1.23 fmt.Rloss = 0;
324     fmt.Gloss = 0;
325     fmt.Bloss = 0;
326     fmt.Aloss = 0;
327     fmt.Rshift = 0;
328     fmt.Gshift = 8;
329     fmt.Bshift = 16;
330     fmt.Ashift = 24;
331     fmt.colorkey = 0;
332     fmt.alpha = 0;
333    
334     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
335    
336 root 1.39 assert (surface2->pitch == surface2->w * 4);
337    
338 root 1.23 EXTEND (SP, 5);
339     PUSHs (sv_2mortal (newSViv (surface2->w)));
340     PUSHs (sv_2mortal (newSViv (surface2->h)));
341     SDL_LockSurface (surface2);
342     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
343     SDL_UnlockSurface (surface2);
344 root 1.24 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
345 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
346 root 1.49 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
347 root 1.23
348     SDL_FreeSurface (surface);
349     SDL_FreeSurface (surface2);
350     }
351    
352 root 1.25 void
353 root 1.39 average (int x, int y, uint32_t *data)
354     PPCODE:
355     {
356     uint32_t r = 0, g = 0, b = 0, a = 0;
357    
358     x = y = x * y;
359    
360     while (x--)
361     {
362     uint32_t p = *data++;
363    
364     r += (p ) & 255;
365     g += (p >> 8) & 255;
366     b += (p >> 16) & 255;
367     a += (p >> 24) & 255;
368     }
369    
370     EXTEND (SP, 4);
371 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
372     PUSHs (sv_2mortal (newSViv (g / y)));
373     PUSHs (sv_2mortal (newSViv (b / y)));
374     PUSHs (sv_2mortal (newSViv (a / y)));
375 root 1.39 }
376    
377     void
378 root 1.25 fatal (char *message)
379     CODE:
380 root 1.50 #ifdef _WIN32
381 root 1.25 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
382     #else
383 root 1.40 fprintf (stderr, "FATAL: %s\n", message);
384 root 1.25 #endif
385     exit (1);
386    
387 root 1.15 MODULE = CFClient PACKAGE = CFClient::Layout
388 root 1.14
389 root 1.15 CFClient::Layout
390 root 1.14 new (SV *class, int base_height = 10)
391     CODE:
392     New (0, RETVAL, 1, struct cf_layout);
393     RETVAL->base_height = base_height;
394     RETVAL->pl = pango_layout_new (context);
395     pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
396     OUTPUT:
397     RETVAL
398    
399     void
400 root 1.15 DESTROY (CFClient::Layout self)
401 root 1.14 CODE:
402     g_object_unref (self->pl);
403     Safefree (self);
404 root 1.13
405 root 1.8 void
406 root 1.35 set_text (CFClient::Layout self, SV *text_)
407     CODE:
408     {
409     STRLEN textlen;
410     char *text = SvPVutf8 (text_, textlen);
411    
412     pango_layout_set_text (self->pl, text, textlen);
413     }
414    
415     void
416 root 1.15 set_markup (CFClient::Layout self, SV *text_)
417 root 1.14 CODE:
418 root 1.5 {
419     STRLEN textlen;
420     char *text = SvPVutf8 (text_, textlen);
421 root 1.14
422     pango_layout_set_markup (self->pl, text, textlen);
423     }
424    
425 root 1.46 SV *
426     get_text (CFClient::Layout self)
427     CODE:
428 root 1.47 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
429 root 1.46 SvUTF8_on (RETVAL);
430     OUTPUT:
431     RETVAL
432    
433 root 1.14 void
434 root 1.16 set_height (CFClient::Layout self, int base_height)
435     CODE:
436     self->base_height = base_height;
437    
438     void
439 root 1.15 set_width (CFClient::Layout self, int max_width = -1)
440 root 1.14 CODE:
441     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
442    
443     void
444 root 1.15 size (CFClient::Layout self)
445 root 1.14 PPCODE:
446     {
447     int w, h;
448    
449 root 1.17 layout_update (self);
450 root 1.14 layout_get_pixel_size (self, &w, &h);
451    
452     EXTEND (SP, 2);
453     PUSHs (sv_2mortal (newSViv (w)));
454     PUSHs (sv_2mortal (newSViv (h)));
455     }
456    
457 root 1.17 int
458     xy_to_index (CFClient::Layout self, int x, int y)
459     CODE:
460     {
461     int index, trailing;
462    
463     layout_update (self);
464     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
465    
466     RETVAL = index;
467     }
468     OUTPUT:
469     RETVAL
470    
471     void
472     cursor_pos (CFClient::Layout self, int index)
473     PPCODE:
474     {
475     PangoRectangle strong_pos;
476     layout_update (self);
477     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
478 root 1.30
479 root 1.17 EXTEND (SP, 3);
480     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
481     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
482     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
483     }
484    
485 root 1.14 void
486 root 1.15 render (CFClient::Layout self)
487 root 1.14 PPCODE:
488     {
489 root 1.5 SV *retval;
490     int w, h;
491     FT_Bitmap bitmap;
492    
493 root 1.17 layout_update (self);
494 root 1.14 layout_get_pixel_size (self, &w, &h);
495 root 1.5
496     retval = newSV (w * h);
497     SvPOK_only (retval);
498     SvCUR_set (retval, w * h);
499    
500     bitmap.rows = h;
501     bitmap.width = w;
502     bitmap.pitch = w;
503     bitmap.buffer = (unsigned char*)SvPVX (retval);
504     bitmap.num_grays = 256;
505     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
506    
507     memset (bitmap.buffer, 0, w * h);
508    
509 root 1.14 pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
510 root 1.1
511 root 1.5 EXTEND (SP, 3);
512     PUSHs (sv_2mortal (newSViv (w)));
513     PUSHs (sv_2mortal (newSViv (h)));
514     PUSHs (sv_2mortal (retval));
515     }
516 root 1.11
517 root 1.15 MODULE = CFClient PACKAGE = CFClient::Texture
518 root 1.11
519     void
520 root 1.37 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
521 root 1.12 PROTOTYPE: $$$;$$
522 root 1.11 CODE:
523     {
524 root 1.12 HV *hv = (HV *)SvRV (self);
525 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
526     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
527 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
528 elmex 1.36 int wrap_mode = SvIV (*hv_fetch (hv, "wrap_mode", 9, 1));
529 root 1.12
530     if (items < 5)
531     {
532 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
533     h = SvNV (*hv_fetch (hv, "h", 1, 1));
534 root 1.12 }
535    
536     glBindTexture (GL_TEXTURE_2D, name);
537 elmex 1.36 if (wrap_mode) {
538     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
539     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
540     }
541 root 1.12 glBegin (GL_QUADS);
542 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
543     glTexCoord2f (0, t); glVertex2f (x , y + h);
544     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
545     glTexCoord2f (s, 0); glVertex2f (x + w, y );
546 root 1.12 glEnd ();
547 root 1.11 }
548 root 1.28
549     MODULE = CFClient PACKAGE = CFClient::Map
550    
551     CFClient::Map
552     new (SV *class, int map_width, int map_height)
553     CODE:
554     New (0, RETVAL, 1, struct map);
555 root 1.42 RETVAL->x = 0;
556     RETVAL->y = 0;
557     RETVAL->w = map_width;
558     RETVAL->h = map_height;
559     RETVAL->ox = 0;
560     RETVAL->oy = 0;
561 root 1.30 RETVAL->faces = 8192;
562     Newz (0, RETVAL->face, RETVAL->faces, mapface);
563 root 1.42 RETVAL->texs = 8192;
564     Newz (0, RETVAL->tex, RETVAL->texs, maptex);
565 root 1.28 RETVAL->rows = 0;
566     RETVAL->row = 0;
567     OUTPUT:
568     RETVAL
569    
570     void
571     DESTROY (CFClient::Map self)
572     CODE:
573     {
574 root 1.30 map_clear (self);
575 root 1.28 Safefree (self->face);
576 root 1.29 Safefree (self);
577     }
578    
579     void
580 root 1.30 clear (CFClient::Map self)
581     CODE:
582     map_clear (self);
583    
584     void
585 root 1.42 set_face (CFClient::Map self, int face, int texid)
586 root 1.29 CODE:
587     {
588 root 1.42 while (self->faces <= face)
589 root 1.28 {
590 root 1.30 Append (mapface, self->face, self->faces, self->faces);
591 root 1.29 self->faces *= 2;
592     }
593 root 1.28
594 root 1.42 self->face [face] = texid;
595     }
596    
597     void
598     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)
599     CODE:
600     {
601     while (self->texs <= texid)
602     {
603     Append (maptex, self->tex, self->texs, self->texs);
604     self->texs *= 2;
605     }
606    
607 root 1.48 {
608     maptex *tex = self->tex + texid;
609 root 1.39
610 root 1.48 tex->name = name;
611     tex->w = w;
612     tex->h = h;
613     tex->s = s;
614     tex->t = t;
615     tex->r = r;
616     tex->g = g;
617     tex->b = b;
618     tex->a = a;
619     }
620 root 1.29 }
621    
622 root 1.42 int
623     ox (CFClient::Map self)
624     ALIAS:
625     oy = 1
626     CODE:
627     switch (ix)
628     {
629     case 0: RETVAL = self->ox; break;
630     case 1: RETVAL = self->oy; break;
631     }
632     OUTPUT:
633     RETVAL
634    
635 root 1.29 void
636 root 1.43 scroll (CFClient::Map self, int dx, int dy)
637     CODE:
638     {
639 root 1.44 if (dx > 0)
640     map_blank (self, self->x, self->y, dx - 1, self->h);
641     else if (dx < 0)
642     map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
643    
644     if (dy > 0)
645     map_blank (self, self->x, self->y, self->w, dy - 1);
646     else if (dy < 0)
647     map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
648 root 1.43
649 root 1.44 self->ox += dx; self->x += dx;
650     self->oy += dy; self->y += dy;
651 root 1.43
652     while (self->y < 0)
653     {
654     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
655    
656     self->rows += MAP_EXTEND_Y;
657     self->y += MAP_EXTEND_Y;
658     }
659 root 1.44 }
660 root 1.43
661 root 1.44 void
662     map1a_update (CFClient::Map self, SV *data_)
663     CODE:
664     {
665 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
666     uint8_t *data_end = (uint8_t *)SvEND (data_);
667 root 1.48 mapcell *cell;
668     int x, y, flags;
669 root 1.43
670 root 1.29 while (data < data_end)
671     {
672 root 1.48 flags = (data [0] << 8) + data [1]; data += 2;
673 root 1.30
674 root 1.48 x = ((flags >> 10) & 63) + self->x;
675     y = ((flags >> 4) & 63) + self->y;
676 root 1.29
677 root 1.48 cell = map_get_cell (self, x, y);
678 root 1.29
679     if (flags & 15)
680     {
681 root 1.45 if (cell->darkness < 0)
682 root 1.29 {
683     cell->darkness = 0;
684     cell->face [0] = 0;
685     cell->face [1] = 0;
686     cell->face [2] = 0;
687     }
688 root 1.45
689 root 1.29 cell->darkness = flags & 8 ? *data++ : 255;
690    
691 root 1.42 //TODO: don't trust server data to be in-range(!)
692    
693 root 1.29 if (flags & 4)
694     {
695 root 1.42 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
696 root 1.29 }
697    
698     if (flags & 2)
699     {
700 root 1.42 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
701 root 1.29 }
702    
703     if (flags & 1)
704     {
705 root 1.42 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
706 root 1.29 }
707     }
708     else
709 root 1.31 cell->darkness = -1;
710 root 1.29 }
711 root 1.28 }
712    
713 root 1.40 SV *
714     mapmap (CFClient::Map self, int w, int h)
715     CODE:
716     {
717     int x0, x1, x;
718     int y0, y1, y;
719     int z;
720     SV *map_sv = newSV (w * h * sizeof (uint32_t));
721     uint32_t *map = (uint32_t *)SvPVX (map_sv);
722    
723     SvPOK_only (map_sv);
724     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
725    
726     x0 = self->x - w / 2; x1 = x0 + w;
727     y0 = self->y - h / 2; y1 = y0 + h;
728    
729     for (y = y0; y < y1; y++)
730     {
731     maprow *row = 0 <= y && y < self->rows
732     ? self->row + y
733     : 0;
734    
735     for (x = x0; x < x1; x++)
736     {
737     int r = 32, g = 32, b = 32, a = 192;
738    
739     if (row && row->c0 <= x && x < row->c1)
740     {
741     mapcell *cell = row->col + (x - row->c0);
742    
743     for (z = 0; z <= 0; z++)
744     {
745 root 1.42 mapface face = cell->face [z];
746 root 1.40
747     if (face)
748     {
749 root 1.42 maptex tex = self->tex [face];
750 root 1.40 int a0 = 255 - tex.a;
751     int a1 = tex.a;
752    
753     r = (r * a0 + tex.r * a1) / 255;
754     g = (g * a0 + tex.g * a1) / 255;
755     b = (b * a0 + tex.b * a1) / 255;
756     a = (a * a0 + tex.a * a1) / 255;
757     }
758     }
759     }
760    
761     *map++ = (r )
762     | (g << 8)
763     | (b << 16)
764     | (a << 24);
765     }
766     }
767    
768     RETVAL = map_sv;
769     }
770     OUTPUT:
771     RETVAL
772    
773 root 1.30 void
774 root 1.38 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
775 root 1.32 PPCODE:
776 root 1.30 {
777 root 1.48 int vx, vy;
778     int x, y, z;
779     int last_name;
780     mapface face;
781 root 1.32 int sw4 = (sw + 3) & ~3;
782     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
783 root 1.35 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
784 root 1.48
785 root 1.42 memset (darkness, 255, sw4 * sh);
786 root 1.32 SvPOK_only (darkness_sv);
787     SvCUR_set (darkness_sv, sw4 * sh);
788    
789 root 1.48 vx = self->x + (self->w - sw) / 2 - shift_x;
790     vy = self->y + (self->h - sh) / 2 - shift_y;
791 root 1.38
792 root 1.42 /*
793     int vx = self->vx = self->w >= sw
794     ? self->x + (self->w - sw) / 2
795     : MIN (self->x, MAX (self->x + self->w - sw + 1, self->vx));
796    
797     int vy = self->vy = self->h >= sh
798     ? self->y + (self->h - sh) / 2
799     : MIN (self->y, MAX (self->y + self->h - sh + 1, self->vy));
800     */
801 root 1.30
802     glColor4ub (255, 255, 255, 255);
803    
804     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
805     glEnable (GL_BLEND);
806     glEnable (GL_TEXTURE_2D);
807     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
808    
809 root 1.48 glBegin (GL_QUADS);
810 root 1.30
811 root 1.48 last_name = 0;
812 root 1.30
813     for (z = 0; z < 3; z++)
814     for (y = 0; y < sh; y++)
815     if (0 <= y + vy && y + vy < self->rows)
816     {
817     maprow *row = self->row + (y + vy);
818    
819     for (x = 0; x < sw; x++)
820     if (row->c0 <= x + vx && x + vx < row->c1)
821     {
822     mapcell *cell = row->col + (x + vx - row->c0);
823 root 1.32
824     darkness[y * sw4 + x] = cell->darkness < 0
825 root 1.33 ? 255 - FOW_DARKNESS
826 root 1.32 : 255 - cell->darkness;
827    
828 root 1.48 face = cell->face [z];
829 root 1.30
830     if (face)
831     {
832 root 1.42 maptex tex = self->tex [face];
833 root 1.30
834     int px = (x + 1) * 32 - tex.w;
835     int py = (y + 1) * 32 - tex.h;
836    
837     if (last_name != tex.name)
838     {
839     glEnd ();
840     last_name = tex.name;
841     glBindTexture (GL_TEXTURE_2D, last_name);
842     glBegin (GL_QUADS);
843     }
844    
845     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
846     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
847     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
848     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
849     }
850     }
851     }
852    
853     glEnd ();
854 root 1.32
855 root 1.34 glDisable (GL_TEXTURE_2D);
856     glDisable (GL_BLEND);
857    
858 root 1.32 EXTEND (SP, 3);
859     PUSHs (sv_2mortal (newSViv (sw4)));
860     PUSHs (sv_2mortal (newSViv (sh)));
861     PUSHs (darkness_sv);
862 root 1.30 }
863    
864 root 1.42 SV *
865     get_rect (CFClient::Map self, int x0, int y0, int w, int h)
866     CODE:
867     {
868     int x, y, x1, y1;
869     SV *data_sv = newSV (w * h * 7 + 5);
870     uint8_t *data = (uint8_t *)SvPVX (data_sv);
871    
872     *data++ = 0; /* version 0 format */
873     *data++ = w >> 8; *data++ = w;
874     *data++ = h >> 8; *data++ = h;
875    
876     // we need to do this 'cause we don't keep an absolute coord system for rows
877     // TODO: treat rows as we treat
878     map_get_row (self, y0 + self->y - self->oy);//D
879     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
880    
881     x0 += self->x - self->ox;
882     y0 += self->y - self->oy;
883    
884     x1 = x0 + w;
885     y1 = y0 + h;
886    
887     for (y = y0; y < y1; y++)
888     {
889     maprow *row = 0 <= y && y < self->rows
890     ? self->row + y
891     : 0;
892    
893     for (x = x0; x < x1; x++)
894     {
895     if (row && row->c0 <= x && x < row->c1)
896     {
897     mapcell *cell = row->col + (x - row->c0);
898     uint8_t flags = 0;
899    
900     if (cell->face [0]) flags |= 1;
901     if (cell->face [1]) flags |= 2;
902     if (cell->face [2]) flags |= 4;
903    
904     *data++ = flags;
905    
906     if (flags & 1)
907     {
908     *data++ = cell->face [0] >> 8;
909     *data++ = cell->face [0];
910     }
911    
912     if (flags & 2)
913     {
914     *data++ = cell->face [1] >> 8;
915     *data++ = cell->face [1];
916     }
917    
918     if (flags & 4)
919     {
920     *data++ = cell->face [2] >> 8;
921     *data++ = cell->face [2];
922     }
923     }
924     else
925     *data++ = 0;
926     }
927     }
928    
929     SvPOK_only (data_sv);
930     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
931     RETVAL = data_sv;
932     }
933     OUTPUT:
934     RETVAL
935    
936     void
937     set_rect (CFClient::Map self, int x0, int y0, uint8_t *data)
938     PPCODE:
939     {
940     int x, y, z;
941 root 1.48 int w, h;
942 root 1.42 int x1, y1;
943    
944     if (*data++ != 0)
945     return; /* version mismatch */
946    
947 root 1.48 w = *data++ << 8; w |= *data++;
948     h = *data++ << 8; h |= *data++;
949 root 1.42
950     // we need to do this 'cause we don't keep an absolute coord system for rows
951     // TODO: treat rows as we treat
952     map_get_row (self, y0 + self->y - self->oy);//D
953     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
954    
955     x0 += self->x - self->ox;
956     y0 += self->y - self->oy;
957    
958     x1 = x0 + w;
959     y1 = y0 + h;
960    
961     for (y = y0; y < y1; y++)
962     {
963     maprow *row = map_get_row (self, y);
964    
965     for (x = x0; x < x1; x++)
966     {
967     uint8_t flags = *data++;
968    
969     if (flags)
970     {
971     mapface face[3] = { 0, 0, 0 };
972    
973     mapcell *cell = row_get_cell (row, x);
974    
975     if (flags & 1) { face[0] = *data++ << 8; face[0] |= *data++; }
976     if (flags & 2) { face[1] = *data++ << 8; face[1] |= *data++; }
977     if (flags & 4) { face[2] = *data++ << 8; face[2] |= *data++; }
978    
979     if (cell->darkness <= 0)
980     {
981     cell->darkness = -1;
982    
983     for (z = 0; z <= 2; z++)
984     {
985     cell->face[z] = face[z];
986    
987     if (face[z] && (face[z] >= self->texs || !self->tex[face [z]].name))
988     XPUSHs (sv_2mortal (newSViv (face[z])));
989     }
990     }
991     }
992     }
993     }
994     }
995