Compare commits

..

5 Commits

Author SHA1 Message Date
2aed98d688 Some refactoring and better usage of text 2021-05-04 12:22:23 +02:00
10138d5fd8 Add draft for text rendering 2021-05-04 12:07:56 +02:00
307d000253 Rename String::get_length 2021-05-04 11:44:54 +02:00
482116018f Add Parallax Demo + some bugfixes
The initialization order in the Application was wrong, so some code has been moved from run to the constructor.
2021-05-03 22:23:15 +02:00
3dacb0c095 Add ability for client to override fixed and dynamic update 2021-05-03 21:33:38 +02:00
12 changed files with 1033 additions and 731 deletions

View File

@ -10,12 +10,16 @@ def add_strict_compile_flags(env):
env.Append(CCFLAGS=["-Wall", "-Wextra", "-pedantic", "-std=c++17"]) env.Append(CCFLAGS=["-Wall", "-Wextra", "-pedantic", "-std=c++17"])
def add_debug_compile_flags(env):
env.Append(CCFLAGS=["-g"])
# Create the environment and create a Compilation Database for use in VSCodium # Create the environment and create a Compilation Database for use in VSCodium
env = Environment(tools=['default', 'compilation_db']) env = Environment(tools=['default', 'compilation_db'])
env.CompilationDatabase() env.CompilationDatabase()
env.Append(CPPPATH=['cpp/', 'include/']) env.Append(CPPPATH=['cpp/', 'include/'])
env.Append(LIBS=['glfw', 'dl']) env.Append(LIBS=['glfw', 'dl', 'freetype'])
add_third_party_includes(env) add_third_party_includes(env)
add_strict_compile_flags(env) add_strict_compile_flags(env)
@ -45,9 +49,11 @@ testEnv.Append(LINKFLAGS=[
add_third_party_includes(testEnv) add_third_party_includes(testEnv)
add_strict_compile_flags(testEnv) add_strict_compile_flags(testEnv)
add_debug_compile_flags(testEnv)
# Build the test programs # Build the test programs
catch_cpp = "test/catch_amalgamated.cpp" catch_cpp = "test/catch_amalgamated.cpp"
testEnv.Program('test/bin/vector-test.out', [catch_cpp, 'test/vector/vector-test.cpp']) testEnv.Program('test/bin/vector-test.out', [catch_cpp, 'test/vector/vector-test.cpp'])
testEnv.Program('test/bin/test-app.out', Glob('test/test-app/*.cpp')) testEnv.Program('test/bin/test-app.out', Glob('test/test-app/*.cpp'))
testEnv.Program('test/bin/parallax-demo.out', Glob('test/parallax-demo/*.cpp'))

View File

@ -6,12 +6,16 @@
namespace Gedeng { namespace Gedeng {
void Application::run() { Application::Application(unsigned long ms_per_update, unsigned int window_size_x, unsigned int window_size_y,
String window_name)
: MS_PER_UPDATE(ms_per_update), WINDOW_SIZE_X(window_size_x), WINDOW_SIZE_Y(window_size_y),
WINDOW_NAME(window_name) {
// Setup Rendering // Setup Rendering
// FIXME: Make these parameters variable, maybe move this to a different function
RenderBackend::initialize_window(WINDOW_SIZE_X, WINDOW_SIZE_Y, WINDOW_NAME); RenderBackend::initialize_window(WINDOW_SIZE_X, WINDOW_SIZE_Y, WINDOW_NAME);
Input::initialize(RenderBackend::get_window()); Input::initialize(RenderBackend::get_window());
}
void Application::run() {
unsigned long previous_time_ms = Time::get_time_ms(); unsigned long previous_time_ms = Time::get_time_ms();
unsigned long time_until_fixed_update_ms = 0.0; unsigned long time_until_fixed_update_ms = 0.0;
@ -31,6 +35,8 @@ void Application::run() {
} }
dynamic_update(static_cast<double>(elapsed_time_ms) / 1000.0); dynamic_update(static_cast<double>(elapsed_time_ms) / 1000.0);
RenderBackend::render();
} }
} }

View File

@ -15,6 +15,11 @@ void RenderBackend::initialize_window(unsigned int width, unsigned int height, S
window = glfwCreateWindow(width, height, title, NULL, NULL); window = glfwCreateWindow(width, height, title, NULL, NULL);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} }
bool RenderBackend::is_window_created() { bool RenderBackend::is_window_created() {

View File

@ -5,13 +5,11 @@ namespace Gedeng {
String::String() : String("") { String::String() : String("") {
} }
String::String(const char *stringText) String::String(const char *stringText) : length(strlen(stringText)), text(new char[length + sizeof(char)]) {
: length(strlen(stringText)), text(new char[length + sizeof(char)]) {
memcpy(text, stringText, length + sizeof(char)); memcpy(text, stringText, length + sizeof(char));
} }
String::String(const String &other) String::String(const String &other) : length(other.get_length()), text(new char[length + sizeof(char)]) {
: length(other.getLength()), text(new char[length + sizeof(char)]) {
memcpy(text, other.c_str(), length + sizeof(char)); memcpy(text, other.c_str(), length + sizeof(char));
} }
@ -116,7 +114,7 @@ const char *String::c_str() const {
return text; return text;
} }
size_t String::getLength() const { size_t String::get_length() const {
return length; return length;
} }

132
cpp/TextLabel.cpp Normal file
View File

@ -0,0 +1,132 @@
// Must be the first include
#include <glad/glad.h>
// Other includes
#include <GLFW/glfw3.h>
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "Gedeng/Logger.h"
#include "Gedeng/TextLabel.h"
namespace Gedeng {
TextLabel::TextLabel(const String &text) : text(text), shader(Shader("Shader/text.vs", "Shader/text.fs")) {
FT_Library ft;
if (FT_Init_FreeType(&ft)) {
GG_CORE_ERROR("Couldn't create font library!");
return;
}
FT_Face face;
if (FT_New_Face(ft, "Resources/Fonts/Inter.ttf", 0, &face)) {
GG_CORE_ERROR("Couldn't load font from path!");
return;
}
// Set size
FT_Set_Pixel_Sizes(face, 0, 12);
// Load first 128 ASCII Characters
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)) {
GG_CORE_ERROR("Couldn't load character glyph!");
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 texture 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, glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
static_cast<unsigned int>(face->glyph->advance.x)};
characters.insert(std::pair<char, Character>(c, character));
}
glBindTexture(GL_TEXTURE_2D, 0);
// destroy FreeType once we're finished
FT_Done_Face(face);
FT_Done_FreeType(ft);
// configure VAO/VBO for texture quads
// -----------------------------------
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(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);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
valid = true;
}
void TextLabel::set_text(const String &text) {
this->text = text;
}
void TextLabel::render_text(float x, float y, float scale, Vector3 color) {
// activate corresponding render state
shader.use();
glUniform3f(glGetUniformLocation(shader.ID, "textColor"), color.x, color.y, color.z);
// FIXME: We need the screen size here... (or UI module size?)
glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(900), 0.0f, static_cast<float>(600));
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(vao);
// iterate through all characters
for (size_t i = 0; i < text.get_length(); i++) {
Character ch = characters[text[i]];
float xpos = x + ch.bearing.x * scale;
float ypos = y - (ch.size.y - ch.bearing.y) * scale;
float w = ch.size.x * scale;
float h = ch.size.y * scale;
// update VBO for each character
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.texture_id);
// update content 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; // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th
// pixels by 64 to get amount of pixels))
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
bool TextLabel::is_valid() {
return valid;
}
} // namespace Gedeng

