mirror of
https://github.com/blawar/GLideN64.git
synced 2024-07-02 09:03:37 +00:00
Refactor TextDrawer: remove direct use of OpenGL
Remove DummyTextDrawer.
This commit is contained in:
parent
e011ee56b5
commit
2483903b74
|
@ -350,6 +350,7 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\RSP.cpp" />
|
||||
<ClCompile Include="..\..\src\SoftwareRender.cpp" />
|
||||
<ClCompile Include="..\..\src\TextDrawer.cpp" />
|
||||
<ClCompile Include="..\..\src\TextureFilterHandler.cpp" />
|
||||
<ClCompile Include="..\..\src\Textures.cpp" />
|
||||
<ClCompile Include="..\..\src\Turbo3D.cpp" />
|
||||
|
@ -442,9 +443,7 @@
|
|||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_ColorBufferReaderWithPixelBuffer.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_ContextImpl.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_GLInfo.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_DummyTextDrawer.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_GraphicsDrawer.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_TextDrawer.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_TextureManipulationObjectFactory.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_UnbufferedDrawer.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_Utils.h" />
|
||||
|
@ -472,6 +471,7 @@
|
|||
<ClInclude Include="..\..\src\GraphicsDrawer.h" />
|
||||
<ClInclude Include="..\..\src\RSP.h" />
|
||||
<ClInclude Include="..\..\src\SoftwareRender.h" />
|
||||
<ClInclude Include="..\..\src\TextDrawer.h" />
|
||||
<ClInclude Include="..\..\src\TextureFilterHandler.h" />
|
||||
<ClInclude Include="..\..\src\Textures.h" />
|
||||
<ClInclude Include="..\..\src\Turbo3D.h" />
|
||||
|
|
|
@ -329,6 +329,9 @@
|
|||
<ClCompile Include="..\..\src\Graphics\OpenGLContext\opengl_BufferedDrawer.cpp">
|
||||
<Filter>Source Files\Graphics\OpenGL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\TextDrawer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\3DMath.h">
|
||||
|
@ -595,12 +598,6 @@
|
|||
<ClInclude Include="..\..\src\GraphicsDrawer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_DummyTextDrawer.h">
|
||||
<Filter>Header Files\Graphics\OpenGL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_TextDrawer.h">
|
||||
<Filter>Header Files\Graphics\OpenGL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_GraphicsDrawer.h">
|
||||
<Filter>Header Files\Graphics\OpenGL</Filter>
|
||||
</ClInclude>
|
||||
|
@ -622,5 +619,8 @@
|
|||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_BufferedDrawer.h">
|
||||
<Filter>Header Files\Graphics\OpenGL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\TextDrawer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -48,6 +48,7 @@ set(GLideN64_SOURCES
|
|||
S2DEX2.cpp
|
||||
S2DEX.cpp
|
||||
SoftwareRender.cpp
|
||||
TextDrawer.cpp
|
||||
TextureFilterHandler.cpp
|
||||
Textures.cpp
|
||||
Turbo3D.cpp
|
||||
|
|
|
@ -249,6 +249,11 @@ ShaderProgram * Context::createOrientationCorrectionShader()
|
|||
return m_impl->createOrientationCorrectionShader();
|
||||
}
|
||||
|
||||
ShaderProgram * Context::createTextDrawerShader()
|
||||
{
|
||||
return m_impl->createTextDrawerShader();
|
||||
}
|
||||
|
||||
void Context::resetShaderProgram()
|
||||
{
|
||||
m_impl->resetShaderProgram();
|
||||
|
@ -269,16 +274,6 @@ void Context::drawLine(f32 _width, SPVertex * _vertices)
|
|||
m_impl->drawLine(_width, _vertices);
|
||||
}
|
||||
|
||||
void Context::drawText(const char *_pText, float _x, float _y)
|
||||
{
|
||||
m_impl->drawText(_pText, _x, _y);
|
||||
}
|
||||
|
||||
void Context::getTextSize(const char *_pText, float & _w, float & _h)
|
||||
{
|
||||
m_impl->getTextSize(_pText, _w, _h);
|
||||
}
|
||||
|
||||
f32 Context::getMaxLineWidth()
|
||||
{
|
||||
return m_impl->getMaxLineWidth();
|
||||
|
|
|
@ -220,6 +220,8 @@ namespace graphics {
|
|||
|
||||
ShaderProgram * createOrientationCorrectionShader();
|
||||
|
||||
ShaderProgram * createTextDrawerShader();
|
||||
|
||||
void resetShaderProgram();
|
||||
|
||||
/*---------------Draw-------------*/
|
||||
|
@ -253,10 +255,6 @@ namespace graphics {
|
|||
|
||||
f32 getMaxLineWidth();
|
||||
|
||||
void drawText(const char *_pText, float _x, float _y);
|
||||
|
||||
void getTextSize(const char *_pText, float & _w, float & _h);
|
||||
|
||||
/*---------------Misc-------------*/
|
||||
|
||||
bool isSupported(SpecialFeatures _feature) const;
|
||||
|
|
|
@ -55,13 +55,12 @@ namespace graphics {
|
|||
virtual ShaderProgram * createTexrectCopyShader() = 0;
|
||||
virtual ShaderProgram * createGammaCorrectionShader() = 0;
|
||||
virtual ShaderProgram * createOrientationCorrectionShader() = 0;
|
||||
virtual ShaderProgram * createTextDrawerShader() = 0;
|
||||
virtual void resetShaderProgram() = 0;
|
||||
virtual void drawTriangles(const Context::DrawTriangleParameters & _params) = 0;
|
||||
virtual void drawRects(const Context::DrawRectParameters & _params) = 0;
|
||||
virtual void drawLine(f32 _width, SPVertex * _vertices) = 0;
|
||||
virtual f32 getMaxLineWidth() = 0;
|
||||
virtual void drawText(const char *_pText, float _x, float _y) = 0;
|
||||
virtual void getTextSize(const char *_pText, float & _w, float & _h) = 0;
|
||||
virtual bool isSupported(SpecialFeatures _feature) const = 0;
|
||||
virtual bool isError() const = 0;
|
||||
virtual bool isFramebufferError() const = 0;
|
||||
|
|
|
@ -387,6 +387,25 @@ namespace glsl {
|
|||
}
|
||||
};
|
||||
|
||||
/*---------------TextDrawerShaderPart-------------*/
|
||||
|
||||
class TextDraw : public ShaderPart
|
||||
{
|
||||
public:
|
||||
TextDraw(const opengl::GLInfo & _glinfo)
|
||||
{
|
||||
m_part =
|
||||
"IN mediump vec2 vTexCoord0; \n"
|
||||
"uniform sampler2D uTex0; \n"
|
||||
"uniform lowp vec4 uColor; \n"
|
||||
"OUT lowp vec4 fragColor; \n"
|
||||
" \n"
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
" fragColor = texture2D(uTex0, vTexCoord0).r * uColor; \n"
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
/*---------------SpecialShader-------------*/
|
||||
|
||||
|
@ -594,7 +613,7 @@ namespace glsl {
|
|||
}
|
||||
};
|
||||
|
||||
/*---------------PostProcessorShaderPart-------------*/
|
||||
/*---------------PostProcessorShader-------------*/
|
||||
|
||||
typedef SpecialShader<VertexShaderTexturedRect, GammaCorrection> GammaCorrectionShaderBase;
|
||||
|
||||
|
@ -638,6 +657,29 @@ namespace glsl {
|
|||
}
|
||||
};
|
||||
|
||||
/*---------------TexrectDrawerShader-------------*/
|
||||
|
||||
typedef SpecialShader<VertexShaderTexturedRect, TextDraw> TextDrawerShaderBase;
|
||||
|
||||
class TextDrawerShader : public TextDrawerShaderBase
|
||||
{
|
||||
public:
|
||||
TextDrawerShader(const opengl::GLInfo & _glinfo,
|
||||
opengl::CachedUseProgram * _useProgram,
|
||||
const ShaderPart * _vertexHeader,
|
||||
const ShaderPart * _fragmentHeader,
|
||||
const ShaderPart * _fragmentEnd)
|
||||
: TextDrawerShaderBase(_glinfo, _useProgram, _vertexHeader, _fragmentHeader, _fragmentEnd)
|
||||
{
|
||||
m_useProgram->useProgram(m_program);
|
||||
const int texLoc = glGetUniformLocation(GLuint(m_program), "uTex0");
|
||||
glUniform1i(texLoc, 0);
|
||||
const int colorLoc = glGetUniformLocation(GLuint(m_program), "uColor");
|
||||
glUniform4fv(colorLoc, 1, config.font.colorf);
|
||||
m_useProgram->useProgram(graphics::ObjectHandle());
|
||||
}
|
||||
};
|
||||
|
||||
/*---------------SpecialShadersFactory-------------*/
|
||||
|
||||
SpecialShadersFactory::SpecialShadersFactory(const opengl::GLInfo & _glinfo,
|
||||
|
@ -691,4 +733,9 @@ namespace glsl {
|
|||
return new OrientationCorrectionShader(m_glinfo, m_useProgram, m_vertexHeader, m_fragmentHeader, m_fragmentEnd);
|
||||
}
|
||||
|
||||
graphics::ShaderProgram * SpecialShadersFactory::createTextDrawerShader() const
|
||||
{
|
||||
return new TextDrawerShader(m_glinfo, m_useProgram, m_vertexHeader, m_fragmentHeader, m_fragmentEnd);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ namespace glsl {
|
|||
|
||||
graphics::ShaderProgram * createOrientationCorrectionShader() const;
|
||||
|
||||
graphics::ShaderProgram * createTextDrawerShader() const;
|
||||
|
||||
private:
|
||||
const opengl::GLInfo & m_glinfo;
|
||||
const ShaderPart * m_vertexHeader;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "opengl_ContextImpl.h"
|
||||
#include "opengl_BufferedDrawer.h"
|
||||
#include "opengl_UnbufferedDrawer.h"
|
||||
#include "opengl_DummyTextDrawer.h"
|
||||
#include "opengl_ColorBufferReaderWithPixelBuffer.h"
|
||||
#include "opengl_ColorBufferReaderWithBufferStorage.h"
|
||||
//#include "opengl_ColorBufferReaderWithEGLImage.h"
|
||||
|
@ -63,7 +62,6 @@ void ContextImpl::init()
|
|||
m_graphicsDrawer.reset(new BufferedDrawer(m_glInfo, m_cachedFunctions->getCachedVertexAttribArray(), m_cachedFunctions->getCachedBindBuffer()));
|
||||
else
|
||||
m_graphicsDrawer.reset(new UnbufferedDrawer(m_glInfo, m_cachedFunctions->getCachedVertexAttribArray()));
|
||||
m_textDrawer.reset(new DummyTextDrawer);
|
||||
}
|
||||
|
||||
m_combinerProgramBuilder.reset(new glsl::CombinerProgramBuilder(m_glInfo, m_cachedFunctions->getCachedUseProgram()));
|
||||
|
@ -363,6 +361,11 @@ graphics::ShaderProgram * ContextImpl::createOrientationCorrectionShader()
|
|||
return m_specialShadersFactory->createOrientationCorrectionShader();
|
||||
}
|
||||
|
||||
graphics::ShaderProgram * ContextImpl::createTextDrawerShader()
|
||||
{
|
||||
return m_specialShadersFactory->createTextDrawerShader();
|
||||
}
|
||||
|
||||
void ContextImpl::resetShaderProgram()
|
||||
{
|
||||
m_cachedFunctions->getCachedUseProgram()->useProgram(graphics::ObjectHandle());
|
||||
|
@ -391,15 +394,6 @@ f32 ContextImpl::getMaxLineWidth()
|
|||
return lineWidthRange[1];
|
||||
}
|
||||
|
||||
void ContextImpl::drawText(const char *_pText, float _x, float _y)
|
||||
{
|
||||
m_textDrawer->drawText(_pText, _x, _y);
|
||||
}
|
||||
|
||||
void ContextImpl::getTextSize(const char *_pText, float & _w, float & _h)
|
||||
{
|
||||
m_textDrawer->getTextSize(_pText, _w, _h);
|
||||
}
|
||||
bool ContextImpl::isSupported(graphics::SpecialFeatures _feature) const
|
||||
{
|
||||
switch (_feature) {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "opengl_GLInfo.h"
|
||||
#include "opengl_CachedFunctions.h"
|
||||
#include "opengl_GraphicsDrawer.h"
|
||||
#include "opengl_TextDrawer.h"
|
||||
|
||||
namespace glsl {
|
||||
class CombinerProgramBuilder;
|
||||
|
@ -119,6 +118,8 @@ namespace opengl {
|
|||
|
||||
graphics::ShaderProgram * createOrientationCorrectionShader() override;
|
||||
|
||||
graphics::ShaderProgram * createTextDrawerShader() override;
|
||||
|
||||
void resetShaderProgram() override;
|
||||
|
||||
void drawTriangles(const graphics::Context::DrawTriangleParameters & _params) override;
|
||||
|
@ -129,10 +130,6 @@ namespace opengl {
|
|||
|
||||
f32 getMaxLineWidth() override;
|
||||
|
||||
void drawText(const char *_pText, float _x, float _y) override;
|
||||
|
||||
void getTextSize(const char *_pText, float & _w, float & _h) override;
|
||||
|
||||
bool isSupported(graphics::SpecialFeatures _feature) const override;
|
||||
|
||||
bool isError() const override;
|
||||
|
@ -156,7 +153,6 @@ namespace opengl {
|
|||
std::unique_ptr<graphics::FramebufferTextureFormats> m_fbTexFormats;
|
||||
|
||||
std::unique_ptr<GraphicsDrawer> m_graphicsDrawer;
|
||||
std::unique_ptr<TextDrawer> m_textDrawer;
|
||||
|
||||
std::unique_ptr<glsl::CombinerProgramBuilder> m_combinerProgramBuilder;
|
||||
std::unique_ptr<glsl::SpecialShadersFactory> m_specialShadersFactory;
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef OPENGL_DUMMY_TEXTDRAWER_H
|
||||
#define OPENGL_DUMMY_TEXTDRAWER_H
|
||||
|
||||
#include "opengl_TextDrawer.h"
|
||||
|
||||
namespace opengl {
|
||||
|
||||
class DummyTextDrawer : public TextDrawer
|
||||
{
|
||||
public:
|
||||
DummyTextDrawer() {}
|
||||
~DummyTextDrawer() {}
|
||||
|
||||
void drawText(const char *_pText, float x, float y) const override {}
|
||||
void getTextSize(const char *_pText, float & _w, float & _h) const override {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // OPENGL_DUMMY_TEXTDRAWER_H
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef TEXTDRAWERIMPL_H
|
||||
#define TEXTDRAWERIMPL_H
|
||||
|
||||
namespace opengl {
|
||||
|
||||
class TextDrawer
|
||||
{
|
||||
public:
|
||||
virtual ~TextDrawer() {}
|
||||
virtual void drawText(const char *_pText, float x, float y) const = 0;
|
||||
virtual void getTextSize(const char *_pText, float & _w, float & _h) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TEXTDRAWERIMPL_H
|
|
@ -1,408 +0,0 @@
|
|||
/* Draw text on screen.
|
||||
* Requires freetype library.
|
||||
* Code is taken from "OpenGL source examples from the OpenGL Programming wikibook:
|
||||
* http://en.wikibooks.org/wiki/OpenGL_Programming"
|
||||
*/
|
||||
|
||||
#define NOMINMAX
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#include "opengl_TextDrawerImpl.h"
|
||||
#include <RSP.h>
|
||||
#include <Config.h>
|
||||
#include <FBOTextureFormats.h>
|
||||
#include <Log.h>
|
||||
|
||||
#include <Graphics/Context.h>
|
||||
#include <Graphics/Parameters.h>
|
||||
|
||||
//#include "ShaderUtils.h"
|
||||
|
||||
struct point {
|
||||
GLfloat x;
|
||||
GLfloat y;
|
||||
GLfloat s;
|
||||
GLfloat t;
|
||||
point() : x(0), y(0), s(0), t(0) {}
|
||||
point(GLfloat _x, GLfloat _y, GLfloat _s, GLfloat _t) : x(_x), y(_y), s(_s), t(_t) {}
|
||||
};
|
||||
|
||||
// Maximum texture width
|
||||
#define MAXWIDTH 1024
|
||||
|
||||
#if defined(GLES3_1)
|
||||
#define SHADER_VERSION "#version 310 es \n"
|
||||
#elif defined(GLES3)
|
||||
#define SHADER_VERSION "#version 300 es \n"
|
||||
#elif defined(GLES2)
|
||||
#define SHADER_VERSION "#version 100 \n"
|
||||
#else
|
||||
#define SHADER_VERSION "#version 330 core \n"
|
||||
#endif
|
||||
|
||||
#ifdef GLES2
|
||||
const GLenum monohromeformat = GL_LUMINANCE;
|
||||
const GLenum monohromeInternalformat = GL_LUMINANCE;
|
||||
#else
|
||||
const GLenum monohromeformat = GL_RED;
|
||||
const GLenum monohromeInternalformat = GL_R8;
|
||||
#endif // GLES2
|
||||
|
||||
static
|
||||
const char * strDrawTextVertexShader =
|
||||
SHADER_VERSION
|
||||
"#if (__VERSION__ > 120) \n"
|
||||
"# define IN in \n"
|
||||
"# define OUT out \n"
|
||||
"#else \n"
|
||||
"# define IN attribute \n"
|
||||
"# define OUT varying \n"
|
||||
"#endif // __VERSION \n"
|
||||
"IN highp vec4 aRectPosition; \n"
|
||||
"OUT mediump vec2 texpos; \n"
|
||||
"void main(void) { \n"
|
||||
" gl_Position = vec4(aRectPosition.xy, 0, 1); \n"
|
||||
" texpos = aRectPosition.zw; \n"
|
||||
"} \n"
|
||||
;
|
||||
|
||||
static
|
||||
const char * strDrawTextFragmentShader =
|
||||
SHADER_VERSION
|
||||
"#if (__VERSION__ > 120) \n"
|
||||
"# define IN in \n"
|
||||
"# define OUT out \n"
|
||||
"# define texture2D texture \n"
|
||||
"#else \n"
|
||||
"# define IN varying \n"
|
||||
"# define OUT \n"
|
||||
"#endif // __VERSION __ \n"
|
||||
"IN mediump vec2 texpos; \n"
|
||||
"uniform sampler2D uTex; \n"
|
||||
"uniform lowp vec4 uColor; \n"
|
||||
"OUT lowp vec4 fragColor; \n"
|
||||
"void main(void) { \n"
|
||||
" fragColor = texture2D(uTex, texpos).r * uColor; \n"
|
||||
#ifdef GLES2
|
||||
" gl_FragColor = fragColor; \n"
|
||||
#endif
|
||||
"} \n"
|
||||
;
|
||||
|
||||
/**
|
||||
* The atlas struct holds a texture that contains the visible US-ASCII characters
|
||||
* of a certain font rendered with a certain character height.
|
||||
* It also contains an array that contains all the information necessary to
|
||||
* generate the appropriate vertex and texture coordinates for each character.
|
||||
*
|
||||
* After the constructor is run, you don't need to use any FreeType functions anymore.
|
||||
*/
|
||||
struct Atlas {
|
||||
GLuint tex; // texture object
|
||||
|
||||
int w; // width of texture in pixels
|
||||
int h; // height of texture in pixels
|
||||
|
||||
struct {
|
||||
float ax; // advance.x
|
||||
float ay; // advance.y
|
||||
|
||||
float bw; // bitmap.width;
|
||||
float bh; // bitmap.height;
|
||||
|
||||
float bl; // bitmap_left;
|
||||
float bt; // bitmap_top;
|
||||
|
||||
float tx; // x offset of glyph in texture coordinates
|
||||
float ty; // y offset of glyph in texture coordinates
|
||||
} c[128]; // character information
|
||||
|
||||
Atlas(FT_Face face, int height) {
|
||||
FT_Set_Pixel_Sizes(face, 0, height);
|
||||
FT_GlyphSlot g = face->glyph;
|
||||
|
||||
int roww = 0;
|
||||
int rowh = 0;
|
||||
w = 0;
|
||||
h = 0;
|
||||
|
||||
memset(c, 0, sizeof c);
|
||||
|
||||
/* Find minimum size for a texture holding all visible ASCII characters */
|
||||
for (int i = 32; i < 128; i++) {
|
||||
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
|
||||
fprintf(stderr, "Loading character %c failed!\n", i);
|
||||
continue;
|
||||
}
|
||||
if (roww + g->bitmap.width + 1 >= MAXWIDTH) {
|
||||
w = std::max(w, roww);
|
||||
h += rowh;
|
||||
roww = 0;
|
||||
rowh = 0;
|
||||
}
|
||||
roww += g->bitmap.width + 1;
|
||||
rowh = std::max(rowh, (int)g->bitmap.rows);
|
||||
}
|
||||
|
||||
w = std::max(w, roww);
|
||||
h += rowh;
|
||||
|
||||
/* Create a texture that will be used to hold all ASCII glyphs */
|
||||
|
||||
graphics::ObjectHandle texHandle = gfxContext.createTexture(graphics::target::TEXTURE_2D);
|
||||
tex = GLuint(texHandle);
|
||||
|
||||
graphics::Context::InitTextureParams initParams;
|
||||
initParams.handle = texHandle;
|
||||
initParams.width = w;
|
||||
initParams.height = h;
|
||||
initParams.internalFormat = monohromeInternalformat;
|
||||
initParams.format = monohromeformat;
|
||||
initParams.dataType = graphics::datatype::UNSIGNED_BYTE;
|
||||
gfxContext.init2DTexture(initParams);
|
||||
|
||||
/* We require 1 byte alignment when uploading texture data */
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
graphics::Context::TexParameters setParams;
|
||||
setParams.handle = texHandle;
|
||||
setParams.target = graphics::target::TEXTURE_2D;
|
||||
setParams.minFilter = graphics::textureParameters::FILTER_LINEAR;
|
||||
setParams.magFilter = graphics::textureParameters::FILTER_LINEAR;
|
||||
setParams.wrapS = graphics::textureParameters::WRAP_CLAMP_TO_EDGE;
|
||||
setParams.wrapT = graphics::textureParameters::WRAP_CLAMP_TO_EDGE;
|
||||
gfxContext.setTextureParameters(setParams);
|
||||
|
||||
/* Paste all glyph bitmaps into the texture, remembering the offset */
|
||||
int ox = 0;
|
||||
int oy = 0;
|
||||
|
||||
rowh = 0;
|
||||
|
||||
for (int i = 32; i < 128; i++) {
|
||||
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
|
||||
fprintf(stderr, "Loading character %c failed!\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ox + g->bitmap.width + 1 >= MAXWIDTH) {
|
||||
oy += rowh;
|
||||
rowh = 0;
|
||||
ox = 0;
|
||||
}
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, g->bitmap.width, g->bitmap.rows, monohromeformat, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
c[i].ax = _FIXED2FLOAT(g->advance.x, 6);
|
||||
c[i].ay = _FIXED2FLOAT(g->advance.y, 6);
|
||||
|
||||
c[i].bw = (float)g->bitmap.width;
|
||||
c[i].bh = (float)g->bitmap.rows;
|
||||
|
||||
c[i].bl = (float)g->bitmap_left;
|
||||
c[i].bt = (float)g->bitmap_top;
|
||||
|
||||
c[i].tx = ox / (float)w;
|
||||
c[i].ty = oy / (float)h;
|
||||
|
||||
rowh = std::max(rowh, (int)g->bitmap.rows);
|
||||
ox += g->bitmap.width + 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Generated a %d x %d (%d kb) texture atlas\n", w, h, w * h / 1024);
|
||||
}
|
||||
|
||||
~Atlas() {
|
||||
gfxContext.deleteTexture(graphics::ObjectHandle(tex));
|
||||
}
|
||||
};
|
||||
|
||||
TextDrawer::TextDrawer() :
|
||||
m_pAtlas(nullptr), m_program(0), m_uTex(0), m_uColor(0), m_vbo(0)
|
||||
{}
|
||||
|
||||
TextDrawer & TextDrawer::get() {
|
||||
static TextDrawer drawer;
|
||||
return drawer;
|
||||
}
|
||||
|
||||
static
|
||||
bool getFontFileName(char * _strName)
|
||||
{
|
||||
#ifdef OS_WINDOWS
|
||||
char * pSysPath = getenv("WINDIR");
|
||||
if (pSysPath == nullptr)
|
||||
return false;
|
||||
sprintf(_strName, "%s/Fonts/%s", pSysPath, config.font.name.c_str());
|
||||
#elif defined (OS_ANDROID)
|
||||
sprintf(_strName, "/system/fonts/%s", config.font.name.c_str());
|
||||
#elif defined (PANDORA)
|
||||
sprintf(_strName, "/usr/share/fonts/truetype/%s", config.font.name.c_str());
|
||||
#else
|
||||
sprintf(_strName, "/usr/share/fonts/truetype/freefont/%s", config.font.name.c_str());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
FT_Library ft;
|
||||
FT_Face face;
|
||||
|
||||
void TextDrawer::init()
|
||||
{
|
||||
if (m_pAtlas != nullptr)
|
||||
return;
|
||||
|
||||
char strBuffer[PLUGIN_PATH_SIZE];
|
||||
const char *fontfilename;
|
||||
if (getFontFileName(strBuffer))
|
||||
fontfilename = strBuffer;
|
||||
else
|
||||
return;
|
||||
|
||||
/* Initialize the FreeType2 library */
|
||||
if (FT_Init_FreeType(&ft)) {
|
||||
fprintf(stderr, "Could not init freetype library\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load a font */
|
||||
if (FT_New_Face(ft, fontfilename, 0, &face)) {
|
||||
fprintf(stderr, "Could not open font %s\n", fontfilename);
|
||||
return;
|
||||
}
|
||||
|
||||
m_program = createRectShaderProgram(strDrawTextVertexShader, strDrawTextFragmentShader);
|
||||
if(m_program == 0)
|
||||
return;
|
||||
|
||||
m_uTex = glGetUniformLocation(m_program, "uTex");
|
||||
m_uColor = glGetUniformLocation(m_program, "uColor");
|
||||
|
||||
if(m_uTex == -1 || m_uColor == -1)
|
||||
return;
|
||||
|
||||
// Create the vertex buffer object
|
||||
glGenBuffers(1, &m_vbo);
|
||||
|
||||
/* Create texture atlas for selected font size */
|
||||
m_pAtlas = new Atlas(face, config.font.size);
|
||||
}
|
||||
|
||||
void TextDrawer::destroy()
|
||||
{
|
||||
if (m_pAtlas == nullptr)
|
||||
return;
|
||||
delete m_pAtlas;
|
||||
m_pAtlas = nullptr;
|
||||
glDeleteBuffers(1, &m_vbo);
|
||||
m_vbo = 0;
|
||||
glDeleteProgram(m_program);
|
||||
m_program = 0;
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(ft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render text using the currently loaded font and currently set font size.
|
||||
* Rendering starts at coordinates (x, y), z is always 0.
|
||||
* The pixel coordinates that the FreeType2 library uses are scaled by (sx, sy).
|
||||
*/
|
||||
void TextDrawer::renderText(const char *_pText, float _x, float _y) const
|
||||
{
|
||||
if (m_pAtlas == nullptr)
|
||||
return;
|
||||
OGLVideo & ogl = video();
|
||||
const float sx = 2.0f / ogl.getWidth();
|
||||
const float sy = 2.0f / ogl.getHeight();
|
||||
|
||||
const u8 *p;
|
||||
|
||||
glUseProgram(m_program);
|
||||
|
||||
/* Enable blending, necessary for our alpha texture */
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
/* Set color */
|
||||
glUniform4fv(m_uColor, 1, config.font.colorf);
|
||||
|
||||
/* Use the texture containing the atlas */
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, m_pAtlas->tex);
|
||||
glUniform1i(m_uTex, 0);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
#ifndef GLES2
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
#endif
|
||||
|
||||
/* Set up the VBO for our vertex data */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
glVertexAttribPointer(SC_RECT_POSITION, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
|
||||
std::vector<point> coords(6 * strlen(_pText));
|
||||
int c = 0;
|
||||
|
||||
/* Loop through all characters */
|
||||
for (p = (const u8 *)_pText; *p; ++p) {
|
||||
/* Calculate the vertex and texture coordinates */
|
||||
float x2 = _x + m_pAtlas->c[*p].bl * sx;
|
||||
float y2 = -_y - m_pAtlas->c[*p].bt * sy;
|
||||
float w = m_pAtlas->c[*p].bw * sx;
|
||||
float h = m_pAtlas->c[*p].bh * sy;
|
||||
|
||||
/* Advance the cursor to the start of the next character */
|
||||
_x += m_pAtlas->c[*p].ax * sx;
|
||||
_y += m_pAtlas->c[*p].ay * sy;
|
||||
|
||||
/* Skip glyphs that have no pixels */
|
||||
if (!w || !h)
|
||||
continue;
|
||||
|
||||
coords[c++] = point(x2, -y2, m_pAtlas->c[*p].tx, m_pAtlas->c[*p].ty);
|
||||
coords[c++] = point(x2 + w, -y2, m_pAtlas->c[*p].tx + m_pAtlas->c[*p].bw / m_pAtlas->w, m_pAtlas->c[*p].ty);
|
||||
coords[c++] = point(x2, -y2 - h, m_pAtlas->c[*p].tx, m_pAtlas->c[*p].ty + m_pAtlas->c[*p].bh / m_pAtlas->h);
|
||||
coords[c++] = point(x2 + w, -y2, m_pAtlas->c[*p].tx + m_pAtlas->c[*p].bw / m_pAtlas->w, m_pAtlas->c[*p].ty);
|
||||
coords[c++] = point(x2, -y2 - h, m_pAtlas->c[*p].tx, m_pAtlas->c[*p].ty + m_pAtlas->c[*p].bh / m_pAtlas->h);
|
||||
coords[c++] = point(x2 + w, -y2 - h, m_pAtlas->c[*p].tx + m_pAtlas->c[*p].bw / m_pAtlas->w, m_pAtlas->c[*p].ty + m_pAtlas->c[*p].bh / m_pAtlas->h);
|
||||
}
|
||||
|
||||
/* Draw all the character on the screen in one go */
|
||||
glBufferData(GL_ARRAY_BUFFER, coords.size()*sizeof(point), coords.data(), GL_DYNAMIC_DRAW);
|
||||
glDrawArrays(GL_TRIANGLES, 0, c);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void TextDrawer::getTextSize(const char *_pText, float & _w, float & _h) const
|
||||
{
|
||||
_w = _h = 0;
|
||||
if (m_pAtlas == nullptr)
|
||||
return;
|
||||
OGLVideo & ogl = video();
|
||||
const float sx = 2.0f / ogl.getWidth();
|
||||
const float sy = 2.0f / ogl.getHeight();
|
||||
float bw, bh;
|
||||
|
||||
for (const u8 *p = (const u8 *)_pText; *p; ++p) {
|
||||
bw = m_pAtlas->c[*p].bw * sx;
|
||||
bh = m_pAtlas->c[*p].bh * sy;
|
||||
|
||||
_w += m_pAtlas->c[*p].ax * sx;
|
||||
_h += m_pAtlas->c[*p].ay * sy;
|
||||
}
|
||||
_w += bw;
|
||||
_h += bh;
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
#include "NoiseTexture.h"
|
||||
#include "ZlutTexture.h"
|
||||
#include "PaletteTexture.h"
|
||||
#include "TextDrawer.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include "DepthBuffer.h"
|
||||
#include "FrameBufferInfo.h"
|
||||
|
@ -1297,13 +1298,13 @@ void GraphicsDrawer::correctTexturedRectParams(TexturedRectParams & _params)
|
|||
void GraphicsDrawer::drawText(const char *_pText, float x, float y)
|
||||
{
|
||||
m_drawingState = DrawingState::Non;
|
||||
gfxContext.drawText(_pText, x, y);
|
||||
g_textDrawer.drawText(_pText, x, y);
|
||||
}
|
||||
|
||||
void GraphicsDrawer::_drawOSD(const char *_pText, float _x, float & _y)
|
||||
{
|
||||
float tW, tH;
|
||||
gfxContext.getTextSize(_pText, tW, tH);
|
||||
g_textDrawer.getTextSize(_pText, tW, tH);
|
||||
|
||||
const bool top = (config.posTop & config.onScreenDisplay.pos) != 0;
|
||||
const bool right = (config.onScreenDisplay.pos == Config::posTopRight) || (config.onScreenDisplay.pos == Config::posBottomRight);
|
||||
|
@ -1352,7 +1353,7 @@ void GraphicsDrawer::drawOSD()
|
|||
const float vp = bottom ? -1 : 1;
|
||||
|
||||
float hShift, vShift;
|
||||
gfxContext.getTextSize("0", hShift, vShift);
|
||||
g_textDrawer.getTextSize("0", hShift, vShift);
|
||||
hShift *= 0.5f;
|
||||
vShift *= 0.5f;
|
||||
const float x = hp - hShift * hp;
|
||||
|
@ -1571,6 +1572,7 @@ void GraphicsDrawer::_initData()
|
|||
g_zlutTexture.init();
|
||||
g_noiseTexture.init();
|
||||
g_paletteTexture.init();
|
||||
g_textDrawer.init();
|
||||
perf.reset();
|
||||
FBInfo::fbInfo.reset();
|
||||
m_texrectDrawer.init();
|
||||
|
@ -1590,6 +1592,7 @@ void GraphicsDrawer::_destroyData()
|
|||
{
|
||||
m_drawingState = DrawingState::Non;
|
||||
m_texrectDrawer.destroy();
|
||||
g_textDrawer.destroy();
|
||||
g_paletteTexture.destroy();
|
||||
g_zlutTexture.destroy();
|
||||
g_noiseTexture.destroy();
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#include "Graphics/Parameter.h"
|
||||
|
||||
namespace graphics {
|
||||
class DrawerImpl;
|
||||
class TextDrawer;
|
||||
class CombinerProgram;
|
||||
}
|
||||
|
||||
|
|
374
src/TextDrawer.cpp
Normal file
374
src/TextDrawer.cpp
Normal file
|
@ -0,0 +1,374 @@
|
|||
/* Draw text on screen.
|
||||
* Requires freetype library.
|
||||
* Code is taken from "OpenGL source examples from the OpenGL Programming wikibook:
|
||||
* http://en.wikibooks.org/wiki/OpenGL_Programming"
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#include "Platform.h"
|
||||
#include "DisplayWindow.h"
|
||||
#include "GraphicsDrawer.h"
|
||||
#include "Textures.h"
|
||||
#include "Config.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "Graphics/Context.h"
|
||||
#include "Graphics/Parameters.h"
|
||||
|
||||
#include "TextDrawer.h"
|
||||
|
||||
using namespace graphics;
|
||||
|
||||
// Maximum texture width
|
||||
#define MAXWIDTH 1024
|
||||
|
||||
TextDrawer g_textDrawer;
|
||||
|
||||
/**
|
||||
* The atlas struct holds a texture that contains the visible US-ASCII characters
|
||||
* of a certain font rendered with a certain character height.
|
||||
* It also contains an array that contains all the information necessary to
|
||||
* generate the appropriate vertex and texture coordinates for each character.
|
||||
*
|
||||
* After the constructor is run, you don't need to use any FreeType functions anymore.
|
||||
*/
|
||||
struct Atlas {
|
||||
CachedTexture * m_pTexture; // texture object
|
||||
|
||||
int w; // width of texture in pixels
|
||||
int h; // height of texture in pixels
|
||||
|
||||
struct {
|
||||
float ax; // advance.x
|
||||
float ay; // advance.y
|
||||
|
||||
float bw; // bitmap.width;
|
||||
float bh; // bitmap.height;
|
||||
|
||||
float bl; // bitmap_left;
|
||||
float bt; // bitmap_top;
|
||||
|
||||
float tx; // x offset of glyph in texture coordinates
|
||||
float ty; // y offset of glyph in texture coordinates
|
||||
} c[128]; // character information
|
||||
|
||||
Atlas(FT_Face face, int height)
|
||||
{
|
||||
FT_Set_Pixel_Sizes(face, 0, height);
|
||||
FT_GlyphSlot g = face->glyph;
|
||||
|
||||
int roww = 0;
|
||||
int rowh = 0;
|
||||
w = 0;
|
||||
h = 0;
|
||||
|
||||
memset(c, 0, sizeof c);
|
||||
|
||||
/* Find minimum size for a texture holding all visible ASCII characters */
|
||||
for (int i = 32; i < 128; i++) {
|
||||
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
|
||||
fprintf(stderr, "Loading character %c failed!\n", i);
|
||||
continue;
|
||||
}
|
||||
if (roww + g->bitmap.width + 1 >= MAXWIDTH) {
|
||||
w = std::max(w, roww);
|
||||
h += rowh;
|
||||
roww = 0;
|
||||
rowh = 0;
|
||||
}
|
||||
roww += g->bitmap.width + 1;
|
||||
rowh = std::max(rowh, (int)g->bitmap.rows);
|
||||
}
|
||||
|
||||
w = std::max(w, roww);
|
||||
h += rowh;
|
||||
|
||||
/* Create a texture that will be used to hold all ASCII glyphs */
|
||||
const FramebufferTextureFormats & fbTexFormats = gfxContext.getFramebufferTextureFormats();
|
||||
|
||||
m_pTexture = textureCache().addFrameBufferTexture(false);
|
||||
m_pTexture->format = G_IM_FMT_I;
|
||||
m_pTexture->clampS = 1;
|
||||
m_pTexture->clampT = 1;
|
||||
m_pTexture->frameBufferTexture = CachedTexture::fbOneSample;
|
||||
m_pTexture->maskS = 0;
|
||||
m_pTexture->maskT = 0;
|
||||
m_pTexture->mirrorS = 0;
|
||||
m_pTexture->mirrorT = 0;
|
||||
m_pTexture->realWidth = w;
|
||||
m_pTexture->realHeight = h;
|
||||
m_pTexture->textureBytes = m_pTexture->realWidth * m_pTexture->realHeight * fbTexFormats.noiseFormatBytes;
|
||||
textureCache().addFrameBufferTextureSize(m_pTexture->textureBytes);
|
||||
|
||||
Context::InitTextureParams initParams;
|
||||
initParams.handle = m_pTexture->name;
|
||||
initParams.textureUnitIndex = textureIndices::Tex[0];
|
||||
initParams.width = w;
|
||||
initParams.height = h;
|
||||
initParams.internalFormat = fbTexFormats.noiseInternalFormat;
|
||||
initParams.format = fbTexFormats.noiseFormat;
|
||||
initParams.dataType = fbTexFormats.noiseType;
|
||||
gfxContext.init2DTexture(initParams);
|
||||
|
||||
Context::TexParameters setParams;
|
||||
setParams.handle = m_pTexture->name;
|
||||
setParams.textureUnitIndex = textureIndices::Tex[0];
|
||||
setParams.target = textureTarget::TEXTURE_2D;
|
||||
setParams.minFilter = textureParameters::FILTER_LINEAR;
|
||||
setParams.magFilter = textureParameters::FILTER_LINEAR;
|
||||
setParams.wrapS = textureParameters::WRAP_CLAMP_TO_EDGE;
|
||||
setParams.wrapT = textureParameters::WRAP_CLAMP_TO_EDGE;
|
||||
gfxContext.setTextureParameters(setParams);
|
||||
|
||||
/* Paste all glyph bitmaps into the texture, remembering the offset */
|
||||
|
||||
/* We require 1 byte alignment when uploading texture data */
|
||||
const s32 curUnpackAlignment = gfxContext.getTextureUnpackAlignment();
|
||||
gfxContext.setTextureUnpackAlignment(1);
|
||||
|
||||
Context::UpdateTextureDataParams updateParams;
|
||||
updateParams.handle = m_pTexture->name;
|
||||
updateParams.textureUnitIndex = textureIndices::Tex[0];
|
||||
updateParams.format = initParams.format;
|
||||
updateParams.internalFormat = initParams.internalFormat;
|
||||
updateParams.dataType = initParams.dataType;
|
||||
|
||||
int ox = 0;
|
||||
int oy = 0;
|
||||
rowh = 0;
|
||||
|
||||
for (int i = 32; i < 128; i++) {
|
||||
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
|
||||
fprintf(stderr, "Loading character %c failed!\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ox + g->bitmap.width + 1 >= MAXWIDTH) {
|
||||
oy += rowh;
|
||||
rowh = 0;
|
||||
ox = 0;
|
||||
}
|
||||
|
||||
updateParams.x = ox;
|
||||
updateParams.y = oy;
|
||||
updateParams.width = g->bitmap.width;
|
||||
updateParams.height = g->bitmap.rows;
|
||||
updateParams.data = g->bitmap.buffer;
|
||||
gfxContext.update2DTexture(updateParams);
|
||||
|
||||
c[i].ax = _FIXED2FLOAT(g->advance.x, 6);
|
||||
c[i].ay = _FIXED2FLOAT(g->advance.y, 6);
|
||||
|
||||
c[i].bw = (float)g->bitmap.width;
|
||||
c[i].bh = (float)g->bitmap.rows;
|
||||
|
||||
c[i].bl = (float)g->bitmap_left;
|
||||
c[i].bt = (float)g->bitmap_top;
|
||||
|
||||
c[i].tx = ox / (float)w;
|
||||
c[i].ty = oy / (float)h;
|
||||
|
||||
rowh = std::max(rowh, (int)g->bitmap.rows);
|
||||
ox += g->bitmap.width + 1;
|
||||
}
|
||||
|
||||
gfxContext.setTextureUnpackAlignment(curUnpackAlignment);
|
||||
|
||||
LOG(LOG_VERBOSE, "Generated a %d x %d (%d kb) texture atlas\n", w, h, w * h / 1024);
|
||||
}
|
||||
|
||||
~Atlas() {
|
||||
textureCache().removeFrameBufferTexture(m_pTexture);
|
||||
m_pTexture = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
static
|
||||
bool getFontFileName(char * _strName)
|
||||
{
|
||||
#ifdef OS_WINDOWS
|
||||
char * pSysPath = getenv("WINDIR");
|
||||
if (pSysPath == nullptr)
|
||||
return false;
|
||||
sprintf(_strName, "%s/Fonts/%s", pSysPath, config.font.name.c_str());
|
||||
#elif defined (OS_ANDROID)
|
||||
sprintf(_strName, "/system/fonts/%s", config.font.name.c_str());
|
||||
#elif defined (PANDORA)
|
||||
sprintf(_strName, "/usr/share/fonts/truetype/%s", config.font.name.c_str());
|
||||
#else
|
||||
sprintf(_strName, "/usr/share/fonts/truetype/freefont/%s", config.font.name.c_str());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
FT_Library ft;
|
||||
FT_Face face;
|
||||
|
||||
void TextDrawer::init()
|
||||
{
|
||||
char strBuffer[PLUGIN_PATH_SIZE];
|
||||
const char *fontfilename;
|
||||
if (getFontFileName(strBuffer))
|
||||
fontfilename = strBuffer;
|
||||
else
|
||||
return;
|
||||
|
||||
/* Initialize the FreeType2 library */
|
||||
if (FT_Init_FreeType(&ft)) {
|
||||
fprintf(stderr, "Could not init freetype library\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load a font */
|
||||
if (FT_New_Face(ft, fontfilename, 0, &face)) {
|
||||
fprintf(stderr, "Could not open font %s\n", fontfilename);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create texture atlas for selected font size */
|
||||
m_atlas.reset(new Atlas(face, config.font.size));
|
||||
|
||||
m_program.reset(gfxContext.createTextDrawerShader());
|
||||
}
|
||||
|
||||
void TextDrawer::destroy()
|
||||
{
|
||||
m_atlas.reset();
|
||||
m_program.reset();
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(ft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render text using the currently loaded font and currently set font size.
|
||||
* Rendering starts at coordinates (x, y), z is always 0.
|
||||
* The pixel coordinates that the FreeType2 library uses are scaled by (sx, sy).
|
||||
*/
|
||||
void TextDrawer::drawText(const char *_pText, float _x, float _y) const
|
||||
{
|
||||
if (!m_atlas)
|
||||
return;
|
||||
|
||||
DisplayWindow & wnd = DisplayWindow::get();
|
||||
const float sx = 2.0f / wnd.getWidth();
|
||||
const float sy = 2.0f / wnd.getHeight();
|
||||
|
||||
const u8 *p;
|
||||
|
||||
|
||||
std::vector<RectVertex> coords;
|
||||
coords.reserve(6 * strlen(_pText));
|
||||
|
||||
RectVertex rect;
|
||||
rect.z = 0.0f;
|
||||
rect.w = 1.0f;
|
||||
|
||||
/* Loop through all characters */
|
||||
for (p = (const u8 *)_pText; *p; ++p) {
|
||||
/* Calculate the vertex and texture coordinates */
|
||||
float x2 = _x + m_atlas->c[*p].bl * sx;
|
||||
float y2 = -_y - m_atlas->c[*p].bt * sy;
|
||||
float w = m_atlas->c[*p].bw * sx;
|
||||
float h = m_atlas->c[*p].bh * sy;
|
||||
|
||||
/* Advance the cursor to the start of the next character */
|
||||
_x += m_atlas->c[*p].ax * sx;
|
||||
_y += m_atlas->c[*p].ay * sy;
|
||||
|
||||
/* Skip glyphs that have no pixels */
|
||||
if (!w || !h)
|
||||
continue;
|
||||
|
||||
rect.x = x2;
|
||||
rect.y = -y2;
|
||||
rect.s0 = m_atlas->c[*p].tx;
|
||||
rect.t0 = m_atlas->c[*p].ty;
|
||||
coords.push_back(rect);
|
||||
|
||||
rect.x = x2 + w;
|
||||
rect.y = -y2;
|
||||
rect.s0 = m_atlas->c[*p].tx + m_atlas->c[*p].bw / m_atlas->w;
|
||||
rect.t0 = m_atlas->c[*p].ty;
|
||||
coords.push_back(rect);
|
||||
|
||||
rect.x = x2;
|
||||
rect.y = -y2 - h;
|
||||
rect.s0 = m_atlas->c[*p].tx;
|
||||
rect.t0 = m_atlas->c[*p].ty + m_atlas->c[*p].bh / m_atlas->h;
|
||||
coords.push_back(rect);
|
||||
|
||||
rect.x = x2 + w;
|
||||
rect.y = -y2;
|
||||
rect.s0 = m_atlas->c[*p].tx + m_atlas->c[*p].bw / m_atlas->w;
|
||||
rect.t0 = m_atlas->c[*p].ty;
|
||||
coords.push_back(rect);
|
||||
|
||||
rect.x = x2;
|
||||
rect.y = -y2 - h;
|
||||
rect.s0 = m_atlas->c[*p].tx;
|
||||
rect.t0 = m_atlas->c[*p].ty + m_atlas->c[*p].bh / m_atlas->h;
|
||||
coords.push_back(rect);
|
||||
|
||||
rect.x = x2 + w;
|
||||
rect.y = -y2 - h;
|
||||
rect.s0 = m_atlas->c[*p].tx + m_atlas->c[*p].bw / m_atlas->w;
|
||||
rect.t0 = m_atlas->c[*p].ty + m_atlas->c[*p].bh / m_atlas->h;
|
||||
coords.push_back(rect);
|
||||
}
|
||||
|
||||
gfxContext.enable(enable::BLEND, true);
|
||||
gfxContext.enable(enable::CULL_FACE, false);
|
||||
gfxContext.enable(enable::DEPTH_TEST, false);
|
||||
gfxContext.enableDepthWrite(false);
|
||||
gfxContext.setBlending(blend::SRC_ALPHA, blend::ONE_MINUS_SRC_ALPHA);
|
||||
m_program->activate();
|
||||
|
||||
Context::TexParameters setParams;
|
||||
setParams.handle = m_atlas->m_pTexture->name;
|
||||
setParams.textureUnitIndex = textureIndices::Tex[0];
|
||||
setParams.target = textureTarget::TEXTURE_2D;
|
||||
setParams.minFilter = textureParameters::FILTER_LINEAR;
|
||||
setParams.magFilter = textureParameters::FILTER_LINEAR;
|
||||
setParams.wrapS = textureParameters::WRAP_CLAMP_TO_EDGE;
|
||||
setParams.wrapT = textureParameters::WRAP_CLAMP_TO_EDGE;
|
||||
setParams.maxMipmapLevel = Parameter(0);
|
||||
gfxContext.setTextureParameters(setParams);
|
||||
|
||||
Context::DrawRectParameters rectParams;
|
||||
rectParams.mode = drawmode::TRIANGLES;
|
||||
rectParams.rectColor.fill(0.0f);
|
||||
rectParams.verticesCount = coords.size();
|
||||
rectParams.vertices = coords.data();
|
||||
rectParams.combiner = m_program.get();
|
||||
gfxContext.drawRects(rectParams);
|
||||
}
|
||||
|
||||
void TextDrawer::getTextSize(const char *_pText, float & _w, float & _h) const
|
||||
{
|
||||
_w = _h = 0;
|
||||
if (!m_atlas)
|
||||
return;
|
||||
|
||||
DisplayWindow & wnd = DisplayWindow::get();
|
||||
const float sx = 2.0f / wnd.getWidth();
|
||||
const float sy = 2.0f / wnd.getHeight();
|
||||
float bw, bh;
|
||||
|
||||
for (const u8 *p = (const u8 *)_pText; *p; ++p) {
|
||||
bw = m_atlas->c[*p].bw * sx;
|
||||
bh = m_atlas->c[*p].bh * sy;
|
||||
|
||||
_w += m_atlas->c[*p].ax * sx;
|
||||
_h += m_atlas->c[*p].ay * sy;
|
||||
}
|
||||
_w += bw;
|
||||
_h += bh;
|
||||
}
|
28
src/TextDrawer.h
Normal file
28
src/TextDrawer.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef TEXTDRAWER_H
|
||||
#define TEXTDRAWER_H
|
||||
|
||||
#include <memory>
|
||||
#include "Graphics/ShaderProgram.h"
|
||||
#include "Graphics/FramebufferTextureFormats.h"
|
||||
|
||||
struct Atlas;
|
||||
|
||||
class TextDrawer
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
|
||||
void destroy();
|
||||
|
||||
void drawText(const char *_pText, float x, float y) const;
|
||||
|
||||
void getTextSize(const char *_pText, float & _w, float & _h) const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Atlas> m_atlas;
|
||||
std::unique_ptr<graphics::ShaderProgram> m_program;
|
||||
};
|
||||
|
||||
extern TextDrawer g_textDrawer;
|
||||
|
||||
#endif // TEXTDRAWER_H
|
|
@ -65,6 +65,7 @@ MY_LOCAL_SRC_FILES := \
|
|||
$(SRCDIR)/S2DEX2.cpp \
|
||||
$(SRCDIR)/S2DEX.cpp \
|
||||
$(SRCDIR)/SoftwareRender.cpp \
|
||||
$(SRCDIR)/TextDrawer.cpp \
|
||||
$(SRCDIR)/TextureFilterHandler.cpp \
|
||||
$(SRCDIR)/Textures.cpp \
|
||||
$(SRCDIR)/Turbo3D.cpp \
|
||||
|
|
Loading…
Reference in New Issue
Block a user