Compare commits
10 Commits
Prerelease
...
Prerelease
Author | SHA1 | Date | |
---|---|---|---|
4ff8d8ff07 | |||
162732e4b7 | |||
289157ab8a | |||
3a658b1096 | |||
480502f89e | |||
d28f680cd0 | |||
2d1e42c23b | |||
abd691b648 | |||
e261b610c2 | |||
8625c52ee9 |
@@ -38,6 +38,12 @@ CPMAddPackage(
|
|||||||
NAME Event
|
NAME Event
|
||||||
URL https://git.redacted.cc/josh/Event/archive/Release-6.zip
|
URL https://git.redacted.cc/josh/Event/archive/Release-6.zip
|
||||||
)
|
)
|
||||||
|
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME ReTexture
|
||||||
|
URL https://git.redacted.cc/Redacted/ReTexture/archive/Prerelease-2.zip
|
||||||
|
)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
#CPMAddPackage(
|
#CPMAddPackage(
|
||||||
#NAME harfbuzz
|
#NAME harfbuzz
|
||||||
@@ -76,6 +82,7 @@ target_include_directories(JGL PUBLIC
|
|||||||
${ReWindow_SOURCE_DIR}/include
|
${ReWindow_SOURCE_DIR}/include
|
||||||
${glad_SOURCE_DIR}/include
|
${glad_SOURCE_DIR}/include
|
||||||
${jlog_SOURCE_DIR}/include
|
${jlog_SOURCE_DIR}/include
|
||||||
|
${ReTexture_SOURCE_DIR}/include
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(JGL_Demo main.cpp)
|
add_executable(JGL_Demo main.cpp)
|
||||||
@@ -93,4 +100,4 @@ if (WIN32)
|
|||||||
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} J3ML ReWindowLibrary glad jlog Event)
|
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} J3ML ReWindowLibrary glad jlog Event)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(JGL_Demo PUBLIC JGL)
|
target_link_libraries(JGL_Demo PUBLIC JGL ReTexture)
|
40
README.md
40
README.md
@@ -4,23 +4,39 @@ Yet Another C++ Rendering Toolkit
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Goals
|
|
||||||
* Provide single-function-calls to render various graphics primitives in 2D and 3D.
|
|
||||||
* Integrated directly with our other toolkits (ReWindow, J3ML)
|
|
||||||
* Quick Rendering of Debug Text, Geometric Widgets, Textures, and so forth.
|
|
||||||
|
|
||||||
## Non-Goals
|
|
||||||
* Full Rendering Engine
|
|
||||||
* OpenGL/Vulkan Wrapper
|
|
||||||
* Asset Loading & Management
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Modern C++ (20)
|
* Modern C++ (20)
|
||||||
* Little-to-no overhead
|
* Provides single-function-calls to render various graphics primitives in 2D and 3D.
|
||||||
* No hand-holding
|
* Integrates directly with our other toolkits (ReWindow, J3ML)
|
||||||
* No-frills, straight up just renders shapes and text.
|
* Quick Rendering of Debug Text, Geometric Widgets, Textures, and so forth.
|
||||||
|
* Little-to-no overhead.
|
||||||
* Integrates right into an existing OpenGL rendering system.
|
* Integrates right into an existing OpenGL rendering system.
|
||||||
|
* High-performance text rendering.
|
||||||
|
|
||||||
|
## API Overview
|
||||||
|
|
||||||
|
### J2D
|
||||||
|
* DrawPixel
|
||||||
|
* DrawLine / DrawGradientLine
|
||||||
|
* DrawSprite
|
||||||
|
* OutlineRect / FillRect / FillGradientRect / FillRoundedRect
|
||||||
|
* OutlineCircle / FillCircle
|
||||||
|
* OutlineTriangle / FillTriangle
|
||||||
|
* DrawString
|
||||||
|
### J3D
|
||||||
|
* DrawLine
|
||||||
|
* DrawString
|
||||||
|
* DrawMatrixGizmo (WIP)
|
||||||
|
* DrawAxisAngleGizmo (WIP)
|
||||||
|
* DrawQuaternionGizmo (WIP)
|
||||||
|
|
||||||
|
### Types
|
||||||
|
* Font
|
||||||
|
* Sprite
|
||||||
|
* Color4/Color3
|
||||||
|
* Gradient
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
39
include/JGL/Font.h
Normal file
39
include/JGL/Font.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <J3ML/LinearAlgebra.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// LMFAO
|
||||||
|
extern "C" typedef struct FT_FaceRec_* FT_Face;
|
||||||
|
extern "C" typedef struct FT_LibraryRec_* FT_Library;
|
||||||
|
|
||||||
|
namespace JGL
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Initializes FreeType engine.
|
||||||
|
bool InitTextEngine();
|
||||||
|
|
||||||
|
/// A Font class implementation.
|
||||||
|
/// Wraps the font's FreeType asset handle and provides helper functions.
|
||||||
|
class Font {
|
||||||
|
public:
|
||||||
|
/// Default constructor does not initialize any members
|
||||||
|
Font() = default;
|
||||||
|
Font(const std::filesystem::path& path);
|
||||||
|
/// Destructor handles freeing of the underlying asset handle.
|
||||||
|
~Font();
|
||||||
|
static Font LoadTTF(const std::filesystem::path& filepath);
|
||||||
|
static std::vector<Font> GetLoadedFonts();
|
||||||
|
/// Returns the bounding-box the given string would occupy at the given point-size, assuming normal (1) scaling.
|
||||||
|
/// @param text The string to measure.
|
||||||
|
/// @param ptSize The font size at which to measure.
|
||||||
|
/// @return The size-in-pixels that would contain the entire text.
|
||||||
|
Vector2 MeasureString(const std::string& text, float ptSize);
|
||||||
|
public:
|
||||||
|
int index = 0;
|
||||||
|
FT_Face face;
|
||||||
|
};
|
||||||
|
}
|
@@ -1,43 +1,53 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
|
||||||
|
/// TODO: FontCache mechanism works amazing, but makes no fucking sense
|
||||||
|
/// Let's document and reorganize it to be a little nicer on the mental :)
|
||||||
|
|
||||||
namespace JGL {
|
namespace JGL {
|
||||||
class CachedGlyph;
|
class CachedGlyph;
|
||||||
class CachedFont;
|
class CachedFont;
|
||||||
class FontCache;
|
class FontCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a single font-character "glyph", that has been cached in-memory for fast retrieval.
|
||||||
class JGL::CachedGlyph {
|
class JGL::CachedGlyph {
|
||||||
private:
|
private:
|
||||||
GLuint texture = 0;
|
|
||||||
char character;
|
char character;
|
||||||
|
std::array<GLfloat, 12> texcoords;
|
||||||
public:
|
public:
|
||||||
int x2offset = 0, y2offset = 0, w = 0, h = 0;
|
int x2offset = 0, y2offset = 0, w = 0, h = 0;
|
||||||
float advanceX = 0, advanceY = 0;
|
float advanceX = 0, advanceY = 0;
|
||||||
|
|
||||||
//CachedGlyph(GLuint texture_id, char c);
|
//CachedGlyph(GLuint texture_id, char c);
|
||||||
CachedGlyph(GLuint texture_id, char c, float x2o, float y2o, float w, float h, float advX, float advY);
|
CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2o, float y2o, float w, float h, float advX, float advY);
|
||||||
char getCharacter();
|
char getCharacter();
|
||||||
const GLuint* getTexture();
|
const std::array<GLfloat, 12> getTexCoords() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Represents a Font object as it exists in the font-cache.
|
||||||
class JGL::CachedFont {
|
class JGL::CachedFont {
|
||||||
private:
|
private:
|
||||||
std::vector<CachedGlyph*> glyphs{};
|
std::map<char, CachedGlyph*> glyphs;
|
||||||
|
GLuint texture = 0;
|
||||||
|
GLsizei texture_width = 0, texture_height = 0;
|
||||||
unsigned int font_size = 0;
|
unsigned int font_size = 0;
|
||||||
unsigned int font_index = 0;
|
unsigned int font_index = 0;
|
||||||
public:
|
public:
|
||||||
void appendGlyph(CachedGlyph* glyph);
|
void appendGlyph(CachedGlyph* glyph);
|
||||||
void eraseGlyph(CachedGlyph* glyph);
|
|
||||||
void eraseGlyph(char c);
|
|
||||||
void eraseGlyph(GLuint texture_id);
|
|
||||||
unsigned int getFontSize();
|
unsigned int getFontSize();
|
||||||
unsigned int getFontIndex();
|
unsigned int getFontIndex();
|
||||||
CachedGlyph* getGlyph(char c);
|
CachedGlyph* getGlyph(char c);
|
||||||
std::vector<CachedGlyph*> getGlyphs();
|
std::map<char, CachedGlyph*> getGlyphs();
|
||||||
CachedFont(unsigned int font_size, unsigned int font_index);
|
const GLuint* getTexture();
|
||||||
|
GLsizei getTextureWidth() const;
|
||||||
|
GLsizei getTextureHeight() const;
|
||||||
|
CachedFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index);
|
||||||
};
|
};
|
||||||
|
|
||||||
class JGL::FontCache {
|
class JGL::FontCache {
|
||||||
@@ -47,7 +57,7 @@ public:
|
|||||||
std::vector<CachedFont*> getFonts();
|
std::vector<CachedFont*> getFonts();
|
||||||
CachedFont* getFont(unsigned int font_size, unsigned int font_index);
|
CachedFont* getFont(unsigned int font_size, unsigned int font_index);
|
||||||
void appendFont(CachedFont* font);
|
void appendFont(CachedFont* font);
|
||||||
void newFont(unsigned int font_size, unsigned int font_index);
|
void newFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index);
|
||||||
void eraseFont(CachedFont* font);
|
void eraseFont(CachedFont* font);
|
||||||
void purgeCache();
|
void purgeCache();
|
||||||
};
|
};
|
||||||
|
@@ -1,6 +1,15 @@
|
|||||||
//
|
/// Josh's Graphics Library
|
||||||
// Created by dawsh on 1/17/24.
|
/// A C++20 Library for rendering 2D and 3D primitives in an OpenGL context.
|
||||||
//
|
/// Developed and Maintained by Josh O'Leary @ Redacted Software.
|
||||||
|
/// Special Thanks to William Tomasine II and Maxine Hayes.
|
||||||
|
/// (c) 2024 Redacted Software
|
||||||
|
/// This work is dedicated to the public domain.
|
||||||
|
|
||||||
|
/// @file JGL.h
|
||||||
|
/// @desc All JGL usable functions are defined here. This is the public API.
|
||||||
|
/// @edit 2024-07-16
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -8,6 +17,7 @@
|
|||||||
#include <JGL/Color4.h>
|
#include <JGL/Color4.h>
|
||||||
#include <JGL/Gradient.h>
|
#include <JGL/Gradient.h>
|
||||||
#include <JGL/FontCache.h>
|
#include <JGL/FontCache.h>
|
||||||
|
#include <JGL/Font.h>
|
||||||
#include <J3ML/LinearAlgebra.h>
|
#include <J3ML/LinearAlgebra.h>
|
||||||
#include <J3ML/LinearAlgebra/Vector2.h>
|
#include <J3ML/LinearAlgebra/Vector2.h>
|
||||||
#include <J3ML/LinearAlgebra/Vector3.h>
|
#include <J3ML/LinearAlgebra/Vector3.h>
|
||||||
@@ -18,19 +28,10 @@
|
|||||||
// OpenGL Wrapper for rendering 2D graphics primitives in both a 2D and 3D context
|
// OpenGL Wrapper for rendering 2D graphics primitives in both a 2D and 3D context
|
||||||
namespace JGL {
|
namespace JGL {
|
||||||
|
|
||||||
using J3ML::LinearAlgebra::Vector2;
|
using namespace J3ML::LinearAlgebra;
|
||||||
using J3ML::LinearAlgebra::Vector3;
|
using namespace J3ML::Geometry;
|
||||||
using J3ML::LinearAlgebra::Matrix3x3;
|
|
||||||
using J3ML::LinearAlgebra::Matrix4x4;
|
|
||||||
using J3ML::LinearAlgebra::AxisAngle;
|
|
||||||
using J3ML::LinearAlgebra::Quaternion;
|
|
||||||
|
|
||||||
using J3ML::Geometry::Sphere;
|
|
||||||
using J3ML::Geometry::OBB;
|
|
||||||
using J3ML::Geometry::Capsule;
|
|
||||||
using J3ML::Geometry::TriangleMesh;
|
|
||||||
using J3ML::Geometry::Plane;
|
|
||||||
|
|
||||||
|
/// TODO:
|
||||||
struct HSV {
|
struct HSV {
|
||||||
float hue;
|
float hue;
|
||||||
float saturation;
|
float saturation;
|
||||||
@@ -51,12 +52,12 @@ namespace JGL {
|
|||||||
Vector3 C;
|
Vector3 C;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Update(const Vector2& window_size);
|
void Update(const Vector2& window_size);
|
||||||
bool InitTextEngine();
|
//bool InitTextEngine();
|
||||||
int LoadFont(const std::string& font_path);
|
Font LoadFont(const std::string& font_path); // TODO: Fully deprecate
|
||||||
void PurgeFontCache();
|
void PurgeFontCache();
|
||||||
|
|
||||||
void UnloadFont(int font_index);
|
void SetActiveFont(const Font& font); // TODO: Implement
|
||||||
// TODO: implement correct coloring
|
// TODO: implement correct coloring
|
||||||
|
|
||||||
/// Drawing functions for primitive 2D Shapes.
|
/// Drawing functions for primitive 2D Shapes.
|
||||||
@@ -86,7 +87,7 @@ namespace JGL {
|
|||||||
/// @param B The end point of the line segment.
|
/// @param B The end point of the line segment.
|
||||||
/// @param thickness The width at which to render the line.
|
/// @param thickness The width at which to render the line.
|
||||||
void DrawLine(const Color3& color, const Vector2& A, const Vector2& B, float thickness = 1);
|
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 DrawLine(const Color3& color, float x, float y, float w, float h, float thickness = 1);
|
||||||
void DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness = 1);
|
void DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness = 1);
|
||||||
void DrawLine(const Color4& color, float x1, float y1, float x2, float y2, float thickness = 1);
|
void DrawLine(const Color4& color, float x1, float y1, float x2, float y2, float thickness = 1);
|
||||||
|
|
||||||
@@ -100,6 +101,10 @@ namespace JGL {
|
|||||||
void OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness = 1);
|
void OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness = 1);
|
||||||
void OutlineRect(const Color3& color, const Vector2& pos, const Vector2& size, float thickness = 1);
|
void OutlineRect(const Color3& color, const Vector2& pos, const Vector2& size, float thickness = 1);
|
||||||
|
|
||||||
|
///Draws a sprite to the screen.
|
||||||
|
void DrawSprite(GLuint texture, const Vector2& pos, const Vector2& size);
|
||||||
|
void DrawSprite(GLuint texture, float x, float y, float w, float h);
|
||||||
|
|
||||||
/// Draws a filled rectangle on the screen.
|
/// Draws a filled rectangle on the screen.
|
||||||
void FillRect(const Color4& color, const Vector2& pos, const Vector2& size);
|
void FillRect(const Color4& color, const Vector2& pos, const Vector2& size);
|
||||||
void FillRect(const Color3& color, const Vector2& pos, const Vector2& size);
|
void FillRect(const Color3& color, const Vector2& pos, const Vector2& size);
|
||||||
@@ -109,7 +114,7 @@ namespace JGL {
|
|||||||
void FillGradientRect(const Color3& color1, const Color3& color2, const Gradient& gradient, const Vector2& pos, const Vector2& size);
|
void FillGradientRect(const Color3& color1, const Color3& color2, const Gradient& gradient, const Vector2& pos, const Vector2& size);
|
||||||
|
|
||||||
/// Draws a filled rectangle with rounded corners on the screen.
|
/// Draws a filled rectangle with rounded corners on the screen.
|
||||||
void FillRoundedRect(const Color4 &color, const Vector2 &pos, const Vector2 &size, float radius = 5, unsigned int subdivisions = 8);
|
void FillRoundedRect(const Color4& color, const Vector2 &pos, const Vector2 &size, float radius = 5, unsigned int subdivisions = 8);
|
||||||
void FillRoundedRect(const Color3& color, const Vector2& pos, const Vector2& size, float radius = 5, unsigned int subdivisions = 8);
|
void FillRoundedRect(const Color3& color, const Vector2& pos, const Vector2& size, float radius = 5, unsigned int subdivisions = 8);
|
||||||
|
|
||||||
/// Draws an outline of a circle on the screen.
|
/// Draws an outline of a circle on the screen.
|
||||||
@@ -130,14 +135,14 @@ namespace JGL {
|
|||||||
void FillTriangle(const Color3& color, const Triangle2D& tri);
|
void FillTriangle(const Color3& color, const Triangle2D& tri);
|
||||||
// TODO: Implement an overload that simply takes 3 Vector3's
|
// TODO: Implement an overload that simply takes 3 Vector3's
|
||||||
|
|
||||||
|
|
||||||
/// Draws a text string on the screen with a given point-size and font.
|
/// Draws a text string on the screen with a given point-size and font.
|
||||||
void DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, unsigned int font_index);
|
void DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font);
|
||||||
void DrawString(const Color3& color, const std::string& text, float x, float y, float scale, u32 size, unsigned int font_index);
|
void DrawString(const Color3& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font);
|
||||||
|
|
||||||
// TODO: Implement the following:
|
// TODO: Implement the following:
|
||||||
void FillTexturedTriangle();
|
void FillTexturedTriangle();
|
||||||
void FillTexturedPolygon();
|
void FillTexturedPolygon();
|
||||||
void DrawSprite();
|
|
||||||
void DrawPartialSprite();
|
void DrawPartialSprite();
|
||||||
void DrawCubicBezierCurve();
|
void DrawCubicBezierCurve();
|
||||||
void OutlinePolygon (const Color4& color, std::vector<Vector2> points);
|
void OutlinePolygon (const Color4& color, std::vector<Vector2> points);
|
||||||
@@ -159,7 +164,7 @@ namespace JGL {
|
|||||||
void WireframeCapsule(const Color3& color, const Capsule& cap, float thickness = 1);
|
void WireframeCapsule(const Color3& color, const Capsule& cap, float thickness = 1);
|
||||||
void FillTriangleMesh(const Color3& color, const TriangleMesh& mesh);
|
void FillTriangleMesh(const Color3& color, const TriangleMesh& mesh);
|
||||||
void WireframeTriangleMesh(const Color3& color, const TriangleMesh& mesh, float thickness = 1);
|
void WireframeTriangleMesh(const Color3& color, const TriangleMesh& mesh, float thickness = 1);
|
||||||
void DrawString(const Color3& color, const std::string& text, const Vector3& pos, const Vector3& angle, float scale, u32 size, unsigned int font_index);
|
void DrawString(const Color3& color, const std::string& text, const Vector3& pos, const Vector3& angle, float scale, u32 size, const Font& font);
|
||||||
|
|
||||||
void DrawMatrixGizmo (const Matrix3x3&, const Vector3&);
|
void DrawMatrixGizmo (const Matrix3x3&, const Vector3&);
|
||||||
void DrawMatrixGizmo (const Matrix4x4&);
|
void DrawMatrixGizmo (const Matrix4x4&);
|
||||||
|
17
main.cpp
17
main.cpp
@@ -3,6 +3,8 @@
|
|||||||
#include <rewindow/types/window.h>
|
#include <rewindow/types/window.h>
|
||||||
#include <JGL/Colors.h>
|
#include <JGL/Colors.h>
|
||||||
#include <J3ML/LinearAlgebra/Vector2.h>
|
#include <J3ML/LinearAlgebra/Vector2.h>
|
||||||
|
#include <JGL/Font.h>
|
||||||
|
#include "jlog/jlog.hpp"
|
||||||
|
|
||||||
using J3ML::LinearAlgebra::Vector2;
|
using J3ML::LinearAlgebra::Vector2;
|
||||||
using namespace JGL;
|
using namespace JGL;
|
||||||
@@ -57,8 +59,8 @@ struct point {
|
|||||||
GLfloat t;
|
GLfloat t;
|
||||||
};
|
};
|
||||||
|
|
||||||
int FreeSans;
|
JGL::Font FreeSans;
|
||||||
int Jupiteroid;
|
JGL::Font Jupiteroid;
|
||||||
|
|
||||||
class JGLDemoWindow : public ReWindow::RWindow
|
class JGLDemoWindow : public ReWindow::RWindow
|
||||||
{
|
{
|
||||||
@@ -69,9 +71,10 @@ public:
|
|||||||
auto aspect = (float) window_size[0] / (float) window_size[1];
|
auto aspect = (float) window_size[0] / (float) window_size[1];
|
||||||
|
|
||||||
gladLoadGL();
|
gladLoadGL();
|
||||||
|
JGL::InitTextEngine();
|
||||||
JGL::Update(getSize());
|
JGL::Update(getSize());
|
||||||
FreeSans = JGL::LoadFont("assets/fonts/FreeSans.ttf");
|
FreeSans = JGL::Font("assets/fonts/FreeSans.ttf");
|
||||||
Jupiteroid = JGL::LoadFont("assets/fonts/Jupiteroid.ttf");
|
Jupiteroid = JGL::Font("assets/fonts/Jupiteroid.ttf");
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
@@ -118,6 +121,12 @@ public:
|
|||||||
J2D::OutlineTriangle(Colors::Blue, {{100, 275}, {0, 275}, {100, 375}});
|
J2D::OutlineTriangle(Colors::Blue, {{100, 275}, {0, 275}, {100, 375}});
|
||||||
J2D::DrawGradientLine(JGL::Colors::Red, JGL::Colors::Blue, {105, 375}, {200, 275}, 2);
|
J2D::DrawGradientLine(JGL::Colors::Red, JGL::Colors::Blue, {105, 375}, {200, 275}, 2);
|
||||||
|
|
||||||
|
auto result = Jupiteroid.MeasureString("Jupiteroid Font", 16);
|
||||||
|
//DEBUG(std::format("Result: {},{}", result.x, result.y ));
|
||||||
|
|
||||||
|
// TODO: Note the discrepancy in Y between the FillRect and DrawString call here.
|
||||||
|
J2D::FillRect(JGL::Colors::Gray, {0, 0}, result);
|
||||||
|
// TODO: Does text render from the middle-point of the glyphs?
|
||||||
J2D::DrawString(JGL::Colors::Green, "Jupteroid Font", 0.f, 16, 1.f, 16, Jupiteroid);
|
J2D::DrawString(JGL::Colors::Green, "Jupteroid Font", 0.f, 16, 1.f, 16, Jupiteroid);
|
||||||
J2D::DrawString(JGL::Colors::White, "Position: " + std::to_string(camera->position.x) + " " + std::to_string(camera->position.y) + " " + std::to_string(camera->position.z), 0, 33, 1,16, Jupiteroid);
|
J2D::DrawString(JGL::Colors::White, "Position: " + std::to_string(camera->position.x) + " " + std::to_string(camera->position.y) + " " + std::to_string(camera->position.z), 0, 33, 1,16, Jupiteroid);
|
||||||
J2D::DrawString(JGL::Colors::White, "ViewAngle: " + std::to_string(camera->angle.x) + " " + std::to_string(camera->angle.y) + " " + std::to_string(camera->angle.z), 0, 50, 1,16, Jupiteroid);
|
J2D::DrawString(JGL::Colors::White, "ViewAngle: " + std::to_string(camera->angle.x) + " " + std::to_string(camera->angle.y) + " " + std::to_string(camera->angle.z), 0, 50, 1,16, Jupiteroid);
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
#include <JGL/FontCache.h>
|
#include <JGL/FontCache.h>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace JGL;
|
using namespace JGL;
|
||||||
|
|
||||||
@@ -7,12 +6,11 @@ char CachedGlyph::getCharacter() {
|
|||||||
return character;
|
return character;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GLuint* CachedGlyph::getTexture() {
|
const std::array<GLfloat, 12> CachedGlyph::getTexCoords() const {
|
||||||
return &texture;
|
return texcoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedGlyph::CachedGlyph(GLuint texture_id, char c, float x2offset, float y2offset, float w, float h, float advanceX, float advanceY) {
|
CachedGlyph::CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2offset, float y2offset, float w, float h, float advanceX, float advanceY) {
|
||||||
texture = texture_id;
|
|
||||||
character = c;
|
character = c;
|
||||||
this->x2offset = x2offset;
|
this->x2offset = x2offset;
|
||||||
this->y2offset = y2offset;
|
this->y2offset = y2offset;
|
||||||
@@ -20,13 +18,14 @@ CachedGlyph::CachedGlyph(GLuint texture_id, char c, float x2offset, float y2offs
|
|||||||
this->h = h;
|
this->h = h;
|
||||||
this->advanceX = advanceX;
|
this->advanceX = advanceX;
|
||||||
this->advanceY = advanceY;
|
this->advanceY = advanceY;
|
||||||
|
this->texcoords = texcoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
//Because most things shown would be english characters. We can cut down on the iteration time significantly
|
//Because most things shown would be english characters. We can cut down on the iteration time significantly
|
||||||
//by putting each english character at the beginning of the list in order of how often they usually occur in text.
|
//by putting each english character at the beginning of the list in order of how often they usually occur in text.
|
||||||
void JGL::CachedFont::appendGlyph(JGL::CachedGlyph* glyph) {
|
void JGL::CachedFont::appendGlyph(JGL::CachedGlyph* glyph) {
|
||||||
glyphs.push_back(glyph);
|
glyphs.emplace(glyph->getCharacter(), glyph);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int JGL::CachedFont::getFontSize() {
|
unsigned int JGL::CachedFont::getFontSize() {
|
||||||
@@ -37,64 +36,50 @@ unsigned int JGL::CachedFont::getFontIndex() {
|
|||||||
return font_index;
|
return font_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO make this code go faster.
|
||||||
CachedGlyph* JGL::CachedFont::getGlyph(char c) {
|
CachedGlyph* JGL::CachedFont::getGlyph(char c) {
|
||||||
for (const auto& g : glyphs)
|
auto it = glyphs.find(c);
|
||||||
if (c == g->getCharacter())
|
if (it != glyphs.end())
|
||||||
return g;
|
return it->second;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedFont::CachedFont(unsigned int font_size, unsigned int font_index) {
|
CachedFont::CachedFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index) {
|
||||||
|
this->texture = texture_id;
|
||||||
|
this->texture_width = texture_width;
|
||||||
|
this->texture_height = texture_height;
|
||||||
this->font_size = font_size;
|
this->font_size = font_size;
|
||||||
this->font_index = font_index;
|
this->font_index = font_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CachedFont::eraseGlyph(CachedGlyph* glyph) {
|
std::map<char, CachedGlyph*> CachedFont::getGlyphs() {
|
||||||
if (glyph == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (int i = 0; i < glyphs.size(); i++)
|
|
||||||
if (glyphs[i] == glyph)
|
|
||||||
glDeleteTextures(1, glyphs[i]->getTexture()),
|
|
||||||
delete glyphs[i],
|
|
||||||
glyphs.erase(glyphs.begin() + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CachedFont::eraseGlyph(char c) {
|
|
||||||
for (int i = 0; i < glyphs.size(); i++)
|
|
||||||
if (glyphs[i]->getCharacter() == c)
|
|
||||||
glDeleteTextures(1, glyphs[i]->getTexture()),
|
|
||||||
delete glyphs[i],
|
|
||||||
glyphs.erase(glyphs.begin() + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CachedFont::eraseGlyph(GLuint texture_id) {
|
|
||||||
for (int i = 0; i < glyphs.size(); i++)
|
|
||||||
if (glyphs[i]->getTexture() == &texture_id)
|
|
||||||
glDeleteTextures(1, glyphs[i]->getTexture()),
|
|
||||||
delete glyphs[i],
|
|
||||||
glyphs.erase(glyphs.begin() + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<CachedGlyph*> CachedFont::getGlyphs() {
|
|
||||||
return glyphs;
|
return glyphs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GLuint* CachedFont::getTexture() {
|
||||||
|
return &texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLsizei CachedFont::getTextureWidth() const {
|
||||||
|
return texture_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLsizei CachedFont::getTextureHeight() const {
|
||||||
|
return texture_height;
|
||||||
|
}
|
||||||
|
|
||||||
void FontCache::appendFont(CachedFont* font) {
|
void FontCache::appendFont(CachedFont* font) {
|
||||||
cachedFonts.push_back(font);
|
cachedFonts.push_back(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FontCache::newFont(unsigned int font_size, unsigned int font_index) {
|
void FontCache::newFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index) {
|
||||||
auto* font = new CachedFont(font_size, font_index);
|
auto* font = new CachedFont(texture_id, texture_width, texture_height, font_size, font_index);
|
||||||
cachedFonts.push_back(font);
|
cachedFonts.push_back(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FontCache::eraseFont(CachedFont* font) {
|
void FontCache::eraseFont(CachedFont* font) {
|
||||||
for (int i = 0; i < cachedFonts.size(); i++) {
|
for (int i = 0; i < cachedFonts.size(); i++) {
|
||||||
if (cachedFonts[i] == font) {
|
if (cachedFonts[i] == font) {
|
||||||
for (auto& g: cachedFonts[i]->getGlyphs())
|
|
||||||
cachedFonts[i]->eraseGlyph(g);
|
|
||||||
|
|
||||||
delete cachedFonts[i];
|
delete cachedFonts[i];
|
||||||
cachedFonts.erase(cachedFonts.begin() + i);
|
cachedFonts.erase(cachedFonts.begin() + i);
|
||||||
}
|
}
|
||||||
|
33
src/JGL.cpp
33
src/JGL.cpp
@@ -23,11 +23,11 @@ namespace JGL {
|
|||||||
using namespace J3ML;
|
using namespace J3ML;
|
||||||
Vector2 wS;
|
Vector2 wS;
|
||||||
|
|
||||||
bool Update(const Vector2& window_size) {
|
void Update(const Vector2& window_size) {
|
||||||
wS = window_size;
|
wS = window_size;
|
||||||
return JGL::InitTextEngine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void J2D::Begin() {
|
void J2D::Begin() {
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
@@ -112,10 +112,10 @@ namespace JGL {
|
|||||||
if (wasColorArrayEnabled)
|
if (wasColorArrayEnabled)
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
/*
|
|
||||||
//Select whatever texture unit was selected before.
|
//Select whatever texture unit was selected before.
|
||||||
glActiveTexture(GL_TEXTURE0 + activeTextureUnit);
|
glActiveTexture(GL_TEXTURE0 + activeTextureUnit);
|
||||||
*/
|
|
||||||
|
|
||||||
//Put the draw color back how it was before.
|
//Put the draw color back how it was before.
|
||||||
glColor4f(oldColor[0], oldColor[1], oldColor[2], oldColor[3]);
|
glColor4f(oldColor[0], oldColor[1], oldColor[2], oldColor[3]);
|
||||||
@@ -123,6 +123,31 @@ namespace JGL {
|
|||||||
inJ2D = false;
|
inJ2D = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void J2D::DrawSprite(GLuint texture, const Vector2& pos, const Vector2& size) {
|
||||||
|
if (!inJ2D)
|
||||||
|
ERROR("Attempt to Render J2D element before J2D begin.")
|
||||||
|
|
||||||
|
const std::vector<Vector2> textureCoordinates = {{0,0}, {1, 0}, {1,1}, {0,1}};
|
||||||
|
const std::vector<Vector2> vertices = {pos, {pos.x + size.x, pos.y}, {pos.x + size.x, pos.y + size.y}, {pos.x, pos.y + size.y}};
|
||||||
|
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
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);
|
||||||
|
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
|
||||||
|
glDrawArrays(GL_QUADS, 0, 4);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void J2D::DrawSprite(GLuint texture, float x, float y, float w, float h) {
|
||||||
|
J2D::DrawSprite(texture, {x, y}, {w, h});
|
||||||
|
}
|
||||||
|
|
||||||
void J2D::FillRect(const Color4& color, const Vector2& pos, const Vector2& size) {
|
void J2D::FillRect(const Color4& color, const Vector2& pos, const Vector2& size) {
|
||||||
if (!inJ2D)
|
if (!inJ2D)
|
||||||
ERROR("Attempt to Render J2D element before J2D begin.")
|
ERROR("Attempt to Render J2D element before J2D begin.")
|
||||||
|
6
src/JGL/Color3.cpp
Normal file
6
src/JGL/Color3.cpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include <JGL/Color3.h>
|
||||||
|
|
||||||
|
namespace JGL
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
6
src/JGL/Color4.cpp
Normal file
6
src/JGL/Color4.cpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include <JGL/Color4.h>
|
||||||
|
|
||||||
|
namespace JGL
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
165
src/JGL/Font.cpp
Normal file
165
src/JGL/Font.cpp
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
#if __linux__
|
||||||
|
#include <freetype2/ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#include FT_OUTLINE_H
|
||||||
|
#endif
|
||||||
|
#if _WIN32
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <JGL/Font.h>
|
||||||
|
|
||||||
|
namespace JGL::Detail
|
||||||
|
{
|
||||||
|
|
||||||
|
FT_Library ft;
|
||||||
|
|
||||||
|
std::vector<Font> fonts;
|
||||||
|
|
||||||
|
// TODO: Deprecating this in favor of class model of resource management.
|
||||||
|
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 : fonts)
|
||||||
|
if (f.index >= newIndex)
|
||||||
|
newIndex = f.index + 1;
|
||||||
|
|
||||||
|
|
||||||
|
font.index = newIndex;
|
||||||
|
|
||||||
|
fonts.push_back(font);
|
||||||
|
|
||||||
|
std::cout << "Loaded font from " << font_path << " with index " << newIndex << std::endl;
|
||||||
|
return newIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InitTextEngine() {
|
||||||
|
if (ft != nullptr)
|
||||||
|
throw std::runtime_error("Error::FREETYPE: FT_Library was initialized but is already initialized.");
|
||||||
|
|
||||||
|
if (FT_Init_FreeType(&ft))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnloadFont(int font_index) {
|
||||||
|
|
||||||
|
auto iter = fonts.begin();
|
||||||
|
while (iter != fonts.end())
|
||||||
|
{
|
||||||
|
if (iter->index == font_index){
|
||||||
|
FT_Done_Face(iter->face);
|
||||||
|
iter = fonts.erase(iter);
|
||||||
|
} else ++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace JGL
|
||||||
|
{
|
||||||
|
|
||||||
|
bool InitTextEngine()
|
||||||
|
{
|
||||||
|
return Detail::InitTextEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
Font::Font(const std::filesystem::path& path)
|
||||||
|
{
|
||||||
|
if (Detail::ft == nullptr)
|
||||||
|
throw new std::runtime_error("Error::FREETYPE: FT_Library was not initialized before attempting to load a font!");
|
||||||
|
|
||||||
|
Font font;
|
||||||
|
if (FT_New_Face(Detail::ft, path.c_str(), 0, &face)) {
|
||||||
|
std::cout << "Error::FREETYPE: Failed to load font!" << std::endl;
|
||||||
|
throw new std::runtime_error("Error::FREETYPE: Failed to load font!");
|
||||||
|
//return -1;
|
||||||
|
}
|
||||||
|
unsigned int newIndex = 0;
|
||||||
|
for (const auto& f : Detail::fonts)
|
||||||
|
if (f.index >= newIndex)
|
||||||
|
newIndex = f.index + 1;
|
||||||
|
|
||||||
|
index = newIndex;
|
||||||
|
Detail::fonts.push_back(font);
|
||||||
|
std::cout << "Loaded font from " << path << " with index " << newIndex << std::endl;
|
||||||
|
//return newIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
Font::~Font()
|
||||||
|
{
|
||||||
|
//Detail::UnloadFont(this->index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Font> Font::GetLoadedFonts() {
|
||||||
|
return Detail::fonts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Font Font::LoadTTF(const std::filesystem::path& path)
|
||||||
|
{
|
||||||
|
return Font(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 Font::MeasureString(const std::string &text, float ptSize) {
|
||||||
|
|
||||||
|
// TODO: Work in-progress implementation unfortunately.
|
||||||
|
// This is likely returning slightly incorrect results for likely several reasons.
|
||||||
|
// Half-ass solution for now ~ dawsh.
|
||||||
|
|
||||||
|
FT_BBox glyph_bbox;
|
||||||
|
|
||||||
|
FT_Set_Pixel_Sizes(this->face, ptSize, ptSize);
|
||||||
|
|
||||||
|
Vector2 extents = Vector2(0,0);
|
||||||
|
|
||||||
|
for (const char& c : text) {
|
||||||
|
|
||||||
|
FT_GlyphSlot slot = face->glyph;
|
||||||
|
auto glyph_index = FT_Get_Char_Index(this->face, c);
|
||||||
|
|
||||||
|
auto error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
Vector2 advance = {static_cast<float>(slot->advance.x >> 6),
|
||||||
|
static_cast<float>(slot->advance.y >> 6)};
|
||||||
|
|
||||||
|
|
||||||
|
extents += advance;
|
||||||
|
|
||||||
|
// Gives smaller results than we'd want.
|
||||||
|
if (extents.y < slot->metrics.height / 64) {
|
||||||
|
extents.y = slot->metrics.height / 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just fucking hardcode it, we know the glyph height is roughly always the ptSize anyway.
|
||||||
|
if (extents.y < ptSize)
|
||||||
|
{
|
||||||
|
extents.y = ptSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return extents;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -1,148 +1,164 @@
|
|||||||
#include <JGL/JGL.h>
|
#include <JGL/JGL.h>
|
||||||
|
|
||||||
|
|
||||||
#if __linux__
|
#if __linux__
|
||||||
#include <freetype2/ft2build.h>
|
#include <freetype2/ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
#include FT_OUTLINE_H
|
||||||
|
#include "jlog/jlog.hpp"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <JGL/Font.h>
|
||||||
|
#include <JGL/FontCache.h>
|
||||||
|
|
||||||
namespace JGL {
|
namespace JGL {
|
||||||
FT_Library ft;
|
|
||||||
|
|
||||||
struct Font {
|
FontCache fontCache; // <-- Not implemented yet
|
||||||
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 PurgeFontCache() {
|
void PurgeFontCache() {
|
||||||
fontCache.purgeCache();
|
fontCache.purgeCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO multi-texturing for 8x speedup. I tried. We'll come back to it later.
|
void J2D::DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font) {
|
||||||
void J2D::DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, unsigned int font_index) {
|
|
||||||
glUseProgram(0); // Fixed-function pipeline.
|
glUseProgram(0); // Fixed-function pipeline.
|
||||||
|
|
||||||
Font font{};
|
CachedFont* cachedFont = fontCache.getFont(size, font.index);
|
||||||
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.
|
//Set up the regular font.
|
||||||
for (const auto& f : faces)
|
//for (const auto &f : Font::GetLoadedFonts())
|
||||||
if (f.index == font_index)
|
// if (f.index == font.index)
|
||||||
font = f;
|
// font = f;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (font.face == nullptr)
|
if (font.face == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FT_Set_Pixel_Sizes(font.face, 0, size);
|
FT_Set_Pixel_Sizes(font.face, 0, size);
|
||||||
|
|
||||||
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
|
//If the font doesn't exist in the cache yet.
|
||||||
|
if (!cachedFont) {
|
||||||
|
DEBUG("Caching font data...");
|
||||||
|
GLuint texture_id;
|
||||||
|
glGenTextures(1, &texture_id);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||||
|
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);
|
||||||
|
|
||||||
std::vector<GLuint> textures(text.length());
|
GLsizei width = 0;
|
||||||
|
GLsizei max_height = 0;
|
||||||
|
|
||||||
//For each character
|
FT_ULong charcode;
|
||||||
for (int i = 0; i < text.length(); i++) {
|
FT_UInt gindex;
|
||||||
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());
|
//We have to loop over the available glyphs twice as we need the
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
//final width and height of the texture before we can construct it
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
//and subsequently upload the glyph data.
|
||||||
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;
|
charcode = FT_Get_First_Char(font.face, &gindex);
|
||||||
y2 = y - glyph->y2offset * scale; // Adjust y-coordinate
|
//Strings are char-based so we only handle charcodes within the extended ASCII range.
|
||||||
w = glyph->w * scale;
|
while (gindex != 0 && charcode < 255) {
|
||||||
h = glyph->h * scale;
|
if (FT_Load_Char(font.face, charcode, FT_LOAD_RENDER))
|
||||||
x += glyph->advanceX * scale;
|
std::cout << "Error::FREETYPE: Failed to load charcode: " << charcode << std::endl;
|
||||||
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;
|
FT_GlyphSlot g = font.face->glyph;
|
||||||
glGenTextures(1, &textures.at(i));
|
width += g->bitmap.width;
|
||||||
glBindTexture(GL_TEXTURE_2D, textures[i]);
|
max_height = std::max(max_height, (GLsizei)g->bitmap.rows);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
|
||||||
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)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLfloat vertices[12] = {x2, y2, x2, y2 + h, x2 + w, y2 + h,x2, y2, x2 + w, y2 + h, x2 + w, y2};
|
fontCache.newFont(texture_id, width, max_height, size, font.index);
|
||||||
GLfloat textureCoordinates[12] = {0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
|
cachedFont = fontCache.getFont(size, font.index);
|
||||||
|
|
||||||
glTexCoordPointer(2, GL_FLOAT, sizeof(GL_FLOAT) * 2, &textureCoordinates);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, max_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
glVertexPointer(2, GL_FLOAT, sizeof(GL_FLOAT) * 2, &vertices);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
GLsizei xoffset = 0;
|
||||||
|
|
||||||
|
charcode = FT_Get_First_Char(font.face, &gindex);
|
||||||
|
while (gindex != 0 && charcode < 255) {
|
||||||
|
if (FT_Load_Char(font.face, charcode, FT_LOAD_RENDER))
|
||||||
|
std::cout << "Error::FREETYPE: Failed to load charcode: " << charcode << std::endl;
|
||||||
|
|
||||||
|
FT_GlyphSlot g = font.face->glyph;
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, 0, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||||
|
|
||||||
|
GLfloat u0 = (GLfloat)xoffset / cachedFont->getTextureWidth();
|
||||||
|
GLfloat u1 = u0 + (GLfloat)g->bitmap.width / cachedFont->getTextureWidth();
|
||||||
|
|
||||||
|
GLfloat v0 = 0.0f;
|
||||||
|
GLfloat v1 = (GLfloat)g->bitmap.rows / cachedFont->getTextureHeight();
|
||||||
|
|
||||||
|
std::array<GLfloat, 12> texcoords = {
|
||||||
|
u0, v0,
|
||||||
|
u0, v1,
|
||||||
|
u1, v1,
|
||||||
|
u0, v0,
|
||||||
|
u1, v1,
|
||||||
|
u1, v0
|
||||||
|
};
|
||||||
|
|
||||||
|
cachedFont->appendGlyph(new CachedGlyph((char)charcode, texcoords, g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
|
||||||
|
|
||||||
|
xoffset += g->bitmap.width;
|
||||||
|
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
|
||||||
|
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
|
||||||
|
|
||||||
|
//Texture parameters are restored when the texture is bound
|
||||||
|
glBindTexture(GL_TEXTURE_2D, *cachedFont->getTexture());
|
||||||
|
|
||||||
|
std::vector<GLfloat> vertices;
|
||||||
|
std::vector<GLfloat> texcoords;
|
||||||
|
|
||||||
|
for (int i = 0; i < text.length(); i++) {
|
||||||
|
float x2, y2, w, h;
|
||||||
|
CachedGlyph *glyph = cachedFont->getGlyph(text.c_str()[i]);
|
||||||
|
if (glyph == nullptr) continue;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::array<GLfloat, 12> glyph_vertices = {
|
||||||
|
x2, y2,
|
||||||
|
x2, y2 + h,
|
||||||
|
x2 + w, y2 + h,
|
||||||
|
x2, y2,
|
||||||
|
x2 + w, y2 + h,
|
||||||
|
x2 + w, y2
|
||||||
|
};
|
||||||
|
auto glyph_texcoords = glyph->getTexCoords();
|
||||||
|
|
||||||
|
//TODO make it like go faster because now the profiler says this is the slowest part.
|
||||||
|
vertices.insert(vertices.end(), glyph_vertices.begin(), glyph_vertices.end());
|
||||||
|
texcoords.insert(texcoords.end(), glyph_texcoords.begin(), glyph_texcoords.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
glVertexPointer(2, GL_FLOAT, sizeof(GLfloat) * 2, vertices.data());
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat) * 2, texcoords.data());
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 2);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void J2D::DrawString(const Color3& color, const std::string& text, float x, float y, float scale, u32 size, unsigned int font_index) {
|
void J2D::DrawString(const Color3& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font) {
|
||||||
J2D::DrawString(Color4::FromColor3(color, 255), text, x, y, scale, size, font_index);
|
J2D::DrawString(Color4::FromColor3(color, 255), text, x, y, scale, size, font);
|
||||||
}
|
}
|
||||||
|
|
||||||
void J3D::DrawString(const Color3& color, const std::string& text, const Vector3& pos, const Vector3& angle, float scale, u32 size, unsigned int font_index) {
|
void J3D::DrawString(const Color3& color, const std::string& text, const Vector3& pos, const Vector3& angle, float scale, u32 size, const Font& font) {
|
||||||
//TODO figure out what the scale should actually be mathematically.
|
//TODO figure out what the scale should actually be mathematically.
|
||||||
scale = scale * 0.002f;
|
scale = scale * 0.002f;
|
||||||
scale = -scale;
|
scale = -scale;
|
||||||
@@ -154,10 +170,10 @@ namespace JGL {
|
|||||||
glUseProgram(0); // Fixed-function pipeline.
|
glUseProgram(0); // Fixed-function pipeline.
|
||||||
glColor4f(color.r, color.g, color.b, 1.0f);
|
glColor4f(color.r, color.g, color.b, 1.0f);
|
||||||
|
|
||||||
Font font;
|
//Font font;
|
||||||
for (auto& f : faces)
|
//for (auto& f : Font::GetLoadedFonts())
|
||||||
if (f.index == font_index)
|
//if (f.index == font.index)
|
||||||
font = f;
|
//font = f;
|
||||||
if (font.face == NULL) {
|
if (font.face == NULL) {
|
||||||
std::cout << "null font" << std::endl;
|
std::cout << "null font" << std::endl;
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user