1
0
forked from 0ad/0ad

GLSL text support

This was SVN commit r11080.
This commit is contained in:
Ykkrosh 2012-02-15 21:53:13 +00:00
parent 5f6e3de42f
commit 832a51da80
10 changed files with 143 additions and 208 deletions

View File

@ -4,8 +4,11 @@ uniform mat4 transform;
varying vec2 v_texcoord;
attribute vec3 a_vertex;
attribute vec2 a_uv0;
void main()
{
gl_Position = transform * gl_Vertex;
v_texcoord = gl_MultiTexCoord0.xy;
gl_Position = transform * vec4(a_vertex, 1.0);
v_texcoord = a_uv0;
}

View File

@ -4,6 +4,8 @@
<vertex file="glsl/gui_text.vs">
<stream name="pos"/>
<stream name="uv0"/>
<attrib name="a_vertex" semantics="gl_Vertex"/>
<attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
</vertex>
<fragment file="glsl/gui_text.fs"/>

View File

@ -91,6 +91,9 @@ void CTextRenderer::Printf(const wchar_t* fmt, ...)
if (ret < 0)
debug_printf(L"CTextRenderer::Printf vswprintf failed (buffer size exceeded?) - return value %d, errno %d\n", ret, errno);
if (ret == 0)
return; // empty string; don't bother storing
SBatch batch;
batch.transform = m_Transform;
batch.color = m_Color;
@ -115,6 +118,9 @@ void CTextRenderer::PrintfAt(float x, float y, const wchar_t* fmt, ...)
if (ret < 0)
debug_printf(L"CTextRenderer::PrintfAt vswprintf failed (buffer size exceeded?) - return value %d, errno %d\n", ret, errno);
if (ret == 0)
return; // empty string; don't bother storing
CMatrix3D translate;
translate.SetTranslation(x, y, 0.0f);
@ -126,17 +132,28 @@ void CTextRenderer::PrintfAt(float x, float y, const wchar_t* fmt, ...)
m_Batches.push_back(batch);
}
struct t2f_v2i
{
t2f_v2i() : u(0), v(0), x(0), y(0) { }
float u, v;
i16 x, y;
};
void CTextRenderer::Render()
{
std::vector<u16> indexes;
std::vector<t2f_v2i> vertexes;
for (size_t i = 0; i < m_Batches.size(); ++i)
{
SBatch& batch = m_Batches[i];
int unit = m_Shader->GetTextureUnit("tex");
if (unit == -1) // just in case the shader doesn't use the sampler
if (batch.text.empty()) // avoid zero-length arrays
continue;
batch.font->Bind(unit);
const std::map<u16, UnifontGlyphData>& glyphs = batch.font->GetGlyphs();
m_Shader->BindTexture("tex", batch.font->GetTexture());
m_Shader->Uniform("transform", batch.transform);
@ -149,7 +166,59 @@ void CTextRenderer::Render()
m_Shader->Uniform("colorMul", batch.color);
unifont_render(batch.text.c_str());
vertexes.clear();
vertexes.resize(batch.text.size()*4);
indexes.clear();
indexes.resize(batch.text.size()*6);
i16 x = 0;
for (size_t i = 0; i < batch.text.size(); ++i)
{
std::map<u16, UnifontGlyphData>::const_iterator it = glyphs.find(batch.text[i]);
if (it == glyphs.end())
it = glyphs.find(0xFFFD); // Use the missing glyph symbol
if (it == glyphs.end()) // Missing the missing glyph symbol - give up
continue;
const UnifontGlyphData& g = it->second;
vertexes[i*4].u = g.u1;
vertexes[i*4].v = g.v0;
vertexes[i*4].x = g.x1 + x;
vertexes[i*4].y = g.y0;
vertexes[i*4+1].u = g.u0;
vertexes[i*4+1].v = g.v0;
vertexes[i*4+1].x = g.x0 + x;
vertexes[i*4+1].y = g.y0;
vertexes[i*4+2].u = g.u0;
vertexes[i*4+2].v = g.v1;
vertexes[i*4+2].x = g.x0 + x;
vertexes[i*4+2].y = g.y1;
vertexes[i*4+3].u = g.u1;
vertexes[i*4+3].v = g.v1;
vertexes[i*4+3].x = g.x1 + x;
vertexes[i*4+3].y = g.y1;
indexes[i*6+0] = i*4+0;
indexes[i*6+1] = i*4+1;
indexes[i*6+2] = i*4+2;
indexes[i*6+3] = i*4+2;
indexes[i*6+4] = i*4+3;
indexes[i*6+5] = i*4+0;
x += g.xadvance;
}
m_Shader->VertexPointer(2, GL_SHORT, sizeof(t2f_v2i), &vertexes[0].x);
m_Shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, sizeof(t2f_v2i), &vertexes[0].u);
glDrawElements(GL_TRIANGLES, indexes.size(), GL_UNSIGNED_SHORT, &indexes[0]);
}
m_Batches.clear();