1411
cpp/vendor/glad.c vendored

File diff suppressed because it is too large Load Diff

View File

@ -6,10 +6,8 @@ namespace Gedeng {
class Application { class Application {
public: public:
Application(unsigned long ms_per_update, unsigned int window_size_x, unsigned int window_size_y, String window_name) Application(unsigned long ms_per_update, unsigned int window_size_x, unsigned int window_size_y,
: MS_PER_UPDATE(ms_per_update), WINDOW_SIZE_X(window_size_x), WINDOW_SIZE_Y(window_size_y), String window_name);
WINDOW_NAME(window_name) {
}
// Virtual since this class will be inherited by user-created applications // Virtual since this class will be inherited by user-created applications
virtual ~Application() = default; virtual ~Application() = default;
@ -25,9 +23,6 @@ class Application {
// To be overridden by client applications // To be overridden by client applications
virtual void dynamic_update(double delta) = 0; virtual void dynamic_update(double delta) = 0;
// TODO: Write note for this: `undefined reference to vtable` can be caused by forgetting `= 0` for pure virtual
// stuff
private: private:
// TODO: These will probably become a separate Settings struct // TODO: These will probably become a separate Settings struct
const unsigned long MS_PER_UPDATE; const unsigned long MS_PER_UPDATE;

View File

@ -2,7 +2,11 @@
// Adapted from LearnOpenGL // Adapted from LearnOpenGL
// Must be the first include
#include <glad/glad.h> #include <glad/glad.h>
// Other includes
#include <GLFW/glfw3.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <fstream> #include <fstream>
@ -152,21 +156,17 @@ class Shader {
if (!success) { if (!success) {
glGetShaderInfoLog(shader, 1024, NULL, infoLog); glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n"
<< infoLog << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
<< "\n -- --------------------------------------------------- -- "
<< std::endl;
} }
} else { } else {
glGetProgramiv(shader, GL_LINK_STATUS, &success); glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success) { if (!success) {
glGetProgramInfoLog(shader, 1024, NULL, infoLog); glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n"
<< infoLog << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
<< "\n -- --------------------------------------------------- -- "
<< std::endl;
} }
} }
} }
}; };
} } // namespace Gedeng

View File

