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

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #include <string.h>
6 #include <stdio.h>
7
8 #include <SDL.h>
9 #include <SDL_image.h>
10 #include <SDL_opengl.h>
11
12 #include <glib/gmacros.h>
13
14 #include <pango/pango.h>
15 #include <pango/pangofc-fontmap.h>
16 #include <pango/pangoft2.h>
17
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
22
23 #include <inttypes.h>
24
25 #define FOW_DARKNESS 32
26
27 #define MAP_EXTEND_X 32
28 #define MAP_EXTEND_Y 512
29
30 static PangoContext *context;
31 static PangoFontMap *fontmap;
32
33 typedef struct cf_layout {
34 PangoLayout *pl;
35 int base_height;
36 } *CFClient__Layout;
37
38 static void
39 substitute_func (FcPattern *pattern, gpointer data)
40 {
41 FcPatternAddBool (pattern, FC_HINTING , 1);
42 FcPatternAddBool (pattern, FC_AUTOHINT, 0);
43 }
44
45 static void
46 layout_update (CFClient__Layout self)
47 {
48 /* use a random scale factor to account for unknown descenders, 0.8 works
49 * reasonably well with bitstream vera
50 */
51 PangoFontDescription *font = pango_context_get_font_description (context);
52 pango_font_description_set_absolute_size (font, self->base_height * (PANGO_SCALE * 8 / 10));
53 }
54
55 static void
56 layout_get_pixel_size (CFClient__Layout self, int *w, int *h)
57 {
58 layout_update (self);
59
60 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 typedef uint16_t mapface;
68
69 typedef struct {
70 GLint name;
71 int w, h;
72 float s, t;
73 uint8_t r, g, b, a;
74 } maptex;
75
76 typedef struct {
77 int16_t darkness;
78 mapface face[3];
79 } mapcell;
80
81 typedef struct {
82 int32_t c0, c1;
83 mapcell *col;
84 } maprow;
85
86 typedef struct map {
87 int x, y, w, h;
88 int ox, oy; /* offset to virtual global coordinate system */
89 int faces;
90 mapface *face;
91
92 int texs;
93 maptex *tex;
94
95 uint32_t rows;
96 maprow *row;
97 } *CFClient__Map;
98
99 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 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 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 self->ox = 0;
191 self->oy = 0;
192 self->row = 0;
193 self->rows = 0;
194 }
195
196 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 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
215 row->col[x - row->c0].darkness = -1;
216 }
217 }
218 }
219
220 MODULE = CFClient PACKAGE = CFClient
221
222 PROTOTYPES: ENABLE
223
224 BOOT:
225 {
226 fontmap = pango_ft2_font_map_new ();
227 pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, substitute_func, 0, 0);
228 context = pango_ft2_font_map_create_context ((PangoFT2FontMap *)fontmap);
229 }
230
231 void
232 lowdelay (int fd, int val = 1)
233 CODE:
234 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
235
236 char *
237 gl_version ()
238 CODE:
239 RETVAL = (char *)glGetString (GL_VERSION);
240 OUTPUT:
241 RETVAL
242
243 char *
244 gl_extensions ()
245 CODE:
246 RETVAL = (char *)glGetString (GL_EXTENSIONS);
247 OUTPUT:
248 RETVAL
249
250 void
251 add_font (char *file)
252 CODE:
253 FcConfigAppFontAddFile (0, (const FcChar8 *)file); /* no idea wether this is required */
254
255 void
256 set_font (char *file)
257 CODE:
258 {
259 int count;
260 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)file, 0, 0, &count);
261 PangoFontDescription *font = pango_fc_font_description_from_pattern (pattern, 0);
262 FcPatternDestroy (pattern);
263 pango_context_set_font_description (context, font);
264 }
265
266 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 croak ("load_image: %s", SDL_GetError ());
282
283 surface = IMG_Load_RW (rw, 1);
284 if (!surface)
285 croak ("load_image: %s", SDL_GetError ());
286
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 assert (surface2->pitch == surface2->w * 4);
308
309 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 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
316 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 void
324 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 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 }
347
348 void
349 fatal (char *message)
350 CODE:
351 #ifdef WIN32
352 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
353 #else
354 fprintf (stderr, "FATAL: %s\n", message);
355 #endif
356 exit (1);
357
358 MODULE = CFClient PACKAGE = CFClient::Layout
359
360 CFClient::Layout
361 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 DESTROY (CFClient::Layout self)
372 CODE:
373 g_object_unref (self->pl);
374 Safefree (self);
375
376 void
377 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 set_markup (CFClient::Layout self, SV *text_)
388 CODE:
389 {
390 STRLEN textlen;
391 char *text = SvPVutf8 (text_, textlen);
392
393 pango_layout_set_markup (self->pl, text, textlen);
394 }
395
396 void
397 set_height (CFClient::Layout self, int base_height)
398 CODE:
399 self->base_height = base_height;
400
401 void
402 set_width (CFClient::Layout self, int max_width = -1)
403 CODE:
404 pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
405
406 void
407 size (CFClient::Layout self)
408 PPCODE:
409 {
410 int w, h;
411
412 layout_update (self);
413 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 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
442 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 void
449 render (CFClient::Layout self)
450 PPCODE:
451 {
452 SV *retval;
453 int w, h;
454 FT_Bitmap bitmap;
455
456 layout_update (self);
457 layout_get_pixel_size (self, &w, &h);
458
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 pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
473
474 EXTEND (SP, 3);
475 PUSHs (sv_2mortal (newSViv (w)));
476 PUSHs (sv_2mortal (newSViv (h)));
477 PUSHs (sv_2mortal (retval));
478 }
479
480 MODULE = CFClient PACKAGE = CFClient::Texture
481
482 void
483 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
484 PROTOTYPE: $$$;$$
485 CODE:
486 {
487 HV *hv = (HV *)SvRV (self);
488 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
489 float t = SvNV (*hv_fetch (hv, "t", 1, 1));
490 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
491 int wrap_mode = SvIV (*hv_fetch (hv, "wrap_mode", 9, 1));
492
493 if (items < 5)
494 {
495 w = SvNV (*hv_fetch (hv, "w", 1, 1));
496 h = SvNV (*hv_fetch (hv, "h", 1, 1));
497 }
498
499 glBindTexture (GL_TEXTURE_2D, name);
500 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 glBegin (GL_QUADS);
505 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 glEnd ();
510 }
511
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 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 RETVAL->faces = 8192;
525 Newz (0, RETVAL->face, RETVAL->faces, mapface);
526 RETVAL->texs = 8192;
527 Newz (0, RETVAL->tex, RETVAL->texs, maptex);
528 RETVAL->rows = 0;
529 RETVAL->row = 0;
530 OUTPUT:
531 RETVAL
532
533 void
534 DESTROY (CFClient::Map self)
535 CODE:
536 {
537 map_clear (self);
538 Safefree (self->face);
539 Safefree (self);
540 }
541
542 void
543 clear (CFClient::Map self)
544 CODE:
545 map_clear (self);
546
547 void
548 set_face (CFClient::Map self, int face, int texid)
549 CODE:
550 {
551 while (self->faces <= face)
552 {
553 Append (mapface, self->face, self->faces, self->faces);
554 self->faces *= 2;
555 }
556
557 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
572 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 }
582
583 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 void
597 scroll (CFClient::Map self, int dx, int dy)
598 CODE:
599 {
600 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
610 self->ox += dx; self->x += dx;
611 self->oy += dy; self->y += dy;
612
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 }
621
622 void
623 map1a_update (CFClient::Map self, SV *data_)
624 CODE:
625 {
626 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
627 uint8_t *data_end = (uint8_t *)SvEND (data_);
628
629 while (data < data_end)
630 {
631 int flags = (data [0] << 8) + data [1]; data += 2;
632
633 int x = ((flags >> 10) & 63) + self->x;
634 int y = ((flags >> 4) & 63) + self->y;
635
636 mapcell *cell = map_get_cell (self, x, y);
637
638 if (flags & 15)
639 {
640 if (cell->darkness < 0) // && x < self->w && y < self->h)
641 {
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 //TODO: don't trust server data to be in-range(!)
651
652 if (flags & 4)
653 {
654 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
655 }
656
657 if (flags & 2)
658 {
659 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
660 }
661
662 if (flags & 1)
663 {
664 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
665 }
666 }
667 else
668 cell->darkness = -1;
669 }
670 }
671
672 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 mapface face = cell->face [z];
705
706 if (face)
707 {
708 maptex tex = self->tex [face];
709 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 void
733 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
734 PPCODE:
735 {
736 int sw4 = (sw + 3) & ~3;
737 SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
738 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
739 memset (darkness, 255, sw4 * sh);
740 SvPOK_only (darkness_sv);
741 SvCUR_set (darkness_sv, sw4 * sh);
742
743 int vx = self->x + (self->w - sw) / 2 - shift_x;
744 int vy = self->y + (self->h - sh) / 2 - shift_y;
745
746 /*
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
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
780 darkness[y * sw4 + x] = cell->darkness < 0
781 ? 255 - FOW_DARKNESS
782 : 255 - cell->darkness;
783
784 mapface face = cell->face [z];
785
786 if (face)
787 {
788 maptex tex = self->tex [face];
789
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
811 glDisable (GL_TEXTURE_2D);
812 glDisable (GL_BLEND);
813
814 EXTEND (SP, 3);
815 PUSHs (sv_2mortal (newSViv (sw4)));
816 PUSHs (sv_2mortal (newSViv (sh)));
817 PUSHs (darkness_sv);
818 }
819
820 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