mirror of https://github.com/PCSX2/pcsx2.git
Added OSD Manager which depends on FreeType2. Added functions into GSDeviceOGL to render OSD and a point shader.
This commit is contained in:
parent
4c084391fc
commit
b8a84d170a
|
@ -5,6 +5,7 @@
|
|||
if (Linux)
|
||||
find_package(ALSA)
|
||||
endif()
|
||||
find_package(Freetype) # GSdx OSD
|
||||
find_package(Gettext) # translation tool
|
||||
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
find_package(Git)
|
||||
|
|
|
@ -141,7 +141,7 @@ endif()
|
|||
# -X11
|
||||
# -zlib
|
||||
#---------------------------------------
|
||||
if(OPENGL_FOUND AND X11_FOUND AND GTKn_FOUND AND ZLIB_FOUND AND PNG_FOUND AND (EGL_FOUND OR NOT EGL_API))
|
||||
if(OPENGL_FOUND AND X11_FOUND AND GTKn_FOUND AND ZLIB_FOUND AND PNG_FOUND AND FREETYPE_FOUND AND (EGL_FOUND OR NOT EGL_API))
|
||||
set(GSdx TRUE)
|
||||
elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/GSdx")
|
||||
set(GSdx FALSE)
|
||||
|
|
|
@ -86,6 +86,7 @@ set(GSdxSources
|
|||
GSRendererNull.cpp
|
||||
GSRendererOGL.cpp
|
||||
GSRendererSW.cpp
|
||||
GSOsdManager.cpp
|
||||
GSSetting.cpp
|
||||
GSSetupPrimCodeGenerator.cpp
|
||||
GSSetupPrimCodeGenerator.x64.cpp
|
||||
|
@ -193,6 +194,7 @@ set(GSdxFinalLibs
|
|||
${GTK2_LIBRARIES}
|
||||
${LIBC_LIBRARIES}
|
||||
${PNG_LIBRARIES}
|
||||
${FREETYPE_LIBRARIES}
|
||||
)
|
||||
|
||||
if(EGL_API AND EGL_FOUND)
|
||||
|
|
|
@ -120,6 +120,7 @@ void GSDevice::Present(const GSVector4i& r, int shader)
|
|||
ShaderConvert_COMPLEX_FILTER}; // FIXME
|
||||
|
||||
Present(m_current, m_backbuffer, GSVector4(r), s_shader[shader]);
|
||||
RenderOsd(m_backbuffer);
|
||||
}
|
||||
|
||||
Flip();
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "GSTexture.h"
|
||||
#include "GSVertex.h"
|
||||
#include "GSAlignedClass.h"
|
||||
#include "GSOsdManager.h"
|
||||
|
||||
enum ShaderConvert {
|
||||
ShaderConvert_COPY = 0,
|
||||
|
@ -132,6 +133,8 @@ protected:
|
|||
virtual void DoExternalFX(GSTexture* sTex, GSTexture* dTex) {}
|
||||
|
||||
public:
|
||||
GSOsdManager m_osd;
|
||||
|
||||
GSDevice();
|
||||
virtual ~GSDevice();
|
||||
|
||||
|
@ -184,6 +187,7 @@ public:
|
|||
void FXAA();
|
||||
void ShadeBoost();
|
||||
void ExternalFX();
|
||||
virtual void RenderOsd(GSTexture* dt) {};
|
||||
|
||||
bool ResizeTexture(GSTexture** t, int w, int h);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "GSDeviceOGL.h"
|
||||
#include "GLState.h"
|
||||
#include "GSUtil.h"
|
||||
#include "GSOsdManager.h"
|
||||
#include <fstream>
|
||||
|
||||
#include "res/glsl_source.h"
|
||||
|
@ -61,6 +62,7 @@ GSDeviceOGL::GSDeviceOGL()
|
|||
, m_palette_ss(0)
|
||||
, m_vs_cb(NULL)
|
||||
, m_ps_cb(NULL)
|
||||
, m_font(NULL)
|
||||
, m_shader(NULL)
|
||||
{
|
||||
memset(&m_merge_obj, 0, sizeof(m_merge_obj));
|
||||
|
@ -537,6 +539,12 @@ bool GSDeviceOGL::Create(GSWnd* wnd)
|
|||
|
||||
fprintf(stdout, "Available VRAM/RAM:%lldMB for textures\n", GLState::available_vram >> 20u);
|
||||
|
||||
// ****************************************************************
|
||||
// Texture Font (OSD)
|
||||
// ****************************************************************
|
||||
GSVector2i tex_font = m_osd.get_texture_font_size();
|
||||
m_font = new GSTextureOGL(GSTextureOGL::Texture, tex_font.x, tex_font.y, GL_R8, m_fbo_read, false);
|
||||
|
||||
// ****************************************************************
|
||||
// Finish window setup and backbuffer
|
||||
// ****************************************************************
|
||||
|
@ -1393,6 +1401,36 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
|
|||
EndScene();
|
||||
}
|
||||
|
||||
void GSDeviceOGL::RenderOsd(GSTexture* dt)
|
||||
{
|
||||
BeginScene();
|
||||
|
||||
m_shader->BindPipeline(m_convert.ps[ShaderConvert_OSD]);
|
||||
|
||||
OMSetDepthStencilState(m_convert.dss);
|
||||
OMSetBlendState((uint8)GSDeviceOGL::m_MERGE_BLEND);
|
||||
OMSetRenderTargets(dt, NULL);
|
||||
|
||||
if(m_osd.m_texture_dirty) {
|
||||
m_osd.upload_texture_atlas(m_font);
|
||||
}
|
||||
|
||||
PSSetShaderResource(0, m_font);
|
||||
PSSetSamplerState(m_convert.pt);
|
||||
|
||||
IASetPrimitiveTopology(GL_TRIANGLES);
|
||||
|
||||
// Note scaling could also be done in shader (require gl3/dx10)
|
||||
size_t count = m_osd.Size();
|
||||
GSVertexPT1* dst = (GSVertexPT1*)m_va->MapVB(count);
|
||||
count = m_osd.GeneratePrimitives(dst, count);
|
||||
m_va->UnmapVB();
|
||||
|
||||
DrawPrimitive();
|
||||
|
||||
EndScene();
|
||||
}
|
||||
|
||||
void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c)
|
||||
{
|
||||
GL_PUSH("DoMerge");
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "GSUniformBufferOGL.h"
|
||||
#include "GSShaderOGL.h"
|
||||
#include "GLState.h"
|
||||
#include "GSOsdManager.h"
|
||||
|
||||
// A couple of flag to determine the blending behavior
|
||||
#define BLEND_A_MAX (0x100) // Impossible blending uses coeff bigger than 1
|
||||
|
@ -484,6 +485,8 @@ public:
|
|||
PSConstantBuffer m_ps_cb_cache;
|
||||
MiscConstantBuffer m_misc_cb_cache;
|
||||
|
||||
GSTextureOGL* m_font;
|
||||
|
||||
GSTexture* CreateSurface(int type, int w, int h, bool msaa, int format);
|
||||
GSTexture* FetchSurface(int type, int w, int h, bool msaa, int format);
|
||||
|
||||
|
@ -492,6 +495,7 @@ public:
|
|||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex) final;
|
||||
void DoExternalFX(GSTexture* sTex, GSTexture* dTex) final;
|
||||
void RenderOsd(GSTexture* dt);
|
||||
|
||||
void OMAttachRt(GSTextureOGL* rt = NULL);
|
||||
void OMAttachDs(GSTextureOGL* ds = NULL);
|
||||
|
|
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2016 Gregory hainaut
|
||||
* Copyright (C) 2016-2016 Jason Brown
|
||||
*
|
||||
* This Program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This Program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "GSdx.h"
|
||||
#include "GSOsdManager.h"
|
||||
|
||||
void GSOsdManager::LoadFont() {
|
||||
FT_Error error = FT_New_Face(m_library, theApp.GetConfigS("osd_fontname").c_str(), 0, &m_face);
|
||||
if (error) {
|
||||
m_face = NULL;
|
||||
fprintf(stderr, "Failed to init the freetype face\n");
|
||||
if(error == FT_Err_Unknown_File_Format)
|
||||
fprintf(stderr, "\tFreetype unknown file format\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LoadSize();
|
||||
}
|
||||
|
||||
void GSOsdManager::LoadSize() {
|
||||
if (!m_face) return;
|
||||
|
||||
m_size = theApp.GetConfigI("osd_fontsize");
|
||||
FT_Error error = FT_Set_Pixel_Sizes(m_face, 0, m_size);;
|
||||
if (error) {
|
||||
fprintf(stderr, "Failed to init the face size\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is not exact, I'm sure there's some convoluted way to determine these
|
||||
* from FreeType but they don't make it easy. */
|
||||
m_atlas_w = m_size * 96; // random guess
|
||||
m_atlas_h = m_size; // another random guess
|
||||
}
|
||||
|
||||
GSOsdManager::GSOsdManager() : m_atlas_h(0)
|
||||
, m_atlas_w(0)
|
||||
, m_max_width(0)
|
||||
, m_texture_dirty(true)
|
||||
{
|
||||
m_log_enabled = theApp.GetConfigB("osd_log_enabled");
|
||||
m_log_speed = theApp.GetConfigI("osd_log_speed");
|
||||
m_log_speed = m_log_speed < 2 ? 2 : m_log_speed > 10 ? 10 : m_log_speed;
|
||||
m_monitor_enabled = theApp.GetConfigB("osd_monitor_enabled");
|
||||
m_indicator_enabled = theApp.GetConfigB("osd_indicator_enabled");
|
||||
m_osd_transparency = theApp.GetConfigI("osd_transparency");
|
||||
m_osd_transparency = m_osd_transparency < 0 ? 0 : m_osd_transparency > 200 ? 200 : m_osd_transparency;
|
||||
|
||||
if (FT_Init_FreeType(&m_library)) {
|
||||
fprintf(stderr, "Failed to init the freetype library\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LoadFont();
|
||||
|
||||
/* The space character's width is used in GeneratePrimitives() */
|
||||
AddGlyph(' ');
|
||||
}
|
||||
|
||||
GSOsdManager::~GSOsdManager() {
|
||||
FT_Done_FreeType(m_library);
|
||||
}
|
||||
|
||||
GSVector2i GSOsdManager::get_texture_font_size() {
|
||||
return GSVector2i(m_atlas_w, m_atlas_h);
|
||||
}
|
||||
|
||||
void GSOsdManager::upload_texture_atlas(GSTexture* t) {
|
||||
if (!m_face) return;
|
||||
|
||||
if (m_char_info.size() > 96) // we only reserved space for this many glyphs
|
||||
fprintf(stderr, "More than 96 glyphs needed for OSD");
|
||||
|
||||
// This can be sped up a bit by only uploading new glyphs
|
||||
int x = 0;
|
||||
for(auto &pair : m_char_info) {
|
||||
if(FT_Load_Char(m_face, pair.first, FT_LOAD_RENDER)) {
|
||||
fprintf(stderr, "failed to load char U%d\n", (int)pair.first);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Size of char
|
||||
pair.second.ax = m_face->glyph->advance.x >> 6;
|
||||
pair.second.ay = m_face->glyph->advance.y >> 6;
|
||||
|
||||
pair.second.bw = m_face->glyph->bitmap.width;
|
||||
pair.second.bh = m_face->glyph->bitmap.rows;
|
||||
|
||||
pair.second.bl = m_face->glyph->bitmap_left;
|
||||
pair.second.bt = m_face->glyph->bitmap_top;
|
||||
|
||||
GSVector4i r(x, 0, x+pair.second.bw, pair.second.bh);
|
||||
if (r.width())
|
||||
t->Update(r, m_face->glyph->bitmap.buffer, m_face->glyph->bitmap.pitch);
|
||||
|
||||
if (r.width() > m_max_width) m_max_width = r.width();
|
||||
|
||||
pair.second.tx = (float)x / m_atlas_w;
|
||||
pair.second.ty = (float)pair.second.bh / m_atlas_h;
|
||||
pair.second.tw = (float)pair.second.bw / m_atlas_w;
|
||||
|
||||
x += pair.second.bw;
|
||||
}
|
||||
|
||||
m_texture_dirty = false;
|
||||
}
|
||||
|
||||
#if __GNUC__ < 5 || ( __GNUC__ == 5 && __GNUC_MINOR__ < 4 )
|
||||
/* This is dumb in that it doesn't check for malformed UTF8. This function
|
||||
* is not expected to operate on user input, but only on compiled in strings */
|
||||
void dumb_utf8_to_utf32(const char *utf8, char32_t *utf32, unsigned size) {
|
||||
while(*utf8 && --size) {
|
||||
if((*utf8 & 0xF1) == 0xF0) {
|
||||
*utf32++ = (utf8[0] & 0x07) << 18 | (utf8[1] & 0x3F) << 12 | (utf8[2] & 0x3F) << 6 | utf8[3] & 0x3F;
|
||||
utf8 += 4;
|
||||
} else if((*utf8 & 0xF0) == 0xE0) {
|
||||
*utf32++ = (utf8[0] & 0x0F) << 12 | (utf8[1] & 0x3F) << 6 | utf8[2] & 0x3F;
|
||||
utf8 += 3;
|
||||
} else if((*utf8 & 0xE0) == 0xC0) {
|
||||
*utf32++ = (utf8[0] & 0x1F) << 6 | utf8[1] & 0x3F;
|
||||
utf8 += 2;
|
||||
} else if((*utf8 & 0x80) == 0x00) {
|
||||
*utf32++ = utf8[0] & 0x7F;
|
||||
utf8 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(size) *utf32 = *utf8; // Copy NUL char
|
||||
}
|
||||
#endif
|
||||
|
||||
void GSOsdManager::AddGlyph(char32_t codepoint) {
|
||||
if (!m_face) return;
|
||||
if(m_char_info.count(codepoint) == 0) {
|
||||
m_texture_dirty = true;
|
||||
m_char_info[codepoint]; // add it
|
||||
if(FT_HAS_KERNING(m_face)) {
|
||||
FT_UInt new_glyph = FT_Get_Char_Index(m_face, codepoint);
|
||||
for(auto pair : m_char_info) {
|
||||
FT_Vector delta;
|
||||
|
||||
FT_UInt glyph_index = FT_Get_Char_Index(m_face, pair.first);
|
||||
FT_Get_Kerning(m_face, glyph_index, new_glyph, FT_KERNING_DEFAULT, &delta);
|
||||
m_kern_info[std::make_pair(pair.first, codepoint)] = delta.x >> 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSOsdManager::Log(const char *utf8, uint32 color) {
|
||||
if(!m_log_enabled)
|
||||
return;
|
||||
|
||||
#if __GNUC__ < 5 || ( __GNUC__ == 5 && __GNUC_MINOR__ < 4 )
|
||||
char32_t buffer[256];
|
||||
dumb_utf8_to_utf32(utf8, buffer, countof(buffer));
|
||||
for(char32_t* c = buffer; *c; ++c) AddGlyph(*c);
|
||||
#else
|
||||
#if _MSC_VER == 1900
|
||||
std::wstring_convert<codecvt_utf8<unsigned int>, unsigned int> conv;
|
||||
#else
|
||||
std::wstring_convert<codecvt_utf8<char32_t>, char32_t> conv;
|
||||
#endif
|
||||
std::u32string buffer = conv.from_bytes(utf8);
|
||||
for(auto const &c : buffer) AddGlyph(c);
|
||||
#endif
|
||||
m_log.push_back(log_info{color, buffer, std::chrono::system_clock::time_point()});
|
||||
|
||||
}
|
||||
|
||||
void GSOsdManager::Monitor(const char *key, const char *value, uint32 color) {
|
||||
if(!m_monitor_enabled)
|
||||
return;
|
||||
|
||||
if(value && *value) {
|
||||
#if __GNUC__ < 5 || ( __GNUC__ == 5 && __GNUC_MINOR__ < 4 )
|
||||
char32_t buffer[256], vbuffer[256];
|
||||
dumb_utf8_to_utf32(key, buffer, countof(buffer));
|
||||
dumb_utf8_to_utf32(value, vbuffer, countof(vbuffer));
|
||||
for(char32_t* c = buffer; *c; ++c) AddGlyph(*c);
|
||||
for(char32_t* c = vbuffer; *c; ++c) AddGlyph(*c);
|
||||
#else
|
||||
#if _MSC_VER == 1900
|
||||
std::wstring_convert<codecvt_utf8<unsigned int>, unsigned int> conv;
|
||||
#else
|
||||
std::wstring_convert<codecvt_utf8<char32_t>, char32_t> conv;
|
||||
#endif
|
||||
std::u32string buffer = conv.from_bytes(key);
|
||||
std::u32string vbuffer = conv.from_bytes(value);
|
||||
for(auto const &c : buffer) AddGlyph(c);
|
||||
for(auto const &c : vbuffer) AddGlyph(c);
|
||||
#endif
|
||||
m_monitor[buffer] = std::make_pair(vbuffer, color);
|
||||
} else {
|
||||
#if __GNUC__ < 5 || ( __GNUC__ == 5 && __GNUC_MINOR__ < 4 )
|
||||
char32_t buffer[256];
|
||||
dumb_utf8_to_utf32(key, buffer, countof(buffer));
|
||||
#else
|
||||
#if _MSC_VER == 1900
|
||||
std::wstring_convert<codecvt_utf8<unsigned int>, unsigned int> conv;
|
||||
#else
|
||||
std::wstring_convert<codecvt_utf8<char32_t>, char32_t> conv;
|
||||
#endif
|
||||
std::u32string buffer = conv.from_bytes(key);
|
||||
#endif
|
||||
m_monitor.erase(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void GSOsdManager::Indicate(const std::string key, bool on) {
|
||||
if(!m_indicator_enabled)
|
||||
return;
|
||||
|
||||
m_indicator[key].on = on;
|
||||
}
|
||||
|
||||
void GSOsdManager::RenderGlyph(GSVertexPT1* dst, const glyph_info g, float x, float y, uint32 color) {
|
||||
float x2 = x + g.bl * (2.0f/m_real_size.x);
|
||||
float y2 = -y - g.bt * (2.0f/m_real_size.y);
|
||||
float w = g.bw * (2.0f/m_real_size.x);
|
||||
float h = g.bh * (2.0f/m_real_size.y);
|
||||
|
||||
dst->p = GSVector4(x2 , -y2 , 0.0f, 0.0f);
|
||||
dst->t = GSVector2(g.tx , 0.0f);
|
||||
dst->c = color;
|
||||
++dst;
|
||||
dst->p = GSVector4(x2 + w, -y2 , 0.0f, 0.0f);
|
||||
dst->t = GSVector2(g.tx + g.tw, 0.0f);
|
||||
dst->c = color;
|
||||
++dst;
|
||||
dst->p = GSVector4(x2 , -y2 - h, 0.0f, 0.0f);
|
||||
dst->t = GSVector2(g.tx , g.ty);
|
||||
dst->c = color;
|
||||
++dst;
|
||||
dst->p = GSVector4(x2 + w, -y2 , 0.0f, 0.0f);
|
||||
dst->t = GSVector2(g.tx + g.tw, 0.0f);
|
||||
dst->c = color;
|
||||
++dst;
|
||||
dst->p = GSVector4(x2 , -y2 - h, 0.0f, 0.0f);
|
||||
dst->t = GSVector2(g.tx , g.ty);
|
||||
dst->c = color;
|
||||
++dst;
|
||||
dst->p = GSVector4(x2 + w, -y2 - h, 0.0f, 0.0f);
|
||||
dst->t = GSVector2(g.tx + g.tw, g.ty);
|
||||
dst->c = color;
|
||||
++dst;
|
||||
}
|
||||
|
||||
void GSOsdManager::RenderString(GSVertexPT1* dst, const std::u32string msg, float x, float y, uint32 color) {
|
||||
char32_t p = 0;
|
||||
for(const auto & c : msg) {
|
||||
if(p) {
|
||||
x += m_kern_info[std::make_pair(p, c)] * (2.0f/m_real_size.x);
|
||||
}
|
||||
|
||||
RenderGlyph(dst, m_char_info[c], x, y, color);
|
||||
|
||||
/* Advance the cursor to the start of the next character */
|
||||
x += m_char_info[c].ax * (2.0f/m_real_size.x);
|
||||
y += m_char_info[c].ay * (2.0f/m_real_size.y);
|
||||
|
||||
dst += 6;
|
||||
|
||||
p = c;
|
||||
}
|
||||
}
|
||||
|
||||
size_t GSOsdManager::Size() {
|
||||
size_t sum = 0;
|
||||
|
||||
if(m_log_enabled) {
|
||||
float offset = 0;
|
||||
|
||||
for(auto it = m_log.begin(); it != m_log.end(); ++it) {
|
||||
float y = 1 - ((m_size+2)*(it-m_log.begin()+1)) * (2.0f/m_real_size.y);
|
||||
if(y + offset < -1) break;
|
||||
|
||||
std::chrono::duration<float> elapsed;
|
||||
if(it->OnScreen.time_since_epoch().count() == 0) {
|
||||
elapsed = std::chrono::seconds(0);
|
||||
} else {
|
||||
elapsed = std::chrono::system_clock::now() - it->OnScreen;
|
||||
if(elapsed > std::chrono::seconds(m_log_speed)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
float ratio = (elapsed - std::chrono::seconds(m_log_speed/2)).count() / std::chrono::seconds(m_log_speed/2).count();
|
||||
ratio = ratio > 1.0f ? 1.0f : ratio < 0.0f ? 0.0f : ratio;
|
||||
|
||||
y += offset += ((m_size+2) * (2.0f/m_real_size.y)) * ratio;
|
||||
sum += it->msg.size();
|
||||
}
|
||||
}
|
||||
|
||||
if(m_monitor_enabled) {
|
||||
for(const auto &pair : m_monitor) {
|
||||
sum += pair.first.size();
|
||||
sum += pair.second.first.size();
|
||||
}
|
||||
}
|
||||
|
||||
if(m_indicator_enabled) {
|
||||
sum += m_indicator.size();
|
||||
}
|
||||
|
||||
return sum * 6;
|
||||
}
|
||||
|
||||
float GSOsdManager::StringSize(const std::u32string msg) {
|
||||
char32_t p = 0;
|
||||
float x = 0.0;
|
||||
|
||||
for(auto c : msg) {
|
||||
if(p) {
|
||||
x += m_kern_info[std::make_pair(p, c)] * (2.0f/m_real_size.x);
|
||||
}
|
||||
|
||||
/* Advance the cursor to the start of the next character */
|
||||
x += m_char_info[c].ax * (2.0f/m_real_size.x);
|
||||
|
||||
p = c;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
size_t GSOsdManager::GeneratePrimitives(GSVertexPT1* dst, size_t count) {
|
||||
size_t drawn = 0;
|
||||
float transparency = 1.0f - m_osd_transparency / 200.0f;
|
||||
|
||||
if(m_log_enabled) {
|
||||
float offset = 0;
|
||||
|
||||
for(auto it = m_log.begin(); it != m_log.end();) {
|
||||
float x = -1 + 8 * (2.0f/m_real_size.x);
|
||||
float y = 1 - ((m_size+2)*(it-m_log.begin()+1)) * (2.0f/m_real_size.y);
|
||||
|
||||
if(y + offset < -1) break;
|
||||
|
||||
if(it->OnScreen.time_since_epoch().count() == 0)
|
||||
it->OnScreen = std::chrono::system_clock::now();
|
||||
|
||||
std::chrono::duration<float> elapsed = std::chrono::system_clock::now() - it->OnScreen;
|
||||
if(elapsed > std::chrono::seconds(m_log_speed)) {
|
||||
it = m_log.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(it->msg.size() * 6 > count - drawn) break;
|
||||
|
||||
float ratio = (elapsed - std::chrono::seconds(m_log_speed/2)).count() / std::chrono::seconds(m_log_speed/2).count();
|
||||
ratio = ratio > 1.0f ? 1.0f : ratio < 0.0f ? 0.0f : ratio;
|
||||
|
||||
y += offset += ((m_size+2) * (2.0f/m_real_size.y)) * ratio;
|
||||
uint32 color = it->color;
|
||||
((uint8 *)&color)[3] = (uint8)(((uint8 *)&color)[3] * (1.0f - ratio) * transparency);
|
||||
RenderString(dst, it->msg, x, y, color);
|
||||
dst += it->msg.size() * 6;
|
||||
drawn += it->msg.size() * 6;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_monitor_enabled) {
|
||||
// pair.first is the key and second is the value and color
|
||||
|
||||
// Since the monitor is right justified, but we render from left to right
|
||||
// we need to find the longest string
|
||||
float first_max = 0.0, second_max = 0.0;
|
||||
for(const auto &pair : m_monitor) {
|
||||
float first_len = StringSize(pair.first);
|
||||
float second_len = StringSize(pair.second.first);
|
||||
|
||||
first_max = first_max < first_len ? first_len : first_max;
|
||||
second_max = second_max < second_len ? second_len : second_max;
|
||||
}
|
||||
|
||||
size_t line = 1;
|
||||
for(const auto &pair : m_monitor) {
|
||||
if((pair.first.size() + pair.second.first.size()) * 6 > count - drawn) break;
|
||||
|
||||
// Calculate where to start rendering from by taking the right most position 1.0
|
||||
// and subtracting (going left) 8 scaled pixels for a margin, then subtracting
|
||||
// the size of the longest key and subtracting a scaled space and finally
|
||||
// subtracting the longest value
|
||||
float x = 1.0f - 8 * (2.0f/m_real_size.x) - first_max - m_char_info[' '].ax * (2.0f/m_real_size.x) - second_max;
|
||||
float y = -1.0f + ((m_size+2)*(2.0f/m_real_size.y)) * line++;
|
||||
|
||||
uint32 color = pair.second.second;
|
||||
((uint8 *)&color)[3] = (uint8)(((uint8 *)&color)[3] * transparency);
|
||||
|
||||
// Render the key
|
||||
RenderString(dst, pair.first, x, y, color);
|
||||
dst += pair.first.size() * 6;
|
||||
drawn += pair.first.size() * 6;
|
||||
|
||||
// Calculate the position for the value
|
||||
x = 1.0f - 8 * (2.0f/m_real_size.x) - second_max;
|
||||
|
||||
// Render the value
|
||||
RenderString(dst, pair.second.first, x, y, color);
|
||||
dst += pair.second.first.size() * 6;
|
||||
drawn += pair.second.first.size() * 6;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_indicator_enabled) {
|
||||
for(const auto pair : m_indicator) {
|
||||
float alpha = 1.0;
|
||||
if(!pair.second.on) {
|
||||
alpha = 0.25;
|
||||
}
|
||||
uint32 color = pair.second.color;
|
||||
((uint8 *)&color)[3] = (uint8)(((uint8 *)&color)[3] * alpha * transparency);
|
||||
RenderGlyph(dst, pair.second.glyph, pair.second.x, pair.second.y, color);
|
||||
dst += 6;
|
||||
drawn += 6;
|
||||
}
|
||||
}
|
||||
|
||||
return drawn;
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2016 Gregory hainaut
|
||||
* Copyright (C) 2016-2016 Jason Brown
|
||||
*
|
||||
* This Program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This Program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "GSVector.h"
|
||||
#include "GSVertex.h"
|
||||
#include "GSTexture.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
class GSOsdManager {
|
||||
struct glyph_info {
|
||||
int32 ax; // advance.x
|
||||
int32 ay; // advance.y
|
||||
|
||||
uint32 bw; // bitmap.width;
|
||||
uint32 bh; // bitmap.rows;
|
||||
|
||||
int32 bl; // bitmap_left;
|
||||
int32 bt; // bitmap_top;
|
||||
|
||||
float tx; // x offset of glyph
|
||||
float ty; // y offset of glyph
|
||||
float tw; // nomalized glyph width
|
||||
};
|
||||
|
||||
std::map<char32_t, glyph_info> m_char_info;
|
||||
std::map<std::pair<char32_t, char32_t>, FT_Pos> m_kern_info;
|
||||
|
||||
FT_Library m_library;
|
||||
FT_Face m_face;
|
||||
FT_UInt m_size;
|
||||
|
||||
uint32 m_atlas_h;
|
||||
uint32 m_atlas_w;
|
||||
int32 m_max_width;
|
||||
|
||||
void compute_glyph_size();
|
||||
|
||||
struct log_info {
|
||||
uint32 color;
|
||||
std::u32string msg;
|
||||
std::chrono::system_clock::time_point OnScreen;
|
||||
};
|
||||
std::vector<log_info> m_log;
|
||||
|
||||
std::map<std::u32string, std::pair<std::u32string, uint32>> m_monitor;
|
||||
|
||||
struct indicator_info {
|
||||
glyph_info glyph;
|
||||
uint32 color;
|
||||
bool on;
|
||||
float x, y;
|
||||
};
|
||||
std::map<std::string, indicator_info> m_indicator;
|
||||
|
||||
void AddGlyph(char32_t codepoint);
|
||||
void RenderGlyph(GSVertexPT1* dst, const glyph_info g, float x, float y, uint32 color);
|
||||
void RenderString(GSVertexPT1* dst, const std::u32string msg, float x, float y, uint32 color);
|
||||
float StringSize(const std::u32string msg);
|
||||
|
||||
bool m_log_enabled;
|
||||
int m_log_speed;
|
||||
bool m_monitor_enabled;
|
||||
bool m_indicator_enabled;
|
||||
int m_osd_transparency;
|
||||
|
||||
public:
|
||||
|
||||
GSOsdManager();
|
||||
~GSOsdManager();
|
||||
|
||||
void LoadFont();
|
||||
void LoadSize();
|
||||
|
||||
GSVector2i get_texture_font_size();
|
||||
|
||||
bool m_texture_dirty;
|
||||
void upload_texture_atlas(GSTexture* t);
|
||||
|
||||
void Log(const char *utf8, uint32 color);
|
||||
void Monitor(const char *key, const char *value, uint32 color);
|
||||
void Indicate(const std::string key, bool on);
|
||||
|
||||
GSVector2i m_real_size;
|
||||
size_t Size();
|
||||
size_t GeneratePrimitives(GSVertexPT1* dst, size_t count);
|
||||
};
|
|
@ -451,6 +451,23 @@ void GSRenderer::VSync(int field)
|
|||
|
||||
// present
|
||||
|
||||
#if 0
|
||||
// This will scale the OSD to the PS2's output resolution.
|
||||
// Will be affected by 2x, 4x, etc scaling.
|
||||
m_dev->m_osd.m_real_size = m_real_size
|
||||
#elif 0
|
||||
// This will scale the OSD to the window's size.
|
||||
// Will maintiain the font size no matter what size the window is.
|
||||
GSVector4i window_size = m_wnd->GetClientRect();
|
||||
m_dev->m_osd.m_real_size.x = window_size.v[2];
|
||||
m_dev->m_osd.m_real_size.y = window_size.v[3];
|
||||
#else
|
||||
// This will scale the OSD to the native resolution.
|
||||
// Will size font relative to the window's size.
|
||||
// TODO this should probably be done with native calls
|
||||
m_dev->m_osd.m_real_size.x = 1024;
|
||||
m_dev->m_osd.m_real_size.y = 768;
|
||||
#endif
|
||||
m_dev->Present(m_wnd->GetClientRect().fit(m_aspectratio), m_shader);
|
||||
|
||||
// snapshot
|
||||
|
|
|
@ -301,17 +301,27 @@ void GSdxApp::Init()
|
|||
m_default_configuration["extrathreads_height"] = "4";
|
||||
m_default_configuration["filter"] = "2";
|
||||
m_default_configuration["force_texture_clear"] = "0";
|
||||
#ifdef _WIN32
|
||||
m_default_configuration["fontname"] = "C:\\Windows\\Fonts\\tahoma.ttf";
|
||||
#else
|
||||
m_default_configuration["fontname"] = "/usr/share/fonts/truetype/freefont/FreeSerif.ttf";
|
||||
#endif
|
||||
m_default_configuration["fontsize"] = "48";
|
||||
m_default_configuration["fxaa"] = "0";
|
||||
m_default_configuration["indicator_enabled"] = "0";
|
||||
m_default_configuration["interlace"] = "7";
|
||||
m_default_configuration["large_framebuffer"] = "1";
|
||||
m_default_configuration["linear_present"] = "1";
|
||||
m_default_configuration["log_enabled"] = "1";
|
||||
m_default_configuration["MaxAnisotropy"] = "0";
|
||||
m_default_configuration["mipmap"] = "1";
|
||||
m_default_configuration["mipmap_hw"] = "0";
|
||||
m_default_configuration["ModeHeight"] = "480";
|
||||
m_default_configuration["ModeWidth"] = "640";
|
||||
m_default_configuration["monitor_enabled"] = "0";
|
||||
m_default_configuration["NTSC_Saturation"] = "1";
|
||||
m_default_configuration["ocldev"] = "";
|
||||
m_default_configuration["osd_transparency"] = "50";
|
||||
m_default_configuration["override_geometry_shader"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_clear_texture"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_draw_buffers_blend"] = "-1";
|
||||
|
|
|
@ -158,6 +158,7 @@
|
|||
<ClCompile Include="GSHwHack.cpp" />
|
||||
<ClCompile Include="GSLocalMemory.cpp" />
|
||||
<ClCompile Include="GSPerfMon.cpp" />
|
||||
<ClCompile Include="GSOsdManager.cpp" />
|
||||
<ClCompile Include="GSPng.cpp" />
|
||||
<ClCompile Include="GSRasterizer.cpp" />
|
||||
<ClCompile Include="GSRenderer.cpp" />
|
||||
|
@ -247,6 +248,7 @@
|
|||
<ClInclude Include="GSFunctionMap.h" />
|
||||
<ClInclude Include="GSLocalMemory.h" />
|
||||
<ClInclude Include="GSPerfMon.h" />
|
||||
<ClInclude Include="GSOsdManager.h" />
|
||||
<ClInclude Include="GSPng.h" />
|
||||
<ClInclude Include="GSRasterizer.h" />
|
||||
<ClInclude Include="GSRenderer.h" />
|
||||
|
|
|
@ -90,6 +90,9 @@
|
|||
<ClCompile Include="GSPerfMon.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GSOsdManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GSRasterizer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -371,6 +374,9 @@
|
|||
<ClInclude Include="GSPerfMon.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GSOsdManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GSRasterizer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -95,6 +95,11 @@ typedef int64 sint64;
|
|||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#if __GNUC__ > 5 || ( __GNUC__ == 5 && __GNUC_MINOR__ >= 4 )
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
#include <complex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
Loading…
Reference in New Issue