ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.43
Committed: Mon Apr 17 06:50:26 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.42: +31 -27 lines
Log Message:
*** empty log message ***

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