NouVeL/ADVect/Graphics.cpp

219 lines
No EOL
6.6 KiB
C++

#include <ft2build.h>
#include FT_FREETYPE_H
#include "Graphics.h"
#include <bgfx/bgfx.h>
#include <bx/math.h>
#include <iostream>
namespace {
FT_Library library;
FT_Error error;
FT_Face face;
struct PosUVVertex
{
f32 x;
f32 y;
f32 z;
f32 u;
f32 v;
};
static PosUVVertex quad_vert[] =
{
{ 0.f, 0.f, 0.0f, 0.0f, 0.0f },
{ 0.f, 1.f, 0.0f, 0.0f, 1.0f },
{ 1.f, 0.f, 0.0f, 1.0f, 0.0f },
{ 1.f, 1.f, 0.0f, 1.0f, 1.0f }
};
PosUVVertex* get_quad_posUV_verts(f32 L, f32 B, f32 W, f32 H) {
return quad_vert;
}
static const uint16_t quad_indices[] =
{
0, 2, 1,
1, 2, 3
};
bgfx::ShaderHandle loadShader(const char* FILENAME)
{
std::string shaderPath{};
switch (bgfx::getRendererType()) {
case bgfx::RendererType::Noop:
case bgfx::RendererType::Direct3D9: shaderPath = "shaders/dx9/"; break;
case bgfx::RendererType::Direct3D11:
case bgfx::RendererType::Direct3D12: shaderPath = "shaders/dx11/"; break;
case bgfx::RendererType::Gnm: shaderPath = "shaders/pssl/"; break;
case bgfx::RendererType::Metal: shaderPath = "shaders/metal/"; break;
case bgfx::RendererType::OpenGL: shaderPath = "shaders/glsl/"; break;
case bgfx::RendererType::OpenGLES: shaderPath = "shaders/essl/"; break;
case bgfx::RendererType::Vulkan: shaderPath = "shaders/spirv/"; break;
}
std::string filePath = shaderPath + FILENAME;
FILE* file = fopen(filePath.c_str(), "rb");
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
const bgfx::Memory* mem = bgfx::alloc(fileSize + 1);
fread(mem->data, 1, fileSize, file);
mem->data[mem->size - 1] = '\0';
fclose(file);
return bgfx::createShader(mem);
}
bgfx::ShaderHandle vsh;
bgfx::ShaderHandle fsh;
bgfx::ProgramHandle program;
bgfx::IndexBufferHandle ibh;
bgfx::VertexBufferHandle vbh;
bgfx::UniformHandle s_texColor;
bgfx::VertexLayout pcvDecl;
std::unordered_map<wchar_t, bgfx::TextureHandle> cache{};
}
namespace ADVect::Graphics {
void Init(u16 width, u16 height) {
error = FT_Init_FreeType(&library);
if (error) {
std::cerr << "FreeType init error: " << error << std::endl;
}
error = FT_New_Face(library, "SourceHanSerif-Heavy.ttc", 0, &face);
if (error == FT_Err_Unknown_File_Format) {
std::cerr << "FreeType Unknown_File_Format: " << error << std::endl;
}
else if (error) {
std::cerr << "FreeType font loading error: " << error << std::endl;
}
error = FT_Set_Char_Size(face, 0, 20 * 64, 72, 72);
if (error == FT_Err_Unknown_File_Format) {
std::cerr << "FreeType Set_Char_Size error: " << error << std::endl;
}
float view[16];
bx::mtxTranslate(view, 0.f, 0.f, 1.0f);
float proj[16];
bx::mtxOrtho(proj, 0.0f, width, 0.0f, height, 0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth);
bgfx::setViewTransform(0, view, proj);
pcvDecl.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
.end();
ibh = bgfx::createIndexBuffer(bgfx::makeRef(quad_indices, sizeof(quad_indices)));
vbh = bgfx::createVertexBuffer(bgfx::makeRef(quad_vert, sizeof(quad_vert)), pcvDecl);
vsh = loadShader("test.vert.bin");
fsh = loadShader("test.frag.bin");
program = bgfx::createProgram(vsh, fsh, true);
s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Sampler);
}
void Destroy() {
FT_Done_Face(face);
FT_Done_FreeType(library);
bgfx::destroy(vsh);
bgfx::destroy(fsh);
bgfx::destroy(program);
bgfx::destroy(ibh);
bgfx::destroy(vbh);
bgfx::destroy(s_texColor);
for (auto it = cache.begin(); it != cache.end(); it++) {
bgfx::destroy(it->second);
cache.erase(it);
}
bgfx::shutdown();
}
void RenderString(const NVL::String& s, u32& pos_x, u32& pos_y, u32 col) {
FT_GlyphSlot slot = face->glyph;
for (const auto& c : s) {
error = FT_Load_Char(face, c, FT_LOAD_RENDER);
if (error) continue;
if (cache.find(c) == cache.end() && slot->bitmap.width != 0) {
const bgfx::Memory* buf = bgfx::copy(slot->bitmap.buffer, slot->bitmap.pitch * slot->bitmap.rows);
cache.emplace(c, bgfx::createTexture2D(
slot->bitmap.width,
slot->bitmap.rows,
false,
1,
bgfx::TextureFormat::A8,
BGFX_TEXTURE_NONE | BGFX_SAMPLER_POINT | BGFX_SAMPLER_UVW_CLAMP,
buf
));
}
pos_x += slot->bitmap_left;
float ypos = pos_y - (slot->bitmap.rows - slot->bitmap_top);
if (slot->bitmap.width != 0) {
float mtx1[16], mtx2[16], mtx3[16];
bx::mtxTranslate(mtx1, (f32)pos_x, (f32)ypos, 0.0f);
bx::mtxScale(mtx2, slot->bitmap.width, slot->bitmap.rows, 1.0f);
bx::mtxMul(mtx3, mtx2, mtx1);
bgfx::setTransform(mtx3);
bgfx::setVertexBuffer(0, vbh);
bgfx::setIndexBuffer(ibh);
bgfx::setTexture(0, s_texColor, cache[c]);
bgfx::setState(BGFX_STATE_DEFAULT | BGFX_STATE_BLEND_ADD);
bgfx::submit(0, program);
}
pos_x += slot->advance.x >> 6;
pos_y += slot->advance.y >> 6;
}
}
void RenderString(const NVL::String& s, u32&& pos_x, u32&& pos_y, u32 col) {
u32 x = pos_x, y = pos_y;
RenderString(s, x, y, col);
}
void RenderStringMarkup(const std::vector<NVL::Environment::Variable>& s, u32 pos_x, u32 pos_y, u32 col) {
const NVL::String& str = std::get<NVL::String>(s[0].value);
// Check ParseMarkup for more information
for (const NVL::Environment::Variable& markup : std::get<std::vector<NVL::Environment::Variable>>(s[1].value)) {
const auto& range = std::get<std::vector<NVL::Environment::Variable>>(std::get<std::vector<NVL::Environment::Variable>>(markup.value)[0].value);
const NVL::Number& begin = std::get<NVL::Number>(range[0].value), end = std::get<NVL::Number>(range[1].value);
for (const NVL::Environment::Variable& combination : std::get<std::vector<NVL::Environment::Variable>>(std::get<std::vector<NVL::Environment::Variable>>(markup.value)[1].value)) {
if (combination.type == NVL::Environment::Type::String) {
const NVL::String& ef = std::get<NVL::String>(combination.value);
RenderString(str.substr(begin, end - begin + 1), pos_x, pos_y, col);
}
else if (combination.type == NVL::Environment::Type::Array) {
const std::vector<NVL::Environment::Variable>& ef_t = std::get<std::vector<NVL::Environment::Variable>>(combination.value);
const NVL::String& ef = std::get<NVL::String>(ef_t[0].value);
const std::vector<NVL::Environment::Variable>& args = std::get<std::vector<NVL::Environment::Variable>>(ef_t[1].value);
RenderString(str.substr(begin, end - begin + 1), pos_x, pos_y, col);
}
}
}
// NVL::String str = std::get<NVL::String>(s.value);
// RenderString(str, pos_x, pos_y, col);
}
}