Refactor & Fix inverted text & More
This commit is contained in:
@@ -49,48 +49,52 @@ namespace JGL {
|
||||
Vector3 C;
|
||||
};
|
||||
|
||||
bool Update(const Vector2& window_size);
|
||||
bool InitTextEngine();
|
||||
inline FontCache fontCache;
|
||||
int LoadFont(const std::string& font_path);
|
||||
|
||||
void UnloadFont(int font_index);
|
||||
// TODO: implement correct coloring
|
||||
|
||||
namespace J2D {
|
||||
void DrawPixel2D(const Color3 &color, const Vector2 &coordinates);
|
||||
void DrawPixel2D(const Color3 &color, float x, float y);
|
||||
void DrawLine2D(const Color3 &color, const Vector2 &A, const Vector2 &B, float thickness = 1);
|
||||
void DrawLine2D(const Color3 &color, float x, float y, float w, float h, float thickness = 1);
|
||||
void DrawCubicBezierCurve2D();
|
||||
void OutlineCircle2D(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions,
|
||||
float thickness = 1);
|
||||
void FillCircle2D(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions);
|
||||
void OutlineTriangle2D(const Color3 &color, const Triangle2D &tri);
|
||||
void FillTriangle2D(const Color3 &color, const Triangle2D &tri);
|
||||
void FillTexturedTriangle2D();
|
||||
void FillTexturedPolygon2D();
|
||||
void DrawSprite2D();
|
||||
void DrawPartialSprite2D();
|
||||
void DrawString2D(const Color3& color, std::string text, float x, float y, float scale, u32 size, unsigned int font_index);
|
||||
void FillRect2D(const Color3 &color, const Vector2 &pos, const Vector2 &size);
|
||||
void OutlineRect2D ( const Color3& color, const Vector2& pos, const Vector2& size, float thickness = 1);
|
||||
void FillRoundedRect2D (const Color3& color, const Vector2& pos, const Vector2& size, float radius);
|
||||
void OutlineRoundedRect2D(const Color3& color, const Vector2& pos, const Vector2& size, float radius, float thickness = 1);
|
||||
void OutlinePolygon2D (const Color3& color, std::vector<Vector2> points);
|
||||
void FillPolygon2D (const Color3& color, std::vector<Vector2> points, float thickness = 1);
|
||||
void GradientFillRect2D ();
|
||||
void Begin();
|
||||
void End();
|
||||
void DrawPixel(const Color3 &color, const Vector2 &coordinates);
|
||||
void DrawPixel(const Color3 &color, float x, float y);
|
||||
void DrawLine(const Color3 &color, const Vector2 &A, const Vector2 &B, float thickness = 1);
|
||||
void DrawLine(const Color3 &color, float x, float y, float w, float h, float thickness = 1);
|
||||
void DrawCubicBezierCurve();
|
||||
void OutlineCircle(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions, float thickness = 1);
|
||||
void FillCircle(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions);
|
||||
void OutlineTriangle(const Color3 &color, const Triangle2D &tri);
|
||||
void FillTriangle(const Color3 &color, const Triangle2D &tri);
|
||||
void FillTexturedTriangle();
|
||||
void FillTexturedPolygon();
|
||||
void DrawSprite();
|
||||
void DrawPartialSprite();
|
||||
void DrawString(const Color3& color, std::string text, float x, float y, float scale, u32 size, unsigned int font_index);
|
||||
void FillRect(const Color3 &color, const Vector2 &pos, const Vector2 &size);
|
||||
void OutlineRect ( const Color3& color, const Vector2& pos, const Vector2& size, float thickness = 1);
|
||||
void FillRoundedRect (const Color3& color, const Vector2& pos, const Vector2& size, float radius);
|
||||
void OutlineRoundedRect(const Color3& color, const Vector2& pos, const Vector2& size, float radius, float thickness = 1);
|
||||
void OutlinePolygon (const Color3& color, std::vector<Vector2> points);
|
||||
void FillPolygon (const Color3& color, std::vector<Vector2> points, float thickness = 1);
|
||||
void GradientFillRect ();
|
||||
}
|
||||
namespace J3D {
|
||||
void DrawLine3D(const Color3& color, const Vector3 &A, const Vector3 &B, float thickness = 1);
|
||||
void FillSphere3D(const Color3& color, const Sphere& sphere);
|
||||
void WireframeSphere3D(const Color3& color, const Sphere& sphere, float thickness = 1);
|
||||
void FillOBB3D(const Color3& color, const OBB& obb);
|
||||
void WireframeOBB3D(const Color3& color, const OBB& obb, float thickness = 1);
|
||||
void FillCapsule3D(const Color3& color, const Capsule& capsule);
|
||||
void WireframeCapsule3D(const Color3& color, const Capsule& cap, float thickness = 1);
|
||||
void FillTriangleMesh3D(const Color3& color, const TriangleMesh& mesh);
|
||||
void WireframeTriangleMesh3D(const Color3& color, const TriangleMesh& mesh, float thickness = 1);
|
||||
void DrawString3D(const Color3& color, const std::string& text, const Vector3& pos, float scale, u32 size, unsigned int font_index);
|
||||
void Begin();
|
||||
void End();
|
||||
void SetMatrix(const std::vector<GLfloat>& matrix, const Vector2& window_size);
|
||||
void DrawLine(const Color3& color, const Vector3 &A, const Vector3 &B, float thickness = 1);
|
||||
void FillSphere(const Color3& color, const Sphere& sphere);
|
||||
void WireframeSphere(const Color3& color, const Sphere& sphere, float thickness = 1);
|
||||
void FillOBB(const Color3& color, const OBB& obb);
|
||||
void WireframeOBB(const Color3& color, const OBB& obb, float thickness = 1);
|
||||
void FillCapsule(const Color3& color, const Capsule& capsule);
|
||||
void WireframeCapsule(const Color3& color, const Capsule& cap, float thickness = 1);
|
||||
void FillTriangleMesh(const Color3& color, const TriangleMesh& mesh);
|
||||
void WireframeTriangleMesh(const Color3& color, const TriangleMesh& mesh, float thickness = 1);
|
||||
void DrawString(const Color3& color, const std::string& text, const Vector3& pos, float scale, u32 size, unsigned int font_index);
|
||||
|
||||
void DrawMatrixGizmo (const Matrix3x3&, const Vector3&);
|
||||
void DrawMatrixGizmo (const Matrix4x4&);
|
||||
|
110
main.cpp
110
main.cpp
@@ -5,17 +5,19 @@
|
||||
#include <J3ML/LinearAlgebra/Vector2.h>
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
using namespace JGL;
|
||||
|
||||
struct Character
|
||||
{
|
||||
unsigned int TextureID; // ID handle of the glyph texture
|
||||
Vector2 Size; // Size of glyph
|
||||
Vector2 Bearing; // Offset from baseline to left/top of glyph
|
||||
unsigned int Advance; // Offset to advance to next glyph
|
||||
};
|
||||
|
||||
std::map<char, Character> Characters;
|
||||
GLuint VAO, VBO;
|
||||
//The Re3D style base projection.
|
||||
std::vector<GLfloat> perspective(float fov, float aspect, float nearPlane, float farPlane) {
|
||||
std::vector<float> result(16);
|
||||
float f = 1.0f / tan(fov * 0.5f * M_PI / 180.0f);
|
||||
result[0] = f / aspect;
|
||||
result[5] = f;
|
||||
result[10] = (farPlane + nearPlane) / (nearPlane - farPlane);
|
||||
result[11] = -1.0f;
|
||||
result[14] = (2.0f * farPlane * nearPlane) / (nearPlane - farPlane);
|
||||
return result;
|
||||
}
|
||||
|
||||
using J3ML::LinearAlgebra::Matrix4x4;
|
||||
|
||||
@@ -32,81 +34,69 @@ int Jupiteroid;
|
||||
class JGLDemoWindow : public ReWindow::RWindow
|
||||
{
|
||||
public:
|
||||
|
||||
JGLDemoWindow() : ReWindow::RWindow() {}
|
||||
JGLDemoWindow(const std::string& title, int width, int height) : ReWindow::RWindow(title, width, height){}
|
||||
|
||||
void initGL() {
|
||||
gladLoadGL();
|
||||
auto window_size = getSize();
|
||||
auto aspect = (float) window_size[0] / (float) window_size[1];
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, getSize().x, getSize().y, 0, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
gladLoadGL();
|
||||
JGL::Update(getSize());
|
||||
FreeSans = JGL::LoadFont("assets/fonts/FreeSans.ttf");
|
||||
Jupiteroid = JGL::LoadFont("assets/fonts/Jupiteroid.ttf");
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
JGL::InitTextEngine();
|
||||
FreeSans = JGL::LoadFont("assets/fonts/FreeSans.ttf");
|
||||
Jupiteroid = JGL::LoadFont("assets/fonts/Jupiteroid.ttf");
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMultMatrixf(perspective(75, aspect, 0.001, 100).data());
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glViewport(0,0,window_size.x,window_size.y);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
|
||||
void display() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, getSize().x, getSize().y, 0, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
JGL::J2D::FillRect2D(JGL::Colors::Blue, {32, 32}, {100.5, 100.5});
|
||||
JGL::J2D::FillRect2D(JGL::Colors::Blue, {32, 32}, {100.5, 100.5});
|
||||
///All 3D elements of the scene and JGL elements *must* be rendered before the 2d stuff.
|
||||
J3D::Begin();
|
||||
J3D::DrawLine(JGL::Colors::Red, {0,0,-1}, {1,0,-1.5});
|
||||
J3D::DrawLine(JGL::Colors::Red, {0,0.0,-1}, {0,0.5,-1});
|
||||
J3D::DrawString(JGL::Colors::Red, "JGL Sample Text", {-13, 1, -10.0f}, 0.0225, 32, FreeSans);
|
||||
J3D::End();
|
||||
|
||||
JGL::Triangle2D tri
|
||||
{
|
||||
{140, 200},
|
||||
{135, 100},
|
||||
{105, 100}
|
||||
};
|
||||
JGL::J2D::FillTriangle2D(JGL::Colors::Yellow, tri);
|
||||
JGL::J2D::DrawLine2D(JGL::Colors::Greens::DarkGreen, {10, 10}, {200, 300});
|
||||
JGL::J3D::DrawLine3D(JGL::Colors::Red, {0,0,0}, {1,0,0});
|
||||
JGL::J3D::DrawLine3D(JGL::Colors::Red, {0,0,0}, {1,0,0});
|
||||
|
||||
JGL::J3D::DrawString3D(JGL::Colors::Red, "JGL Sample Text", {1, -32, 0.5f}, 1.f, 32, FreeSans);
|
||||
JGL::J2D::DrawString2D(JGL::Colors::Green, "Jupiteroid Font", 0.f, -48.f, 1.f, 16, Jupiteroid);
|
||||
|
||||
//glFlush();
|
||||
J2D::Begin();
|
||||
J2D::FillRect(JGL::Colors::Blue, {32, 32}, {100.5, 100.5});
|
||||
J2D::FillTriangle(JGL::Colors::Yellow, {{140, 200},{135, 100},{105, 100}});
|
||||
J2D::DrawLine(JGL::Colors::Greens::DarkGreen, {10, 10}, {200, 300});
|
||||
J2D::DrawString(JGL::Colors::Green, "Jupteroid Font", 0.f, -48.f, 1.f, 16, Jupiteroid);
|
||||
J2D::End();
|
||||
}
|
||||
|
||||
void OnRefresh(float elapsed) override
|
||||
{
|
||||
void OnRefresh(float elapsed) override {
|
||||
display();
|
||||
this->glSwapBuffers();
|
||||
}
|
||||
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent& e) override
|
||||
{
|
||||
return true;
|
||||
glSwapBuffers();
|
||||
}
|
||||
|
||||
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent& e) override {return true;}
|
||||
JGLDemoWindow() : ReWindow::RWindow() {}
|
||||
JGLDemoWindow(const std::string& title, int width, int height) : ReWindow::RWindow(title, width, height){}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int main(int argc, char** argv) {
|
||||
auto* window = new JGLDemoWindow("JGL Demo Window", 1280, 720);
|
||||
window->setRenderer(RenderingAPI::OPENGL);
|
||||
window->Open();
|
||||
window->initGL();
|
||||
window->setResizable(false);
|
||||
while (window->isAlive())
|
||||
{
|
||||
|
||||
while (window->isAlive()) {
|
||||
window->pollEvents();
|
||||
window->refresh();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
512
src/JGL.cpp
512
src/JGL.cpp
@@ -2,378 +2,170 @@
|
||||
// Created by dawsh on 1/17/24.
|
||||
//
|
||||
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
#include <JGL/JGL.h>
|
||||
#include <glad/glad.h>
|
||||
#include <JGL/Color3.h>
|
||||
#if __linux__
|
||||
#include <freetype2/ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#endif
|
||||
#if _WIN32
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#endif
|
||||
|
||||
GLuint program;
|
||||
namespace JGL
|
||||
{
|
||||
FT_Library ft;
|
||||
|
||||
struct Font {
|
||||
int index = 0;
|
||||
FT_Face face;
|
||||
};
|
||||
|
||||
std::vector<Font> faces;
|
||||
bool wasDepthTest = false;
|
||||
|
||||
namespace JGL {
|
||||
using namespace J3ML;
|
||||
bool InitTextEngine() {
|
||||
if (FT_Init_FreeType(&ft))
|
||||
return true;
|
||||
return false;
|
||||
Vector2 wS;
|
||||
|
||||
bool Update(const Vector2& window_size) {
|
||||
wS = window_size;
|
||||
return JGL::InitTextEngine();
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
int LoadFont(const std::string &font_path) {
|
||||
if (ft == nullptr)
|
||||
return -1;
|
||||
void J2D::Begin() {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
// Switch to orthographic projection
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(0, wS.x, wS.y, 0, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
Font font;
|
||||
if (FT_New_Face(ft, font_path.c_str(), 0, &font.face)) {
|
||||
std::cout << "Error::FREETYPE: Failed to load font!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int newIndex = 0;
|
||||
for (const auto& f : faces)
|
||||
if (f.index >= newIndex)
|
||||
newIndex = f.index + 1;
|
||||
|
||||
font.index = newIndex;
|
||||
faces.push_back(font);
|
||||
std::cout << "Loaded font from " << font_path << " with index " << newIndex << std::endl;
|
||||
return newIndex;
|
||||
wasDepthTest = false;
|
||||
if (glIsEnabled(GL_DEPTH_TEST))
|
||||
wasDepthTest = true,
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void UnloadFont(int font_index) {
|
||||
for (int i = 0; i < faces.size(); i++)
|
||||
if (faces[i].index == font_index)
|
||||
FT_Done_Face(faces[i].face),
|
||||
faces.erase(faces.begin() + i);
|
||||
void J2D::End() {
|
||||
//Change back to the previous projection (The 3D one in Re3D's case.
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
if (wasDepthTest)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
namespace J2D {
|
||||
void FillRect2D(const Color3 &color, const Vector2 &pos, const Vector2 &size) {
|
||||
auto vp_pos = pos;
|
||||
auto vp_size = size;
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(color.r / 255.f, color.g / 255.f, color.b / 255.f);
|
||||
glVertex2f(vp_pos.x, vp_pos.y);
|
||||
glVertex2f(vp_pos.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void OutlineRect2D(const Color3 &color, const Vector2 &pos, const Vector2 &size, float thickness) {
|
||||
auto vp_pos = pos;
|
||||
auto vp_size = size;
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glLineWidth(thickness);
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
glVertex2f(vp_pos.x, vp_pos.y);
|
||||
glVertex2f(vp_pos.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void DrawLine2D(const Color3 &color, const Vector2 &A, const Vector2 &B, float thickness) {
|
||||
auto vp_a = A;
|
||||
auto vp_b = B;
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glLineWidth(thickness);
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
glVertex2f(vp_a.x, vp_a.y);
|
||||
glVertex2f(vp_b.x, vp_b.y);
|
||||
glEnd();
|
||||
|
||||
}
|
||||
|
||||
void DrawLine2D(const Color3 &color, float x, float y, float w, float h, float thickness) {
|
||||
DrawLine2D(color, {x, y}, {w, h}, thickness);
|
||||
}
|
||||
|
||||
void DrawPixel2D(const Color3 &color, float x, float y) {
|
||||
DrawPixel2D(color, {x, y});
|
||||
}
|
||||
|
||||
void DrawPixel2D(const Color3 &color, const Vector2 &coordinates) {
|
||||
auto vp_pos = coordinates;
|
||||
glBegin(GL_POINT);
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
glVertex2f(vp_pos.x, vp_pos.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void
|
||||
OutlineCircle2D(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions, float thickness) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
GLfloat angle;
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
float step = (2.f * M_PI) / (float) subdivisions;
|
||||
for (angle = 0.0f; angle < (2.f * M_PI); angle += step) {
|
||||
GLfloat x = radius * sin(angle);
|
||||
GLfloat y = radius * cos(angle);
|
||||
x += center.x;
|
||||
y += center.y;
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void FillCircle2D(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions) {
|
||||
glBegin(GL_POLYGON);
|
||||
GLfloat angle;
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
float step = (2.f * M_PI) / (float) subdivisions;
|
||||
for (angle = 0.0f; angle < (2.f * M_PI); angle += step) {
|
||||
GLfloat x = radius * sin(angle);
|
||||
GLfloat y = radius * cos(angle);
|
||||
x += center.x;
|
||||
y += center.y;
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void OutlineTriangle2D(const Color3 &color, const Triangle2D &tri) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glColor3f(color.r / 255.f, color.g / 255.f, color.b / 255.f);
|
||||
glVertex2f(tri.A.x, tri.A.y);
|
||||
glVertex2f(tri.B.x, tri.B.y);
|
||||
glVertex2f(tri.C.x, tri.C.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void FillTriangle2D(const Color3 &color, const Triangle2D &tri) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glColor3f(color.r / 255.f, color.g / 255.f, color.b / 255.f);
|
||||
glVertex2f(tri.A.x, tri.A.y);
|
||||
glVertex2f(tri.B.x, tri.B.y);
|
||||
glVertex2f(tri.C.x, tri.C.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void DrawString2D(const Color3& color, std::string text, float x, float y, float scale, u32 size, unsigned int font_index) {
|
||||
glUseProgram(0); // Fixed-function pipeline.
|
||||
|
||||
Font font{};
|
||||
CachedFont* cachedFont = fontCache.getFont(size, font_index);
|
||||
|
||||
//If the font doesn't exist in the cache yet.
|
||||
if (!cachedFont) {
|
||||
fontCache.newFont(size, font_index);
|
||||
cachedFont = fontCache.getFont(size, font_index);
|
||||
}
|
||||
|
||||
//Set up the regular font.
|
||||
for (const auto& f : faces)
|
||||
if (f.index == font_index)
|
||||
font = f;
|
||||
if (font.face == nullptr)
|
||||
return;
|
||||
|
||||
GLfloat currentColor[4];
|
||||
glGetFloatv(GL_CURRENT_COLOR, currentColor);
|
||||
|
||||
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, 1.0f);
|
||||
|
||||
FT_Set_Pixel_Sizes(font.face, 0, size);
|
||||
|
||||
std::vector<GLuint> textures(text.length());
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
//For each character
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
float x2, y2, w, h;
|
||||
//If the font is in the cache already.
|
||||
if (cachedFont->getGlyph(text.c_str()[i])) {
|
||||
CachedGlyph* glyph = cachedFont->getGlyph(text.c_str()[i]);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, *glyph->getTexture());
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
x2 = x + glyph->x2offset * scale;
|
||||
y2 = -y - glyph->y2offset * scale; // Adjust y-coordinate
|
||||
w = glyph->w * scale;
|
||||
h = glyph->h * scale;
|
||||
x += glyph->advanceX * scale;
|
||||
y += glyph->advanceY * scale;
|
||||
|
||||
} else {
|
||||
if (FT_Load_Char(font.face, text.c_str()[i], FT_LOAD_RENDER))
|
||||
continue;
|
||||
|
||||
FT_GlyphSlot g = font.face->glyph;
|
||||
glGenTextures(1, &textures.at(i));
|
||||
glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
|
||||
x2 = x + g->bitmap_left * scale;
|
||||
y2 = -y - g->bitmap_top * scale; // Adjust y-coordinate
|
||||
w = g->bitmap.width * scale;
|
||||
h = g->bitmap.rows * scale;
|
||||
x += (g->advance.x >> 6) * scale;
|
||||
y += (g->advance.y >> 6) * scale;
|
||||
cachedFont->appendGlyph(new CachedGlyph(textures.at(i), text.c_str()[i], g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
|
||||
}
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(x2, y2);
|
||||
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex2f(x2, y2 + h);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(x2 + w, y2 + h);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(x2, y2);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(x2 + w, y2 + h);
|
||||
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex2f(x2 + w, y2);
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
//for (unsigned int& texture : textures)
|
||||
//glDeleteTextures(1, &texture);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
||||
glColor4f(currentColor[0], currentColor[1], currentColor[2], currentColor[3]); //Set draw color back to whatever it was before.
|
||||
}
|
||||
void J2D::FillRect(const Color3 &color, const Vector2 &pos, const Vector2 &size) {
|
||||
auto vp_pos = pos;
|
||||
auto vp_size = size;
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(color.r / 255.f, color.g / 255.f, color.b / 255.f);
|
||||
glVertex2f(vp_pos.x, vp_pos.y);
|
||||
glVertex2f(vp_pos.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
namespace J3D
|
||||
{
|
||||
void DrawLine3D(const Color3& color, const Vector3& A, const Vector3& B, float thickness)
|
||||
{
|
||||
glBegin(GL_LINES);
|
||||
glLineWidth(thickness);
|
||||
glColor3f(color.r/255.f, color.g/255.f, color.b/255.f);
|
||||
glVertex3f(A.x, A.y, A.z);
|
||||
glVertex3f(B.x, B.y, B.z);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void DrawString3D(const Color3& color, const std::string& text, const Vector3& pos, float scale, u32 size, unsigned int font_index)
|
||||
{
|
||||
float x = pos.x;
|
||||
float y = pos.y;
|
||||
float z = pos.z;
|
||||
GLfloat currentColor[4];
|
||||
std::vector<GLuint> textures(text.length());;
|
||||
glGetFloatv(GL_CURRENT_COLOR, currentColor);
|
||||
glUseProgram(0); // Fixed-function pipeline.
|
||||
glColor4f(color.r, color.g, color.b, 1.0f);
|
||||
|
||||
Font font;
|
||||
for (auto& f : faces)
|
||||
if (f.index == font_index)
|
||||
font = f;
|
||||
if (font.face == NULL) {
|
||||
std::cout << "null font" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
FT_Set_Pixel_Sizes(font.face, 0, size);
|
||||
|
||||
//for (c = text.c_str(); *c; c++)
|
||||
for (int i = 0; i < text.length(); i++)
|
||||
{
|
||||
if (FT_Load_Char(font.face, text.c_str()[i], FT_LOAD_RENDER))
|
||||
continue;
|
||||
|
||||
FT_GlyphSlot g = font.face->glyph;
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glGenTextures(1, &textures.at(i));
|
||||
glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
|
||||
float x2 = x + g->bitmap_left * scale;
|
||||
float y2 = -y - g->bitmap_top * scale; // Adjust y-coordinate
|
||||
float z2 = z;
|
||||
float w = g->bitmap.width * scale;
|
||||
float h = g->bitmap.rows * scale;
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex3f(x2, y2, z2);
|
||||
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex3f(x2, y2 + h, z2);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex3f(x2 + w, y2 + h, z2);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex3f(x2, y2, z2);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex3f(x2 + w, y2 + h, z2);
|
||||
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex3f(x2 + w, y2, z2);
|
||||
|
||||
glEnd();
|
||||
|
||||
x += (g->advance.x >> 6) * scale;
|
||||
y += (g->advance.y >> 6) * scale;
|
||||
|
||||
}
|
||||
|
||||
for (unsigned int& texture : textures)
|
||||
glDeleteTextures(1, &texture);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
||||
glColor4f(currentColor[0], currentColor[1], currentColor[2], currentColor[3]); //Set draw color back to whatever it was before.
|
||||
}
|
||||
|
||||
void J2D::OutlineRect(const Color3 &color, const Vector2 &pos, const Vector2 &size, float thickness) {
|
||||
auto vp_pos = pos;
|
||||
auto vp_size = size;
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glLineWidth(thickness);
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
glVertex2f(vp_pos.x, vp_pos.y);
|
||||
glVertex2f(vp_pos.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void J2D::DrawLine(const Color3 &color, const Vector2 &A, const Vector2 &B, float thickness) {
|
||||
auto vp_a = A;
|
||||
auto vp_b = B;
|
||||
glBegin(GL_LINES);
|
||||
glLineWidth(thickness);
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
glVertex2f(vp_a.x, vp_a.y);
|
||||
glVertex2f(vp_b.x, vp_b.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void J2D::DrawLine(const Color3 &color, float x, float y, float w, float h, float thickness) {
|
||||
DrawLine(color, {x, y}, {w, h}, thickness);
|
||||
}
|
||||
|
||||
void J2D::DrawPixel(const Color3 &color, float x, float y) {
|
||||
DrawPixel(color, {x, y});
|
||||
}
|
||||
|
||||
void J2D::DrawPixel(const Color3 &color, const Vector2 &coordinates) {
|
||||
auto vp_pos = coordinates;
|
||||
glBegin(GL_POINT);
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
glVertex2f(vp_pos.x, vp_pos.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void J2D::OutlineCircle(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions, float thickness) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
GLfloat angle;
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
float step = (2.f * M_PI) / (float) subdivisions;
|
||||
for (angle = 0.0f; angle < (2.f * M_PI); angle += step) {
|
||||
GLfloat x = radius * sin(angle);
|
||||
GLfloat y = radius * cos(angle);
|
||||
x += center.x;
|
||||
y += center.y;
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void J2D::FillCircle(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions) {
|
||||
glBegin(GL_POLYGON);
|
||||
GLfloat angle;
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
float step = (2.f * M_PI) / (float) subdivisions;
|
||||
for (angle = 0.0f; angle < (2.f * M_PI); angle += step) {
|
||||
GLfloat x = radius * sin(angle);
|
||||
GLfloat y = radius * cos(angle);
|
||||
x += center.x;
|
||||
y += center.y;
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void J2D::OutlineTriangle(const Color3 &color, const Triangle2D &tri) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glColor3f(color.r / 255.f, color.g / 255.f, color.b / 255.f);
|
||||
glVertex2f(tri.A.x, tri.A.y);
|
||||
glVertex2f(tri.B.x, tri.B.y);
|
||||
glVertex2f(tri.C.x, tri.C.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void J2D::FillTriangle(const Color3 &color, const Triangle2D &tri) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glColor3f(color.r / 255.f, color.g / 255.f, color.b / 255.f);
|
||||
glVertex2f(tri.A.x, tri.A.y);
|
||||
glVertex2f(tri.B.x, tri.B.y);
|
||||
glVertex2f(tri.C.x, tri.C.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void J3D::Begin() {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
wasDepthTest = false;
|
||||
if (glIsEnabled(GL_DEPTH_TEST))
|
||||
wasDepthTest = true,
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void J3D::End() {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
if (wasDepthTest)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
void J3D::DrawLine(const Color3 &color, const Vector3 &A, const Vector3 &B, float thickness) {
|
||||
glBegin(GL_LINES);
|
||||
glLineWidth(thickness);
|
||||
glColor3f(color.r / 255.f, color.g / 255.f, color.b / 255.f);
|
||||
glVertex3f(A.x, A.y, A.z);
|
||||
glVertex3f(B.x, B.y, B.z);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
245
src/JGL/TextRendering.cpp
Normal file
245
src/JGL/TextRendering.cpp
Normal file
@@ -0,0 +1,245 @@
|
||||
#include <JGL/JGL.h>
|
||||
|
||||
#if __linux__
|
||||
#include <freetype2/ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#endif
|
||||
#if _WIN32
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#endif
|
||||
|
||||
namespace JGL {
|
||||
FT_Library ft;
|
||||
|
||||
struct Font {
|
||||
int index = 0;
|
||||
FT_Face face;
|
||||
};
|
||||
std::vector<Font> faces;
|
||||
|
||||
int LoadFont(const std::string &font_path) {
|
||||
if (ft == nullptr)
|
||||
return -1;
|
||||
|
||||
Font font;
|
||||
if (FT_New_Face(ft, font_path.c_str(), 0, &font.face)) {
|
||||
std::cout << "Error::FREETYPE: Failed to load font!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
unsigned int newIndex = 0;
|
||||
for (const auto& f : faces)
|
||||
if (f.index >= newIndex)
|
||||
newIndex = f.index + 1;
|
||||
|
||||
font.index = newIndex;
|
||||
faces.push_back(font);
|
||||
std::cout << "Loaded font from " << font_path << " with index " << newIndex << std::endl;
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
bool InitTextEngine() {
|
||||
if (FT_Init_FreeType(&ft))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void UnloadFont(int font_index) {
|
||||
for (int i = 0; i < faces.size(); i++)
|
||||
if (faces[i].index == font_index)
|
||||
FT_Done_Face(faces[i].face),
|
||||
faces.erase(faces.begin() + i);
|
||||
}
|
||||
|
||||
FontCache fontCache;
|
||||
void J2D::DrawString(const Color3& color, std::string text, float x, float y, float scale, u32 size, unsigned int font_index) {
|
||||
glUseProgram(0); // Fixed-function pipeline.
|
||||
|
||||
Font font{};
|
||||
CachedFont* cachedFont = fontCache.getFont(size, font_index);
|
||||
|
||||
//If the font doesn't exist in the cache yet.
|
||||
if (!cachedFont) {
|
||||
fontCache.newFont(size, font_index);
|
||||
cachedFont = fontCache.getFont(size, font_index);
|
||||
}
|
||||
|
||||
//Set up the regular font.
|
||||
for (const auto& f : faces)
|
||||
if (f.index == font_index)
|
||||
font = f;
|
||||
if (font.face == nullptr)
|
||||
return;
|
||||
|
||||
GLfloat currentColor[4];
|
||||
glGetFloatv(GL_CURRENT_COLOR, currentColor);
|
||||
|
||||
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, 1.0f);
|
||||
|
||||
FT_Set_Pixel_Sizes(font.face, 0, size);
|
||||
|
||||
std::vector<GLuint> textures(text.length());
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
//For each character
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
float x2, y2, w, h;
|
||||
//If the font is in the cache already.
|
||||
if (cachedFont->getGlyph(text.c_str()[i])) {
|
||||
CachedGlyph* glyph = cachedFont->getGlyph(text.c_str()[i]);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, *glyph->getTexture());
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
x2 = x + glyph->x2offset * scale;
|
||||
y2 = -y - glyph->y2offset * scale; // Adjust y-coordinate
|
||||
w = glyph->w * scale;
|
||||
h = glyph->h * scale;
|
||||
x += glyph->advanceX * scale;
|
||||
y += glyph->advanceY * scale;
|
||||
|
||||
} else {
|
||||
if (FT_Load_Char(font.face, text.c_str()[i], FT_LOAD_RENDER))
|
||||
continue;
|
||||
|
||||
FT_GlyphSlot g = font.face->glyph;
|
||||
glGenTextures(1, &textures.at(i));
|
||||
glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
|
||||
x2 = x + g->bitmap_left * scale;
|
||||
y2 = -y - g->bitmap_top * scale; // Adjust y-coordinate
|
||||
w = g->bitmap.width * scale;
|
||||
h = g->bitmap.rows * scale;
|
||||
x += (g->advance.x >> 6) * scale;
|
||||
y += (g->advance.y >> 6) * scale;
|
||||
cachedFont->appendGlyph(new CachedGlyph(textures.at(i), text.c_str()[i], g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
|
||||
}
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(x2, y2);
|
||||
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex2f(x2, y2 + h);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(x2 + w, y2 + h);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(x2, y2);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(x2 + w, y2 + h);
|
||||
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex2f(x2 + w, y2);
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
//for (unsigned int& texture : textures)
|
||||
//glDeleteTextures(1, &texture);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
||||
glColor4f(currentColor[0], currentColor[1], currentColor[2], currentColor[3]); //Set draw color back to whatever it was before.
|
||||
}
|
||||
|
||||
void J3D::DrawString(const Color3& color, const std::string& text, const Vector3& pos, float scale, u32 size, unsigned int font_index) {
|
||||
float x = pos.x;
|
||||
float y = pos.y;
|
||||
float z = pos.z;
|
||||
GLfloat currentColor[4];
|
||||
std::vector<GLuint> textures(text.length());;
|
||||
glGetFloatv(GL_CURRENT_COLOR, currentColor);
|
||||
glUseProgram(0); // Fixed-function pipeline.
|
||||
glColor4f(color.r, color.g, color.b, 1.0f);
|
||||
|
||||
Font font;
|
||||
for (auto& f : faces)
|
||||
if (f.index == font_index)
|
||||
font = f;
|
||||
if (font.face == NULL) {
|
||||
std::cout << "null font" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
FT_Set_Pixel_Sizes(font.face, 0, size);
|
||||
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
if (FT_Load_Char(font.face, text.c_str()[i], FT_LOAD_RENDER))
|
||||
continue;
|
||||
|
||||
FT_GlyphSlot g = font.face->glyph;
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glGenTextures(1, &textures.at(i));
|
||||
glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
|
||||
float x2 = x + g->bitmap_left * scale;
|
||||
float y2 = y + g->bitmap_top * scale; // Adjust y-coordinate to invert the text
|
||||
float z2 = z;
|
||||
float w = g->bitmap.width * scale;
|
||||
float h = g->bitmap.rows * scale;
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex3f(x2, y2, z2);
|
||||
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex3f(x2, y2 - h, z2);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex3f(x2 + w, y2 - h, z2);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex3f(x2, y2, z2);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex3f(x2 + w, y2 - h, z2);
|
||||
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex3f(x2 + w, y2, z2);
|
||||
|
||||
glEnd();
|
||||
|
||||
x += (g->advance.x >> 6) * scale;
|
||||
y += (g->advance.y >> 6) * scale;
|
||||
}
|
||||
|
||||
for (unsigned int& texture : textures)
|
||||
glDeleteTextures(1, &texture);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
||||
glColor4f(currentColor[0], currentColor[1], currentColor[2], currentColor[3]); // Set draw color back to whatever it was before.
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user