| 1 |
#include <vector> |
| 2 |
|
| 3 |
#include "salloc.h" |
| 4 |
|
| 5 |
struct rc_key_t |
| 6 |
{ |
| 7 |
GLenum mode; |
| 8 |
GLenum format; // 0, GL_T2F_V3F, GL_V2F |
| 9 |
GLuint texname; |
| 10 |
unsigned char r, g, b, a; |
| 11 |
|
| 12 |
bool operator == (const rc_key_t &o) const |
| 13 |
{ |
| 14 |
return mode == o.mode |
| 15 |
&& format == o.format |
| 16 |
&& texname == o.texname |
| 17 |
&& r == o.r |
| 18 |
&& g == o.g |
| 19 |
&& b == o.b |
| 20 |
&& a == o.a; |
| 21 |
} |
| 22 |
}; |
| 23 |
|
| 24 |
namespace std { |
| 25 |
template <> |
| 26 |
struct hash<rc_key_t> |
| 27 |
{ |
| 28 |
size_t operator () (const rc_key_t &v) const |
| 29 |
{ |
| 30 |
return v.mode + (v.format << 4) + v.texname + (v.r << 8) + (v.g << 16) + (v.b << 24) + v.a; |
| 31 |
} |
| 32 |
}; |
| 33 |
} |
| 34 |
|
| 35 |
struct rc_t |
| 36 |
{ |
| 37 |
struct glyph_data |
| 38 |
{ |
| 39 |
uint8_t u, v, w, h; |
| 40 |
uint16_t x, y; |
| 41 |
}; |
| 42 |
|
| 43 |
struct array_t |
| 44 |
: std::vector<uint8_t, slice_allocator<uint8_t>> |
| 45 |
{ |
| 46 |
using std::vector<uint8_t, slice_allocator<uint8_t>>::vector; |
| 47 |
|
| 48 |
template<typename T> |
| 49 |
T &append () |
| 50 |
{ |
| 51 |
auto ofs = size (); |
| 52 |
resize (ofs + sizeof (T)); |
| 53 |
return *(T *)(data () + ofs); |
| 54 |
} |
| 55 |
|
| 56 |
void v2f (float x, float y) |
| 57 |
{ |
| 58 |
auto &vec = append<float[2]> (); |
| 59 |
vec[0] = x / 2; |
| 60 |
vec[1] = y / 2; |
| 61 |
} |
| 62 |
|
| 63 |
void t2f_v3f (float u, float v, float x, float y, float z) |
| 64 |
{ |
| 65 |
auto &vec = append<float[5]> (); |
| 66 |
vec[0] = u; |
| 67 |
vec[1] = v; |
| 68 |
vec[2] = x; |
| 69 |
vec[3] = y; |
| 70 |
vec[4] = z; |
| 71 |
} |
| 72 |
|
| 73 |
void glyph (int u, int v, int w, int h, int x, int y) |
| 74 |
{ |
| 75 |
if (w && h) |
| 76 |
{ |
| 77 |
auto &c = append<glyph_data> (); |
| 78 |
|
| 79 |
c.u = u; |
| 80 |
c.v = v; |
| 81 |
c.w = w; |
| 82 |
c.h = h; |
| 83 |
c.x = x + w; |
| 84 |
c.y = y + h; |
| 85 |
} |
| 86 |
} |
| 87 |
}; |
| 88 |
|
| 89 |
int drawcount = 0; |
| 90 |
ska::flat_hash_map<rc_key_t, array_t, std::hash<rc_key_t>, std::equal_to<rc_key_t>, slice_allocator<rc_key_t>> h; |
| 91 |
|
| 92 |
void clear () |
| 93 |
{ |
| 94 |
drawcount = 0; |
| 95 |
h.clear (); |
| 96 |
} |
| 97 |
|
| 98 |
array_t &array (const rc_key_t &k) |
| 99 |
{ |
| 100 |
return h[k]; |
| 101 |
} |
| 102 |
|
| 103 |
void draw () |
| 104 |
{ |
| 105 |
for (auto &&it = h.begin (); it != h.end (); ++it) |
| 106 |
{ |
| 107 |
rc_key_t &key = it->first; |
| 108 |
array_t &arr = it->second; |
| 109 |
GLsizei stride; |
| 110 |
|
| 111 |
if (key.texname) |
| 112 |
{ |
| 113 |
glBindTexture (GL_TEXTURE_2D, key.texname); |
| 114 |
glEnable (GL_TEXTURE_2D); |
| 115 |
} |
| 116 |
else |
| 117 |
glDisable (GL_TEXTURE_2D); |
| 118 |
|
| 119 |
glColor4ub (key.r, key.g, key.b, key.a); |
| 120 |
|
| 121 |
if (key.format) |
| 122 |
{ |
| 123 |
stride = key.format == GL_T2F_V3F ? sizeof (float) * 5 |
| 124 |
: key.format == GL_V2F ? sizeof (float) * 2 |
| 125 |
: 65536; |
| 126 |
|
| 127 |
glInterleavedArrays (key.format, 0, (void *)arr.data ()); |
| 128 |
//glLockArraysEXT (0, len / stride); |
| 129 |
glDrawArrays (key.mode, 0, arr.size () / stride); |
| 130 |
//glUnlockArraysEXT (); |
| 131 |
} |
| 132 |
else |
| 133 |
{ |
| 134 |
// optimised character quad storage. slower but nice on memory. |
| 135 |
// reduces storage requirements from 80 bytes/char to 8 |
| 136 |
auto *c = (glyph_data *) arr.data (); |
| 137 |
auto *e = (glyph_data *)(arr.data () + arr.size ()); |
| 138 |
|
| 139 |
glBegin (key.mode); // practically must be quads |
| 140 |
|
| 141 |
while (c < e) |
| 142 |
{ |
| 143 |
glTexCoord2f ( c->u * (1.f / TC_WIDTH), c->v * (1.f / TC_HEIGHT)); glVertex2i (c->x - c->w, c->y - c->h); |
| 144 |
glTexCoord2f ((c->u + c->w) * (1.f / TC_WIDTH), c->v * (1.f / TC_HEIGHT)); glVertex2i (c->x , c->y - c->h); |
| 145 |
glTexCoord2f ((c->u + c->w) * (1.f / TC_WIDTH), (c->v + c->h) * (1.f / TC_HEIGHT)); glVertex2i (c->x , c->y ); |
| 146 |
glTexCoord2f ( c->u * (1.f / TC_WIDTH), (c->v + c->h) * (1.f / TC_HEIGHT)); glVertex2i (c->x - c->w, c->y ); |
| 147 |
|
| 148 |
++c; |
| 149 |
} |
| 150 |
|
| 151 |
glEnd (); |
| 152 |
} |
| 153 |
} |
| 154 |
|
| 155 |
glDisable (GL_TEXTURE_2D); |
| 156 |
|
| 157 |
if (ecb_expect_false (++drawcount == 16)) |
| 158 |
for (auto &&it = h.begin (); it != h.end (); ++it) |
| 159 |
it->second.shrink_to_fit (); |
| 160 |
} |
| 161 |
}; |
| 162 |
|