View File

@ -1035,7 +1035,6 @@ void CInput::Draw()
}
CFont font(font_name);
font.Bind();
// We'll have to setup clipping manually, since we're doing the rendering manually.
CRect cliparea(m_CachedActualSize);

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2010 Wildfire Games
/* Copyright (c) 2012 Wildfire Games
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -35,16 +35,7 @@
#include "ogl_tex.h"
#include "lib/res/h_mgr.h"
struct GlyphData
{
float u0, v0, u1, v1;
i16 x0, y0, x1, y1;
i16 xadvance;
};
typedef std::map<u16, GlyphData> glyphmap;
static glyphmap* BoundGlyphs = NULL;
typedef std::map<u16, UnifontGlyphData> glyphmap;
struct UniFont
{
@ -149,7 +140,7 @@ static Status UniFont_reload(UniFont* f, const PIVFS& vfs, const VfsPath& basena
GLfloat w = (GLfloat)Width / (GLfloat)TextureWidth;
GLfloat h = (GLfloat)Height / (GLfloat)TextureHeight;
GlyphData g = { u, -v, u+w, -v+h, (i16)OffsetX, (i16)-OffsetY, (i16)(OffsetX+Width), (i16)(-OffsetY+Height), (i16)Advance };
UnifontGlyphData g = { u, -v, u+w, -v+h, (i16)OffsetX, (i16)-OffsetY, (i16)(OffsetX+Width), (i16)(-OffsetY+Height), (i16)Advance };
(*f->glyphs)[(u16)Codepoint] = g;
}
@ -212,27 +203,10 @@ Handle unifont_load(const PIVFS& vfs, const VfsPath& pathname, size_t flags)
Status unifont_unload(Handle& h)
{
H_DEREF(h, UniFont, f);
// unbind ourself, so people will get errors if
// they draw more text without binding a new font
if (BoundGlyphs == f->glyphs)
BoundGlyphs = NULL;
return h_free(h, H_UniFont);
}
Status unifont_bind(const Handle h, size_t unit)
{
H_DEREF(h, UniFont, f);
ogl_tex_bind(f->ht, unit);
BoundGlyphs = f->glyphs;
return INFO::OK;
}
int unifont_linespacing(const Handle h)
{
H_DEREF(h, UniFont, f);
@ -267,122 +241,6 @@ int unifont_character_width(const Handle h, wchar_t c)
return it->second.xadvance;
}
struct t2f_v2i
{
float u, v;
i16 x, y;
};
void glvwprintf(const wchar_t* fmt, va_list args)
{
const int buf_size = 1024;
wchar_t buf[buf_size];
int ret = vswprintf(buf, buf_size-1, fmt, args);
if(ret < 0) {
debug_printf(L"glwprintf failed (buffer size exceeded?) - return value %d, errno %d\n", ret, errno);
}
// Make sure there's always null termination
buf[buf_size-1] = 0;
int advance = 0;
unifont_render(buf, &advance);
// Move into position for subsequent prints
#if CONFIG2_GLES
#warning TODO: implement unifont for GLES
#else
glTranslatef((float)advance, 0, 0);
#endif
}
void unifont_render(const wchar_t* str, int* advance)
{
ENSURE(BoundGlyphs != NULL); // You always need to bind something first
// Count the number of characters
size_t len = wcslen(str);
// 0 glyphs -> nothing to do (avoid BoundsChecker warning)
if (!len)
return;
t2f_v2i* vertexes = new t2f_v2i[len*4];
i16 x = 0;
for (size_t i = 0; i < len; ++i)
{
glyphmap::iterator it = BoundGlyphs->find(str[i]);
if (it == BoundGlyphs->end())
it = BoundGlyphs->find(0xFFFD); // Use the missing glyph symbol
if (it == BoundGlyphs->end()) // Missing the missing glyph symbol - give up
continue;
const GlyphData& g = it->second;
vertexes[i*4].u = g.u1;
vertexes[i*4].v = g.v0;
vertexes[i*4].x = g.x1 + x;
vertexes[i*4].y = g.y0;
vertexes[i*4+1].u = g.u0;
vertexes[i*4+1].v = g.v0;
vertexes[i*4+1].x = g.x0 + x;
vertexes[i*4+1].y = g.y0;
vertexes[i*4+2].u = g.u0;
vertexes[i*4+2].v = g.v1;
vertexes[i*4+2].x = g.x0 + x;
vertexes[i*4+2].y = g.y1;
vertexes[i*4+3].u = g.u1;
vertexes[i*4+3].v = g.v1;
vertexes[i*4+3].x = g.x1 + x;
vertexes[i*4+3].y = g.y1;
x += g.xadvance;
}
ogl_WarnIfError();
#if CONFIG2_GLES
#warning TODO: implement unifont for GLES
#else
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_SHORT, sizeof(t2f_v2i), (u8*)vertexes + offsetof(t2f_v2i, x));
glTexCoordPointer(2, GL_FLOAT, sizeof(t2f_v2i), (u8*)vertexes + offsetof(t2f_v2i, u));
glDrawArrays(GL_QUADS, 0, (GLsizei)len*4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
ogl_WarnIfError();
#endif
if (advance)
*advance = x;
delete[] vertexes;
}
void glwprintf(const wchar_t* fmt, ...)
{
va_list args;
va_start(args, fmt);
glvwprintf(fmt, args);
va_end(args);
}
Status unifont_stringsize(const Handle h, const wchar_t* text, int& width, int& height)
{
H_DEREF(h, UniFont, f);
@ -410,3 +268,28 @@ Status unifont_stringsize(const Handle h, const wchar_t* text, int& width, int&
return INFO::OK;
}
const glyphmap& unifont_get_glyphs(const Handle h)
{
UniFont* const f = H_USER_DATA(h, UniFont);
if(!f)
{
DEBUG_WARN_ERR(ERR::INVALID_HANDLE);
static glyphmap dummy;
return dummy;
}
return *f->glyphs;
}
Handle unifont_get_texture(const Handle h)
{
UniFont* const f = H_USER_DATA(h, UniFont);
if(!f)
{
DEBUG_WARN_ERR(ERR::INVALID_HANDLE);
return 0;
}
return f->ht;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2010 Wildfire Games
/* Copyright (c) 2012 Wildfire Games
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -48,42 +48,6 @@ extern Handle unifont_load(const PIVFS& vfs, const VfsPath& pathname, size_t fla
**/
extern Status unifont_unload(Handle& h);
/**
* Use a font for all subsequent glwprintf() calls.
*
* Must be called before any glwprintf().
**/
extern Status unifont_bind(Handle h, size_t unit);
/**
* Output text at current OpenGL modelview pos.
*
* @param fmt - see fprintf
*
* this assumes an environment roughly like:
* glEnable(GL_TEXTURE_2D);
* glDisable(GL_CULL_FACE);
* glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
* glEnable(GL_BLEND);
* glDisable(GL_ALPHA_TEST);
* glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
**/
extern void glwprintf(const wchar_t* fmt, ...) WPRINTF_ARGS(1);
/**
* Varargs version of glwprintf.
*
* @param fmt
* @param args
* @see vfprintf
**/
extern void glvwprintf(const wchar_t* fmt, va_list args) VWPRINTF_ARGS(1);
/**
* Output text, and return advance distance (if @p advance not NULL).
*/
extern void unifont_render(const wchar_t* str, int* advance = NULL);
/**
* Determine pixel extents of a string.
*
@ -117,4 +81,24 @@ int unifont_character_width(const Handle h, wchar_t c);
**/
int unifont_linespacing(const Handle h);
// Raw access to font data (since it's convenient to move as much of the
// processing as possible to outside lib/):
struct UnifontGlyphData
{
float u0, v0, u1, v1;
i16 x0, y0, x1, y1;
i16 xadvance;
};
/**
* @return glyph data for all glyphs in this font.
*/
const std::map<u16, UnifontGlyphData>& unifont_get_glyphs(const Handle h);
/**
* @return texture handle for this font.
*/
Handle unifont_get_texture(const Handle h);
#endif // INCLUDED_UNIFONT

