principia/src/textbuffer.cc

424 lines
9.7 KiB
C++

#include "textbuffer.hh"
#include "material.hh"
static tms::gbuffer *verts;
static tms::gbuffer *verts2;
static tms::gbuffer *indices;
static tms::varray *va;
static tms::varray *va2;
static tms::mesh *mesh;
static tms::mesh *mesh2;
static tms::entity *e;
static tms::entity *e2;
static int n = 0;
static int n2 = 0;
struct textbuf_vert {
tvec3 pos;
tvec2 uv;
tvec4 color;
};
static textbuf_vert base[4];
void textbuffer::_init()
{
tms_infof("Initializing textbuffer...");
verts = new tms::gbuffer(4*TEXTBUFFER_MAX*sizeof(struct textbuf_vert));
verts->usage = TMS_GBUFFER_STREAM_DRAW;
verts2 = new tms::gbuffer(4*TEXTBUFFER_MAX*sizeof(struct textbuf_vert));
verts2->usage = TMS_GBUFFER_STREAM_DRAW;
indices = new tms::gbuffer(6*TEXTBUFFER_MAX*sizeof(uint16_t));
indices->usage = TMS_GBUFFER_STATIC_DRAW;
indices->target = GL_ELEMENT_ARRAY_BUFFER;
va = new tms::varray(3);
va->map_attribute("position", 3, GL_FLOAT, verts);
va->map_attribute("uv", 2, GL_FLOAT, verts);
va->map_attribute("vcolor", 4, GL_FLOAT, verts);
va2 = new tms::varray(3);
va2->map_attribute("position", 3, GL_FLOAT, verts2);
va2->map_attribute("uv", 2, GL_FLOAT, verts2);
va2->map_attribute("vcolor", 4, GL_FLOAT, verts2);
uint16_t *i = (uint16_t*)indices->get_buffer();
for (int x=0; x<TEXTBUFFER_MAX; x++) {
int o = x*6;
int vo = x*4;
i[o+0] = vo;
i[o+1] = vo+1;
i[o+2] = vo+2;
i[o+3] = vo;
i[o+4] = vo+2;
i[o+5] = vo+3;
}
indices->upload();
base[0] = (textbuf_vert){
(tvec3){.5f,.5f,0.f},
(tvec2){.5f, 1.f},
(tvec4){0.f, 0.f, 0.f, 0.f},
};
base[1] = (textbuf_vert){
(tvec3){-.5f,.5f,0.f},
(tvec2){0.f, 1.f},
(tvec4){0.f, 0.f, 0.f, 0.f},
};
base[2] = (textbuf_vert){
(tvec3){-.5f,-.5f,0.f},
(tvec2){0.f, .5f},
(tvec4){0.f, 0.f, 0.f, 0.f},
};
base[3] = (textbuf_vert){
(tvec3){.5f,-.5f,0.f},
(tvec2){.5f, .5f},
(tvec4){0.f, 0.f, 0.f, 0.f},
};
reset();
}
void
textbuffer::reset()
{
n = 0;
n2 = 0;
}
void
textbuffer::upload()
{
if (mesh) {
mesh->i_start = 0;
mesh->i_count = n*6;
}
if (mesh2) {
mesh2->i_start = 0;
mesh2->i_count = n2*6;
}
if (n) verts->upload_partial(n*4*sizeof(struct textbuf_vert));
if (n2) verts2->upload_partial(n2*4*sizeof(struct textbuf_vert));
}
tms::entity *
textbuffer::get_entity()
{
if (e) return e;
e = new tms::entity();
mesh = new tms::mesh(va, indices);
e->prio = 3;
e->set_mesh(mesh);
e->set_material(&m_charbuf);
mesh->i_start = 0;
mesh->i_count = n*9*3;
return e;
}
void
custom_update(struct tms_entity *e)
{
tms_debugf("hello");
}
tms::entity *
textbuffer::get_entity2()
{
if (e2) return e2;
mesh2 = new tms::mesh(va2, indices);
mesh2->i_start = 0;
mesh2->i_count = n2*9*3;
e2 = new tms::entity();
e2->prio = 0;
e2->set_mesh(mesh2);
e2->set_material(&m_charbuf2);
return e2;
}
void
textbuffer::add_char(glyph *gl,
float x, float y, float z,
float r, float g, float b, float a,
float w, float h)
{
tms_sprite *s = gl->sprite;
int bx = 505;
int by = 950;
int tx = 530;
int ty = 1024;
#define TEX_WIDTH 1024.f
#define TEX_HEIGHT 1024.f
tvec2 uvb = {(float)bx / TEX_WIDTH, (float)by / TEX_HEIGHT};
tvec2 uvt = {(float)tx / TEX_WIDTH, (float)ty / TEX_HEIGHT};
if (n < TEXTBUFFER_MAX) {
textbuf_vert *_b = (textbuf_vert *)verts->get_buffer();
for (int ix=0; ix<4; ix++) {
_b[n*4+ix] = base[ix];
_b[n*4+ix].pos.x *= w;
_b[n*4+ix].pos.y *= h;
_b[n*4+ix].pos.x += x;
_b[n*4+ix].pos.y += y;
_b[n*4+ix].pos.z += z;
_b[n*4+ix].color.r = r;
_b[n*4+ix].color.g = g;
_b[n*4+ix].color.b = b;
_b[n*4+ix].color.a = a;
float x = ((ix == 0 || ix == 3) ? s->tr.x : s->bl.x);
float y = (ix < 2 ? s->tr.y : s->bl.y);
_b[n*4+ix].uv.x = x;
_b[n*4+ix].uv.y = y;
}
n++;
}
}
void
textbuffer::add_bg(
float x, float y, float z,
float r, float g, float b, float a,
float w, float h)
{
if (n < TEXTBUFFER_MAX) {
textbuf_vert *_b = (textbuf_vert *)verts->get_buffer();
for (int ix=0; ix<4; ix++) {
_b[n*4+ix] = base[ix];
_b[n*4+ix].pos.x *= w;
_b[n*4+ix].pos.y *= h;
_b[n*4+ix].pos.x += x;
_b[n*4+ix].pos.y += y;
_b[n*4+ix].pos.z += z;
_b[n*4+ix].color.r = r;
_b[n*4+ix].color.g = g;
_b[n*4+ix].color.b = b;
_b[n*4+ix].color.a = a;
_b[n*4+ix].uv.x = .001;
_b[n*4+ix].uv.y = .999;
}
n++;
}
}
void
textbuffer::add_char2(glyph *gl,
float x, float y, float z,
float r, float g, float b, float a,
float w, float h)
{
tms_sprite *s = gl->sprite;
int bx = 505;
int by = 950;
int tx = 530;
int ty = 1024;
#define TEX_WIDTH 1024.f
#define TEX_HEIGHT 1024.f
tvec2 uvb = {(float)bx / TEX_WIDTH, (float)by / TEX_HEIGHT};
tvec2 uvt = {(float)tx / TEX_WIDTH, (float)ty / TEX_HEIGHT};
if (n2 < TEXTBUFFER_MAX) {
textbuf_vert *_b = (textbuf_vert *)verts2->get_buffer();
for (int ix=0; ix<4; ix++) {
_b[n2*4+ix] = base[ix];
_b[n2*4+ix].pos.x *= w;
_b[n2*4+ix].pos.y *= h;
_b[n2*4+ix].pos.x += x;
_b[n2*4+ix].pos.y += y;
_b[n2*4+ix].pos.z += z;
_b[n2*4+ix].color.r = r;
_b[n2*4+ix].color.g = g;
_b[n2*4+ix].color.b = b;
_b[n2*4+ix].color.a = a;
float x = ((ix == 0 || ix == 3) ? s->tr.x : s->bl.x);
float y = (ix < 2 ? s->tr.y : s->bl.y);
_b[n2*4+ix].uv.x = x;
_b[n2*4+ix].uv.y = y;
}
n2++;
}
}
void
textbuffer::add_text(p_text *text, float scale)
{
p_text::text_glyph *g = 0;
for (int i=0; i<text->num_glyphs; ++i) {
g = &text->glyphs[i];
textbuffer::add_char(g->parent,
g->x, g->y,
2.0,
1.0, 1.0, 1.0, 1.0,
scale * g->get_bw(),
scale * g->get_bh()
);
}
}
void
textbuffer::add_text(const char *text, p_font *font,
float x, float y, float z,
float r, float g, float b, float a,
float scale,
uint8_t horizontal_align/*=ALIGN_CENTER*/,
uint8_t vertical_align/*=ALIGN_CENTER*/,
bool bg/*=false*/
)
{
float width = 0.f;
float max_width = 0.f;
float line_height = font->get_height() * scale;
float height = line_height;
int slen = strlen(text);
struct glyph *gl;
for (int i=0; i<slen; ++i) {
if ((gl = font->get_glyph(text[i]))) {
if (gl->newline) {
height += line_height;
width = 0.f;
continue;
}
width += gl->ax * scale;
if (width > max_width) {
max_width = width;
}
}
}
if (width == 0.f) {
height -= line_height;
}
width = max_width;
float mid_x = x;
float mid_y = y;
if (horizontal_align == ALIGN_CENTER) {
x -= max_width/2.f;
} else if (horizontal_align == ALIGN_RIGHT) {
x -= max_width;
}
float base_x = x;
if (vertical_align == ALIGN_CENTER) {
y += height/2.f;
} else if (vertical_align == ALIGN_TOP) {
y -= height;
}
if (bg) {
textbuffer::add_bg(mid_x,mid_y+line_height*.75f,z,0,0,0,.5*a, max_width+.1, height+.1);
}
for (int i=0; i<slen; ++i) {
if ((gl = font->get_glyph(text[i]))) {
float x2 = x + (gl->bl + gl->bw/2.f) * scale;
float y2 = y + (gl->bt - gl->bh/2.f) * scale;
if (gl->newline) {
x = base_x;
y -= line_height;
continue;
}
x += gl->ax * scale;
textbuffer::add_char(gl,
x2,
y2,
z + 0.01f,
r, g, b, a,
gl->bw*scale,
gl->bh*scale
);
}
}
}
void
textbuffer::add_text2(const char *text, p_font *font,
float x, float y, float z,
float r, float g, float b, float a,
float scale,
uint8_t horizontal_align/*=ALIGN_CENTER*/,
uint8_t vertical_align/*=ALIGN_CENTER*/
)
{
float width = 0.f;
float height = font->get_height() * scale;
int slen = strlen(text);
struct glyph *gl;
for (int i=0; i<slen; ++i) {
if ((gl = font->get_glyph(text[i]))) {
width += gl->ax * scale;
}
}
if (horizontal_align == ALIGN_CENTER) {
x -= width/2.f;
} else if (horizontal_align == ALIGN_RIGHT) {
x -= width;
}
if (vertical_align == ALIGN_CENTER) {
y -= height/2.f;
} else if (vertical_align == ALIGN_TOP) {
y -= height;
}
for (int i=0; i<slen; ++i) {
if ((gl = font->get_glyph(text[i]))) {
float x2 = x + (gl->bl + gl->bw/2.f) * scale;
float y2 = y + (gl->bt - gl->bh/2.f) * scale;
x += gl->ax * scale;
textbuffer::add_char2(gl,
x2,
y2,
z + 0.01f,
.0f, .0f, .0f, 1.f,
gl->bw*scale,
gl->bh*scale
);
}
}
}