--- deliantra/Deliantra-Client/Client.xs 2007/07/29 04:14:45 1.213 +++ deliantra/Deliantra-Client/Client.xs 2007/08/19 12:56:24 1.230 @@ -19,6 +19,11 @@ #ifdef _WIN32 # undef pipe +// microsoft vs. C +# define sqrtf(x) sqrt(x) +# define roundf(x) (int)(x) +# define atan2f(x,y) atan2(x,y) +# define M_PI 3.14159265f #endif #include @@ -111,6 +116,7 @@ } #include "texcache.c" +#include "rendercache.c" #include "pango-font.c" #include "pango-fontmap.c" @@ -146,6 +152,7 @@ float r, g, b, a; // default color for rgba mode int base_height; CFPlus__Font font; + rc_t *rc; } *CFPlus__Layout; static CFPlus__Font default_font; @@ -198,7 +205,7 @@ typedef uint16_t faceid; typedef struct { - int name; + GLuint name; int w, h; float s, t; uint8_t r, g, b, a; @@ -710,7 +717,7 @@ { av_clear (texture_av); - SDL_WM_SetCaption ("Crossfire+ Client " VERSION, "Crossfire+"); + SDL_WM_SetCaption ("Crossfire TRT Client " VERSION, "Crossfire TRT"); #define GL_FUNC(ptr,name) gl.name = (ptr)SDL_GL_GetProcAddress ("gl" # name); #include "glfunc.h" #undef GL_FUNC @@ -806,7 +813,7 @@ } int -Mix_OpenAudio (int frequency = 44100, int format = MIX_DEFAULT_FORMAT, int channels = 2, int chunksize = 4096) +Mix_OpenAudio (int frequency = 44100, int format = MIX_DEFAULT_FORMAT, int channels = 2, int chunksize = 1024) POSTCALL: Mix_HookMusicFinished (music_finished); Mix_ChannelFinished (channel_finished); @@ -817,6 +824,9 @@ int Mix_AllocateChannels (int numchans = -1) +const char * +Mix_GetError () + void lowdelay (int fd, int val = 1) CODE: @@ -1029,6 +1039,7 @@ RETVAL->a = 1.; RETVAL->base_height = MIN_FONT_HEIGHT; RETVAL->font = 0; + RETVAL->rc = rc_alloc (); pango_layout_set_wrap (RETVAL->pl, PANGO_WRAP_WORD_CHAR); layout_update_font (RETVAL); @@ -1039,6 +1050,7 @@ DESTROY (CFPlus::Layout self) CODE: g_object_unref (self->pl); + rc_free (self->rc); Safefree (self); void @@ -1300,13 +1312,37 @@ void render (CFPlus::Layout self, float x, float y, int flags = 0) - PPCODE: + CODE: + rc_clear (self->rc); pango_opengl_render_layout_subpixel ( self->pl, + self->rc, x * PANGO_SCALE, y * PANGO_SCALE, self->r, self->g, self->b, self->a, flags ); + // we assume that context_change actually clears/frees stuff + // and does not do any recomputation... + pango_layout_context_changed (self->pl); + +void +draw (CFPlus::Layout self) + CODE: +{ + glEnable (GL_TEXTURE_2D); + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glEnable (GL_BLEND); + gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, + GL_ONE , GL_ONE_MINUS_SRC_ALPHA); + glEnable (GL_ALPHA_TEST); + glAlphaFunc (GL_GREATER, 7.f / 255.f); + + rc_draw (self->rc); + + glDisable (GL_ALPHA_TEST); + glDisable (GL_BLEND); + glDisable (GL_TEXTURE_2D); +} MODULE = CFPlus PACKAGE = CFPlus::Texture @@ -1349,6 +1385,9 @@ float t = SvNV (*hv_fetch (hv, "t", 1, 1)); int name = SvIV (*hv_fetch (hv, "name", 4, 1)); + if (name <= 0) + XSRETURN_EMPTY; + if (items < 5) { w = SvNV (*hv_fetch (hv, "w", 1, 1)); @@ -1546,14 +1585,16 @@ } } -void +SV * map1a_update (CFPlus::Map self, SV *data_, int extmap) CODE: { uint8_t *data = (uint8_t *)SvPVbyte_nolen (data_); uint8_t *data_end = (uint8_t *)SvEND (data_); mapcell *cell; - int x, y, flags; + int x, y, z, flags; + AV *missing = newAV (); + RETVAL = newRV_noinc ((SV *)missing); while (data < data_end - 1) { @@ -1614,31 +1655,34 @@ cell->darkness = *data++ + 1; } - if (flags & 4) - { - faceid face = (data [0] << 8) + data [1]; data += 2; - need_facenum (self, face); - cell->tile [0] = self->face2tile [face]; - } + for (z = 0; z <= 2; ++z) + if (flags & (4 >> z)) + { + faceid face = (data [0] << 8) + data [1]; data += 2; + need_facenum (self, face); + cell->tile [z] = self->face2tile [face]; - if (flags & 2) - { - faceid face = (data [0] << 8) + data [1]; data += 2; - need_facenum (self, face); - cell->tile [1] = self->face2tile [face]; - } + if (cell->tile [z]) + { + maptex *tex = self->tex + cell->tile [z]; + if (!tex->name) + av_push (missing, newSViv (cell->tile [z])); - if (flags & 1) - { - faceid face = (data [0] << 8) + data [1]; data += 2; - need_facenum (self, face); - cell->tile [2] = self->face2tile [face]; - } + if (tex->smoothtile) + { + maptex *smooth = self->tex + tex->smoothtile; + if (!smooth->name) + av_push (missing, newSViv (tex->smoothtile)); + } + } + } } else cell->darkness = 0; } } + OUTPUT: + RETVAL SV * mapmap (CFPlus::Map self, int x0, int y0, int w, int h) @@ -1699,12 +1743,16 @@ draw (CFPlus::Map self, int mx, int my, int sw, int sh, int T) CODE: { + int x, y, z; + HV *smooth = (HV *)sv_2mortal ((SV *)newHV ()); uint32_t smooth_level[256 / 32]; // one bit for every possible smooth level - static uint8_t smooth_max[256][256]; // egad, fats and wasteful on memory (64k) + static uint8_t smooth_max[256][256]; // egad, fast and wasteful on memory (64k) smooth_key skey; - int x, y, z; - int last_name; + + rc_t *rc = rc_alloc (); + rc_key_t key; + rc_array_t *arr; // thats current max. sorry. if (sw > 255) sw = 255; @@ -1713,16 +1761,14 @@ // clear key, in case of extra padding memset (&skey, 0, sizeof (skey)); - glColor4ub (255, 255, 255, 255); - - glEnable (GL_BLEND); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_TEXTURE_2D); - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - - glBegin (GL_QUADS); - - last_name = 0; + memset (&key, 0, sizeof (key)); + key.r = 255; + key.g = 255; + key.b = 255; + key.a = 255; + key.mode = GL_QUADS; + key.format = GL_T2F_V3F; + key.texname = -1; mx += self->x; my += self->y; @@ -1749,6 +1795,10 @@ } } + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + for (z = 0; z <= 2; z++) { memset (smooth_level, 0, sizeof (smooth_level)); @@ -1767,42 +1817,47 @@ if (tile) { maptex tex = self->tex [tile]; - int px = (x + 1) * T - tex.w; - int py = (y + 1) * T - tex.h; + int px, py; - // suppressing texture state switches here - // is only moderately effective, but worth the extra effort - if (last_name != tex.name) + if (key.texname != tex.name) { if (!tex.name) tex = self->tex [2]; /* missing, replace by noface */ - glEnd (); - glBindTexture (GL_TEXTURE_2D, last_name = tex.name); - glBegin (GL_QUADS); + key.texname = tex.name; + arr = rc_array (rc, &key); } - glTexCoord2f (0 , 0 ); glVertex2f (px , py ); - glTexCoord2f (0 , tex.t); glVertex2f (px , py + tex.h); - glTexCoord2f (tex.s, tex.t); glVertex2f (px + tex.w, py + tex.h); - glTexCoord2f (tex.s, 0 ); glVertex2f (px + tex.w, py ); + px = (x + 1) * T - tex.w; + py = (y + 1) * T - tex.h; + + rc_t2f_v3f (arr, 0 , 0 , px , py , 0); + rc_t2f_v3f (arr, 0 , tex.t, px , py + tex.h, 0); + rc_t2f_v3f (arr, tex.s, tex.t, px + tex.w, py + tex.h, 0); + rc_t2f_v3f (arr, tex.s, 0 , px + tex.w, py , 0); if (cell->flags && z == 2) { + // overlays such as the speech bubble, probably more to come if (cell->flags & 1) { maptex tex = self->tex [1]; int px = x * T + T * 2 / 32; int py = y * T - T * 6 / 32; - glEnd (); - glBindTexture (GL_TEXTURE_2D, last_name = tex.name); - glBegin (GL_QUADS); - - glTexCoord2f (0 , 0 ); glVertex2f (px , py ); - glTexCoord2f (0 , tex.t); glVertex2f (px , py + T); - glTexCoord2f (tex.s, tex.t); glVertex2f (px + T, py + T); - glTexCoord2f (tex.s, 0 ); glVertex2f (px + T, py ); + if (tex.name) + { + if (key.texname != tex.name) + { + key.texname = tex.name; + arr = rc_array (rc, &key); + } + + rc_t2f_v3f (arr, 0 , 0 , px , py , 0); + rc_t2f_v3f (arr, 0 , tex.t, px , py + T, 0); + rc_t2f_v3f (arr, tex.s, tex.t, px + T, py + T, 0); + rc_t2f_v3f (arr, tex.s, 0 , px + T, py , 0); + } } } @@ -1848,11 +1903,16 @@ } } + rc_draw (rc); + rc_clear (rc); + // go through all smoothlevels, lowest to highest, then draw. // this is basically counting sort { int w, b; + glEnable (GL_TEXTURE_2D); + glBegin (GL_QUADS); for (w = 0; w < 256 / 32; ++w) { uint32_t smask = smooth_level [w]; @@ -1881,50 +1941,52 @@ float dx = tex.s * .0625f; // 16 images/row float dy = tex.t * .5f ; // 2 images/column - // this time naively avoiding texture state changes - // save gobs of state changes. - if (last_name != tex.name) - { - if (!tex.name) - continue; // smoothing not yet available - - glEnd (); - glBindTexture (GL_TEXTURE_2D, last_name = tex.name); - glBegin (GL_QUADS); - } - - if (border) - { - float ox = border * dx; - - glTexCoord2f (ox , 0.f ); glVertex2f (px , py ); - glTexCoord2f (ox , dy ); glVertex2f (px , py + T); - glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py + T); - glTexCoord2f (ox + dx, 0.f ); glVertex2f (px + T, py ); - } - - if (corner) + if (tex.name) { - float ox = corner * dx; - - glTexCoord2f (ox , dy ); glVertex2f (px , py ); - glTexCoord2f (ox , dy * 2.f); glVertex2f (px , py + T); - glTexCoord2f (ox + dx, dy * 2.f); glVertex2f (px + T, py + T); - glTexCoord2f (ox + dx, dy ); glVertex2f (px + T, py ); + // this time avoiding texture state changes + // save gobs of state changes. + if (key.texname != tex.name) + { + glEnd (); + glBindTexture (GL_TEXTURE_2D, key.texname = tex.name); + glBegin (GL_QUADS); + } + + if (border) + { + float ox = border * dx; + + glTexCoord2f (ox , 0.f ); glVertex2i (px , py ); + glTexCoord2f (ox , dy ); glVertex2i (px , py + T); + glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py + T); + glTexCoord2f (ox + dx, 0.f ); glVertex2i (px + T, py ); + } + + if (corner) + { + float ox = corner * dx; + + glTexCoord2f (ox , dy ); glVertex2i (px , py ); + glTexCoord2f (ox , dy * 2.f); glVertex2i (px , py + T); + glTexCoord2f (ox + dx, dy * 2.f); glVertex2i (px + T, py + T); + glTexCoord2f (ox + dx, dy ); glVertex2i (px + T, py ); + } } } } } } + + glEnd (); + glDisable (GL_TEXTURE_2D); + key.texname = -1; } hv_clear (smooth); } - glEnd (); - - glDisable (GL_TEXTURE_2D); glDisable (GL_BLEND); + rc_free (rc); // top layer: overlays such as the health bar for (y = 0; y < sh; y++) @@ -2183,7 +2245,7 @@ int x1, y1; if (*data++ != 0) - return; /* version mismatch */ + XSRETURN_EMPTY; /* version mismatch */ w = *data++ << 8; w |= *data++; h = *data++ << 8; h |= *data++; @@ -2259,15 +2321,39 @@ OUTPUT: RETVAL -void -close (CFPlus::RW self) - CODE: - SDL_RWclose (self); +# fails on win32: +# CFPlus.xs(2268) : error C2059: syntax error : '(' +#void +#close (CFPlus::RW self) +# CODE: +# (self->(close)) (self); MODULE = CFPlus PACKAGE = CFPlus::Channel PROTOTYPES: DISABLE +CFPlus::Channel +find () + CODE: +{ + RETVAL = Mix_GroupAvailable (-1); + + if (RETVAL < 0) + { + RETVAL = Mix_GroupOldest (-1); + + if (RETVAL < 0) + XSRETURN_UNDEF; + + Mix_HaltChannel (RETVAL); + } + + Mix_UnregisterAllEffects (RETVAL); + Mix_Volume (RETVAL, 128); +} + OUTPUT: + RETVAL + void halt (CFPlus::Channel self) CODE: @@ -2286,7 +2372,7 @@ int volume (CFPlus::Channel self, int volume) CODE: - RETVAL = Mix_Volume (self, volume); + RETVAL = Mix_Volume (self, CLAMP (volume, 0, 128)); OUTPUT: RETVAL @@ -2298,17 +2384,27 @@ void set_panning (CFPlus::Channel self, int left, int right) CODE: + left = CLAMP (left , 0, 255); + right = CLAMP (right, 0, 255); Mix_SetPanning (self, left, right); void set_distance (CFPlus::Channel self, int distance) CODE: - Mix_SetDistance (self, distance); + Mix_SetDistance (self, CLAMP (distance, 0, 255)); void set_position (CFPlus::Channel self, int angle, int distance) CODE: - Mix_SetPosition (self, angle, distance); + +void +set_position_r (CFPlus::Channel self, int dx, int dy, int maxdistance) + CODE: +{ + int distance = sqrtf (dx * dx + dy * dy) * (255.f / sqrtf (maxdistance * maxdistance)); + int angle = 360 + (int)roundf (atan2f (dx, -dy) * 180.f / (float)M_PI); + Mix_SetPosition (self, angle, CLAMP (distance, 0, 255)); +} void set_reverse_stereo (CFPlus::Channel self, int flip) @@ -2334,15 +2430,27 @@ int volume (CFPlus::MixChunk self, int volume = -1) CODE: + if (items > 1) + volume = CLAMP (volume, 0, 128); RETVAL = Mix_VolumeChunk (self, volume); OUTPUT: RETVAL CFPlus::Channel -play (CFPlus::MixChunk self, int channel = -1, int loops = 0, int ticks = -1) +play (CFPlus::MixChunk self, CFPlus::Channel channel = -1, int loops = 0, int ticks = -1) CODE: +{ RETVAL = Mix_PlayChannelTimed (channel, self, loops, ticks); - Mix_UnregisterAllEffects (RETVAL); + + if (RETVAL < 0) + XSRETURN_UNDEF; + + if (channel < 0) + { + Mix_UnregisterAllEffects (RETVAL); + Mix_Volume (RETVAL, 128); + } +} OUTPUT: RETVAL @@ -2352,6 +2460,8 @@ volume (int volume = -1) PROTOTYPE: ;$ CODE: + if (items > 0) + volume = CLAMP (volume, 0, 128); RETVAL = Mix_VolumeMusic (volume); OUTPUT: RETVAL @@ -2441,6 +2551,12 @@ const_iv (GL_LUMINANCE_ALPHA), const_iv (GL_FLOAT), const_iv (GL_UNSIGNED_INT_8_8_8_8_REV), + const_iv (GL_COMPRESSED_ALPHA_ARB), + const_iv (GL_COMPRESSED_LUMINANCE_ARB), + const_iv (GL_COMPRESSED_LUMINANCE_ALPHA_ARB), + const_iv (GL_COMPRESSED_INTENSITY_ARB), + const_iv (GL_COMPRESSED_RGB_ARB), + const_iv (GL_COMPRESSED_RGBA_ARB), const_iv (GL_COMPILE), const_iv (GL_PROXY_TEXTURE_1D), const_iv (GL_PROXY_TEXTURE_2D), @@ -2746,8 +2862,7 @@ SV *draw_y_sv = GvSV (draw_y_gv); SV *draw_w_sv = GvSV (draw_w_gv); SV *draw_h_sv = GvSV (draw_h_gv); - SV *hover; - double draw_x, draw_y, draw_w, draw_h; + double draw_x, draw_y; if (!SvROK (self)) croak ("CFPlus::Base::draw: %s not a reference", SvPV_nolen (self)); @@ -2785,7 +2900,7 @@ if (svp && SvTRUE (*svp)) { - glColor4f (1*0.2f, 0.8*0.2f, 0.5*0.2f, 0.2f); + glColor4f (1.0f * 0.2f, 0.8f * 0.2f, 0.5f * 0.2f, 0.2f); glEnable (GL_BLEND); glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBegin (GL_QUADS);