ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.44
Committed: Mon Apr 17 07:30:20 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.43: +16 -20 lines
Log Message:
we _have_ to scroll as soon as we receive the scorll command, for persistent map cahcxing to sta yin sync, fortunately the display list caching will keep us from viewing the map before we receive a map1a

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5 root 1.5 #include <string.h>
6 root 1.25 #include <stdio.h>
7 root 1.5
8 root 1.2 #include <SDL.h>
9 root 1.23 #include <SDL_image.h>
10 root 1.3 #include <SDL_opengl.h>
11 root 1.5
12 root 1.30 #include <glib/gmacros.h>
13    
14 root 1.5 #include <pango/pango.h>
15 root 1.10 #include <pango/pangofc-fontmap.h>
16 root 1.5 #include <pango/pangoft2.h>
17    
18 root 1.10 #include <sys/types.h>
19     #include <sys/socket.h>
20     #include <netinet/in.h>
21     #include <netinet/tcp.h>
22    
23 root 1.28 #include <inttypes.h>
24    
25 root 1.29 #define FOW_DARKNESS 32
26    
27     #define MAP_EXTEND_X 32
28     #define MAP_EXTEND_Y 512
29    
30 root 1.5 static PangoContext *context;
31     static PangoFontMap *fontmap;
32 root 1.2
33 root 1.14 typedef struct cf_layout {
34     PangoLayout *pl;
35     int base_height;
36 root 1.15 } *CFClient__Layout;
37 root 1.14
38     static void
39 root 1.19 substitute_func (FcPattern *pattern, gpointer data)
40     {
41 root 1.20 FcPatternAddBool (pattern, FC_HINTING , 1);
42 root 1.35 FcPatternAddBool (pattern, FC_AUTOHINT, 0);
43 root 1.19 }
44    
45     static void
46 root 1.17 layout_update (CFClient__Layout self)
47     {
48 root 1.19 /* use a random scale factor to account for unknown descenders, 0.8 works
49     * reasonably well with bitstream vera
50     */
51 root 1.17 PangoFontDescription *font = pango_context_get_font_description (context);
52 root 1.19 pango_font_description_set_absolute_size (font, self->base_height * (PANGO_SCALE * 8 / 10));
53 root 1.17 }
54    
55     static void
56 root 1.15 layout_get_pixel_size (CFClient__Layout self, int *w, int *h)
57 root 1.14 {
58 root 1.19 layout_update (self);
59 root 1.16
60 root 1.14 pango_layout_get_pixel_size (self->pl, w, h);
61    
62     *w = (*w + 3) & ~3;
63     if (!*w) *w = 1;
64     if (!*h) *h = 1;
65     }
66    
67 root 1.42 typedef uint16_t mapface;
68    
69 root 1.28 typedef struct {
70 root 1.30 GLint name;
71     int w, h;
72     float s, t;
73 root 1.39 uint8_t r, g, b, a;
74 root 1.42 } maptex;
75 root 1.30
76     typedef struct {
77 root 1.29 int16_t darkness;
78 root 1.42 mapface face[3];
79 root 1.28 } mapcell;
80    
81     typedef struct {
82 root 1.30 int32_t c0, c1;
83 root 1.28 mapcell *col;
84     } maprow;
85    
86     typedef struct map {
87     int x, y, w, h;
88 root 1.42 int ox, oy; /* offset to virtual global coordinate system */
89 root 1.28 int faces;
90 root 1.30 mapface *face;
91 root 1.28
92 root 1.42 int texs;
93     maptex *tex;
94    
95 root 1.28 uint32_t rows;
96     maprow *row;
97     } *CFClient__Map;
98    
99 root 1.30 static char *
100     prepend (char *ptr, int sze, int inc)
101     {
102     char *p;
103    
104     New (0, p, sze + inc, char);
105     Zero (p, inc, char);
106     Move (ptr, p + inc, sze, char);
107     Safefree (ptr);
108    
109     return p;
110     }
111    
112     static char *
113     append (char *ptr, int sze, int inc)
114     {
115     Renew (ptr, sze + inc, char);
116     Zero (ptr + sze, inc, char);
117    
118     return ptr;
119     }
120    
121     #define Append(type,ptr,sze,inc) (ptr) = (type *)append ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
122     #define Prepend(type,ptr,sze,inc) (ptr) = (type *)prepend ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
123    
124 root 1.42 static maprow *
125     map_get_row (CFClient__Map self, int y)
126     {
127     if (0 > y)
128     {
129     int extend = - y + MAP_EXTEND_Y;
130     Prepend (maprow, self->row, self->rows, extend);
131    
132     self->rows += extend;
133     self->y += extend;
134     y += extend;
135     }
136     else if (y >= self->rows)
137     {
138     int extend = y - self->rows + MAP_EXTEND_Y;
139     Append (maprow, self->row, self->rows, extend);
140     self->rows += extend;
141     }
142    
143     return self->row + y;
144     }
145    
146     static mapcell *
147     row_get_cell (maprow *row, int x)
148     {
149     if (!row->col)
150     {
151     Newz (0, row->col, MAP_EXTEND_X, mapcell);
152     row->c0 = x - MAP_EXTEND_X / 4;
153     row->c1 = row->c0 + MAP_EXTEND_X;
154     }
155    
156     if (row->c0 > x)
157     {
158     int extend = row->c0 - x + MAP_EXTEND_X;
159     Prepend (mapcell, row->col, row->c1 - row->c0, extend);
160     row->c0 -= extend;
161     }
162     else if (x >= row->c1)
163     {
164     int extend = x - row->c1 + MAP_EXTEND_X;
165     Append (mapcell, row->col, row->c1 - row->c0, extend);
166     row->c1 += extend;
167     }
168    
169     return row->col + (x - row->c0);
170     }
171    
172     static mapcell *
173     map_get_cell (CFClient__Map self, int x, int y)
174     {
175     return row_get_cell (map_get_row (self, y), x);
176     }
177    
178 root 1.30 static void
179     map_clear (CFClient__Map self)
180     {
181     int r;
182    
183     for (r = 0; r < self->rows; r++)
184     Safefree (self->row[r].col);
185    
186     Safefree (self->row);
187    
188     self->x = 0;
189     self->y = 0;
190 root 1.42 self->ox = 0;
191     self->oy = 0;
192 root 1.30 self->row = 0;
193     self->rows = 0;
194     }
195    
196 root 1.29 static void
197     map_blank (CFClient__Map self, int x0, int y0, int w, int h)
198     {
199     int x, y;
200    
201     for (y = y0; y < y0 + h; y++)
202 root 1.30 if (y >= 0)
203     {
204     if (y >= self->rows)
205     break;
206    
207     maprow *row = self->row + y;
208    
209     for (x = x0; x < x0 + w; x++)
210     if (x >= row->c0)
211     {
212     if (x >= row->c1)
213     break;
214 root 1.29
215 root 1.31 row->col[x - row->c0].darkness = -1;
216 root 1.30 }
217     }
218 root 1.29 }
219    
220 root 1.15 MODULE = CFClient PACKAGE = CFClient
221 root 1.1
222 root 1.11 PROTOTYPES: ENABLE
223    
224 root 1.5 BOOT:
225     {
226     fontmap = pango_ft2_font_map_new ();
227 root 1.19 pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, substitute_func, 0, 0);
228 root 1.8 context = pango_ft2_font_map_create_context ((PangoFT2FontMap *)fontmap);
229 root 1.5 }
230    
231 root 1.10 void
232     lowdelay (int fd, int val = 1)
233     CODE:
234     setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
235    
236 root 1.3 char *
237 root 1.4 gl_version ()
238     CODE:
239 root 1.5 RETVAL = (char *)glGetString (GL_VERSION);
240 root 1.4 OUTPUT:
241     RETVAL
242    
243     char *
244 root 1.3 gl_extensions ()
245     CODE:
246 root 1.5 RETVAL = (char *)glGetString (GL_EXTENSIONS);
247 root 1.3 OUTPUT:
248     RETVAL
249    
250 root 1.5 void
251 root 1.13 add_font (char *file)
252     CODE:
253     FcConfigAppFontAddFile (0, (const FcChar8 *)file); /* no idea wether this is required */
254    
255     void
256 root 1.9 set_font (char *file)
257 root 1.8 CODE:
258     {
259 root 1.9 int count;
260     FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)file, 0, 0, &count);
261 root 1.10 PangoFontDescription *font = pango_fc_font_description_from_pattern (pattern, 0);
262 root 1.9 FcPatternDestroy (pattern);
263 root 1.8 pango_context_set_font_description (context, font);
264     }
265    
266 root 1.23 void
267     load_image_inline (SV *image_)
268     ALIAS:
269     load_image_file = 1
270     PPCODE:
271     {
272     STRLEN image_len;
273     char *image = (char *)SvPVbyte (image_, image_len);
274     SDL_Surface *surface, *surface2;
275     SDL_PixelFormat fmt;
276     SDL_RWops *rw = ix
277     ? SDL_RWFromFile (image, "r")
278     : SDL_RWFromConstMem (image, image_len);
279    
280     if (!rw)
281 root 1.41 croak ("load_image: %s", SDL_GetError ());
282 root 1.23
283     surface = IMG_Load_RW (rw, 1);
284     if (!surface)
285 root 1.41 croak ("load_image: %s", SDL_GetError ());
286 root 1.23
287     fmt.palette = NULL;
288     fmt.BitsPerPixel = 32;
289     fmt.BytesPerPixel = 4;
290     fmt.Rmask = 0x000000ff;
291     fmt.Gmask = 0x0000ff00;
292     fmt.Bmask = 0x00ff0000;
293     fmt.Amask = 0xff000000;
294     fmt.Rloss = 0;
295     fmt.Gloss = 0;
296     fmt.Bloss = 0;
297     fmt.Aloss = 0;
298     fmt.Rshift = 0;
299     fmt.Gshift = 8;
300     fmt.Bshift = 16;
301     fmt.Ashift = 24;
302     fmt.colorkey = 0;
303     fmt.alpha = 0;
304    
305     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
306    
307 root 1.39 assert (surface2->pitch == surface2->w * 4);
308    
309 root 1.23 EXTEND (SP, 5);
310     PUSHs (sv_2mortal (newSViv (surface2->w)));
311     PUSHs (sv_2mortal (newSViv (surface2->h)));
312     SDL_LockSurface (surface2);
313     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
314     SDL_UnlockSurface (surface2);
315 root 1.24 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
316 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
317     PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_INT_8_8_8_8_REV)));
318    
319     SDL_FreeSurface (surface);
320     SDL_FreeSurface (surface2);
321     }
322    
323 root 1.25 void
324 root 1.39 average (int x, int y, uint32_t *data)
325     PPCODE:
326     {
327     uint32_t r = 0, g = 0, b = 0, a = 0;
328    
329     x = y = x * y;
330    
331     while (x--)
332     {
333     uint32_t p = *data++;
334    
335     r += (p ) & 255;
336     g += (p >> 8) & 255;
337     b += (p >> 16) & 255;
338     a += (p >> 24) & 255;
339     }
340    
341     EXTEND (SP, 4);
342 root 1.40 PUSHs (sv_2mortal (newSViv (r / y)));
343     PUSHs (sv_2mortal (newSViv (g / y)));
344     PUSHs (sv_2mortal (newSViv (b / y)));
345     PUSHs (sv_2mortal (newSViv (a / y)));
346 root 1.39 }
347    
348     void
349 root 1.25 fatal (char *message)
350     CODE:
351     #ifdef WIN32
352     MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
353     #else
354 root 1.40 fprintf (stderr, "FATAL: %s\n", message);
355 root 1.25 #endif
356     exit (1);
357    
358 root 1.15 MODULE = CFClient PACKAGE = CFClient::Layout
359 root 1.14
360 root 1.15 CFClient::Layout
361 root 1.14 new (SV *class, int base_height = 10)
362     CODE:
363     New (0, RETVAL, 1, struct cf_layout);
364     RETVAL->base_height = base_height;
365     RETVAL->pl = pango_layout_new (context);
366     pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
367     OUTPUT:
368     RETVAL
369    
370     void
371 root 1.15 DESTROY (CFClient::Layout self)
372 root 1.14 CODE:
373     g_object_unref (self->pl);
374     Safefree (self);
375 root 1.13
376 root 1.8 void
377 root 1.35 set_text (CFClient::Layout self, SV *text_)
378     CODE:
379     {
380     STRLEN textlen;
381     char *text = SvPVutf8 (text_, textlen);
382    
383     pango_layout_set_text (self->pl, text, textlen);
384     }
385    
386     void
387 root 1.15 set_markup (CFClient::Layout self, SV *text_)
388 root 1.14 CODE:
389 root 1.5 {
390     STRLEN textlen;
391     char *text = SvPVutf8 (text_, textlen);
392 root 1.14
393     pango_layout_set_markup (self->pl, text, textlen);
394     }
395    
396     void
397 root 1.16 set_height (CFClient::Layout self, int base_height)
398     CODE:
399     self->base_height = base_height;
400    
401     void
402 root 1.15 set_width (CFClient::Layout self, int max_width = -1)
403 root 1.14 CODE:
404     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
405    
406     void
407 root 1.15 size (CFClient::Layout self)
408 root 1.14 PPCODE:
409     {
410     int w, h;
411    
412 root 1.17 layout_update (self);
413 root 1.14 layout_get_pixel_size (self, &w, &h);
414    
415     EXTEND (SP, 2);
416     PUSHs (sv_2mortal (newSViv (w)));
417     PUSHs (sv_2mortal (newSViv (h)));
418     }
419    
420 root 1.17 int
421     xy_to_index (CFClient::Layout self, int x, int y)
422     CODE:
423     {
424     int index, trailing;
425    
426     layout_update (self);
427     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
428    
429     RETVAL = index;
430     }
431     OUTPUT:
432     RETVAL
433    
434     void
435     cursor_pos (CFClient::Layout self, int index)
436     PPCODE:
437     {
438     PangoRectangle strong_pos;
439     layout_update (self);
440     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
441 root 1.30
442 root 1.17 EXTEND (SP, 3);
443     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
444     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
445     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
446     }
447    
448 root 1.14 void
449 root 1.15 render (CFClient::Layout self)
450 root 1.14 PPCODE:
451     {
452 root 1.5 SV *retval;
453     int w, h;
454     FT_Bitmap bitmap;
455    
456 root 1.17 layout_update (self);
457 root 1.14 layout_get_pixel_size (self, &w, &h);
458 root 1.5
459     retval = newSV (w * h);
460     SvPOK_only (retval);
461     SvCUR_set (retval, w * h);
462    
463     bitmap.rows = h;
464     bitmap.width = w;
465     bitmap.pitch = w;
466     bitmap.buffer = (unsigned char*)SvPVX (retval);
467     bitmap.num_grays = 256;
468     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
469    
470     memset (bitmap.buffer, 0, w * h);
471    
472 root 1.14 pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
473 root 1.1
474 root 1.5 EXTEND (SP, 3);
475     PUSHs (sv_2mortal (newSViv (w)));
476     PUSHs (sv_2mortal (newSViv (h)));
477     PUSHs (sv_2mortal (retval));
478     }
479 root 1.11
480 root 1.15 MODULE = CFClient PACKAGE = CFClient::Texture
481 root 1.11
482     void
483 root 1.37 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
484 root 1.12 PROTOTYPE: $$$;$$
485 root 1.11 CODE:
486     {
487 root 1.12 HV *hv = (HV *)SvRV (self);
488 root 1.37 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
489     float t = SvNV (*hv_fetch (hv, "t", 1, 1));
490 root 1.12 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
491 elmex 1.36 int wrap_mode = SvIV (*hv_fetch (hv, "wrap_mode", 9, 1));
492 root 1.12
493     if (items < 5)
494     {
495 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
496     h = SvNV (*hv_fetch (hv, "h", 1, 1));
497 root 1.12 }
498    
499     glBindTexture (GL_TEXTURE_2D, name);
500 elmex 1.36 if (wrap_mode) {
501     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
502     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
503     }
504 root 1.12 glBegin (GL_QUADS);
505 root 1.37 glTexCoord2f (0, 0); glVertex2f (x , y );
506     glTexCoord2f (0, t); glVertex2f (x , y + h);
507     glTexCoord2f (s, t); glVertex2f (x + w, y + h);
508     glTexCoord2f (s, 0); glVertex2f (x + w, y );
509 root 1.12 glEnd ();
510 root 1.11 }
511 root 1.28
512     MODULE = CFClient PACKAGE = CFClient::Map
513    
514     CFClient::Map
515     new (SV *class, int map_width, int map_height)
516     CODE:
517     New (0, RETVAL, 1, struct map);
518 root 1.42 RETVAL->x = 0;
519     RETVAL->y = 0;
520     RETVAL->w = map_width;
521     RETVAL->h = map_height;
522     RETVAL->ox = 0;
523     RETVAL->oy = 0;
524 root 1.30 RETVAL->faces = 8192;
525     Newz (0, RETVAL->face, RETVAL->faces, mapface);
526 root 1.42 RETVAL->texs = 8192;
527     Newz (0, RETVAL->tex, RETVAL->texs, maptex);
528 root 1.28 RETVAL->rows = 0;
529     RETVAL->row = 0;
530     OUTPUT:
531     RETVAL
532    
533     void
534     DESTROY (CFClient::Map self)
535     CODE:
536     {
537 root 1.30 map_clear (self);
538 root 1.28 Safefree (self->face);
539 root 1.29 Safefree (self);
540     }
541    
542     void
543 root 1.30 clear (CFClient::Map self)
544     CODE:
545     map_clear (self);
546    
547     void
548 root 1.42 set_face (CFClient::Map self, int face, int texid)
549 root 1.29 CODE:
550     {
551 root 1.42 while (self->faces <= face)
552 root 1.28 {
553 root 1.30 Append (mapface, self->face, self->faces, self->faces);
554 root 1.29 self->faces *= 2;
555     }
556 root 1.28
557 root 1.42 self->face [face] = texid;
558     }
559    
560     void
561     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)
562     CODE:
563     {
564     while (self->texs <= texid)
565     {
566     Append (maptex, self->tex, self->texs, self->texs);
567     self->texs *= 2;
568     }
569    
570     maptex *tex = self->tex + texid;
571 root 1.39
572 root 1.42 tex->name = name;
573     tex->w = w;
574     tex->h = h;
575     tex->s = s;
576     tex->t = t;
577     tex->r = r;
578     tex->g = g;
579     tex->b = b;
580     tex->a = a;
581 root 1.29 }
582    
583 root 1.42 int
584     ox (CFClient::Map self)
585     ALIAS:
586     oy = 1
587     CODE:
588     switch (ix)
589     {
590     case 0: RETVAL = self->ox; break;
591     case 1: RETVAL = self->oy; break;
592     }
593     OUTPUT:
594     RETVAL
595    
596 root 1.29 void
597 root 1.43 scroll (CFClient::Map self, int dx, int dy)
598     CODE:
599     {
600 root 1.44 if (dx > 0)
601     map_blank (self, self->x, self->y, dx - 1, self->h);
602     else if (dx < 0)
603     map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
604    
605     if (dy > 0)
606     map_blank (self, self->x, self->y, self->w, dy - 1);
607     else if (dy < 0)
608     map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
609 root 1.43
610 root 1.44 self->ox += dx; self->x += dx;
611     self->oy += dy; self->y += dy;
612 root 1.43
613     while (self->y < 0)
614     {
615     Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
616    
617     self->rows += MAP_EXTEND_Y;
618     self->y += MAP_EXTEND_Y;
619     }
620 root 1.44 }
621 root 1.43
622 root 1.44 void
623     map1a_update (CFClient::Map self, SV *data_)
624     CODE:
625     {
626 root 1.30 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
627     uint8_t *data_end = (uint8_t *)SvEND (data_);
628 root 1.43
629 root 1.29 while (data < data_end)
630     {
631     int flags = (data [0] << 8) + data [1]; data += 2;
632 root 1.30
633 root 1.29 int x = ((flags >> 10) & 63) + self->x;
634     int y = ((flags >> 4) & 63) + self->y;
635    
636 root 1.42 mapcell *cell = map_get_cell (self, x, y);
637 root 1.29
638     if (flags & 15)
639     {
640 root 1.42 if (cell->darkness < 0) // && x < self->w && y < self->h)
641 root 1.29 {
642     cell->darkness = 0;
643     cell->face [0] = 0;
644     cell->face [1] = 0;
645     cell->face [2] = 0;
646     }
647    
648     cell->darkness = flags & 8 ? *data++ : 255;
649    
650 root 1.42 //TODO: don't trust server data to be in-range(!)
651    
652 root 1.29 if (flags & 4)
653     {
654 root 1.42 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
655 root 1.29 }
656    
657     if (flags & 2)
658     {
659 root 1.42 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
660 root 1.29 }
661    
662     if (flags & 1)
663     {
664 root 1.42 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
665 root 1.29 }
666     }
667     else
668 root 1.31 cell->darkness = -1;
669 root 1.29 }
670 root 1.28 }
671    
672 root 1.40 SV *
673     mapmap (CFClient::Map self, int w, int h)
674     CODE:
675     {
676     int x0, x1, x;
677     int y0, y1, y;
678     int z;
679     SV *map_sv = newSV (w * h * sizeof (uint32_t));
680     uint32_t *map = (uint32_t *)SvPVX (map_sv);
681    
682     SvPOK_only (map_sv);
683     SvCUR_set (map_sv, w * h * sizeof (uint32_t));
684    
685     x0 = self->x - w / 2; x1 = x0 + w;
686     y0 = self->y - h / 2; y1 = y0 + h;
687    
688     for (y = y0; y < y1; y++)
689     {
690     maprow *row = 0 <= y && y < self->rows
691     ? self->row + y
692     : 0;
693    
694     for (x = x0; x < x1; x++)
695     {
696     int r = 32, g = 32, b = 32, a = 192;
697    
698     if (row && row->c0 <= x && x < row->c1)
699     {
700     mapcell *cell = row->col + (x - row->c0);
701    
702     for (z = 0; z <= 0; z++)
703     {
704 root 1.42 mapface face = cell->face [z];
705 root 1.40
706     if (face)
707     {
708 root 1.42 maptex tex = self->tex [face];
709 root 1.40 int a0 = 255 - tex.a;
710     int a1 = tex.a;
711    
712     r = (r * a0 + tex.r * a1) / 255;
713     g = (g * a0 + tex.g * a1) / 255;
714     b = (b * a0 + tex.b * a1) / 255;
715     a = (a * a0 + tex.a * a1) / 255;
716     }
717     }
718     }
719    
720     *map++ = (r )
721     | (g << 8)
722     | (b << 16)
723     | (a << 24);
724     }
725     }
726    
727     RETVAL = map_sv;
728     }
729     OUTPUT:
730     RETVAL
731    
732 root 1.30 void
733 root 1.38 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
734 root 1.32 PPCODE:
735 root 1.30 {
736 root 1.32 int sw4 = (sw + 3) & ~3;
737     SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
738 root 1.35 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
739 root 1.42 memset (darkness, 255, sw4 * sh);
740 root 1.32 SvPOK_only (darkness_sv);
741     SvCUR_set (darkness_sv, sw4 * sh);
742    
743 root 1.38 int vx = self->x + (self->w - sw) / 2 - shift_x;
744     int vy = self->y + (self->h - sh) / 2 - shift_y;
745    
746 root 1.42 /*
747     int vx = self->vx = self->w >= sw
748     ? self->x + (self->w - sw) / 2
749     : MIN (self->x, MAX (self->x + self->w - sw + 1, self->vx));
750    
751     int vy = self->vy = self->h >= sh
752     ? self->y + (self->h - sh) / 2
753     : MIN (self->y, MAX (self->y + self->h - sh + 1, self->vy));
754     */
755 root 1.30
756     glColor4ub (255, 255, 255, 255);
757    
758     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
759     glEnable (GL_BLEND);
760     glEnable (GL_TEXTURE_2D);
761     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
762    
763     int x, y, z;
764    
765     int last_name = 0;
766    
767     glBegin (GL_QUADS);
768    
769     for (z = 0; z < 3; z++)
770     for (y = 0; y < sh; y++)
771     if (0 <= y + vy && y + vy < self->rows)
772     {
773     maprow *row = self->row + (y + vy);
774    
775     for (x = 0; x < sw; x++)
776     if (row->c0 <= x + vx && x + vx < row->c1)
777     {
778     mapcell *cell = row->col + (x + vx - row->c0);
779 root 1.32
780     darkness[y * sw4 + x] = cell->darkness < 0
781 root 1.33 ? 255 - FOW_DARKNESS
782 root 1.32 : 255 - cell->darkness;
783    
784 root 1.42 mapface face = cell->face [z];
785 root 1.30
786     if (face)
787     {
788 root 1.42 maptex tex = self->tex [face];
789 root 1.30
790     int px = (x + 1) * 32 - tex.w;
791     int py = (y + 1) * 32 - tex.h;
792    
793     if (last_name != tex.name)
794     {
795     glEnd ();
796     last_name = tex.name;
797     glBindTexture (GL_TEXTURE_2D, last_name);
798     glBegin (GL_QUADS);
799     }
800    
801     glTexCoord2f (0 , 0 ); glVertex2f (px , py );
802     glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
803     glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
804     glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
805     }
806     }
807     }
808    
809     glEnd ();
810 root 1.32
811 root 1.34 glDisable (GL_TEXTURE_2D);
812     glDisable (GL_BLEND);
813    
814 root 1.32 EXTEND (SP, 3);
815     PUSHs (sv_2mortal (newSViv (sw4)));
816     PUSHs (sv_2mortal (newSViv (sh)));
817     PUSHs (darkness_sv);
818 root 1.30 }
819    
820 root 1.42 SV *
821     get_rect (CFClient::Map self, int x0, int y0, int w, int h)
822     CODE:
823     {
824     int x, y, x1, y1;
825     SV *data_sv = newSV (w * h * 7 + 5);
826     uint8_t *data = (uint8_t *)SvPVX (data_sv);
827    
828     *data++ = 0; /* version 0 format */
829     *data++ = w >> 8; *data++ = w;
830     *data++ = h >> 8; *data++ = h;
831    
832     // we need to do this 'cause we don't keep an absolute coord system for rows
833     // TODO: treat rows as we treat
834     map_get_row (self, y0 + self->y - self->oy);//D
835     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
836    
837     x0 += self->x - self->ox;
838     y0 += self->y - self->oy;
839    
840     x1 = x0 + w;
841     y1 = y0 + h;
842    
843     for (y = y0; y < y1; y++)
844     {
845     maprow *row = 0 <= y && y < self->rows
846     ? self->row + y
847     : 0;
848    
849     for (x = x0; x < x1; x++)
850     {
851     if (row && row->c0 <= x && x < row->c1)
852     {
853     mapcell *cell = row->col + (x - row->c0);
854    
855     uint8_t flags = 0;
856    
857     if (cell->face [0]) flags |= 1;
858     if (cell->face [1]) flags |= 2;
859     if (cell->face [2]) flags |= 4;
860    
861     *data++ = flags;
862    
863     if (flags & 1)
864     {
865     *data++ = cell->face [0] >> 8;
866     *data++ = cell->face [0];
867     }
868    
869     if (flags & 2)
870     {
871     *data++ = cell->face [1] >> 8;
872     *data++ = cell->face [1];
873     }
874    
875     if (flags & 4)
876     {
877     *data++ = cell->face [2] >> 8;
878     *data++ = cell->face [2];
879     }
880     }
881     else
882     *data++ = 0;
883     }
884     }
885    
886     SvPOK_only (data_sv);
887     SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
888     RETVAL = data_sv;
889     }
890     OUTPUT:
891     RETVAL
892    
893     void
894     set_rect (CFClient::Map self, int x0, int y0, uint8_t *data)
895     PPCODE:
896     {
897     int x, y, z;
898     int x1, y1;
899    
900     if (*data++ != 0)
901     return; /* version mismatch */
902    
903     int w = *data++ << 8; w |= *data++;
904     int h = *data++ << 8; h |= *data++;
905    
906     // we need to do this 'cause we don't keep an absolute coord system for rows
907     // TODO: treat rows as we treat
908     map_get_row (self, y0 + self->y - self->oy);//D
909     map_get_row (self, y0 + self->y - self->oy + h - 1);//D
910    
911     x0 += self->x - self->ox;
912     y0 += self->y - self->oy;
913    
914     x1 = x0 + w;
915     y1 = y0 + h;
916    
917     for (y = y0; y < y1; y++)
918     {
919     maprow *row = map_get_row (self, y);
920    
921     for (x = x0; x < x1; x++)
922     {
923     uint8_t flags = *data++;
924    
925     if (flags)
926     {
927     mapface face[3] = { 0, 0, 0 };
928    
929     mapcell *cell = row_get_cell (row, x);
930    
931     if (flags & 1) { face[0] = *data++ << 8; face[0] |= *data++; }
932     if (flags & 2) { face[1] = *data++ << 8; face[1] |= *data++; }
933     if (flags & 4) { face[2] = *data++ << 8; face[2] |= *data++; }
934    
935     if (cell->darkness <= 0)
936     {
937     cell->darkness = -1;
938    
939     for (z = 0; z <= 2; z++)
940     {
941     cell->face[z] = face[z];
942    
943     if (face[z] && (face[z] >= self->texs || !self->tex[face [z]].name))
944     XPUSHs (sv_2mortal (newSViv (face[z])));
945     }
946     }
947     }
948     }
949     }
950     }
951