diff --git a/projects/msvc12/GLideN64.vcxproj b/projects/msvc12/GLideN64.vcxproj
index 23b79863..8c850bbb 100644
--- a/projects/msvc12/GLideN64.vcxproj
+++ b/projects/msvc12/GLideN64.vcxproj
@@ -350,6 +350,7 @@
+
@@ -442,9 +443,7 @@
-
-
@@ -472,6 +471,7 @@
+
diff --git a/projects/msvc12/GLideN64.vcxproj.filters b/projects/msvc12/GLideN64.vcxproj.filters
index 5bc4376b..148f9fb2 100644
--- a/projects/msvc12/GLideN64.vcxproj.filters
+++ b/projects/msvc12/GLideN64.vcxproj.filters
@@ -329,6 +329,9 @@
Source Files\Graphics\OpenGL
+
+ Source Files
+
@@ -595,12 +598,6 @@
Header Files
-
- Header Files\Graphics\OpenGL
-
-
- Header Files\Graphics\OpenGL
-
Header Files\Graphics\OpenGL
@@ -622,5 +619,8 @@
Header Files\Graphics\OpenGL
+
+ Header Files
+
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 254cee5c..0250b906 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -48,6 +48,7 @@ set(GLideN64_SOURCES
S2DEX2.cpp
S2DEX.cpp
SoftwareRender.cpp
+ TextDrawer.cpp
TextureFilterHandler.cpp
Textures.cpp
Turbo3D.cpp
diff --git a/src/Graphics/Context.cpp b/src/Graphics/Context.cpp
index f6ed7db4..d3a9daa5 100644
--- a/src/Graphics/Context.cpp
+++ b/src/Graphics/Context.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();
diff --git a/src/Graphics/Context.h b/src/Graphics/Context.h
index 5ba6c93c..e1914e52 100644
--- a/src/Graphics/Context.h
+++ b/src/Graphics/Context.h
@@ -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;
diff --git a/src/Graphics/ContextImpl.h b/src/Graphics/ContextImpl.h
index c056c9f5..4d0eed63 100644
--- a/src/Graphics/ContextImpl.h
+++ b/src/Graphics/ContextImpl.h
@@ -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;
diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_SpecialShadersFactory.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_SpecialShadersFactory.cpp
index a7983061..7d9a7d89 100644
--- a/src/Graphics/OpenGLContext/GLSL/glsl_SpecialShadersFactory.cpp
+++ b/src/Graphics/OpenGLContext/GLSL/glsl_SpecialShadersFactory.cpp
@@ -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 GammaCorrectionShaderBase;
@@ -638,6 +657,29 @@ namespace glsl {
}
};
+ /*---------------TexrectDrawerShader-------------*/
+
+ typedef SpecialShader 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);
+ }
+
}
diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_SpecialShadersFactory.h b/src/Graphics/OpenGLContext/GLSL/glsl_SpecialShadersFactory.h
index 2878f9cf..f0401321 100644
--- a/src/Graphics/OpenGLContext/GLSL/glsl_SpecialShadersFactory.h
+++ b/src/Graphics/OpenGLContext/GLSL/glsl_SpecialShadersFactory.h
@@ -36,6 +36,8 @@ namespace glsl {
graphics::ShaderProgram * createOrientationCorrectionShader() const;
+ graphics::ShaderProgram * createTextDrawerShader() const;
+
private:
const opengl::GLInfo & m_glinfo;
const ShaderPart * m_vertexHeader;
diff --git a/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp b/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp
index aebe4e0b..e2292e8e 100644
--- a/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp
+++ b/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp
@@ -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) {
diff --git a/src/Graphics/OpenGLContext/opengl_ContextImpl.h b/src/Graphics/OpenGLContext/opengl_ContextImpl.h
index feb89af0..5e05eb98 100644
--- a/src/Graphics/OpenGLContext/opengl_ContextImpl.h
+++ b/src/Graphics/OpenGLContext/opengl_ContextImpl.h
@@ -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 m_fbTexFormats;
std::unique_ptr m_graphicsDrawer;
- std::unique_ptr m_textDrawer;
std::unique_ptr m_combinerProgramBuilder;
std::unique_ptr m_specialShadersFactory;
diff --git a/src/Graphics/OpenGLContext/opengl_DummyTextDrawer.h b/src/Graphics/OpenGLContext/opengl_DummyTextDrawer.h
deleted file mode 100644
index 4d84e843..00000000
--- a/src/Graphics/OpenGLContext/opengl_DummyTextDrawer.h
+++ /dev/null
@@ -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
diff --git a/src/Graphics/OpenGLContext/opengl_TextDrawer.h b/src/Graphics/OpenGLContext/opengl_TextDrawer.h
deleted file mode 100644
index 2be42427..00000000
--- a/src/Graphics/OpenGLContext/opengl_TextDrawer.h
+++ /dev/null
@@ -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
diff --git a/src/Graphics/OpenGLContext/opengl_TextDrawerImpl.cpp b/src/Graphics/OpenGLContext/opengl_TextDrawerImpl.cpp
deleted file mode 100644
index 1d01a7d9..00000000
--- a/src/Graphics/OpenGLContext/opengl_TextDrawerImpl.cpp
+++ /dev/null
@@ -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
-#include
-#include
-#include
-#include
-
-#include
-#include FT_FREETYPE_H
-
-#include "opengl_TextDrawerImpl.h"
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-//#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 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;
-}
diff --git a/src/GraphicsDrawer.cpp b/src/GraphicsDrawer.cpp
index dd959900..ac29ba19 100644
--- a/src/GraphicsDrawer.cpp
+++ b/src/GraphicsDrawer.cpp
@@ -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();
diff --git a/src/GraphicsDrawer.h b/src/GraphicsDrawer.h
index 2357c464..fb38a73d 100644
--- a/src/GraphicsDrawer.h
+++ b/src/GraphicsDrawer.h
@@ -7,8 +7,6 @@
#include "Graphics/Parameter.h"
namespace graphics {
- class DrawerImpl;
- class TextDrawer;
class CombinerProgram;
}
diff --git a/src/TextDrawer.cpp b/src/TextDrawer.cpp
new file mode 100644
index 00000000..33309005
--- /dev/null
+++ b/src/TextDrawer.cpp
@@ -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
+#include
+#include
+#include
+#include
+
+#include
+#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 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;
+}
diff --git a/src/TextDrawer.h b/src/TextDrawer.h
new file mode 100644
index 00000000..883160a9
--- /dev/null
+++ b/src/TextDrawer.h
@@ -0,0 +1,28 @@
+#ifndef TEXTDRAWER_H
+#define TEXTDRAWER_H
+
+#include
+#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 m_atlas;
+ std::unique_ptr m_program;
+};
+
+extern TextDrawer g_textDrawer;
+
+#endif // TEXTDRAWER_H
diff --git a/src/mupen64plus-video-gliden64.mk b/src/mupen64plus-video-gliden64.mk
index c4f88305..415e0b3a 100644
--- a/src/mupen64plus-video-gliden64.mk
+++ b/src/mupen64plus-video-gliden64.mk
@@ -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 \