#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; 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 { return v.mode + (v.format << 4) + v.texname + (v.r << 8) + (v.g << 16) + (v.b << 24) + v.a; } }; } struct rc_t { struct glyph_data { uint8_t u, v, w, h; uint16_t x, y; }; struct array_t : std::vector> { using std::vector>::vector; template T &append () { auto ofs = size (); resize (ofs + sizeof (T)); return *(T *)(data () + ofs); } void v2f (float x, float y) { auto &vec = append (); vec[0] = x / 2; vec[1] = y / 2; } 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; } void glyph (int u, int v, int w, int h, int x, int y) { if (w && h) { auto &c = append (); c.u = u; c.v = v; c.w = w; c.h = h; c.x = x + w; c.y = y + h; } } }; 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 (); } };