ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.55
Committed: Thu Apr 20 08:11:56 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.54: +8 -7 lines
Log Message:
map overview rectangle

File Contents

# Content
1 #ifdef _WIN32
2 # include <malloc.h>
3 #endif
4
5 #include "EXTERN.h"
6 #include "perl.h"
7 #include "XSUB.h"
8
9 #include <string.h>
10 #include <stdio.h>
11
12 #include <SDL.h>
13 #include <SDL_image.h>
14 #include <SDL_mixer.h>
15 #include <SDL_opengl.h>
16
17 #include <glib/gmacros.h>
18
19 #include <pango/pango.h>
20 #include <pango/pangofc-fontmap.h>
21 #include <pango/pangoft2.h>
22
23 #ifndef _WIN32
24 # include <sys/types.h>
25 # include <sys/socket.h>
26 # include <netinet/in.h>
27 # include <netinet/tcp.h>
28 # include <inttypes.h>
29 #else
30 typedef unsigned char uint8_t;
31 typedef unsigned short uint16_t;
32 typedef unsigned int uint32_t;
33 typedef signed char int8_t;
34 typedef signed short int16_t;
35 typedef signed int int32_t;
36 #endif
37
38 #define FOW_DARKNESS 32
39
40 #define MAP_EXTEND_X 32
41 #define MAP_EXTEND_Y 512
42
43 typedef Mix_Chunk *CFClient__MixChunk;
44 typedef Mix_Music *CFClient__MixMusic;
45
46 static PangoContext *context;
47 static PangoFontMap *fontmap;
48
49 typedef struct cf_layout {
50 PangoLayout *pl;
51 int base_height;
52 } *CFClient__Layout;
53
54 static void
55 substitute_func (FcPattern *pattern, gpointer data)
56 {
57 FcPatternAddBool (pattern, FC_HINTING , 1);
58 FcPatternAddBool (pattern, FC_AUTOHINT, 0);
59 }
60
61 static void
62 layout_update (CFClient__Layout self)
63 {
64 /* use a random scale factor to account for unknown descenders, 0.8 works
65 * reasonably well with bitstream vera
66 */
67 PangoFontDescription *font = pango_context_get_font_description (context);
68
69 int height = self->base_height * (PANGO_SCALE * 8 / 10);
70
71 if (pango_font_description_get_size (font) != height)
72 {
73 pango_font_description_set_absolute_size (font, height);
74 pango_layout_context_changed (self->pl);
75 }
76 }
77
78 static void
79 layout_get_pixel_size (CFClient__Layout self, int *w, int *h)
80 {
81 layout_update (self);
82
83 pango_layout_get_pixel_size (self->pl, w, h);
84
85 *w = (*w + 3) & ~3;
86 if (!*w) *w = 1;
87 if (!*h) *h = 1;
88 }
89
90 typedef uint16_t mapface;
91
92 typedef struct {
93 GLint name;
94 int w, h;
95 float s, t;
96 uint8_t r, g, b, a;
97 } maptex;
98
99 typedef struct {
100 int16_t darkness;
101 mapface face[3];
102 } mapcell;
103
104 typedef struct {
105 int32_t c0, c1;
106 mapcell *col;
107 } maprow;
108
109 typedef struct map {
110 int x, y, w, h;
111 int ox, oy; /* offset to virtual global coordinate system */
112 int faces;
113 mapface *face;
114
115 int texs;
116 maptex *tex;
117
118 int32_t rows;
119 maprow *row;
120 } *CFClient__Map;
121
122 static char *
123 prepend (char *ptr, int sze, int inc)
124 {
125 char *p;
126
127 New (0, p, sze + inc, char);
128 Zero (p, inc, char);
129 Move (ptr, p + inc, sze, char);
130 Safefree (ptr);
131
132 return p;
133 }
134
135 static char *
136 append (char *ptr, int sze, int inc)
137 {
138 Renew (ptr, sze + inc, char);
139 Zero (ptr + sze, inc, char);
140
141 return ptr;
142 }
143
144 #define Append(type,ptr,sze,inc) (ptr) = (type *)append ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
145 #define Prepend(type,ptr,sze,inc) (ptr) = (type *)prepend ((char *)ptr, (sze) * sizeof (type), (inc) * sizeof (type))
146
147 static maprow *
148 map_get_row (CFClient__Map self, int y)
149 {
150 if (0 > y)
151 {
152 int extend = - y + MAP_EXTEND_Y;
153 Prepend (maprow, self->row, self->rows, extend);
154
155 self->rows += extend;
156 self->y += extend;
157 y += extend;
158 }
159 else if (y >= self->rows)
160 {
161 int extend = y - self->rows + MAP_EXTEND_Y;
162 Append (maprow, self->row, self->rows, extend);
163 self->rows += extend;
164 }
165
166 return self->row + y;
167 }
168
169 static mapcell *
170 row_get_cell (maprow *row, int x)
171 {
172 if (!row->col)
173 {
174 Newz (0, row->col, MAP_EXTEND_X, mapcell);
175 row->c0 = x - MAP_EXTEND_X / 4;
176 row->c1 = row->c0 + MAP_EXTEND_X;
177 }
178
179 if (row->c0 > x)
180 {
181 int extend = row->c0 - x + MAP_EXTEND_X;
182 Prepend (mapcell, row->col, row->c1 - row->c0, extend);
183 row->c0 -= extend;
184 }
185 else if (x >= row->c1)
186 {
187 int extend = x - row->c1 + MAP_EXTEND_X;
188 Append (mapcell, row->col, row->c1 - row->c0, extend);
189 row->c1 += extend;
190 }
191
192 return row->col + (x - row->c0);
193 }
194
195 static mapcell *
196 map_get_cell (CFClient__Map self, int x, int y)
197 {
198 return row_get_cell (map_get_row (self, y), x);
199 }
200
201 static void
202 map_clear (CFClient__Map self)
203 {
204 int r;
205
206 for (r = 0; r < self->rows; r++)
207 Safefree (self->row[r].col);
208
209 Safefree (self->row);
210
211 self->x = 0;
212 self->y = 0;
213 self->ox = 0;
214 self->oy = 0;
215 self->row = 0;
216 self->rows = 0;
217 }
218
219 static void
220 map_blank (CFClient__Map self, int x0, int y0, int w, int h)
221 {
222 int x, y;
223 maprow *row;
224
225 for (y = y0; y < y0 + h; y++)
226 if (y >= 0)
227 {
228 if (y >= self->rows)
229 break;
230
231 row = self->row + y;
232
233 for (x = x0; x < x0 + w; x++)
234 if (x >= row->c0)
235 {
236 if (x >= row->c1)
237 break;
238
239 row->col[x - row->c0].darkness = -1;
240 }
241 }
242 }
243
244 MODULE = CFClient PACKAGE = CFClient
245
246 PROTOTYPES: ENABLE
247
248 BOOT:
249 {
250 HV *stash = gv_stashpv ("CFClient", 1);
251 static const struct {
252 const char *name;
253 IV iv;
254 } *civ, const_iv[] = {
255 # define const_iv(name) { # name, (IV)name }
256 const_iv (SDL_ACTIVEEVENT),
257 const_iv (SDL_KEYDOWN),
258 const_iv (SDL_KEYUP),
259 const_iv (SDL_MOUSEMOTION),
260 const_iv (SDL_MOUSEBUTTONDOWN),
261 const_iv (SDL_MOUSEBUTTONUP),
262 const_iv (SDL_JOYAXISMOTION),
263 const_iv (SDL_JOYBALLMOTION),
264 const_iv (SDL_JOYHATMOTION),
265 const_iv (SDL_JOYBUTTONDOWN),
266 const_iv (SDL_JOYBUTTONUP),
267 const_iv (SDL_QUIT),
268 const_iv (SDL_SYSWMEVENT),
269 const_iv (SDL_EVENT_RESERVEDA),
270 const_iv (SDL_EVENT_RESERVEDB),
271 const_iv (SDL_VIDEORESIZE),
272 const_iv (SDL_VIDEOEXPOSE),
273 const_iv (SDL_USEREVENT),
274 const_iv (SDLK_KP0),
275 const_iv (SDLK_KP1),
276 const_iv (SDLK_KP2),
277 const_iv (SDLK_KP3),
278 const_iv (SDLK_KP4),
279 const_iv (SDLK_KP5),
280 const_iv (SDLK_KP6),
281 const_iv (SDLK_KP7),
282 const_iv (SDLK_KP8),
283 const_iv (SDLK_KP9),
284 const_iv (SDLK_KP_PERIOD),
285 const_iv (SDLK_KP_DIVIDE),
286 const_iv (SDLK_KP_MULTIPLY),
287 const_iv (SDLK_KP_MINUS),
288 const_iv (SDLK_KP_PLUS),
289 const_iv (SDLK_KP_ENTER),
290 const_iv (SDLK_KP_EQUALS),
291 const_iv (SDLK_UP),
292 const_iv (SDLK_DOWN),
293 const_iv (SDLK_RIGHT),
294 const_iv (SDLK_LEFT),
295 const_iv (SDLK_INSERT),
296 const_iv (SDLK_HOME),
297 const_iv (SDLK_END),
298 const_iv (SDLK_PAGEUP),
299 const_iv (SDLK_PAGEDOWN),
300 const_iv (SDLK_F1),
301 const_iv (SDLK_F2),
302 const_iv (SDLK_F3),
303 const_iv (SDLK_F4),
304 const_iv (SDLK_F5),
305 const_iv (SDLK_F6),
306 const_iv (SDLK_F7),
307 const_iv (SDLK_F8),
308 const_iv (SDLK_F9),
309 const_iv (SDLK_F10),
310 const_iv (SDLK_F11),
311 const_iv (SDLK_F12),
312 const_iv (SDLK_F13),
313 const_iv (SDLK_F14),
314 const_iv (SDLK_F15),
315 const_iv (SDLK_NUMLOCK),
316 const_iv (SDLK_CAPSLOCK),
317 const_iv (SDLK_SCROLLOCK),
318 const_iv (SDLK_RSHIFT),
319 const_iv (SDLK_LSHIFT),
320 const_iv (SDLK_RCTRL),
321 const_iv (SDLK_LCTRL),
322 const_iv (SDLK_RALT),
323 const_iv (SDLK_LALT),
324 const_iv (SDLK_RMETA),
325 const_iv (SDLK_LMETA),
326 const_iv (SDLK_LSUPER),
327 const_iv (SDLK_RSUPER),
328 const_iv (SDLK_MODE),
329 const_iv (SDLK_COMPOSE),
330 const_iv (SDLK_HELP),
331 const_iv (SDLK_PRINT),
332 const_iv (SDLK_SYSREQ),
333 const_iv (SDLK_BREAK),
334 const_iv (SDLK_MENU),
335 const_iv (SDLK_POWER),
336 const_iv (SDLK_EURO),
337 const_iv (SDLK_UNDO),
338 const_iv (KMOD_NONE),
339 const_iv (KMOD_LSHIFT),
340 const_iv (KMOD_RSHIFT),
341 const_iv (KMOD_LCTRL),
342 const_iv (KMOD_RCTRL),
343 const_iv (KMOD_LALT),
344 const_iv (KMOD_RALT),
345 const_iv (KMOD_LMETA),
346 const_iv (KMOD_RMETA),
347 const_iv (KMOD_NUM),
348 const_iv (KMOD_CAPS),
349 const_iv (KMOD_MODE),
350 const_iv (KMOD_CTRL),
351 const_iv (KMOD_SHIFT),
352 const_iv (KMOD_ALT),
353 const_iv (KMOD_META)
354 # undef const_iv
355 };
356
357 for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
358 newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
359
360 fontmap = pango_ft2_font_map_new ();
361 pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, substitute_func, 0, 0);
362 context = pango_ft2_font_map_create_context ((PangoFT2FontMap *)fontmap);
363 }
364
365 int
366 SDL_Init (U32 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO)
367
368 void
369 SDL_Quit ()
370
371 void
372 SDL_ListModes ()
373 PPCODE:
374 {
375 SDL_Rect **m;
376
377 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
378 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
379 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
380 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 1);
381
382 SDL_GL_SetAttribute (SDL_GL_ACCUM_RED_SIZE, 0);
383 SDL_GL_SetAttribute (SDL_GL_ACCUM_GREEN_SIZE, 0);
384 SDL_GL_SetAttribute (SDL_GL_ACCUM_BLUE_SIZE, 0);
385 SDL_GL_SetAttribute (SDL_GL_ACCUM_ALPHA_SIZE, 0);
386
387 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
388 SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 15);
389 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 0);
390
391 SDL_EnableUNICODE (1);
392 SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
393
394 m = SDL_ListModes (0, SDL_FULLSCREEN | SDL_OPENGL);
395
396 if (m && m != (SDL_Rect **)-1)
397 while (*m)
398 {
399 AV *av = newAV ();
400 av_push (av, newSViv ((*m)->w));
401 av_push (av, newSViv ((*m)->h));
402 XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
403
404 ++m;
405 }
406 }
407
408 int
409 SDL_SetVideoMode (int w, int h, int fullscreen)
410 CODE:
411 RETVAL = !!SDL_SetVideoMode (
412 w, h, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)
413 );
414 SDL_WM_SetCaption ("Crossfire+ Client " VERSION, "Crossfire+");
415 OUTPUT:
416 RETVAL
417
418 void
419 SDL_GL_SwapBuffers ()
420
421 void
422 SDL_PollEvent ()
423 PPCODE:
424 {
425 SDL_Event ev;
426
427 while (SDL_PollEvent (&ev))
428 {
429 HV *hv = newHV ();
430 hv_store (hv, "type", 4, newSViv (ev.type), 0);
431 switch (ev.type)
432 {
433 case SDL_KEYDOWN:
434 case SDL_KEYUP:
435 hv_store (hv, "state", 5, newSViv (ev.key.state), 0);
436 hv_store (hv, "sym", 3, newSViv (ev.key.keysym.sym), 0);
437 hv_store (hv, "mod", 3, newSViv (ev.key.keysym.mod), 0);
438 hv_store (hv, "unicode", 7, newSViv (ev.key.keysym.unicode), 0);
439 break;
440
441 case SDL_ACTIVEEVENT:
442 hv_store (hv, "gain", 4, newSViv (ev.active.gain), 0);
443 hv_store (hv, "state", 5, newSViv (ev.active.state), 0);
444 break;
445
446 case SDL_MOUSEMOTION:
447 hv_store (hv, "state", 5, newSViv (ev.motion.state), 0);
448 hv_store (hv, "x", 1, newSViv (ev.motion.x), 0);
449 hv_store (hv, "y", 1, newSViv (ev.motion.y), 0);
450 hv_store (hv, "xrel", 4, newSViv (ev.motion.xrel), 0);
451 hv_store (hv, "yrel", 4, newSViv (ev.motion.yrel), 0);
452 break;
453
454 case SDL_MOUSEBUTTONDOWN:
455 case SDL_MOUSEBUTTONUP:
456 hv_store (hv, "button", 6, newSViv (ev.button.button), 0);
457 hv_store (hv, "state", 5, newSViv (ev.button.state), 0);
458 hv_store (hv, "x", 1, newSViv (ev.button.x), 0);
459 hv_store (hv, "y", 1, newSViv (ev.button.y), 0);
460 }
461
462 XPUSHs (sv_2mortal (newRV_noinc ((SV *)hv)));
463 }
464 }
465
466 int
467 Mix_OpenAudio (int frequency = 22050, int format = MIX_DEFAULT_FORMAT, int channels = 1, int chunksize = 512)
468
469 void
470 Mix_CloseAudio ()
471
472 int
473 Mix_AllocateChannels (int numchans = -1)
474
475 void
476 lowdelay (int fd, int val = 1)
477 CODE:
478 #ifndef _WIN32
479 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
480 #endif
481
482 char *
483 gl_version ()
484 CODE:
485 RETVAL = (char *)glGetString (GL_VERSION);
486 OUTPUT:
487 RETVAL
488
489 char *
490 gl_extensions ()
491 CODE:
492 RETVAL = (char *)glGetString (GL_EXTENSIONS);
493 OUTPUT:
494 RETVAL
495
496 void
497 add_font (char *file)
498 CODE:
499 FcConfigAppFontAddFile (0, (const FcChar8 *)file); /* no idea wether this is required */
500
501 void
502 set_font (char *file)
503 CODE:
504 {
505 int count;
506 FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)file, 0, 0, &count);
507 PangoFontDescription *font = pango_fc_font_description_from_pattern (pattern, 0);
508 FcPatternDestroy (pattern);
509 pango_context_set_font_description (context, font);
510 }
511
512 void
513 load_image_inline (SV *image_)
514 ALIAS:
515 load_image_file = 1
516 PPCODE:
517 {
518 STRLEN image_len;
519 char *image = (char *)SvPVbyte (image_, image_len);
520 SDL_Surface *surface, *surface2;
521 SDL_PixelFormat fmt;
522 SDL_RWops *rw = ix
523 ? SDL_RWFromFile (image, "r")
524 : SDL_RWFromConstMem (image, image_len);
525
526 if (!rw)
527 croak ("load_image: %s", SDL_GetError ());
528
529 surface = IMG_Load_RW (rw, 1);
530 if (!surface)
531 croak ("load_image: %s", SDL_GetError ());
532
533 fmt.palette = NULL;
534 fmt.BitsPerPixel = 32;
535 fmt.BytesPerPixel = 4;
536 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
537 fmt.Rmask = 0x000000ff;
538 fmt.Gmask = 0x0000ff00;
539 fmt.Bmask = 0x00ff0000;
540 fmt.Amask = 0xff000000;
541 #else
542 fmt.Rmask = 0xff000000;
543 fmt.Gmask = 0x00ff0000;
544 fmt.Bmask = 0x0000ff00;
545 fmt.Amask = 0x000000ff;
546 #endif
547 fmt.Rloss = 0;
548 fmt.Gloss = 0;
549 fmt.Bloss = 0;
550 fmt.Aloss = 0;
551 fmt.Rshift = 0;
552 fmt.Gshift = 8;
553 fmt.Bshift = 16;
554 fmt.Ashift = 24;
555 fmt.colorkey = 0;
556 fmt.alpha = 0;
557
558 surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
559
560 assert (surface2->pitch == surface2->w * 4);
561
562 EXTEND (SP, 5);
563 PUSHs (sv_2mortal (newSViv (surface2->w)));
564 PUSHs (sv_2mortal (newSViv (surface2->h)));
565 SDL_LockSurface (surface2);
566 PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
567 SDL_UnlockSurface (surface2);
568 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
569 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
570 PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_BYTE)));
571
572 SDL_FreeSurface (surface);
573 SDL_FreeSurface (surface2);
574 }
575
576 void
577 average (int x, int y, uint32_t *data)
578 PPCODE:
579 {
580 uint32_t r = 0, g = 0, b = 0, a = 0;
581
582 x = y = x * y;
583
584 while (x--)
585 {
586 uint32_t p = *data++;
587
588 r += (p ) & 255;
589 g += (p >> 8) & 255;
590 b += (p >> 16) & 255;
591 a += (p >> 24) & 255;
592 }
593
594 EXTEND (SP, 4);
595 PUSHs (sv_2mortal (newSViv (r / y)));
596 PUSHs (sv_2mortal (newSViv (g / y)));
597 PUSHs (sv_2mortal (newSViv (b / y)));
598 PUSHs (sv_2mortal (newSViv (a / y)));
599 }
600
601 void
602 fatal (char *message)
603 CODE:
604 #ifdef _WIN32
605 MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
606 #else
607 fprintf (stderr, "FATAL: %s\n", message);
608 #endif
609 exit (1);
610
611 MODULE = CFClient PACKAGE = CFClient::Layout
612
613 CFClient::Layout
614 new (SV *class, int base_height = 10)
615 CODE:
616 New (0, RETVAL, 1, struct cf_layout);
617 RETVAL->base_height = base_height;
618 RETVAL->pl = pango_layout_new (context);
619 pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
620 OUTPUT:
621 RETVAL
622
623 void
624 DESTROY (CFClient::Layout self)
625 CODE:
626 g_object_unref (self->pl);
627 Safefree (self);
628
629 void
630 set_text (CFClient::Layout self, SV *text_)
631 CODE:
632 {
633 STRLEN textlen;
634 char *text = SvPVutf8 (text_, textlen);
635
636 pango_layout_set_text (self->pl, text, textlen);
637 }
638
639 void
640 set_markup (CFClient::Layout self, SV *text_)
641 CODE:
642 {
643 STRLEN textlen;
644 char *text = SvPVutf8 (text_, textlen);
645
646 pango_layout_set_markup (self->pl, text, textlen);
647 }
648
649 SV *
650 get_text (CFClient::Layout self)
651 CODE:
652 RETVAL = newSVpv (pango_layout_get_text (self->pl), 0);
653 SvUTF8_on (RETVAL);
654 OUTPUT:
655 RETVAL
656
657 void
658 set_height (CFClient::Layout self, int base_height)
659 CODE:
660 self->base_height = base_height;
661
662 void
663 set_width (CFClient::Layout self, int max_width = -1)
664 CODE:
665 pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
666
667 void
668 size (CFClient::Layout self)
669 PPCODE:
670 {
671 int w, h;
672
673 layout_update (self);
674 layout_get_pixel_size (self, &w, &h);
675
676 EXTEND (SP, 2);
677 PUSHs (sv_2mortal (newSViv (w)));
678 PUSHs (sv_2mortal (newSViv (h)));
679 }
680
681 int
682 xy_to_index (CFClient::Layout self, int x, int y)
683 CODE:
684 {
685 int index, trailing;
686
687 layout_update (self);
688 pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
689
690 RETVAL = index;
691 }
692 OUTPUT:
693 RETVAL
694
695 void
696 cursor_pos (CFClient::Layout self, int index)
697 PPCODE:
698 {
699 PangoRectangle strong_pos;
700 layout_update (self);
701 pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
702
703 EXTEND (SP, 3);
704 PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
705 PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
706 PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
707 }
708
709 void
710 render (CFClient::Layout self)
711 PPCODE:
712 {
713 SV *retval;
714 int w, h;
715 FT_Bitmap bitmap;
716
717 layout_update (self);
718 layout_get_pixel_size (self, &w, &h);
719
720 retval = newSV (w * h);
721 SvPOK_only (retval);
722 SvCUR_set (retval, w * h);
723
724 bitmap.rows = h;
725 bitmap.width = w;
726 bitmap.pitch = w;
727 bitmap.buffer = (unsigned char*)SvPVX (retval);
728 bitmap.num_grays = 256;
729 bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
730
731 memset (bitmap.buffer, 0, w * h);
732
733 pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
734
735 EXTEND (SP, 3);
736 PUSHs (sv_2mortal (newSViv (w)));
737 PUSHs (sv_2mortal (newSViv (h)));
738 PUSHs (sv_2mortal (retval));
739 }
740
741 MODULE = CFClient PACKAGE = CFClient::Texture
742
743 void
744 draw_quad (SV *self, float x, float y, float w = 0, float h = 0)
745 PROTOTYPE: $$$;$$
746 CODE:
747 {
748 HV *hv = (HV *)SvRV (self);
749 float s = SvNV (*hv_fetch (hv, "s", 1, 1));
750 float t = SvNV (*hv_fetch (hv, "t", 1, 1));
751 int name = SvIV (*hv_fetch (hv, "name", 4, 1));
752 int wrap_mode = SvIV (*hv_fetch (hv, "wrap_mode", 9, 1));
753
754 if (items < 5)
755 {
756 w = SvNV (*hv_fetch (hv, "w", 1, 1));
757 h = SvNV (*hv_fetch (hv, "h", 1, 1));
758 }
759
760 glBindTexture (GL_TEXTURE_2D, name);
761 if (wrap_mode) {
762 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
763 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
764 }
765 glBegin (GL_QUADS);
766 glTexCoord2f (0, 0); glVertex2f (x , y );
767 glTexCoord2f (0, t); glVertex2f (x , y + h);
768 glTexCoord2f (s, t); glVertex2f (x + w, y + h);
769 glTexCoord2f (s, 0); glVertex2f (x + w, y );
770 glEnd ();
771 }
772
773 MODULE = CFClient PACKAGE = CFClient::Map
774
775 CFClient::Map
776 new (SV *class, int map_width, int map_height)
777 CODE:
778 New (0, RETVAL, 1, struct map);
779 RETVAL->x = 0;
780 RETVAL->y = 0;
781 RETVAL->w = map_width;
782 RETVAL->h = map_height;
783 RETVAL->ox = 0;
784 RETVAL->oy = 0;
785 RETVAL->faces = 8192;
786 Newz (0, RETVAL->face, RETVAL->faces, mapface);
787 RETVAL->texs = 8192;
788 Newz (0, RETVAL->tex, RETVAL->texs, maptex);
789 RETVAL->rows = 0;
790 RETVAL->row = 0;
791 OUTPUT:
792 RETVAL
793
794 void
795 DESTROY (CFClient::Map self)
796 CODE:
797 {
798 map_clear (self);
799 Safefree (self->face);
800 Safefree (self);
801 }
802
803 void
804 clear (CFClient::Map self)
805 CODE:
806 map_clear (self);
807
808 void
809 set_face (CFClient::Map self, int face, int texid)
810 CODE:
811 {
812 while (self->faces <= face)
813 {
814 Append (mapface, self->face, self->faces, self->faces);
815 self->faces *= 2;
816 }
817
818 self->face [face] = texid;
819 }
820
821 void
822 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)
823 CODE:
824 {
825 while (self->texs <= texid)
826 {
827 Append (maptex, self->tex, self->texs, self->texs);
828 self->texs *= 2;
829 }
830
831 {
832 maptex *tex = self->tex + texid;
833
834 tex->name = name;
835 tex->w = w;
836 tex->h = h;
837 tex->s = s;
838 tex->t = t;
839 tex->r = r;
840 tex->g = g;
841 tex->b = b;
842 tex->a = a;
843 }
844 }
845
846 int
847 ox (CFClient::Map self)
848 ALIAS:
849 oy = 1
850 CODE:
851 switch (ix)
852 {
853 case 0: RETVAL = self->ox; break;
854 case 1: RETVAL = self->oy; break;
855 }
856 OUTPUT:
857 RETVAL
858
859 void
860 scroll (CFClient::Map self, int dx, int dy)
861 CODE:
862 {
863 if (dx > 0)
864 map_blank (self, self->x, self->y, dx - 1, self->h);
865 else if (dx < 0)
866 map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
867
868 if (dy > 0)
869 map_blank (self, self->x, self->y, self->w, dy - 1);
870 else if (dy < 0)
871 map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
872
873 self->ox += dx; self->x += dx;
874 self->oy += dy; self->y += dy;
875
876 while (self->y < 0)
877 {
878 Prepend (maprow, self->row, self->rows, MAP_EXTEND_Y);
879
880 self->rows += MAP_EXTEND_Y;
881 self->y += MAP_EXTEND_Y;
882 }
883 }
884
885 void
886 map1a_update (CFClient::Map self, SV *data_)
887 CODE:
888 {
889 uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_);
890 uint8_t *data_end = (uint8_t *)SvEND (data_);
891 mapcell *cell;
892 int x, y, flags;
893
894 while (data < data_end)
895 {
896 flags = (data [0] << 8) + data [1]; data += 2;
897
898 x = ((flags >> 10) & 63) + self->x;
899 y = ((flags >> 4) & 63) + self->y;
900
901 cell = map_get_cell (self, x, y);
902
903 if (flags & 15)
904 {
905 if (cell->darkness < 0)
906 {
907 cell->darkness = 0;
908 cell->face [0] = 0;
909 cell->face [1] = 0;
910 cell->face [2] = 0;
911 }
912
913 cell->darkness = flags & 8 ? *data++ : 255;
914
915 //TODO: don't trust server data to be in-range(!)
916
917 if (flags & 4)
918 {
919 cell->face [0] = self->face [(data [0] << 8) + data [1]]; data += 2;
920 }
921
922 if (flags & 2)
923 {
924 cell->face [1] = self->face [(data [0] << 8) + data [1]]; data += 2;
925 }
926
927 if (flags & 1)
928 {
929 cell->face [2] = self->face [(data [0] << 8) + data [1]]; data += 2;
930 }
931 }
932 else
933 cell->darkness = -1;
934 }
935 }
936
937 SV *
938 mapmap (CFClient::Map self, int x0, int y0, int w, int h)
939 CODE:
940 {
941 int x1, x;
942 int y1, y;
943 int z;
944 SV *map_sv = newSV (w * h * sizeof (uint32_t));
945 uint32_t *map = (uint32_t *)SvPVX (map_sv);
946
947 SvPOK_only (map_sv);
948 SvCUR_set (map_sv, w * h * sizeof (uint32_t));
949
950 x0 += self->x; x1 = x0 + w;
951 y0 += self->y; y1 = y0 + h;
952
953 for (y = y0; y < y1; y++)
954 {
955 maprow *row = 0 <= y && y < self->rows
956 ? self->row + y
957 : 0;
958
959 for (x = x0; x < x1; x++)
960 {
961 int r = 32, g = 32, b = 32, a = 192;
962
963 if (row && row->c0 <= x && x < row->c1)
964 {
965 mapcell *cell = row->col + (x - row->c0);
966
967 for (z = 0; z <= 0; z++)
968 {
969 mapface face = cell->face [z];
970
971 if (face)
972 {
973 maptex tex = self->tex [face];
974 int a0 = 255 - tex.a;
975 int a1 = tex.a;
976
977 r = (r * a0 + tex.r * a1) / 255;
978 g = (g * a0 + tex.g * a1) / 255;
979 b = (b * a0 + tex.b * a1) / 255;
980 a = (a * a0 + tex.a * a1) / 255;
981 }
982 }
983 }
984
985 *map++ = (r )
986 | (g << 8)
987 | (b << 16)
988 | (a << 24);
989 }
990 }
991
992 RETVAL = map_sv;
993 }
994 OUTPUT:
995 RETVAL
996
997 void
998 draw (CFClient::Map self, int shift_x, int shift_y, int x0, int y0, int sw, int sh)
999 PPCODE:
1000 {
1001 int vx, vy;
1002 int x, y, z;
1003 int last_name;
1004 mapface face;
1005 int sw4 = (sw + 3) & ~3;
1006 SV *darkness_sv = sv_2mortal (newSV (sw4 * sh));
1007 uint8_t *darkness = (uint8_t *)SvPVX (darkness_sv);
1008
1009 memset (darkness, 255, sw4 * sh);
1010 SvPOK_only (darkness_sv);
1011 SvCUR_set (darkness_sv, sw4 * sh);
1012
1013 vx = self->x + (self->w - sw) / 2 - shift_x;
1014 vy = self->y + (self->h - sh) / 2 - shift_y;
1015
1016 /*
1017 int vx = self->vx = self->w >= sw
1018 ? self->x + (self->w - sw) / 2
1019 : MIN (self->x, MAX (self->x + self->w - sw + 1, self->vx));
1020
1021 int vy = self->vy = self->h >= sh
1022 ? self->y + (self->h - sh) / 2
1023 : MIN (self->y, MAX (self->y + self->h - sh + 1, self->vy));
1024 */
1025
1026 glColor4ub (255, 255, 255, 255);
1027
1028 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1029 glEnable (GL_BLEND);
1030 glEnable (GL_TEXTURE_2D);
1031 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1032
1033 glBegin (GL_QUADS);
1034
1035 last_name = 0;
1036
1037 for (z = 0; z < 3; z++)
1038 for (y = 0; y < sh; y++)
1039 if (0 <= y + vy && y + vy < self->rows)
1040 {
1041 maprow *row = self->row + (y + vy);
1042
1043 for (x = 0; x < sw; x++)
1044 if (row->c0 <= x + vx && x + vx < row->c1)
1045 {
1046 mapcell *cell = row->col + (x + vx - row->c0);
1047
1048 darkness[y * sw4 + x] = cell->darkness < 0
1049 ? 255 - FOW_DARKNESS
1050 : 255 - cell->darkness;
1051
1052 face = cell->face [z];
1053
1054 if (face)
1055 {
1056 maptex tex = self->tex [face];
1057
1058 int px = (x + 1) * 32 - tex.w;
1059 int py = (y + 1) * 32 - tex.h;
1060
1061 if (last_name != tex.name)
1062 {
1063 glEnd ();
1064 last_name = tex.name;
1065 glBindTexture (GL_TEXTURE_2D, last_name);
1066 glBegin (GL_QUADS);
1067 }
1068
1069 glTexCoord2f (0 , 0 ); glVertex2f (px , py );
1070 glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h);
1071 glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h);
1072 glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py );
1073 }
1074 }
1075 }
1076
1077 glEnd ();
1078
1079 glDisable (GL_TEXTURE_2D);
1080 glDisable (GL_BLEND);
1081
1082 EXTEND (SP, 3);
1083 PUSHs (sv_2mortal (newSViv (sw4)));
1084 PUSHs (sv_2mortal (newSViv (sh)));
1085 PUSHs (darkness_sv);
1086 }
1087
1088 SV *
1089 get_rect (CFClient::Map self, int x0, int y0, int w, int h)
1090 CODE:
1091 {
1092 int x, y, x1, y1;
1093 SV *data_sv = newSV (w * h * 7 + 5);
1094 uint8_t *data = (uint8_t *)SvPVX (data_sv);
1095
1096 *data++ = 0; /* version 0 format */
1097 *data++ = w >> 8; *data++ = w;
1098 *data++ = h >> 8; *data++ = h;
1099
1100 // we need to do this 'cause we don't keep an absolute coord system for rows
1101 // TODO: treat rows as we treat columns
1102 map_get_row (self, y0 + self->y - self->oy);//D
1103 map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1104
1105 x0 += self->x - self->ox;
1106 y0 += self->y - self->oy;
1107
1108 x1 = x0 + w;
1109 y1 = y0 + h;
1110
1111 for (y = y0; y < y1; y++)
1112 {
1113 maprow *row = 0 <= y && y < self->rows
1114 ? self->row + y
1115 : 0;
1116
1117 for (x = x0; x < x1; x++)
1118 {
1119 if (row && row->c0 <= x && x < row->c1)
1120 {
1121 mapcell *cell = row->col + (x - row->c0);
1122 uint8_t flags = 0;
1123
1124 if (cell->face [0]) flags |= 1;
1125 if (cell->face [1]) flags |= 2;
1126 if (cell->face [2]) flags |= 4;
1127
1128 *data++ = flags;
1129
1130 if (flags & 1)
1131 {
1132 *data++ = cell->face [0] >> 8;
1133 *data++ = cell->face [0];
1134 }
1135
1136 if (flags & 2)
1137 {
1138 *data++ = cell->face [1] >> 8;
1139 *data++ = cell->face [1];
1140 }
1141
1142 if (flags & 4)
1143 {
1144 *data++ = cell->face [2] >> 8;
1145 *data++ = cell->face [2];
1146 }
1147 }
1148 else
1149 *data++ = 0;
1150 }
1151 }
1152
1153 SvPOK_only (data_sv);
1154 SvCUR_set (data_sv, data - (uint8_t *)SvPVX (data_sv));
1155 RETVAL = data_sv;
1156 }
1157 OUTPUT:
1158 RETVAL
1159
1160 void
1161 set_rect (CFClient::Map self, int x0, int y0, uint8_t *data)
1162 PPCODE:
1163 {
1164 int x, y, z;
1165 int w, h;
1166 int x1, y1;
1167
1168 if (*data++ != 0)
1169 return; /* version mismatch */
1170
1171 w = *data++ << 8; w |= *data++;
1172 h = *data++ << 8; h |= *data++;
1173
1174 // we need to do this 'cause we don't keep an absolute coord system for rows
1175 // TODO: treat rows as we treat columns
1176 map_get_row (self, y0 + self->y - self->oy);//D
1177 map_get_row (self, y0 + self->y - self->oy + h - 1);//D
1178
1179 x0 += self->x - self->ox;
1180 y0 += self->y - self->oy;
1181
1182 x1 = x0 + w;
1183 y1 = y0 + h;
1184
1185 for (y = y0; y < y1; y++)
1186 {
1187 maprow *row = map_get_row (self, y);
1188
1189 for (x = x0; x < x1; x++)
1190 {
1191 uint8_t flags = *data++;
1192
1193 if (flags)
1194 {
1195 mapface face[3] = { 0, 0, 0 };
1196
1197 mapcell *cell = row_get_cell (row, x);
1198
1199 if (flags & 1) { face[0] = *data++ << 8; face[0] |= *data++; }
1200 if (flags & 2) { face[1] = *data++ << 8; face[1] |= *data++; }
1201 if (flags & 4) { face[2] = *data++ << 8; face[2] |= *data++; }
1202
1203 if (cell->darkness <= 0)
1204 {
1205 cell->darkness = -1;
1206
1207 for (z = 0; z <= 2; z++)
1208 {
1209 cell->face[z] = face[z];
1210
1211 if (face[z] && (face[z] >= self->texs || !self->tex[face [z]].name))
1212 XPUSHs (sv_2mortal (newSViv (face[z])));
1213 }
1214 }
1215 }
1216 }
1217 }
1218 }
1219
1220 MODULE = CFClient PACKAGE = CFClient::MixChunk
1221
1222 CFClient::MixChunk
1223 new_from_file (SV *class, char *path)
1224 CODE:
1225 RETVAL = Mix_LoadWAV (path);
1226 OUTPUT:
1227 RETVAL
1228
1229 void
1230 DESTROY (CFClient::MixChunk self)
1231 CODE:
1232 Mix_FreeChunk (self);
1233
1234 int
1235 volume (CFClient::MixChunk self, int volume = -1)
1236 CODE:
1237 RETVAL = Mix_VolumeChunk (self, volume);
1238 OUTPUT:
1239 RETVAL
1240
1241 int
1242 play (CFClient::MixChunk self, int channel = -1, int loops = 0, int ticks = -1)
1243 CODE:
1244 RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks);
1245 OUTPUT:
1246 RETVAL
1247
1248 MODULE = CFClient PACKAGE = CFClient::MixMusic
1249
1250 int
1251 volume (int volume = -1)
1252 CODE:
1253 RETVAL = Mix_VolumeMusic (volume);
1254 OUTPUT:
1255 RETVAL
1256
1257 CFClient::MixMusic
1258 new_from_file (SV *class, char *path)
1259 CODE:
1260 RETVAL = Mix_LoadMUS (path);
1261 OUTPUT:
1262 RETVAL
1263
1264 void
1265 DESTROY (CFClient::MixMusic self)
1266 CODE:
1267 Mix_FreeMusic (self);
1268
1269 int
1270 play (CFClient::MixMusic self, int loops = -1)
1271 CODE:
1272 RETVAL = Mix_PlayMusic (self, loops);
1273 OUTPUT:
1274 RETVAL
1275
1276 MODULE = CFClient PACKAGE = CFClient::OpenGL
1277
1278 BOOT:
1279 {
1280 HV *stash = gv_stashpv ("CFClient::OpenGL", 1);
1281 static const struct {
1282 const char *name;
1283 IV iv;
1284 } *civ, const_iv[] = {
1285 # define const_iv(name) { # name, (IV)name }
1286 const_iv (GL_COLOR_MATERIAL),
1287 const_iv (GL_SMOOTH),
1288 const_iv (GL_FLAT),
1289 const_iv (GL_BLEND),
1290 const_iv (GL_AND),
1291 const_iv (GL_SRC_ALPHA),
1292 const_iv (GL_ONE_MINUS_SRC_ALPHA),
1293 const_iv (GL_RGB),
1294 const_iv (GL_RGBA),
1295 const_iv (GL_UNSIGNED_BYTE),
1296 const_iv (GL_ALPHA4),
1297 const_iv (GL_ALPHA),
1298 const_iv (GL_FLOAT),
1299 const_iv (GL_UNSIGNED_INT_8_8_8_8_REV),
1300 const_iv (GL_COMPILE),
1301 const_iv (GL_TEXTURE_1D),
1302 const_iv (GL_TEXTURE_2D),
1303 const_iv (GL_TEXTURE_ENV),
1304 const_iv (GL_TEXTURE_MAG_FILTER),
1305 const_iv (GL_TEXTURE_MIN_FILTER),
1306 const_iv (GL_TEXTURE_ENV_MODE),
1307 const_iv (GL_TEXTURE_WRAP_S),
1308 const_iv (GL_TEXTURE_WRAP_T),
1309 const_iv (GL_CLAMP),
1310 const_iv (GL_REPEAT),
1311 const_iv (GL_NEAREST),
1312 const_iv (GL_LINEAR),
1313 const_iv (GL_MODULATE),
1314 const_iv (GL_REPLACE),
1315 const_iv (GL_COLOR_BUFFER_BIT),
1316 const_iv (GL_PROJECTION),
1317 const_iv (GL_MODELVIEW),
1318 const_iv (GL_COLOR_LOGIC_OP),
1319 const_iv (GL_CONVOLUTION_2D),
1320 const_iv (GL_CONVOLUTION_BORDER_MODE),
1321 const_iv (GL_CONSTANT_BORDER),
1322 const_iv (GL_LINES),
1323 const_iv (GL_QUADS),
1324 const_iv (GL_LINE_LOOP),
1325 const_iv (GL_PERSPECTIVE_CORRECTION_HINT),
1326 const_iv (GL_FASTEST),
1327 # undef const_iv
1328 };
1329
1330 for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
1331 newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
1332 }
1333
1334 int glGetError ()
1335
1336 void glClear (int mask)
1337
1338 void glClearColor (float r, float g, float b, float a = 1.0)
1339 PROTOTYPE: @
1340
1341 void glEnable (int cap)
1342
1343 void glDisable (int cap)
1344
1345 void glShadeModel (int mode)
1346
1347 void glHint (int target, int mode)
1348
1349 void glBlendFunc (int sfactor, int dfactor)
1350
1351 void glLogicOp (int opcode)
1352
1353 void glMatrixMode (int mode)
1354
1355 void glPushMatrix ()
1356
1357 void glPopMatrix ()
1358
1359 void glLoadIdentity ()
1360
1361 void glOrtho (double left, double right, double bottom, double top, double near, double far)
1362
1363 void glViewport (int x, int y, int width, int height)
1364
1365 void glTranslate (float x, float y, float z = 0.)
1366 CODE:
1367 glTranslatef (x, y, z);
1368
1369 void glScale (float x, float y, float z)
1370 CODE:
1371 glScalef (x, y, z);
1372
1373 void glRotate (float angle, float x, float y, float z)
1374 CODE:
1375 glRotatef (angle, x, y, z);
1376
1377 void glBegin (int mode)
1378
1379 void glEnd ()
1380
1381 void glColor (float r, float g, float b, float a = 1.0)
1382 PROTOTYPE: @
1383 CODE:
1384 glColor4f (r, g, b, a);
1385
1386 void glVertex (float x, float y, float z = 0.)
1387 CODE:
1388 glVertex3f (x, y, z);
1389
1390 void glTexCoord (float s, float t)
1391 CODE:
1392 glTexCoord2f (s, t);
1393
1394 void glTexEnv (int target, int pname, float param)
1395 CODE:
1396 glTexEnvf (target, pname, param);
1397
1398 void glTexParameter (int target, int pname, float param)
1399 CODE:
1400 glTexParameterf (target, pname, param);
1401
1402 void glBindTexture (int target, int name)
1403
1404 void glConvolutionParameter (int target, int pname, float params)
1405 CODE:
1406 glConvolutionParameterf (target, pname, params);
1407
1408 void glConvolutionFilter2D (int target, int internalformat, int width, int height, int format, int type, char *data)
1409
1410 void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, char *data)
1411
1412 void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border)
1413
1414 int glGenTexture ()
1415 CODE:
1416 {
1417 GLuint name;
1418 glGenTextures (1, &name);
1419 RETVAL = name;
1420 }
1421 OUTPUT:
1422 RETVAL
1423
1424 void glDeleteTexture (int name)
1425 CODE:
1426 {
1427 GLuint name_ = name;
1428 glDeleteTextures (1, &name_);
1429 }
1430
1431 int glGenList ()
1432 CODE:
1433 RETVAL = glGenLists (1);
1434 OUTPUT:
1435 RETVAL
1436
1437 void glDeleteList (int list)
1438 CODE:
1439 glDeleteLists (list, 1);
1440
1441 void glNewList (int list, int mode = GL_COMPILE)
1442
1443 void glEndList ()
1444
1445 void glCallList (int list)
1446