189 lines
3.9 KiB
C++
189 lines
3.9 KiB
C++
|
|
#include <GL/glew.h>
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#include <ft2build.h>
|
|
#include FT_FREETYPE_H
|
|
|
|
#include <glm/vec2.hpp>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
#include "mesh.hpp"
|
|
#include "arrays.hpp"
|
|
#include "font.hpp"
|
|
|
|
using namespace Sim::Graphics;
|
|
|
|
struct Character
|
|
{
|
|
unsigned long handle;
|
|
float advance;
|
|
glm::vec2 size;
|
|
glm::vec2 bearing;
|
|
};
|
|
|
|
static Character chars[128];
|
|
|
|
void Font::init()
|
|
{
|
|
FT_Library ft;
|
|
FT_Face face;
|
|
|
|
if(FT_Init_FreeType(&ft))
|
|
{
|
|
std::cout << "Error: failed to init freetype\n";
|
|
return;
|
|
}
|
|
|
|
if(FT_New_Face(ft, "../assets/font/DroidSans.ttf", 0, &face))
|
|
{
|
|
std::cout << "Error: failed to load freetype font\n";
|
|
return;
|
|
}
|
|
|
|
int size = 256;
|
|
float m = 1.0f / size;
|
|
|
|
FT_Set_Pixel_Sizes(face, 0, size);
|
|
|
|
GLuint texids[128];
|
|
std::vector<glm::vec<4, unsigned char>> pixels;
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
for(int i = 0; i < 128; i++)
|
|
{
|
|
if(FT_Load_Char(face, (char)i, FT_LOAD_RENDER))
|
|
{
|
|
std::cout << "Error: failed to load glyph " << i << "\n";
|
|
}
|
|
|
|
int width = face->glyph->bitmap.width;
|
|
int height = face->glyph->bitmap.rows;
|
|
int offx = face->glyph->bitmap_left;
|
|
int offy = face->glyph->bitmap_top;
|
|
|
|
Character& c = chars[i];
|
|
c.advance = face->glyph->advance.x * m / 64.0;
|
|
c.size = {width * m, height * m};
|
|
c.bearing = {offx * m, offy * m};
|
|
|
|
if(c.size.x == 0 || c.size.y == 0)
|
|
{
|
|
c.handle = 0;
|
|
continue;
|
|
}
|
|
|
|
pixels.resize(width * height);
|
|
|
|
for(int i = 0; i < width * height; i++)
|
|
{
|
|
pixels[i] = glm::vec<4, unsigned char>(face->glyph->bitmap.buffer[i]);
|
|
}
|
|
|
|
glCreateTextures(GL_TEXTURE_2D, 1, &texids[i]);
|
|
|
|
glTextureStorage2D(texids[i], 1, GL_RGBA8, width, height);
|
|
glTextureSubImage2D(texids[i], 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
|
|
|
|
glTextureParameteri(texids[i], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTextureParameteri(texids[i], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTextureParameteri(texids[i], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTextureParameteri(texids[i], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
c.handle = glGetTextureHandleARB(texids[i]);
|
|
glMakeTextureHandleResidentARB(c.handle);
|
|
|
|
chars[i] = c;
|
|
}
|
|
|
|
FT_Done_FreeType(ft);
|
|
}
|
|
|
|
void Mesh::load_text(const char* text, double size)
|
|
{
|
|
std::vector<Arrays::Vertex> vertices;
|
|
std::vector<unsigned int> indices;
|
|
|
|
float x = 0, y = size;
|
|
unsigned int at = 0;
|
|
|
|
if(text[0] == '\0')
|
|
{
|
|
this->vertices.clear();
|
|
this->indices.clear();
|
|
return;
|
|
}
|
|
|
|
for(unsigned int i = 0; text[i] != '\0'; i++)
|
|
{
|
|
char c = text[i];
|
|
Character ch = chars[c];
|
|
|
|
if(c == '\n')
|
|
{
|
|
x = 0;
|
|
y += size;
|
|
continue;
|
|
}
|
|
|
|
if(ch.handle == 0)
|
|
{
|
|
x += ch.advance * size;
|
|
continue;
|
|
}
|
|
|
|
unsigned int index[6] = {
|
|
at, at + 1, at + 3,
|
|
at, at + 3, at + 2
|
|
};
|
|
|
|
float sx = x + ch.bearing.x * size;
|
|
float sy = y - ch.bearing.y * size;
|
|
float ex = sx + ch.size.x * size;
|
|
float ey = sy + ch.size.y * size;
|
|
|
|
vertices.push_back(Arrays::Vertex{.texid=ch.handle, .texpos={0, 0}, .pos={sx, sy, 0, 1}, .normal={0, 0, -1}, .material={0, 0, 1}});
|
|
vertices.push_back(Arrays::Vertex{.texid=ch.handle, .texpos={0, 1}, .pos={sx, ey, 0, 1}, .normal={0, 0, -1}, .material={0, 0, 1}});
|
|
vertices.push_back(Arrays::Vertex{.texid=ch.handle, .texpos={1, 0}, .pos={ex, sy, 0, 1}, .normal={0, 0, -1}, .material={0, 0, 1}});
|
|
vertices.push_back(Arrays::Vertex{.texid=ch.handle, .texpos={1, 1}, .pos={ex, ey, 0, 1}, .normal={0, 0, -1}, .material={0, 0, 1}});
|
|
indices.insert(indices.end(), &index[0], &index[6]);
|
|
|
|
at += 4;
|
|
x += ch.advance * size;
|
|
}
|
|
|
|
this->vertices = std::move(vertices);
|
|
this->indices = std::move(indices);
|
|
}
|
|
|
|
void Mesh::load_text(const char* text, double size, glm::vec2 align)
|
|
{
|
|
glm::vec2 max;
|
|
|
|
load_text(text, size);
|
|
|
|
for(Arrays::Vertex& v : vertices)
|
|
{
|
|
if(v.pos.x > max.x)
|
|
{
|
|
max.x = v.pos.x;
|
|
}
|
|
|
|
if(v.pos.y > max.y)
|
|
{
|
|
max.y = v.pos.y;
|
|
}
|
|
}
|
|
|
|
align *= max;
|
|
|
|
for(Arrays::Vertex& v : vertices)
|
|
{
|
|
v.pos.x -= align.x;
|
|
v.pos.y -= align.y;
|
|
}
|
|
}
|
|
|