--- deliantra/Deliantra-Client/rendercache.c 2008/01/13 08:31:45 1.9 +++ deliantra/Deliantra-Client/rendercache.c 2018/11/19 01:37:28 1.16 @@ -1,178 +1,162 @@ -typedef struct { +#include + +#include "salloc.h" + +struct rc_key_t +{ GLenum mode; GLenum format; // 0, GL_T2F_V3F, GL_V2F GLuint texname; unsigned char r, g, b, a; -} rc_key_t; - -typedef struct { - HV *hv; -} rc_t; - -typedef SV rc_array_t; - -static rc_t * -rc_alloc (void) -{ - rc_t *rc = g_slice_new0 (rc_t); - rc->hv = newHV (); - - return rc; -} - -static void -rc_free (rc_t *rc) -{ - SvREFCNT_dec (rc->hv); - g_slice_free (rc_t, rc); -} - -static void -rc_clear (rc_t *rc) -{ - hv_clear (rc->hv); -} - -static rc_array_t * -rc_array (rc_t *rc, rc_key_t *k) -{ - SV *sv = *hv_fetch (rc->hv, (char *)k, sizeof (*k), 1); - if (SvTYPE (sv) != SVt_PV) + bool operator == (const rc_key_t &o) const + { + return mode == o.mode + && format == o.format + && texname == o.texname + && r == o.r + && g == o.g + && b == o.b + && a == o.a; + } +}; + +namespace std { + template <> + struct hash + { + size_t operator () (const rc_key_t &v) const { - sv_upgrade (sv, SVt_PV); - SvPOK_only (sv); + return v.mode + (v.format << 4) + v.texname + (v.r << 8) + (v.g << 16) + (v.b << 24) + v.a; } - - return sv; + }; } -static void -rc_v2f (rc_array_t *arr, float x, float y) +struct rc_t { - STRLEN len = SvCUR (arr) + sizeof (float) * 2; - SvGROW (arr, len); - - ((float *)SvEND (arr))[0] = x; - ((float *)SvEND (arr))[1] = y; + struct glyph_data + { + uint8_t u, v, w, h; + uint16_t x, y; + }; - SvCUR_set (arr, len); -} - -static void -rc_t2f_v3f (rc_array_t *arr, float u, float v, float x, float y, float z) -{ - STRLEN len = SvCUR (arr) + sizeof (float) * 5; - SvGROW (arr, len); + struct array_t + : std::vector> + { + using std::vector>::vector; - ((float *)SvEND (arr))[0] = u; - ((float *)SvEND (arr))[1] = v; - - ((float *)SvEND (arr))[2] = x; - ((float *)SvEND (arr))[3] = y; - ((float *)SvEND (arr))[4] = z; - - SvCUR_set (arr, len); -} - -static void -rc_glyph (rc_array_t *arr, int u, int v, int w, int h, int x, int y) -{ - if (w && h) + template + T &append () { - U8 *c; - STRLEN len = SvCUR (arr); - SvGROW (arr, len + 2 * 2 + 1 * 4); - c = (U8 *)SvEND (arr); - - x += w; - y += h; - - *c++ = u; - *c++ = v; - *c++ = w; - *c++ = h; - - // use ber-encoding for up to 14 bits (16k) - *c = 0x80 | (x >> 7); c += (x >> 7) ? 1 : 0; *c++ = x & 0x7f; - *c = 0x80 | (y >> 7); c += (y >> 7) ? 1 : 0; *c++ = y & 0x7f; - - SvCUR_set (arr, c - (U8 *)SvPVX (arr)); + auto ofs = size (); + resize (ofs + sizeof (T)); + return *(T *)(data () + ofs); } -} - -static void -rc_draw (rc_t *rc) -{ - HE *he; - hv_iterinit (rc->hv); - while ((he = hv_iternext (rc->hv))) + void v2f (float x, float y) { - rc_key_t *key = (rc_key_t *)HeKEY (he); - rc_array_t *arr = HeVAL (he); - STRLEN len; - char *arr_pv = SvPV (arr, len); - GLsizei stride; - - if (key->texname) - { - glBindTexture (GL_TEXTURE_2D, key->texname); - glEnable (GL_TEXTURE_2D); - } - else - glDisable (GL_TEXTURE_2D); + auto &vec = append (); + vec[0] = x / 2; + vec[1] = y / 2; + } - glColor4ub (key->r, key->g, key->b, key->a); + void t2f_v3f (float u, float v, float x, float y, float z) + { + auto &vec = append (); + vec[0] = u; + vec[1] = v; + vec[2] = x; + vec[3] = y; + vec[4] = z; + } - if (key->format) - { - stride = key->format == GL_T2F_V3F ? sizeof (float) * 5 - : key->format == GL_V2F ? sizeof (float) * 2 - : 65536; - - glInterleavedArrays (key->format, 0, (void *)arr_pv); - //glLockArraysEXT (0, len / stride); - glDrawArrays (key->mode, 0, len / stride); - //glUnlockArraysEXT (); - } - else + void glyph (int u, int v, int w, int h, int x, int y) + { + if (w && h) { - // optimised character quad storage. slower but nice on memory. - // reduces storage requirements from 80 bytes/char to 6-8 - U8 *c = (U8 *)arr_pv; - U8 *e = c + len; - - glBegin (key->mode); // practically must be quads - - while (c < e) - { - int u, v, x, y, w, h; - - u = *c++; - v = *c++; - w = *c++; - h = *c++; - - x = *c++; if (x > 0x7f) x = ((x & 0x7f) << 7) | *c++; - y = *c++; if (y > 0x7f) y = ((y & 0x7f) << 7) | *c++; - - x -= w; - y -= h; - - glTexCoord2f ( u * (1.f / TC_WIDTH), v * (1.f / TC_HEIGHT)); glVertex2i (x , y ); - glTexCoord2f ((u + w) * (1.f / TC_WIDTH), v * (1.f / TC_HEIGHT)); glVertex2i (x + w, y ); - glTexCoord2f ((u + w) * (1.f / TC_WIDTH), (v + h) * (1.f / TC_HEIGHT)); glVertex2i (x + w, y + h); - glTexCoord2f ( u * (1.f / TC_WIDTH), (v + h) * (1.f / TC_HEIGHT)); glVertex2i (x , y + h); - } + auto &c = append (); - glEnd (); + c.u = u; + c.v = v; + c.w = w; + c.h = h; + c.x = x + w; + c.y = y + h; } } + }; - glDisable (GL_TEXTURE_2D); -} - - + int drawcount = 0; + ska::flat_hash_map, std::equal_to, slice_allocator> h; + void clear () + { + drawcount = 0; + h.clear (); + } + + array_t &array (const rc_key_t &k) + { + return h[k]; + } + + void draw () + { + for (auto &&it = h.begin (); it != h.end (); ++it) + { + rc_key_t &key = it->first; + array_t &arr = it->second; + GLsizei stride; + + if (key.texname) + { + glBindTexture (GL_TEXTURE_2D, key.texname); + glEnable (GL_TEXTURE_2D); + } + else + glDisable (GL_TEXTURE_2D); + + glColor4ub (key.r, key.g, key.b, key.a); + + if (key.format) + { + stride = key.format == GL_T2F_V3F ? sizeof (float) * 5 + : key.format == GL_V2F ? sizeof (float) * 2 + : 65536; + + glInterleavedArrays (key.format, 0, (void *)arr.data ()); + //glLockArraysEXT (0, len / stride); + glDrawArrays (key.mode, 0, arr.size () / stride); + //glUnlockArraysEXT (); + } + else + { + // optimised character quad storage. slower but nice on memory. + // reduces storage requirements from 80 bytes/char to 8 + auto *c = (glyph_data *) arr.data (); + auto *e = (glyph_data *)(arr.data () + arr.size ()); + + glBegin (key.mode); // practically must be quads + + while (c < e) + { + glTexCoord2f ( c->u * (1.f / TC_WIDTH), c->v * (1.f / TC_HEIGHT)); glVertex2i (c->x - c->w, c->y - c->h); + glTexCoord2f ((c->u + c->w) * (1.f / TC_WIDTH), c->v * (1.f / TC_HEIGHT)); glVertex2i (c->x , c->y - c->h); + glTexCoord2f ((c->u + c->w) * (1.f / TC_WIDTH), (c->v + c->h) * (1.f / TC_HEIGHT)); glVertex2i (c->x , c->y ); + glTexCoord2f ( c->u * (1.f / TC_WIDTH), (c->v + c->h) * (1.f / TC_HEIGHT)); glVertex2i (c->x - c->w, c->y ); + + ++c; + } + + glEnd (); + } + } + + glDisable (GL_TEXTURE_2D); + + if (ecb_expect_false (++drawcount == 16)) + for (auto &&it = h.begin (); it != h.end (); ++it) + it->second.shrink_to_fit (); + } +};