forked from 0ad/0ad
GLSL text support
This was SVN commit r11080.
This commit is contained in:
parent
5f6e3de42f
commit
832a51da80
@ -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;
|
||||
}
|
||||
|
@ -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"/>
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user