ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/Client.xs
Revision: 1.29
Committed: Thu Apr 13 01:55:38 2006 UTC (18 years, 1 month ago) by root
Branch: MAIN
Changes since 1.28: +184 -12 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     #include <pango/pango.h>
13 root 1.10 #include <pango/pangofc-fontmap.h>
14 root 1.5 #include <pango/pangoft2.h>
15    
16 root 1.10 #include <sys/types.h>
17     #include <sys/socket.h>
18     #include <netinet/in.h>
19     #include <netinet/tcp.h>
20    
21 root 1.28 #include <inttypes.h>
22    
23 root 1.29 #define FOW_DARKNESS 32
24    
25     #define MAP_EXTEND_X 32
26     #define MAP_EXTEND_Y 512
27    
28 root 1.5 static PangoContext *context;
29     static PangoFontMap *fontmap;
30 root 1.2
31 root 1.14 typedef struct cf_layout {
32     PangoLayout *pl;
33     int base_height;
34 root 1.15 } *CFClient__Layout;
35 root 1.14
36     static void
37 root 1.19 substitute_func (FcPattern *pattern, gpointer data)
38     {
39 root 1.20 FcPatternAddBool (pattern, FC_HINTING , 1);
40     FcPatternAddBool (pattern, FC_AUTOHINT, 1);
41 root 1.19 }
42    
43     static void
44 root 1.17 layout_update (CFClient__Layout self)
45     {
46 root 1.19 /* use a random scale factor to account for unknown descenders, 0.8 works
47     * reasonably well with bitstream vera
48     */
49 root 1.17 PangoFontDescription *font = pango_context_get_font_description (context);
50 root 1.19 pango_font_description_set_absolute_size (font, self->base_height * (PANGO_SCALE * 8 / 10));
51 root 1.17 }
52    
53     static void
54 root 1.15 layout_get_pixel_size (CFClient__Layout self, int *w, int *h)
55 root 1.14 {
56 root 1.19 layout_update (self);
57 root 1.16
58 root 1.14 pango_layout_get_pixel_size (self->pl, w, h);
59    
60     *w = (*w + 3) & ~3;
61     if (!*w) *w = 1;
62     if (!*h) *h = 1;
63     }
64    
65 root 1.28 typedef struct {
66 root 1.29 int16_t darkness;
67 root 1.28 uint16_t face[3];
68     } mapcell;
69    
70     typedef struct {
71 root 1.29 uint32_t c0, c1;
72 root 1.28 mapcell *col;
73     } maprow;
74    
75     typedef struct map {
76     int x, y, w, h;
77     int faces;
78     GLint *face;
79    
80     uint32_t rows;
81     maprow *row;
82     } *CFClient__Map;
83    
84 root 1.29 static void
85     map_blank (CFClient__Map self, int x0, int y0, int w, int h)
86     {
87     int x, y;
88    
89     for (y = y0; y < y0 + h; y++)
90     {
91     if (y >= self->rows)
92     break;
93    
94     maprow *row = self->row + y;
95    
96     for (x = x0; x < x0 + w; x++)
97     if (x >= row->c0)
98     {
99     if (x >= row->c1)
100     break;
101    
102     row->col[x].darkness = -1;
103     }
104     }
105     }
106    
107 root 1.15 MODULE = CFClient PACKAGE = CFClient
108 root 1.1
109 root 1.11 PROTOTYPES: ENABLE
110    
111 root 1.5 BOOT:
112     {
113     fontmap = pango_ft2_font_map_new ();
114 root 1.19 pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, substitute_func, 0, 0);
115 root 1.8 context = pango_ft2_font_map_create_context ((PangoFT2FontMap *)fontmap);
116 root 1.5 }
117    
118 root 1.10 void
119     lowdelay (int fd, int val = 1)
120     CODE:
121     setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
122    
123 root 1.3 char *
124 root 1.4 gl_version ()
125     CODE:
126 root 1.5 RETVAL = (char *)glGetString (GL_VERSION);
127 root 1.4 OUTPUT:
128     RETVAL
129    
130     char *
131 root 1.3 gl_extensions ()
132     CODE:
133 root 1.5 RETVAL = (char *)glGetString (GL_EXTENSIONS);
134 root 1.3 OUTPUT:
135     RETVAL
136    
137 root 1.5 void
138 root 1.13 add_font (char *file)
139     CODE:
140     FcConfigAppFontAddFile (0, (const FcChar8 *)file); /* no idea wether this is required */
141    
142     void
143 root 1.9 set_font (char *file)
144 root 1.8 CODE:
145     {
146 root 1.9 int count;
147     FcPattern *pattern = FcFreeTypeQuery ((const FcChar8 *)file, 0, 0, &count);
148 root 1.10 PangoFontDescription *font = pango_fc_font_description_from_pattern (pattern, 0);
149 root 1.9 FcPatternDestroy (pattern);
150 root 1.8 pango_context_set_font_description (context, font);
151     }
152    
153 root 1.23 void
154     load_image_inline (SV *image_)
155     ALIAS:
156     load_image_file = 1
157     PPCODE:
158     {
159     STRLEN image_len;
160     char *image = (char *)SvPVbyte (image_, image_len);
161     SDL_Surface *surface, *surface2;
162     SDL_PixelFormat fmt;
163     SDL_RWops *rw = ix
164     ? SDL_RWFromFile (image, "r")
165     : SDL_RWFromConstMem (image, image_len);
166    
167     if (!rw)
168     croak ("load_image: unable to open file");
169    
170     surface = IMG_Load_RW (rw, 1);
171     if (!surface)
172     croak ("load_image: unable to read file");
173    
174     fmt.palette = NULL;
175     fmt.BitsPerPixel = 32;
176     fmt.BytesPerPixel = 4;
177     fmt.Rmask = 0x000000ff;
178     fmt.Gmask = 0x0000ff00;
179     fmt.Bmask = 0x00ff0000;
180     fmt.Amask = 0xff000000;
181     fmt.Rloss = 0;
182     fmt.Gloss = 0;
183     fmt.Bloss = 0;
184     fmt.Aloss = 0;
185     fmt.Rshift = 0;
186     fmt.Gshift = 8;
187     fmt.Bshift = 16;
188     fmt.Ashift = 24;
189     fmt.colorkey = 0;
190     fmt.alpha = 0;
191    
192     surface2 = SDL_ConvertSurface (surface, &fmt, SDL_SWSURFACE);
193    
194     EXTEND (SP, 5);
195     PUSHs (sv_2mortal (newSViv (surface2->w)));
196     PUSHs (sv_2mortal (newSViv (surface2->h)));
197     SDL_LockSurface (surface2);
198     PUSHs (sv_2mortal (newSVpvn (surface2->pixels, surface2->h * surface2->pitch)));
199     SDL_UnlockSurface (surface2);
200 root 1.24 PUSHs (sv_2mortal (newSViv (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA) ? GL_RGBA : GL_RGB)));
201 root 1.23 PUSHs (sv_2mortal (newSViv (GL_RGBA)));
202     PUSHs (sv_2mortal (newSViv (GL_UNSIGNED_INT_8_8_8_8_REV)));
203    
204     SDL_FreeSurface (surface);
205     SDL_FreeSurface (surface2);
206     }
207    
208 root 1.25 void
209     fatal (char *message)
210     CODE:
211     #ifdef WIN32
212     MessageBox (0, message, "Crossfire+ Fatal Error", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
213     #else
214     fprintf (stderr, "%s\n", message);
215     #endif
216     exit (1);
217    
218 root 1.15 MODULE = CFClient PACKAGE = CFClient::Layout
219 root 1.14
220 root 1.15 CFClient::Layout
221 root 1.14 new (SV *class, int base_height = 10)
222     CODE:
223     New (0, RETVAL, 1, struct cf_layout);
224     RETVAL->base_height = base_height;
225     RETVAL->pl = pango_layout_new (context);
226     pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR);
227     OUTPUT:
228     RETVAL
229    
230     void
231 root 1.15 DESTROY (CFClient::Layout self)
232 root 1.14 CODE:
233     g_object_unref (self->pl);
234     Safefree (self);
235 root 1.13
236 root 1.8 void
237 root 1.15 set_markup (CFClient::Layout self, SV *text_)
238 root 1.14 CODE:
239 root 1.5 {
240     STRLEN textlen;
241     char *text = SvPVutf8 (text_, textlen);
242 root 1.14
243     pango_layout_set_markup (self->pl, text, textlen);
244     }
245    
246     void
247 root 1.16 set_height (CFClient::Layout self, int base_height)
248     CODE:
249     self->base_height = base_height;
250    
251     void
252 root 1.15 set_width (CFClient::Layout self, int max_width = -1)
253 root 1.14 CODE:
254     pango_layout_set_width (self->pl, max_width < 0 ? max_width : max_width * PANGO_SCALE);
255    
256     void
257 root 1.15 size (CFClient::Layout self)
258 root 1.14 PPCODE:
259     {
260     int w, h;
261    
262 root 1.17 layout_update (self);
263 root 1.14 layout_get_pixel_size (self, &w, &h);
264    
265     EXTEND (SP, 2);
266     PUSHs (sv_2mortal (newSViv (w)));
267     PUSHs (sv_2mortal (newSViv (h)));
268     }
269    
270 root 1.17 int
271     xy_to_index (CFClient::Layout self, int x, int y)
272     CODE:
273     {
274     int index, trailing;
275    
276     layout_update (self);
277     pango_layout_xy_to_index (self->pl, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
278    
279     RETVAL = index;
280     }
281     OUTPUT:
282     RETVAL
283    
284     void
285     cursor_pos (CFClient::Layout self, int index)
286     PPCODE:
287     {
288     PangoRectangle strong_pos;
289     layout_update (self);
290     pango_layout_get_cursor_pos (self->pl, index, &strong_pos, 0);
291     EXTEND (SP, 3);
292     PUSHs (sv_2mortal (newSViv (strong_pos.x / PANGO_SCALE)));
293     PUSHs (sv_2mortal (newSViv (strong_pos.y / PANGO_SCALE)));
294     PUSHs (sv_2mortal (newSViv (strong_pos.height / PANGO_SCALE)));
295     }
296    
297 root 1.14 void
298 root 1.15 render (CFClient::Layout self)
299 root 1.14 PPCODE:
300     {
301 root 1.5 SV *retval;
302     int w, h;
303     FT_Bitmap bitmap;
304    
305 root 1.17 layout_update (self);
306 root 1.14 layout_get_pixel_size (self, &w, &h);
307 root 1.5
308     retval = newSV (w * h);
309     SvPOK_only (retval);
310     SvCUR_set (retval, w * h);
311    
312     bitmap.rows = h;
313     bitmap.width = w;
314     bitmap.pitch = w;
315     bitmap.buffer = (unsigned char*)SvPVX (retval);
316     bitmap.num_grays = 256;
317     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
318    
319     memset (bitmap.buffer, 0, w * h);
320    
321 root 1.14 pango_ft2_render_layout (&bitmap, self->pl, 0 * PANGO_SCALE, 0 * PANGO_SCALE);
322 root 1.1
323 root 1.5 EXTEND (SP, 3);
324     PUSHs (sv_2mortal (newSViv (w)));
325     PUSHs (sv_2mortal (newSViv (h)));
326     PUSHs (sv_2mortal (retval));
327     }
328 root 1.11
329 root 1.15 MODULE = CFClient PACKAGE = CFClient::Texture
330 root 1.11
331     void
332 root 1.12 draw_quad (SV *self, double x, double y, double w = 0, double h = 0)
333     PROTOTYPE: $$$;$$
334 root 1.11 CODE:
335     {
336 root 1.12 HV *hv = (HV *)SvRV (self);
337     double s = SvNV (*hv_fetch (hv, "s", 1, 1));
338     double t = SvNV (*hv_fetch (hv, "t", 1, 1));
339     int name = SvIV (*hv_fetch (hv, "name", 4, 1));
340    
341     if (items < 5)
342     {
343 root 1.18 w = SvNV (*hv_fetch (hv, "w", 1, 1));
344     h = SvNV (*hv_fetch (hv, "h", 1, 1));
345 root 1.12 }
346    
347     glBindTexture (GL_TEXTURE_2D, name);
348     glBegin (GL_QUADS);
349     glTexCoord2d (0, 0); glVertex2d (x , y );
350     glTexCoord2d (0, t); glVertex2d (x , y + h);
351     glTexCoord2d (s, t); glVertex2d (x + w, y + h);
352     glTexCoord2d (s, 0); glVertex2d (x + w, y );
353     glEnd ();
354 root 1.11 }
355 root 1.28
356     MODULE = CFClient PACKAGE = CFClient::Map
357    
358     CFClient::Map
359     new (SV *class, int map_width, int map_height)
360     CODE:
361     New (0, RETVAL, 1, struct map);
362     RETVAL->x = 0;
363     RETVAL->y = 0;
364     RETVAL->w = map_width;
365     RETVAL->h = map_height;
366 root 1.29 RETVAL->faces = 1;
367     Newz (0, RETVAL->face, 1, GLint);
368 root 1.28 RETVAL->rows = 0;
369     RETVAL->row = 0;
370 root 1.29 printf ("new map %d,%d\n", map_width, map_height);//D
371 root 1.28 OUTPUT:
372     RETVAL
373    
374     void
375     DESTROY (CFClient::Map self)
376     CODE:
377     {
378     int r, c;
379    
380 root 1.29 printf ("detroy map\n");//D
381 root 1.28 Safefree (self->face);
382 root 1.29
383 root 1.28 for (r = 0; r < self->rows; r++)
384 root 1.29 Safefree (self->row[r].col);
385    
386     Safefree (self->row);
387     Safefree (self);
388     }
389    
390     void
391     set_face (CFClient::Map self, int facenum, int face)
392     CODE:
393     {
394     while (self->faces < facenum)
395 root 1.28 {
396 root 1.29 printf ("setface %d (%d) = %d\n",facenum, self->faces, face);//D
397     Renew (self->face, self->faces * 2, GLint);
398     Zero (self->face + self->faces, self->faces, GLint);
399     self->faces *= 2;
400     }
401 root 1.28
402 root 1.29 self->face [facenum] = face;
403     }
404    
405     void
406     scroll (CFClient::Map self, int dx, int dy)
407     CODE:
408     {
409     printf ("map_scroll %d,%d\n", dx, dy);//D
410     if (dx > 0)
411     map_blank (self, self->x, self->y, dx - 1, self->h);
412     else if (dx < 0)
413     map_blank (self, self->x + self->w + dx + 1, self->y, 1 - dx, self->h);
414    
415     if (dy > 0)
416     map_blank (self, self->x, self->y, self->w, dy - 1);
417     else if (dy < 0)
418     map_blank (self, self->x, self->y + self->h + dy + 1, self->w, 1 - dy);
419    
420     self->x += dx;
421     self->y += dy;
422    
423     while (self->y < 0)
424     {
425     maprow *row;
426    
427     New (0, row, self->rows + MAP_EXTEND_Y, maprow);
428     Move (self->row, row + MAP_EXTEND_Y, self->rows, maprow);
429     Zero (row, MAP_EXTEND_Y, maprow);
430    
431     self->rows += MAP_EXTEND_Y;
432     self->y += MAP_EXTEND_Y;
433     self->row = row;
434     }
435    
436     if (self->x < 0)
437     {
438     int y;
439     for (y = 0; y < self->rows; y++)
440     {
441     self->row[y].c0 += self->x;
442     self->row[y].c1 += self->x;
443     }
444    
445     self->x = 0;
446 root 1.28 }
447 root 1.29 }
448 root 1.28
449 root 1.29 void
450     map1a_update (CFClient::Map self, SV *data_)
451     CODE:
452     {
453     uint8_t *data = (uint8_t *)SvPVbytes_nolen (data_);
454     uint8_t *data_end = (uint8_t *)SvEND (data_) + 1;
455    
456     while (data < data_end)
457     {
458     int flags = (data [0] << 8) + data [1]; data += 2;
459     int x = ((flags >> 10) & 63) + self->x;
460     int y = ((flags >> 4) & 63) + self->y;
461    
462     while (y >= self->rows)
463     {
464     Renew (self->row, self->rows + MAP_EXTEND_Y, maprow);
465     Zero (self->row + self->rows, MAP_EXTEND_Y, maprow);
466    
467     self->rows += MAP_EXTEND_Y;
468     }
469    
470     assert (y < self->rows);//D
471    
472     maprow *row = self->row + y;
473    
474     if (!row->col)
475     {
476     Newz (0, row->col, MAP_EXTEND_X, mapcell);
477     row->c0 = self->x - MAP_EXTEND_X / 4;
478     row->c1 = row->c0 + MAP_EXTEND_X;
479     }
480    
481     if (row->c0 > x)
482     {
483     int extend = row->c0 - x + MAP_EXTEND_X;
484     mapcell *col;
485    
486     New (0, col, row->c1 - row->c0 + extend, mapcell);
487     Move (row->col, col + extend, row->c1 - row->c0, mapcell);
488     Zero (col, extend, mapcell);
489    
490     row->col = col;
491     row->c0 -= extend;
492     }
493     else if (x >= row->c1)
494     {
495     int extend = x - row->c1 + MAP_EXTEND_X;
496    
497     Renew (row->col, row->c1 - row->c0 + extend, mapcell);
498     Zero (row->col + row->c1 - row->c0, extend, mapcell);
499    
500     row->c1 += extend;
501     }
502    
503     assert (x >= row->c0);//D
504     assert (x < row->c1);//D
505     mapcell *cell = row->col + (x - row->c0);
506    
507     if (flags & 15)
508     {
509     if (cell->darkness < 0)
510     {
511     cell->darkness = 0;
512     cell->face [0] = 0;
513     cell->face [1] = 0;
514     cell->face [2] = 0;
515     }
516    
517     cell->darkness = flags & 8 ? *data++ : 255;
518    
519     if (flags & 4)
520     {
521     cell->face [0] = (data [0] << 8) + data [1]; data += 2;
522     }
523    
524     if (flags & 2)
525     {
526     cell->face [1] = (data [0] << 8) + data [1]; data += 2;
527     }
528    
529     if (flags & 1)
530     {
531     cell->face [2] = (data [0] << 8) + data [1]; data += 2;
532     }
533     }
534     else
535     cell->darkness = -1;
536     }
537 root 1.28 }
538