05: refactor code and implement dynamic buffers

This commit is contained in:
0xdeadbeer 2023-12-03 11:55:15 +01:00
parent 67aa648299
commit 8455ffac2e
23 changed files with 355 additions and 211 deletions

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

22
05-opengl/src/common.cpp Normal file
View File

@ -0,0 +1,22 @@
#include <iostream>
#include <fstream>
#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;
}

5
05-opengl/src/common.hpp Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <string>
std::string read_file(const char *path);

View File

@ -2,69 +2,52 @@
#include <fstream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/mat4x4.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#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);
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);
}
return new_shader;
}
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;
}

View File

@ -3,17 +3,16 @@
#include <iostream>
#include <vector>
#include <GLFW/glfw3.h>
#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<Object*> objects;
std::vector<Sprite *> sprites;
unsigned int vao;
unsigned int vbo;
unsigned int ebo;
unsigned int vshader;
unsigned int fshader;
unsigned int program;
Program program;
};

View File

@ -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;

View File

@ -1,45 +0,0 @@
#include <GL/glew.h>
#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);
}

View File

@ -1,28 +0,0 @@
#pragma once
#include <vector>
#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<float> vertices;
std::vector<int> indices;
unsigned int vao;
unsigned int vbo;
unsigned int ebo;
Game *game;
};

38
05-opengl/src/program.cpp Normal file
View File

@ -0,0 +1,38 @@
#include <iostream>
#include <GL/glew.h>
#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;
}

13
05-opengl/src/program.hpp Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <vector>
#include "shader.hpp"
struct Program {
unsigned int id;
std::vector<Shader> shaders;
Program();
int add_shader(const char *path, unsigned int type);
int link();
};

31
05-opengl/src/shader.cpp Normal file
View File

@ -0,0 +1,31 @@
#include <iostream>
#include <GL/glew.h>
#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;
}

8
05-opengl/src/shader.hpp Normal file
View File

@ -0,0 +1,8 @@
#pragma once
struct Shader {
unsigned int id;
unsigned int type;
unsigned int load(const char *path, unsigned int type);
};

79
05-opengl/src/sprite.cpp Normal file
View File

@ -0,0 +1,79 @@
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <stb/stb_image.h>
#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);
}

33
05-opengl/src/sprite.hpp Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include <vector>
#include <glm/vec3.hpp>
#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<struct vertex> vertices;
std::vector<int> indices;
unsigned int vao;
unsigned int vbo;
unsigned int ebo;
Game *game;
Sprite(const char *path, enum TextureType type);
void bake();
};

View File

@ -1,8 +1,12 @@
#include <GL/glew.h>
#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;
}

View File

@ -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;
};