Attempting Text Input

This commit is contained in:
2024-02-14 19:23:29 -05:00
parent 328245f81a
commit 406abbb5bd
3 changed files with 227 additions and 81 deletions

BIN
content/FreeSans.ttf Normal file

Binary file not shown.

View File

@@ -5,17 +5,13 @@
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Vector2.h>
#include "J3ML/LinearAlgebra/Vector3.h"
#include <J3ML/LinearAlgebra/Vector3.h>
// OpenGL Wrapper for rendering 2D graphics primitives in both a 2D and 3D context
namespace JGL {
// All functions accept coordinates in pixel-screen space [0, 600]
// and are internally transformed to OpenGL clip space [-1, +1]
using namespace LinearAlgebra;
struct RGBTuple {
int r; int g; int b;
};
@@ -214,7 +210,12 @@ namespace JGL {
}
}
using J3ML::LinearAlgebra::Vector2;
using J3ML::LinearAlgebra::Vector3;
using J3ML::LinearAlgebra::Matrix3x3;
using J3ML::LinearAlgebra::Matrix4x4;
using J3ML::LinearAlgebra::AxisAngle;
using J3ML::LinearAlgebra::Quaternion;
struct HSV {
float hue;

295
main.cpp
View File

@@ -1,26 +1,163 @@
#include <GL/glut.h>
#include "JGL/JGL.h"
//#include <GL/glew.h>
#include <glad/glad.h>
#include <JGL/JGL.h>
#include <rewindow/types/window.h>
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
#include <iostream>
#include <LearnOpenGL/Shader.h>
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#endif
void initGL()
struct Character
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glOrtho(-100.f, 100.f, -100.f, 100.f, -100.f, 100.f);
}
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;
unsigned int VAO, VBO;
const std::string vertexShader = "#version 330 core\n"
"layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>\n"
"out vec2 TexCoords;\n"
"\n"
"uniform mat4 projection;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);\n"
" TexCoords = vertex.zw;\n"
"} ";
const std::string fragmentShader = "#version 330 core\n"
"layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>\n"
"out vec2 TexCoords;\n"
"\n"
"uniform mat4 projection;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);\n"
" TexCoords = vertex.zw;\n"
"} ";
using J3ML::LinearAlgebra::Matrix4x4;
void display() {
glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer
glMatrixMode(GL_MODELVIEW); // To operate on the Model-View matrix
glLoadIdentity(); // Reset the model-view matrix.
// Define shapes enclosed within a pair of glBegin and glEnd
class JGLDemoWindow : public ReWindow::RWindow
{
public:
LearnOpenGL::Shader shader;
JGLDemoWindow() : ReWindow::RWindow()
{
glBegin(GL_QUADS); // Each set of 4 vertices form a quad
}
void initGL()
{
gladLoadGL();
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
shader = LearnOpenGL::Shader(vertexShader, fragmentShader);
Matrix4x4 projection = Matrix4x4::D3DOrthoProjLH(0.0f, 1.0f, 1280, 720);
shader.use();
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "projection"), 1, GL_FALSE, projection.ptr());
//initGL(); // Our own OpenGL initialization
FT_Library ft;
if (FT_Init_FreeType(&ft))
{
std::cout << "Error::FREETYPE: " << std::endl;
return;
}
FT_Face face;
if (FT_New_Face(ft, "content/FreeSans.ttf", 0, &face))
{
std::cout << "Error::FREETYPE: Failed to load font!" << std::endl;
}
FT_Set_Pixel_Sizes(face, 0, 48);
if (FT_Load_Char(face, 'X', FT_LOAD_RENDER))
{
std::cout << "Error::FREETYPE: Failed to load Glyph" << std::endl;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction
for (unsigned char c = 0; c < 128; c++)
{
// load character glyph
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
{
std::cout << "ERROR::FREETYPE: Failed to load Glyph!" << std::endl;
continue;
}
// Generate Texture
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
// set textured options
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);
// now store character for later use
Character character = {
texture,
{(float)face->glyph->bitmap.width, (float)face->glyph->bitmap.rows},
{(float)face->glyph->bitmap_left, (float)face->glyph->bitmap_top},
(unsigned int)face->glyph->advance.x
};
Characters.insert(std::pair<char, Character>(c, character));
}
glBindTexture(GL_TEXTURE_2D, 0);
FT_Done_Face(face);
FT_Done_FreeType(ft);
// configure VAO/VBO for texture quads
glGenBuffers(6*4, &VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)* 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer
glMatrixMode(GL_MODELVIEW); // To operate on the Model-View matrix
glLoadIdentity(); // Reset the model-view matrix.
// Define shapes enclosed within a pair of glBegin and glEnd
glBegin(GL_QUADS); // Each set of 4 vertices form a quad
glColor3f(1.f, 0.f, 0.f);
glVertex2f(-0.8f, 0.1f);
glVertex2f(-0.2f, 0.1f);
@@ -41,11 +178,10 @@ void display() {
glVertex2f(-0.5f, -0.3f);
glColor3f(1.f, 1.f, 1.f); // White
glVertex2f(-0.9f, -0.3f);
glEnd();
glEnd();
glBegin(GL_TRIANGLES);
glBegin(GL_TRIANGLES);
glColor3f(0.0f, 0.0f, 1.f); // Blue
glVertex2f(0.1f, -0.6f);
glVertex2f(0.7f, -0.6f);
@@ -57,9 +193,9 @@ void display() {
glVertex2f(0.9f, -0.4f);
glColor3f(0.f, 0.f, 1.f); // Blue
glVertex2f(0.6f, -0.9f);
glEnd();
glEnd();
glBegin(GL_POLYGON); // These verts form a closed polygon
glBegin(GL_POLYGON); // These verts form a closed polygon
glColor3f(1.f, 1.f, 0.f); // Yellow
glVertex2f(0.4f, 0.2f);
glVertex2f(0.6f, 0.2f);
@@ -67,76 +203,85 @@ void display() {
glVertex2f(0.6f, 0.6f);
glVertex2f(0.4f, 0.6f);
glVertex2f(0.3f, 0.4f);
glEnd();
glEnd();
JGL::J2D::FillRect2D(JGL::Colors::White, {0, 0}, {128, 128});
JGL::J2D::OutlineRect2D(JGL::Colors::Red, {0, 0}, {128, 128}, 4);
JGL::J2D::DrawPixel2D(JGL::Colors::Green, {0, 0});
JGL::J2D::FillRect2D(JGL::Colors::White, {0, 0}, {128, 128});
JGL::J2D::OutlineRect2D(JGL::Colors::Red, {0, 0}, {128, 128}, 4);
JGL::J2D::DrawPixel2D(JGL::Colors::Green, {0, 0});
JGL::J2D::FillCircle2D(JGL::Colors::Purples::DarkViolet, {0, 0}, 0.75f, 64);
JGL::J2D::FillCircle2D(JGL::Colors::Purples::DarkViolet, {0, 0}, 0.75f, 64);
RenderText("WHATS BOPPIN", 25.f, 25.f, 1.f, JGL::Colors::White);
glFlush(); // Render now
}
int windowWidth = 640; // Windowed mode's width
int windowHeight = 480; // Windowed mode's height
int windowPosX = 50; // Windowed mode's top-left corner x
int windowPosY = 50; // Windowed mode's top-left corner y
bool fullscreenMode = true;
void specialKeys(int key, int x, int y) {
switch(key) {
case GLUT_KEY_F1:
fullscreenMode = !fullscreenMode;
if (fullscreenMode) {
windowPosX = glutGet(GLUT_WINDOW_X);
windowPosY = glutGet(GLUT_WINDOW_Y);
windowWidth = glutGet(GLUT_WINDOW_WIDTH);
windowHeight = glutGet(GLUT_WINDOW_HEIGHT);
glutFullScreen();
} else {
glutReshapeWindow(windowWidth, windowHeight);
glutPositionWindow(windowPosX, windowPosY);
}
break;
glFlush(); // Render now
}
}
// Handler for window re-size event. Called back when the window first appears
// and whenever the window is re-sized with its new width and height
void reshape(GLsizei width, GLsizei height) {
if (height == 0) height = 1;
GLfloat aspect = (GLfloat) width / (GLfloat) height;
void RenderText(std::string text, float x, float y, float scale, JGL::Color3 color)
{
// TODO: implement shader.pushColor();
shader.use();
glUniform3f(glGetUniformLocation(shader.ID, "textColor"), color.r, color.g, color.b);
glActiveTexture(GL_TEXTURE0);
glBindBuffer(GL_VERTEX_ARRAY, VAO);
// Set the viewport to cover the new window
glViewport(0, 0, width, height);
// iterate through all characters
std::string::const_iterator c;
for (c = text.begin(); c != text.end(); c++)
{
Character ch = Characters[*c];
float xpos = x + ch.Bearing.x * scale;
float ypos = y - (ch.Size.y - ch.Bearing.y) * scale;
// Set the aspect ratio of the clipping area to match the viewport
glMatrixMode(GL_PROJECTION); // Operate on the Projection Matrix;
glLoadIdentity(); // Reset the projection matrix
if (width >= height) {
// Aspect >= 1, set the height from -1 to 1
gluOrtho2D(-1.0 * aspect, 1.0 * aspect, -1.0, 1.0);
} else {
// Aspect < 1, set the width from -1 to 1, with larger height
gluOrtho2D(-1.0, 1.0, -1.0 / aspect, 1.0 / aspect);
float w = ch.Size.x * scale;
float h = ch.Size.y * scale;
float vertices[6][4] = {
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos, ypos, 0.0f, 1.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos + w, ypos + h, 1.0f, 0.0f }
};
// render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
// update contents of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // be sure to use glBufferSubData and not glBufferData
glBindBuffer(GL_ARRAY_BUFFER, 0);
// render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
// now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.Advance >> 6) * scale;
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
void OnRefresh(float elapsed) override
{
display();
this->glSwapBuffers();
}
void OnResize()
{
//reshape();
}
};
int main(int argc, char** argv)
{
glutInit(&argc, argv); // Initialize GLUT
glutCreateWindow("Vertex, Primitive, & Color"); // Create window with given title
glutInitWindowSize(320, 320); // Set the window's initial width & height - non-square
glutInitWindowPosition(50, 50); // Position the window's initial top-left corner
glutDisplayFunc(display); // Register callback handler for window re-paint event
glutReshapeFunc(reshape); // Register callback handler for window re-size event
glutSpecialFunc(specialKeys); // Register callback handler for special-key event
initGL(); // Our own OpenGL initialization
glutMainLoop();
JGLDemoWindow* window = new JGLDemoWindow();
window->init(RenderingAPI::OPENGL, "Window", 800, 600, false);
window->initGL();
window->setResizable(true);
while (window->isAlive())
{
window->pollEvents();
window->refresh();
}
return 0;
}