@ -48,7 +48,7 @@ class String {
const char *c_str() const; const char *c_str() const;
/// Return the length of the String (without the terminator). /// Return the length of the String (without the terminator).
size_t getLength() const; size_t get_length() const;
private: private:
size_t length; size_t length;

View File

@ -0,0 +1,41 @@
#pragma once
#include <ft2build.h>
#include <glm/glm.hpp>
#include <map>
#include FT_FREETYPE_H
#include "Gedeng/Shader.h"
#include "Gedeng/String.h"
#include "Gedeng/Vector3.h"
namespace Gedeng {
class TextLabel {
public:
TextLabel(const String &text = String(""));
void set_text(const String &text);
void render_text(float x, float y, float scale, Vector3 color);
bool is_valid();
private:
struct Character {
unsigned int texture_id; // ID handle of the glyph texture
glm::ivec2 size; // Size of glyph
glm::ivec2 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;
String text;
bool valid;
Shader shader;
};
} // namespace Gedeng

View File

@ -2,6 +2,14 @@
namespace Gedeng { namespace Gedeng {
class Vector3 {}; class Vector3 {
public:
Vector3(float x, float y, float z) : x(x), y(y), z(z) {
}
float x;
float y;
float z;
};
} // namespace Gedeng } // namespace Gedeng

112
test/parallax-demo/main.cpp Normal file
View File

@ -0,0 +1,112 @@
#include "Gedeng/Logger.h"
#include "Gedeng/TextLabel.h"
#include "Gedeng/Vector3.h"
#define GEDENG_MAIN
#include <Gedeng.h>
class ParallaxApp : public Gedeng::Application {
public:
ParallaxApp(unsigned long ms_per_update, unsigned int window_size_x, unsigned int window_size_y,
Gedeng::String window_name)
: Application(ms_per_update, window_size_x, window_size_y, window_name), number_of_steps(10.0),
number_of_refinement_steps(10.0), bump_depth(0.1),
render_shader(Gedeng::Shader("Shader/bump.vs", "Shader/bump.fs")),
camera(Gedeng::Camera(90, 1920, 1080, 0.1, 1000.0)),
albedo("Resources/Textures/PavingStones/PavingStones070_2K_Color.jpg", Gedeng::Texture::Settings()),
bump("Resources/Textures/PavingStones/PavingStones070_2K_Displacement.jpg", Gedeng::Texture::Settings()),
normal("Resources/Textures/PavingStones/PavingStones070_2K_Normal.jpg", Gedeng::Texture::Settings()) {
// Move and rotate the camera so we see the quad well
camera.translate(glm::vec3(0.0, -1.0, 1.0));
camera.rotate(30, glm::vec3(1.0, 0.0, 0.0));
}
~ParallaxApp() = default;
void fixed_update(double delta) override {
// Settings for bump mapping
if (Gedeng::Input::is_key_down(GLFW_KEY_Q)) {
number_of_steps += delta * 5.0;
}
if (Gedeng::Input::is_key_down(GLFW_KEY_W)) {
number_of_steps -= delta * 5.0;
}
if (Gedeng::Input::is_key_down(GLFW_KEY_A)) {
number_of_refinement_steps += delta * 5.0;
}
if (Gedeng::Input::is_key_down(GLFW_KEY_S)) {
number_of_refinement_steps -= delta * 5.0;
}
if (Gedeng::Input::is_key_down(GLFW_KEY_Z)) {
bump_depth += delta * 0.1;
}
if (Gedeng::Input::is_key_down(GLFW_KEY_X)) {
bump_depth -= delta * 0.1;
}
Gedeng::String text;
text += std::to_string(number_of_steps).c_str();
text += " steps, ";
text += std::to_string(number_of_refinement_steps).c_str();
text += " refinement steps, ";
text += std::to_string(bump_depth).c_str();
text += " bump depth";
debug_text.set_text(text);
}
void dynamic_update(double delta) override {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
render_shader.use();
// Camera
render_shader.setMat4("projection", camera.get_projection());
render_shader.setMat4("view", camera.get_view());
render_shader.setVec3("viewPos", camera.get_translation());
// Lighting
render_shader.setVec3("lightPos", glm::vec3(0.0, 1.0, 5.0));
render_shader.setFloat("number_of_steps", glm::max(0.0f, number_of_steps));
render_shader.setFloat("number_of_refinement_steps", glm::max(0.0f, number_of_refinement_steps));
render_shader.setFloat("bump_depth", glm::max(0.0f, bump_depth));
// Textures
albedo.bind_to(0);
normal.bind_to(1);
bump.bind_to(2);
// Quad which is rendered onto
quad_mesh.rotate(delta * 25.0f, glm::normalize(glm::vec3(0.0, 0.0, 1.0)));
quad_mesh.render(render_shader);
debug_text.render_text(25.0f, 25.0f, 1.0f, Gedeng::Vector3(1.0, 1.0, 0.0));
}
private:
float number_of_steps;
float number_of_refinement_steps;
float bump_depth;
Gedeng::Shader render_shader;
Gedeng::VertexBuffer vertex_rectangle;
Gedeng::Camera camera;
Gedeng::Texture albedo;
Gedeng::Texture bump;
Gedeng::Texture normal;
Gedeng::QuadMesh quad_mesh;
Gedeng::TextLabel debug_text;
};
Gedeng::Application *Gedeng::create_application() {
GG_CLIENT_INFO("Creating Application");
return new ParallaxApp(20, 900, 600, String("Parallax Demo"));
}