mirror of
https://github.com/blawar/GLideN64.git
synced 2024-07-05 10:33:37 +00:00
Add TextDrawer for on-screen text messages.
This commit is contained in:
parent
19a274f9e5
commit
f4bb31e50e
|
@ -34,6 +34,7 @@ set(GLideN64_SOURCES
|
|||
Turbo3D.cpp
|
||||
ZSort.cpp
|
||||
Textures.cpp
|
||||
TextDrawer.cpp
|
||||
VI.cpp
|
||||
common/CommonAPIImpl_common.cpp
|
||||
)
|
||||
|
@ -126,6 +127,10 @@ if(SDL)
|
|||
)
|
||||
endif(SDL)
|
||||
|
||||
SET( ENV{FREETYPE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../freetype )
|
||||
FIND_PACKAGE( Freetype REQUIRED )
|
||||
include_directories( ${FREETYPE_INCLUDE_DIRS} )
|
||||
|
||||
if(OPT)
|
||||
add_definitions(
|
||||
-D__CRC_OPT
|
||||
|
|
8
Config.h
8
Config.h
|
@ -1,6 +1,7 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include <string>
|
||||
#include "Types.h"
|
||||
|
||||
struct Config
|
||||
|
@ -54,6 +55,13 @@ struct Config
|
|||
u32 N64DepthCompare;
|
||||
} frameBufferEmulation;
|
||||
|
||||
struct
|
||||
{
|
||||
std::string name;
|
||||
u32 size;
|
||||
float color[4];
|
||||
} font;
|
||||
|
||||
u32 enableFog;
|
||||
u32 enableNoise;
|
||||
u32 enableLOD;
|
||||
|
|
|
@ -119,21 +119,22 @@
|
|||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>glN64.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile>GLideN64.h</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<AdditionalIncludeDirectories>../freetype/include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>GLideNHQ\build_vs\Debug\libGLideNHQ.lib;opengl32.lib;glu32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>freetype253MT_D.lib;GLideNHQ\build_vs\Debug\libGLideNHQ.lib;opengl32.lib;glu32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>c:\Games\N64\Plugin\GLideN64.dll</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)New glNintendo64().pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<ImportLibrary>$(OutDir)New glNintendo64().lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalLibraryDirectories>%BOOST_ROOT%/lib32-msvc-12.0</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>%BOOST_ROOT%/lib32-msvc-12.0;../freetype/lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_mupenplus|Win32'">
|
||||
|
@ -148,19 +149,19 @@
|
|||
<PrecompiledHeaderFile>glN64.h</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>inc</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>inc;../freetype/include</AdditionalIncludeDirectories>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>GLideNHQ\build_vs\Debug\libGLideNHQ.lib;opengl32.lib;glu32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>freetype253MT_D.lib;GLideNHQ\build_vs\Debug\libGLideNHQ.lib;opengl32.lib;glu32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>c:\Games\N64\M64Py\mupen64plus-video-GLideN64.dll </OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)New glNintendo64().pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<ImportLibrary>$(OutDir)New glNintendo64().lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalLibraryDirectories>%BOOST_ROOT%/lib32-msvc-12.0</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>%BOOST_ROOT%/lib32-msvc-12.0;../freetype/lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
|
@ -180,9 +181,10 @@
|
|||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<AdditionalIncludeDirectories>../freetype/include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>GLideNHQ\build_vs\Release\libGLideNHQ.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>freetype253MT.lib;GLideNHQ\build_vs\Release\libGLideNHQ.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>c:\Games\N64\Plugin\GLideN64.dll</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -190,7 +192,7 @@
|
|||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<ImportLibrary>$(OutDir)New glNintendo64().lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalLibraryDirectories>%BOOST_ROOT%/lib32-msvc-12.0</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>%BOOST_ROOT%/lib32-msvc-12.0;../freetype/lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_mupenplus|Win32'">
|
||||
|
@ -208,12 +210,12 @@
|
|||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>inc</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>inc;../freetype/include</AdditionalIncludeDirectories>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>GLideNHQ\build_vs\Release\libGLideNHQ.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>freetype253MT.lib;GLideNHQ\build_vs\Release\libGLideNHQ.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>c:\Games\N64\M64Py\mupen64plus-video-GLideN64.dll</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -221,7 +223,7 @@
|
|||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<ImportLibrary>$(OutDir)New glNintendo64().lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalLibraryDirectories>%BOOST_ROOT%/lib32-msvc-12.0</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>%BOOST_ROOT%/lib32-msvc-12.0;../freetype/lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 1964|Win32'">
|
||||
|
@ -293,6 +295,7 @@
|
|||
<ClCompile Include="OpenGL.cpp" />
|
||||
<ClCompile Include="RDP.CPP" />
|
||||
<ClCompile Include="RSP.cpp" />
|
||||
<ClCompile Include="TextDrawer.cpp" />
|
||||
<ClCompile Include="Textures.cpp" />
|
||||
<ClCompile Include="Turbo3D.cpp" />
|
||||
<ClCompile Include="VI.cpp" />
|
||||
|
@ -373,6 +376,7 @@
|
|||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="RSP.h" />
|
||||
<ClInclude Include="Shaders.h" />
|
||||
<ClInclude Include="TextDrawer.h" />
|
||||
<ClInclude Include="Textures.h" />
|
||||
<ClInclude Include="Turbo3D.h" />
|
||||
<ClInclude Include="Types.h" />
|
||||
|
|
|
@ -189,6 +189,9 @@
|
|||
<ClCompile Include="F3DSWSE.cpp">
|
||||
<Filter>Source Files\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TextDrawer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="3DMath.h">
|
||||
|
@ -329,6 +332,9 @@
|
|||
<ClInclude Include="GLideNHQ\Ext_TxFilter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextDrawer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Resource.rc">
|
||||
|
|
27
OpenGL.cpp
27
OpenGL.cpp
|
@ -26,6 +26,7 @@
|
|||
#include "VI.h"
|
||||
#include "Config.h"
|
||||
#include "Log.h"
|
||||
#include "TextDrawer.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -1077,6 +1078,12 @@ void OGLRender::drawTexturedRect(const TexturedRectParams & _params)
|
|||
_updateViewport();
|
||||
}
|
||||
|
||||
void OGLRender::drawText(const char *_pText, float x, float y)
|
||||
{
|
||||
m_renderState = rsNone;
|
||||
TextDrawer::get().renderText(_pText, x, y);
|
||||
}
|
||||
|
||||
void OGLRender::clearDepthBuffer()
|
||||
{
|
||||
if (config.frameBufferEmulation.enable && frameBufferList().getCurrent() == NULL)
|
||||
|
@ -1154,6 +1161,7 @@ void OGLRender::_initData()
|
|||
DepthBuffer_Init();
|
||||
FrameBuffer_Init();
|
||||
Combiner_Init();
|
||||
TextDrawer::get().init();
|
||||
m_renderState = rsNone;
|
||||
|
||||
gSP.changed = gDP.changed = 0xFFFFFFFF;
|
||||
|
@ -1170,6 +1178,7 @@ void OGLRender::_initData()
|
|||
void OGLRender::_destroyData()
|
||||
{
|
||||
m_renderState = rsNone;
|
||||
TextDrawer::get().destroy();
|
||||
Combiner_Destroy();
|
||||
FrameBuffer_Destroy();
|
||||
DepthBuffer_Destroy();
|
||||
|
@ -1224,7 +1233,7 @@ void displayLoadProgress(const wchar_t *format, ...)
|
|||
{
|
||||
va_list args;
|
||||
wchar_t wbuf[INFO_BUF];
|
||||
// char buf[INFO_BUF];
|
||||
char buf[INFO_BUF];
|
||||
|
||||
// process input
|
||||
va_start(args, format);
|
||||
|
@ -1232,9 +1241,21 @@ void displayLoadProgress(const wchar_t *format, ...)
|
|||
va_end(args);
|
||||
|
||||
// XXX: convert to multibyte
|
||||
// wcstombs(buf, wbuf, INFO_BUF);
|
||||
wcstombs(buf, wbuf, INFO_BUF);
|
||||
|
||||
OutputDebugStringW(wbuf);
|
||||
FrameBuffer* pBuffer = frameBufferList().getCurrent();
|
||||
if (pBuffer != NULL)
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
||||
OGLRender & render = video().getRender();
|
||||
float black[4] = {0, 0, 0, 0};
|
||||
render.clearColorBuffer(black);
|
||||
render.drawText(buf, -0.9f, 0);
|
||||
video().swapBuffers();
|
||||
|
||||
if (pBuffer != NULL)
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, pBuffer->m_FBO);
|
||||
//OutputDebugStringW(wbuf);
|
||||
}
|
||||
|
||||
void TextureFilterHandler::init()
|
||||
|
|
1
OpenGL.h
1
OpenGL.h
|
@ -57,6 +57,7 @@ public:
|
|||
{}
|
||||
};
|
||||
void drawTexturedRect(const TexturedRectParams & _params);
|
||||
void drawText(const char *_pText, float x, float y);
|
||||
void clearDepthBuffer();
|
||||
void clearColorBuffer( float * _pColor );
|
||||
|
||||
|
|
341
TextDrawer.cpp
Normal file
341
TextDrawer.cpp
Normal file
|
@ -0,0 +1,341 @@
|
|||
/* 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 "TextDrawer.h"
|
||||
#include "Config.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
|
||||
|
||||
static
|
||||
const char * strDrawTextVertexShader =
|
||||
"#version 330 core \n"
|
||||
"in highp vec4 aPosition; \n"
|
||||
"varying mediump vec2 texpos; \n"
|
||||
"void main(void) { \n"
|
||||
" gl_Position = vec4(aPosition.xy, 0, 1); \n"
|
||||
" texpos = aPosition.zw; \n"
|
||||
"} \n"
|
||||
;
|
||||
|
||||
static
|
||||
const char * strDrawTextFragmentShader =
|
||||
"#version 330 core \n"
|
||||
"varying mediump vec2 texpos; \n"
|
||||
"uniform sampler2D uTex; \n"
|
||||
"uniform vec4 uColor; \n"
|
||||
"out lowp vec4 fragColor; \n"
|
||||
"void main(void) { \n"
|
||||
" fragColor = texture2D(uTex, texpos).r * uColor; \n"
|
||||
"} \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, g->bitmap.rows);
|
||||
}
|
||||
|
||||
w = std::max(w, roww);
|
||||
h += rowh;
|
||||
|
||||
/* Create a texture that will be used to hold all ASCII glyphs */
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
|
||||
|
||||
/* We require 1 byte alignment when uploading texture data */
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
/* Clamping to edges is important to prevent artifacts when scaling */
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
/* Linear filtering usually looks best for text */
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
/* 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, GL_RED, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
c[i].ax = g->advance.x >> 6;
|
||||
c[i].ay = g->advance.y >> 6;
|
||||
|
||||
c[i].bw = g->bitmap.width;
|
||||
c[i].bh = g->bitmap.rows;
|
||||
|
||||
c[i].bl = g->bitmap_left;
|
||||
c[i].bt = g->bitmap_top;
|
||||
|
||||
c[i].tx = ox / (float)w;
|
||||
c[i].ty = oy / (float)h;
|
||||
|
||||
rowh = std::max(rowh, 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() {
|
||||
glDeleteTextures(1, &tex);
|
||||
}
|
||||
};
|
||||
|
||||
TextDrawer::TextDrawer() :
|
||||
m_pAtlas(NULL), 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)
|
||||
{
|
||||
char * pWinPath = getenv("WINDIR");
|
||||
if (pWinPath == NULL)
|
||||
return false;
|
||||
// sprintf(_strName, "%s/Fonts/ARIALN.TTF", pWinPath);
|
||||
sprintf(_strName, "%s/Fonts/%s", pWinPath, config.font.name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
FT_Library ft;
|
||||
FT_Face face;
|
||||
|
||||
void TextDrawer::init()
|
||||
{
|
||||
if (m_pAtlas != NULL)
|
||||
return;
|
||||
|
||||
char strBuffer[MAX_PATH];
|
||||
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;
|
||||
}
|
||||
|
||||
GLint status;
|
||||
|
||||
GLuint draw_text_vertex_shader_object = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(draw_text_vertex_shader_object, 1, &strDrawTextVertexShader, NULL);
|
||||
glCompileShader(draw_text_vertex_shader_object);
|
||||
glGetShaderiv(draw_text_vertex_shader_object, GL_COMPILE_STATUS, &status);
|
||||
assert(status == GL_TRUE);
|
||||
|
||||
GLuint draw_text_fragment_shader_object = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(draw_text_fragment_shader_object, 1, &strDrawTextFragmentShader, NULL);
|
||||
glCompileShader(draw_text_fragment_shader_object);
|
||||
glGetShaderiv(draw_text_fragment_shader_object, GL_COMPILE_STATUS, &status);
|
||||
assert(status == GL_TRUE);
|
||||
|
||||
m_program = glCreateProgram();
|
||||
glBindAttribLocation(m_program, SC_POSITION, "aPosition");
|
||||
glAttachShader(m_program, draw_text_vertex_shader_object);
|
||||
glAttachShader(m_program, draw_text_fragment_shader_object);
|
||||
glLinkProgram(m_program);
|
||||
glDeleteShader(draw_text_vertex_shader_object);
|
||||
glDeleteShader(draw_text_fragment_shader_object);
|
||||
glGetProgramiv(m_program, GL_LINK_STATUS, &status);
|
||||
assert(status == GL_TRUE);
|
||||
|
||||
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 == NULL)
|
||||
return;
|
||||
delete m_pAtlas;
|
||||
m_pAtlas = NULL;
|
||||
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 == NULL)
|
||||
return;
|
||||
OGLVideo & ogl = video();
|
||||
const float sx = 2.0 / ogl.getWidth();
|
||||
const float sy = 2.0 / ogl.getHeight();
|
||||
|
||||
const u8 *p;
|
||||
|
||||
glUseProgram(m_program);
|
||||
|
||||
/* Enable blending, necessary for our alpha texture */
|
||||
glEnable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
/* Set color */
|
||||
glUniform4fv(m_uColor, 1, config.font.color);
|
||||
|
||||
/* Use the texture containing the atlas */
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, m_pAtlas->tex);
|
||||
glUniform1i(m_uTex, 0);
|
||||
|
||||
/* Set up the VBO for our vertex data */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
glVertexAttribPointer(SC_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);
|
||||
}
|
21
TextDrawer.h
Normal file
21
TextDrawer.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef TEXTDRAWER_H
|
||||
#define TEXTDRAWER_H
|
||||
#include "OpenGL.h"
|
||||
|
||||
class TextDrawer
|
||||
{
|
||||
friend class OGLRender;
|
||||
TextDrawer();
|
||||
void init();
|
||||
void destroy();
|
||||
void renderText(const char *_pText, float x, float y) const;
|
||||
static TextDrawer & get();
|
||||
|
||||
struct Atlas * m_pAtlas;
|
||||
GLuint m_program;
|
||||
GLint m_uTex;
|
||||
GLint m_uColor;
|
||||
GLuint m_vbo;
|
||||
};
|
||||
|
||||
#endif // TEXTDRAWER_H
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "../Config.h"
|
||||
#include "../GLideN64.h"
|
||||
#include "../GBI.h"
|
||||
#include "../RSP.h"
|
||||
#include "../Textures.h"
|
||||
#include "../OpenGL.h"
|
||||
|
@ -47,7 +48,7 @@ bool Config_SetDefault()
|
|||
//#Texture Settings
|
||||
res = ConfigSetDefaultBool(g_configVideoGliden64, "ForceBilinear", 0, "Force bilinear texture filter");
|
||||
assert(res == M64ERR_SUCCESS);
|
||||
res = ConfigSetDefaultInt(g_configVideoGliden64, "CacheSize", 192, "Size of texture cache in megabytes. Good value is VRAM*3/4");
|
||||
res = ConfigSetDefaultInt(g_configVideoGliden64, "CacheSize", 500, "Size of texture cache in megabytes. Good value is VRAM*3/4");
|
||||
assert(res == M64ERR_SUCCESS);
|
||||
res = ConfigSetDefaultInt(g_configVideoGliden64, "TextureBitDepth", 1, "Texture bit depth (0=16bit only, 1=16 and 32 bit, 2=32bit only)");
|
||||
assert(res == M64ERR_SUCCESS);
|
||||
|
@ -101,6 +102,14 @@ bool Config_SetDefault()
|
|||
res = ConfigSetDefaultBool(g_configVideoGliden64, "txDump", 0, "Enable dump of loaded N64 textures.");
|
||||
assert(res == M64ERR_SUCCESS);
|
||||
|
||||
res = ConfigSetDefaultString(g_configVideoGliden64, "fontName", "comic.ttf", "File name of True Type Font for text messages.");
|
||||
assert(res == M64ERR_SUCCESS);
|
||||
res = ConfigSetDefaultInt(g_configVideoGliden64, "fontSize", 30, "Font size.");
|
||||
assert(res == M64ERR_SUCCESS);
|
||||
res = ConfigSetDefaultString(g_configVideoGliden64, "fontColor", "B5E61D", "Font color in RGB format.");
|
||||
assert(res == M64ERR_SUCCESS);
|
||||
|
||||
|
||||
return res == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -147,6 +156,22 @@ void Config_LoadConfig()
|
|||
config.textureFilter.txHresAltCRC = ConfigGetParamBool(g_configVideoGliden64, "txHresAltCRC");
|
||||
config.textureFilter.txHiresCacheCompression = ConfigGetParamBool(g_configVideoGliden64, "txHiresCacheCompression");
|
||||
config.textureFilter.txDump = ConfigGetParamBool(g_configVideoGliden64, "txDump");
|
||||
//#Font settings
|
||||
config.font.name = ConfigGetParamString(g_configVideoGliden64, "fontName");
|
||||
if (config.font.name.empty())
|
||||
config.font.name = "comic.ttf";
|
||||
char buf[16];
|
||||
sprintf(buf, "0x%s", ConfigGetParamString(g_configVideoGliden64, "fontColor"));
|
||||
long int uColor = strtol(buf, NULL, 16);
|
||||
if (uColor != 0) {
|
||||
config.font.color[0] = _FIXED2FLOAT(_SHIFTR(uColor, 16, 8), 8);
|
||||
config.font.color[1] = _FIXED2FLOAT(_SHIFTR(uColor, 8, 8), 8);
|
||||
config.font.color[2] = _FIXED2FLOAT(_SHIFTR(uColor, 0, 8), 8);
|
||||
config.font.color[3] = 1.0f;
|
||||
}
|
||||
config.font.size = ConfigGetParamInt(g_configVideoGliden64, "fontSize");
|
||||
if (config.font.size == 0)
|
||||
config.font.size = 30;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -14,8 +14,10 @@ ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL;
|
|||
ptr_ConfigOpenSection ConfigOpenSection = NULL;
|
||||
ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL;
|
||||
ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL;
|
||||
ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
|
||||
ptr_ConfigGetParamInt ConfigGetParamInt = NULL;
|
||||
ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
|
||||
ptr_ConfigGetParamString ConfigGetParamString = NULL;
|
||||
|
||||
/* definitions of pointers to Core video extension functions */
|
||||
ptr_VidExt_Init CoreVideo_Init = NULL;
|
||||
|
@ -39,8 +41,10 @@ m64p_error PluginAPI::PluginStartup(m64p_dynlib_handle _CoreLibHandle)
|
|||
ConfigOpenSection = (ptr_ConfigOpenSection)DLSYM(_CoreLibHandle, "ConfigOpenSection");
|
||||
ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt)DLSYM(_CoreLibHandle, "ConfigSetDefaultInt");
|
||||
ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool)DLSYM(_CoreLibHandle, "ConfigSetDefaultBool");
|
||||
ConfigSetDefaultString = (ptr_ConfigSetDefaultString)DLSYM(_CoreLibHandle, "ConfigSetDefaultString");
|
||||
ConfigGetParamInt = (ptr_ConfigGetParamInt)DLSYM(_CoreLibHandle, "ConfigGetParamInt");
|
||||
ConfigGetParamBool = (ptr_ConfigGetParamBool)DLSYM(_CoreLibHandle, "ConfigGetParamBool");
|
||||
ConfigGetParamString = (ptr_ConfigGetParamString)DLSYM(_CoreLibHandle, "ConfigGetParamString");
|
||||
|
||||
/* Get the core Video Extension function pointers from the library handle */
|
||||
CoreVideo_Init = (ptr_VidExt_Init) DLSYM(_CoreLibHandle, "VidExt_Init");
|
||||
|
|
Loading…
Reference in New Issue
Block a user