View File

@ -180,7 +180,6 @@ void CConsole::Render()
PROFILE3_GPU("console");
CFont font(CONSOLE_FONT);
font.Bind();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

View File

@ -48,11 +48,6 @@ CFont::~CFont()
unifont_unload(h);
}
void CFont::Bind(size_t unit)
{
unifont_bind(h, unit);
}
bool CFont::HasRGB()
{
return unifont_has_rgb(h);
@ -77,3 +72,13 @@ void CFont::CalculateStringSize(const CStrW& string, int& width, int& height)
{
unifont_stringsize(h, string.c_str(), width, height);
}
const std::map<u16, UnifontGlyphData>& CFont::GetGlyphs()
{
return unifont_get_glyphs(h);
}
Handle CFont::GetTexture()
{
return unifont_get_texture(h);
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2012 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -21,16 +21,7 @@
#include "lib/res/handle.h"
class CStrW;
/*
To use CFont:
CFont font("name");
font.Bind();
glwprintf(L"Hello world");
*/
struct UnifontGlyphData;
class CFont
{
@ -38,12 +29,13 @@ public:
CFont(const CStrW& name);
~CFont();
void Bind(size_t unit = 0);
bool HasRGB();
int GetLineSpacing();
int GetHeight();
int GetCharacterWidth(wchar_t c);
void CalculateStringSize(const CStrW& string, int& w, int& h);
const std::map<u16, UnifontGlyphData>& GetGlyphs();
Handle GetTexture();
private:
Handle h;

View File

@ -173,7 +173,6 @@ void CProfileViewer::RenderProfile()
CStrW font_name = L"mono-stroke-10";
CFont font(font_name);
font.Bind();
int lineSpacing = font.GetLineSpacing();
// Render background