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