diff --git a/05-opengl/Makefile b/05-opengl/Makefile index a7faf5c..e004347 100644 --- a/05-opengl/Makefile +++ b/05-opengl/Makefile @@ -1,6 +1,6 @@ CC=g++ -CFLAGS=`pkg-config --cflags glfw3 glew` -LDFLAGS=`pkg-config --libs glfw3 glew` +CFLAGS=-std=c++20 `pkg-config --cflags glfw3 glew glm` +LDFLAGS=`pkg-config --libs glfw3 glew glm` INCLUDE=/usr/include/stb/ TARGET=opengl SDIR=src diff --git a/05-opengl/assets/linux.png b/05-opengl/assets/linux.png deleted file mode 100644 index 29ab51d..0000000 Binary files a/05-opengl/assets/linux.png and /dev/null differ diff --git a/05-opengl/assets/player/idle.png b/05-opengl/assets/player/idle.png new file mode 100644 index 0000000..4cf0c43 Binary files /dev/null and b/05-opengl/assets/player/idle.png differ diff --git a/05-opengl/assets/player/run.png b/05-opengl/assets/player/run.png new file mode 100644 index 0000000..615b222 Binary files /dev/null and b/05-opengl/assets/player/run.png differ diff --git a/05-opengl/assets/shaders/shader.frag b/05-opengl/assets/shaders/fragment.glsl similarity index 82% rename from 05-opengl/assets/shaders/shader.frag rename to 05-opengl/assets/shaders/fragment.glsl index 51a6aac..fd74ddb 100644 --- a/05-opengl/assets/shaders/shader.frag +++ b/05-opengl/assets/shaders/fragment.glsl @@ -6,6 +6,7 @@ uniform sampler2D texture1; void main() { color = texture(texture1, tex_coord); +// color = vec4(1.0, 0.0, 0.0, 1.0); if (color.a < 0.1) discard; diff --git a/05-opengl/assets/shaders/shader.vert b/05-opengl/assets/shaders/shader.vert deleted file mode 100644 index 07744c4..0000000 --- a/05-opengl/assets/shaders/shader.vert +++ /dev/null @@ -1,11 +0,0 @@ -#version 330 core - -layout (location = 0) in vec3 pos; -layout (location = 1) in vec2 texture_coord; - -out vec2 tex_coord; - -void main() { - gl_Position = vec4(pos.xyz, 1.0); - tex_coord = texture_coord; -} diff --git a/05-opengl/assets/shaders/vertex.glsl b/05-opengl/assets/shaders/vertex.glsl new file mode 100644 index 0000000..0ed2722 --- /dev/null +++ b/05-opengl/assets/shaders/vertex.glsl @@ -0,0 +1,20 @@ +#version 330 core + +layout (location = 0) in vec3 pos; +layout (location = 1) in vec2 texture_coord; + +uniform vec3 size; +uniform ivec3 offset; +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +out vec2 tex_coord; + +void main() { + vec3 new_pos = pos.xyz + offset.xyz; + new_pos = new_pos.xyz * size.xyz; + + gl_Position = projection * view * model * vec4(new_pos.xyz, 1.0); + tex_coord = texture_coord; +} diff --git a/05-opengl/assets/wall.jpg b/05-opengl/assets/wall.jpg deleted file mode 100644 index 4963198..0000000 Binary files a/05-opengl/assets/wall.jpg and /dev/null differ diff --git a/05-opengl/src/common.cpp b/05-opengl/src/common.cpp new file mode 100644 index 0000000..28eecd8 --- /dev/null +++ b/05-opengl/src/common.cpp @@ -0,0 +1,22 @@ +#include +#include +#include "common.hpp" + +std::string read_file(const char *path) { + std::string content; + std::ifstream fs(path, std::ios::in); + + if(!fs.is_open()) { + std::cerr << "Error: Could not read file " << path << ". File does not exist." << std::endl; + return NULL; + } + + std::string line = ""; + while(!fs.eof()) { + std::getline(fs, line); + content.append(line + "\n"); + } + + fs.close(); + return content; +} diff --git a/05-opengl/src/common.hpp b/05-opengl/src/common.hpp new file mode 100644 index 0000000..a600248 --- /dev/null +++ b/05-opengl/src/common.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +std::string read_file(const char *path); diff --git a/05-opengl/src/game.cpp b/05-opengl/src/game.cpp index 78495a6..cce5642 100644 --- a/05-opengl/src/game.cpp +++ b/05-opengl/src/game.cpp @@ -2,69 +2,52 @@ #include #include #include +#include +#include +#include #include "game.hpp" #include "texture.hpp" -#include "object.hpp" +#include "sprite.hpp" #include "other/stb_image.h" Game::Game(GLFWwindow *window) { this->window = window; - this->program = glCreateProgram(); + this->program = Program(); + stbi_set_flip_vertically_on_load(true); } -void Game::setup() { -} - -void Game::run(int initial_width, int initial_height) { +// code this later lol +int Game::setup(int initial_width, int initial_height) { glfwSetKeyCallback(this->window, Game::input_callback); glfwSetFramebufferSizeCallback(this->window, Game::resize_callback); Game::resize_callback(this->window, initial_width, initial_height); - this->vshader = Game::load_shader("assets/shaders/shader.vert", GL_VERTEX_SHADER); - if (!this->vshader) - return; - - this->fshader = Game::load_shader("assets/shaders/shader.frag", GL_FRAGMENT_SHADER); - if (!this->fshader) - return; - - if (Game::link_program()) - return; - - stbi_set_flip_vertically_on_load(true); - - int width; - int height; - int channels; - unsigned char *image_bytes = stbi_load("assets/wall.jpg", &width, &height, &channels, 0); - if (image_bytes == NULL) { - std::cout << "Error: failed loading image data" << std::endl; - return; + int ret = this->program.add_shader("assets/shaders/vertex.glsl", GL_VERTEX_SHADER); + if (ret != 0) { + std::cout << "Error: failed adding vertex shader" << std::endl; + return -1; } - Texture new_texture; - new_texture.bind_texture(); - new_texture.load_data(image_bytes, width, height); + ret = this->program.add_shader("assets/shaders/fragment.glsl", GL_FRAGMENT_SHADER); + if (ret != 0) { + std::cout << "Error: failed adding fragment shader" << std::endl; + return -1; + } - stbi_image_free(image_bytes); + if (this->program.link() != 0) { + std::cout << "Error: failed linking program" << std::endl; + return -1; + } - Object new_object(this, new_texture); + glUseProgram(this->program.id); + return 0; +} - new_object.vertices = { - 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, - 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f - }; - - new_object.indices = { - 0, 1, 3, - 1, 2, 3 - }; - - new_object.bake(); - this->objects.push_back(&new_object); +void Game::run() { + Sprite sprite("assets/player/idle.png", SPLIT_TEXTURE); + sprite.bake(); + this->sprites.push_back(&sprite); Game::logic(); } @@ -91,8 +74,8 @@ void Game::logic() { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); - for (int i = 0; i < this->objects.size(); i++) - (*this->objects[i]).draw(); + for (int i = 0; i < this->sprites.size(); i++) + Game::draw(this->sprites[i]); glfwPollEvents(); glfwSwapBuffers(this->window); @@ -101,64 +84,44 @@ void Game::logic() { glBindVertexArray(0); } -unsigned int Game::load_shader(const char *path, unsigned int type) { - std::string source = Game::read_file(path); - const char *bytes = source.c_str(); +void Game::draw(Sprite *sprite) { + unsigned int program = this->program.id; + glUseProgram(program); - unsigned int new_shader = glCreateShader(type); - if (!new_shader) - return 0; + glUniform3i(glGetUniformLocation(program, "offset"), sprite->pos.x, sprite->pos.y, sprite->pos.z); + glUniform3f(glGetUniformLocation(program, "size"), sprite->size.x, sprite->size.y, sprite->size.z); + glUniform1i(glGetUniformLocation(program, "texture1"), 0); - glShaderSource(new_shader, 1, &bytes, NULL); - glCompileShader(new_shader); + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); - int success; - char info_log[512]; - glGetShaderiv(new_shader, GL_COMPILE_STATUS, &success); + glm::mat4 view = glm::mat4(1.0f); + view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); - if (!success) { - glGetShaderInfoLog(new_shader, 512, NULL, info_log); - std::cout << "Error: failed compiling new shader " << info_log << std::endl; - return 0; - } + glm::mat4 projection = glm::mat4(1.0f); - return new_shader; + int width, height; + float half_width, half_height; + glfwGetWindowSize(this->window, &width, &height); + + half_width = (float) width / 2; + half_height = (float) height / 2; + + projection = glm::ortho(-half_width/100, half_width/100, -half_height/100, half_height/100, 0.1f, 100.0f); + + glUniformMatrix4fv(glGetUniformLocation(program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(glGetUniformLocation(program,"view"), 1, GL_FALSE, glm::value_ptr(view)); + glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + + glBindVertexArray(sprite->vao); + glBindBuffer(GL_ARRAY_BUFFER, sprite->vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sprite->ebo); + + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(struct vertex) * sprite->vertices.size(), sprite->vertices.data()); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * sprite->indices.size(), sprite->indices.data()); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, sprite->texture.texture_id); + + glDrawElements(GL_TRIANGLES, sprite->indices.size(), GL_UNSIGNED_INT, 0); } - -int Game::link_program() { - glAttachShader(this->program, this->vshader); - glAttachShader(this->program, this->fshader); - glLinkProgram(this->program); - - int success; - char info_log[512]; - glGetProgramiv(this->program, GL_LINK_STATUS, &success); - - if (!success) { - glGetProgramInfoLog(this->program, 512, NULL, info_log); - std::cout << "Error: failed linking program " << info_log << std::endl; - return -1; - } - - return 0; -} - -std::string Game::read_file(const char *path) { - std::string content; - std::ifstream fs(path, std::ios::in); - - if(!fs.is_open()) { - std::cerr << "Error: Could not read file " << path << ". File does not exist." << std::endl; - return NULL; - } - - std::string line = ""; - while(!fs.eof()) { - std::getline(fs, line); - content.append(line + "\n"); - } - - fs.close(); - return content; -} - diff --git a/05-opengl/src/game.hpp b/05-opengl/src/game.hpp index 689bb15..fec1f6e 100644 --- a/05-opengl/src/game.hpp +++ b/05-opengl/src/game.hpp @@ -3,17 +3,16 @@ #include #include #include -#include "object.hpp" +#include "program.hpp" +#include "sprite.hpp" class Game { public: Game(GLFWwindow *window); - static std::string read_file(const char *path); - unsigned int load_shader(const char *path, unsigned int type); - int link_program(); - void setup(); - void run(int initial_width, int initial_height); + int setup(int initial_width, int initial_height); + void run(); void logic(); + void draw(Sprite *sprite); // callbacks static void input_callback(GLFWwindow *window, int key, int scancode, int action, int mods); @@ -21,13 +20,7 @@ public: GLFWwindow *window; - std::vector objects; + std::vector sprites; - unsigned int vao; - unsigned int vbo; - unsigned int ebo; - - unsigned int vshader; - unsigned int fshader; - unsigned int program; + Program program; }; diff --git a/05-opengl/src/main.cpp b/05-opengl/src/main.cpp index b2cde83..317fb8b 100644 --- a/05-opengl/src/main.cpp +++ b/05-opengl/src/main.cpp @@ -32,8 +32,8 @@ int main() { } Game main_game(window); - - main_game.run(initial_width, initial_height); + main_game.setup(initial_width, initial_height); + main_game.run(); glfwTerminate(); return 0; diff --git a/05-opengl/src/object.cpp b/05-opengl/src/object.cpp deleted file mode 100644 index ccfc21e..0000000 --- a/05-opengl/src/object.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include "game.hpp" -#include "object.hpp" - -Object::Object(Game *game, Texture texture) { - this->texture = texture; - this->game = game; - - glGenVertexArrays(1, &this->vao); - glGenBuffers(1, &this->vbo); - glGenBuffers(1, &this->ebo); -} - -void Object::bake() { - glBindVertexArray(this->vao); - - glBindBuffer(GL_ARRAY_BUFFER, this->vbo); - glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(float), &this->vertices[0], GL_STATIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(int), &this->indices[0], GL_STATIC_DRAW); - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *) 0); - glEnableVertexAttribArray(0); - - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *) (6 * sizeof(float))); - glEnableVertexAttribArray(1); - - glBindVertexArray(0); -} - -void Object::draw() { - glUseProgram(this->game->program); - - glUniform1i(glGetUniformLocation(this->game->program, "texture1"), 0); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, this->texture.texture_id); - - glBindVertexArray(this->vao); - glBindBuffer(GL_ARRAY_BUFFER, this->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ebo); - - glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0); -} diff --git a/05-opengl/src/object.hpp b/05-opengl/src/object.hpp deleted file mode 100644 index 96e7ab1..0000000 --- a/05-opengl/src/object.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include "texture.hpp" - -class Game; -class Texture; - -class Object { -public: - Object(Game *game, Texture texture); - - void bake(); - void draw(); - - Texture texture; - int x; - int y; - - std::vector vertices; - std::vector indices; - - unsigned int vao; - unsigned int vbo; - unsigned int ebo; - - Game *game; -}; diff --git a/05-opengl/src/program.cpp b/05-opengl/src/program.cpp new file mode 100644 index 0000000..379c302 --- /dev/null +++ b/05-opengl/src/program.cpp @@ -0,0 +1,38 @@ +#include +#include +#include "program.hpp" + +Program::Program() { + this->id = glCreateProgram(); +} + +int Program::add_shader(const char *path, unsigned int type) { + Shader new_shader; + unsigned int ret = new_shader.load(path, type); + + if (!ret) + return -1; + + this->shaders.push_back(new_shader); + + return 0; +} + +int Program::link() { + for (int shader = 0; shader < this->shaders.size(); shader++) + glAttachShader(this->id, this->shaders[shader].id); + + glLinkProgram(this->id); + + int success; + char info_log[512]; + glGetProgramiv(this->id, GL_LINK_STATUS, &success); + + if (!success) { + glGetProgramInfoLog(this->id, 512, NULL, info_log); + std::cout << "Error: failed linking program. " << info_log << std::endl; + return -1; + } + + return 0; +} diff --git a/05-opengl/src/program.hpp b/05-opengl/src/program.hpp new file mode 100644 index 0000000..436db25 --- /dev/null +++ b/05-opengl/src/program.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include +#include "shader.hpp" + +struct Program { + unsigned int id; + std::vector shaders; + + Program(); + int add_shader(const char *path, unsigned int type); + int link(); +}; diff --git a/05-opengl/src/shader.cpp b/05-opengl/src/shader.cpp new file mode 100644 index 0000000..d27148e --- /dev/null +++ b/05-opengl/src/shader.cpp @@ -0,0 +1,31 @@ +#include +#include +#include "shader.hpp" +#include "common.hpp" + +unsigned int Shader::load(const char *path, unsigned int type) { + std::string source_s = read_file(path); + const char *source = source_s.c_str(); + + unsigned int new_shader = glCreateShader(type); + if (!new_shader) + return 0; + + glShaderSource(new_shader, 1, &source, NULL); + glCompileShader(new_shader); + + int success; + char info_log[512]; + glGetShaderiv(new_shader, GL_COMPILE_STATUS, &success); + + if (!success) { + glGetShaderInfoLog(new_shader, 512, NULL, info_log); + std::cout << "Error: failed compiling new shader " << info_log << std::endl; + return 0; + } + + this->id = new_shader; + this->type = type; + + return new_shader; +} diff --git a/05-opengl/src/shader.hpp b/05-opengl/src/shader.hpp new file mode 100644 index 0000000..b4e2807 --- /dev/null +++ b/05-opengl/src/shader.hpp @@ -0,0 +1,8 @@ +#pragma once + +struct Shader { + unsigned int id; + unsigned int type; + + unsigned int load(const char *path, unsigned int type); +}; diff --git a/05-opengl/src/sprite.cpp b/05-opengl/src/sprite.cpp new file mode 100644 index 0000000..21892fa --- /dev/null +++ b/05-opengl/src/sprite.cpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include "game.hpp" +#include "sprite.hpp" + +Sprite::Sprite(const char *path, enum TextureType type) : texture(type) { + int image_width; + int image_height; + int image_resolution; + int image_channels; + + unsigned char *image_bytes = stbi_load(path, &image_width, &image_height, &image_channels, 0); + if (image_bytes == NULL) { + std::cout << "Error: failed loading image data" << std::endl; + return; + } + + this->texture.bind_texture(); + this->texture.load_data(image_bytes, image_width, image_height, image_height); + + stbi_image_free(image_bytes); + + glGenVertexArrays(1, &this->vao); + glGenBuffers(1, &this->vbo); + glGenBuffers(1, &this->ebo); + + this->pos = glm::vec3(0.0f); + this->size = glm::vec3(1.0f); + this->rot = glm::vec3(0.0f); +} + +void Sprite::bake() { + struct vertex v1 = { {0.5f, 0.5f, 0.0f}, {1.0f, 1.0f} }; + struct vertex v2 = { {0.5f, -0.5f, 0.0f}, {1.0f, 0.0f} }; + struct vertex v3 = { {-0.5f, -0.5f, 0.0f}, {0.0f, 0.0f} }; + struct vertex v4 = { {-0.5f, 0.5f, 0.0f}, {0.0f, 1.0f} }; + + this->vertices.push_back(v1); + this->vertices.push_back(v2); + this->vertices.push_back(v3); + this->vertices.push_back(v4); + + this->indices = { + 0, 1, 3, + 1, 2, 3 + }; + + Texture &tex = this->texture; + if (tex.type == SPLIT_TEXTURE) { + for (int i = 0; i < this->vertices.size(); i++) { + struct vertex *v = &this->vertices[i]; + + float tex_x = ((tex.cell_x + v->texture[0]) * tex.cell_res) / tex.texture_width; + float tex_y = ((tex.cell_y + v->texture[1]) * tex.cell_res) / tex.texture_height; + + v->texture[0] = tex_x; + v->texture[1] = tex_y; + } + } + + glBindVertexArray(this->vao); + + glBindBuffer(GL_ARRAY_BUFFER, this->vbo); + glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(struct vertex), nullptr, GL_DYNAMIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(int), nullptr, GL_DYNAMIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void *) offsetof(vertex, position)); + glEnableVertexAttribArray(0); + + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void *) offsetof(vertex, texture)); + glEnableVertexAttribArray(1); + + glBindVertexArray(0); +} diff --git a/05-opengl/src/sprite.hpp b/05-opengl/src/sprite.hpp new file mode 100644 index 0000000..dc0c215 --- /dev/null +++ b/05-opengl/src/sprite.hpp @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include "texture.hpp" + +class Game; +class Texture; + +struct vertex { + float position[3]; + float texture[2]; +}; + +class Sprite { +public: + Texture texture; + + glm::vec3 pos; + glm::vec3 size; + glm::vec3 rot; + + std::vector vertices; + std::vector indices; + + unsigned int vao; + unsigned int vbo; + unsigned int ebo; + + Game *game; + + Sprite(const char *path, enum TextureType type); + void bake(); +}; diff --git a/05-opengl/src/texture.cpp b/05-opengl/src/texture.cpp index cf1f17b..b3816d5 100644 --- a/05-opengl/src/texture.cpp +++ b/05-opengl/src/texture.cpp @@ -1,8 +1,12 @@ #include #include "texture.hpp" -Texture::Texture() { +Texture::Texture(enum TextureType type) { glGenTextures(1, &this->texture_id); + this->type = type; + this->cell_x = 0; + this->cell_y = 0; + this->cell_res = 0; } void Texture::bind_texture() { @@ -11,11 +15,15 @@ void Texture::bind_texture() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - 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_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } -void Texture::load_data(unsigned char *bytes, int width, int height) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, bytes); +void Texture::load_data(unsigned char *bytes, int width, int height, int cell_res) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bytes); glGenerateMipmap(GL_TEXTURE_2D); + + this->texture_width = width; + this->texture_height = height; + this->cell_res = cell_res; } diff --git a/05-opengl/src/texture.hpp b/05-opengl/src/texture.hpp index 70bee18..69bd625 100644 --- a/05-opengl/src/texture.hpp +++ b/05-opengl/src/texture.hpp @@ -1,10 +1,24 @@ #pragma once +enum TextureType { + FULL_TEXTURE, + SPLIT_TEXTURE, + DYNAMIC_TEXTURE +}; + class Texture { public: unsigned int texture_id; - Texture(); + Texture(enum TextureType type); void bind_texture(); - void load_data(unsigned char *bytes, int width, int height); + void load_data(unsigned char *bytes, int width, int height, int cell_res); + + enum TextureType type; + int texture_width; + int texture_height; + int cell_res; + + int cell_x; + int cell_y; };