revamped resource system
This commit is contained in:
@@ -5,7 +5,6 @@ set(CMAKE_CXX_STANDARD 20)
|
|||||||
|
|
||||||
set (GLAD_SOURCE_DIR _ThirdParty/glad/src)
|
set (GLAD_SOURCE_DIR _ThirdParty/glad/src)
|
||||||
set (GLAD_INCLUDE_DIR _ThirdParty/glad/include)
|
set (GLAD_INCLUDE_DIR _ThirdParty/glad/include)
|
||||||
|
|
||||||
include_directories(${GLAD_INCLUDE_DIR})
|
include_directories(${GLAD_INCLUDE_DIR})
|
||||||
|
|
||||||
set (GLFW_BUILD_EXAMPLES OFF)
|
set (GLFW_BUILD_EXAMPLES OFF)
|
||||||
@@ -20,7 +19,9 @@ add_subdirectory(_ThirdParty/assimp)
|
|||||||
|
|
||||||
add_subdirectory(glm)
|
add_subdirectory(glm)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} src/main.cpp ${GLAD_SOURCE_DIR}/gl.c
|
add_executable(${PROJECT_NAME}
|
||||||
|
src/main.cpp
|
||||||
|
${GLAD_SOURCE_DIR}/gl.c
|
||||||
src/Mesh.cpp
|
src/Mesh.cpp
|
||||||
src/Mesh.h
|
src/Mesh.h
|
||||||
src/Model.cpp
|
src/Model.cpp
|
||||||
@@ -31,8 +32,11 @@ add_executable(${PROJECT_NAME} src/main.cpp ${GLAD_SOURCE_DIR}/gl.c
|
|||||||
src/ModelLoader.h
|
src/ModelLoader.h
|
||||||
src/ShaderProgram.cpp
|
src/ShaderProgram.cpp
|
||||||
src/ShaderProgram.h
|
src/ShaderProgram.h
|
||||||
src/Texture.cpp
|
src/Texture.h
|
||||||
src/Texture.h)
|
src/TextureLoader.cpp
|
||||||
|
src/TextureLoader.h
|
||||||
|
src/ShaderLoader.cpp
|
||||||
|
src/ShaderLoader.h)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} glfw spdlog assimp glm)
|
target_link_libraries(${PROJECT_NAME} glfw spdlog assimp glm)
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE ${ASSIMP_INCLUDE_INSTALL_DIR})
|
target_include_directories(${PROJECT_NAME} PRIVATE ${ASSIMP_INCLUDE_INSTALL_DIR})
|
||||||
|
|||||||
46
resources/cube.obj
Normal file
46
resources/cube.obj
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Blender v2.76 (sub 0) OBJ File: ''
|
||||||
|
# www.blender.org
|
||||||
|
mtllib cube.mtl
|
||||||
|
o Cube
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -0.999999
|
||||||
|
v 0.999999 1.000000 1.000001
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
vt 1.000000 0.333333
|
||||||
|
vt 1.000000 0.666667
|
||||||
|
vt 0.666667 0.666667
|
||||||
|
vt 0.666667 0.333333
|
||||||
|
vt 0.666667 0.000000
|
||||||
|
vt 0.000000 0.333333
|
||||||
|
vt 0.000000 0.000000
|
||||||
|
vt 0.333333 0.000000
|
||||||
|
vt 0.333333 1.000000
|
||||||
|
vt 0.000000 1.000000
|
||||||
|
vt 0.000000 0.666667
|
||||||
|
vt 0.333333 0.333333
|
||||||
|
vt 0.333333 0.666667
|
||||||
|
vt 1.000000 0.000000
|
||||||
|
vn 0.000000 -1.000000 0.000000
|
||||||
|
vn 0.000000 1.000000 0.000000
|
||||||
|
vn 1.000000 0.000000 0.000000
|
||||||
|
vn -0.000000 0.000000 1.000000
|
||||||
|
vn -1.000000 -0.000000 -0.000000
|
||||||
|
vn 0.000000 0.000000 -1.000000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 2/1/1 3/2/1 4/3/1
|
||||||
|
f 8/1/2 7/4/2 6/5/2
|
||||||
|
f 5/6/3 6/7/3 2/8/3
|
||||||
|
f 6/8/4 7/5/4 3/4/4
|
||||||
|
f 3/9/5 7/10/5 8/11/5
|
||||||
|
f 1/12/6 4/13/6 8/11/6
|
||||||
|
f 1/4/1 2/1/1 4/3/1
|
||||||
|
f 5/14/2 8/1/2 6/5/2
|
||||||
|
f 1/12/3 5/6/3 2/8/3
|
||||||
|
f 2/12/4 6/8/4 3/4/4
|
||||||
|
f 4/13/5 3/9/5 8/11/5
|
||||||
|
f 5/6/6 1/12/6 8/11/6
|
||||||
@@ -5,23 +5,27 @@
|
|||||||
#ifndef B_ENGINE_MATERIAL_H
|
#ifndef B_ENGINE_MATERIAL_H
|
||||||
#define B_ENGINE_MATERIAL_H
|
#define B_ENGINE_MATERIAL_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
alignas(16) glm::vec3 ambient;
|
glm::vec3 ambient;
|
||||||
alignas(16) glm::vec3 diffuse;
|
glm::vec3 diffuse;
|
||||||
alignas(16) glm::vec3 specular;
|
glm::vec3 specular;
|
||||||
float shininess;
|
float shininess;
|
||||||
} PhongProperties;
|
} PhongProperties;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
Texture* diffuse;
|
std::shared_ptr<Texture> diffuse;
|
||||||
Texture* specular;
|
std::shared_ptr<Texture> specular;
|
||||||
Texture* normal;
|
std::shared_ptr<Texture> normal;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
|
||||||
PhongProperties phong;
|
PhongProperties phong;
|
||||||
} Material;
|
} Material;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
Mesh::Mesh(const std::vector<float> &positions, const std::vector<float> &uvs, const std::vector<float> &normals, const std::vector<unsigned int> &indices) {
|
Mesh::Mesh(const std::vector<float> &positions, const std::vector<float> &uvs, const std::vector<float> &normals, const std::vector<unsigned int> &indices) {
|
||||||
vao = 0;
|
vao = 0;
|
||||||
ebo = 0;
|
ebo = 0;
|
||||||
|
numIndices = indices.size();
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ Mesh::Mesh(const std::vector<float> &positions, const std::vector<float> &uvs, c
|
|||||||
glBindBuffer(GL_ARRAY_BUFFER, normalVbo);
|
glBindBuffer(GL_ARRAY_BUFFER, normalVbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(float), normals.data(), GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(float), normals.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glGenBuffers(1, &ebo);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public:
|
|||||||
|
|
||||||
GLuint vao;
|
GLuint vao;
|
||||||
GLuint ebo;
|
GLuint ebo;
|
||||||
|
unsigned int numIndices;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //B_ENGINE_MESH_H
|
#endif //B_ENGINE_MESH_H
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
#ifndef B_ENGINE_MODEL_H
|
#ifndef B_ENGINE_MODEL_H
|
||||||
#define B_ENGINE_MODEL_H
|
#define B_ENGINE_MODEL_H
|
||||||
|
|
||||||
#include <string>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Mesh.h"
|
#include "Mesh.h"
|
||||||
@@ -14,9 +14,10 @@
|
|||||||
class Model
|
class Model
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int numMeshes;
|
static std::shared_ptr<Model> load_from_file(std::string_view filename);
|
||||||
std::vector<Mesh> meshes;
|
|
||||||
std::vector<Material> materials;
|
std::vector<std::shared_ptr<Mesh>> meshes;
|
||||||
|
std::vector<std::shared_ptr<Material>> materials;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //B_ENGINE_MODEL_H
|
#endif //B_ENGINE_MODEL_H
|
||||||
@@ -10,16 +10,23 @@
|
|||||||
#include <assimp/postprocess.h>
|
#include <assimp/postprocess.h>
|
||||||
#include <assimp/scene.h>
|
#include <assimp/scene.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<Model>> ModelLoader::models;
|
||||||
|
|
||||||
void process_ai_node(aiNode* node, const aiScene* scene, Model* model);
|
void process_ai_node(aiNode* node, const aiScene* scene, Model* model);
|
||||||
Mesh process_ai_mesh(aiMesh* aiMesh, const aiScene* scene, Model* model);
|
|
||||||
|
Mesh process_ai_mesh(const aiMesh* aiMesh);
|
||||||
|
Material process_ai_material(aiMaterial* mat);
|
||||||
|
|
||||||
std::shared_ptr<Model> ModelLoader::load_from_file(std::string_view _path)
|
std::shared_ptr<Model> ModelLoader::load_from_file(std::string_view _path)
|
||||||
{
|
{
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
|
|
||||||
const aiScene* scene = importer.ReadFile(_path.data(),
|
const aiScene* scene = importer.ReadFile(_path.data(),
|
||||||
/*aiProcess_CalcTangentSpace |*/
|
aiProcess_Triangulate |
|
||||||
aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs |
|
aiProcess_GenSmoothNormals |
|
||||||
|
aiProcess_FlipUVs |
|
||||||
aiProcess_CalcTangentSpace);
|
aiProcess_CalcTangentSpace);
|
||||||
|
|
||||||
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
|
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
|
||||||
@@ -30,21 +37,29 @@ std::shared_ptr<Model> ModelLoader::load_from_file(std::string_view _path)
|
|||||||
|
|
||||||
auto model = std::make_shared<Model>();
|
auto model = std::make_shared<Model>();
|
||||||
|
|
||||||
process_ai_node(scene->mRootNode, scene, model.get());
|
model->materials.resize(scene->mNumMaterials);
|
||||||
|
for (unsigned int i = 0; i < scene->mNumMaterials; i++) {
|
||||||
|
aiMaterial* mat = scene->mMaterials[i];
|
||||||
|
model->materials[i] = std::make_shared<Material>(process_ai_material(mat));
|
||||||
|
}
|
||||||
|
|
||||||
|
model->meshes.resize(scene->mNumMeshes);
|
||||||
|
for (unsigned int i = 0; i < scene->mNumMeshes; i++) {
|
||||||
|
aiMesh* mesh = scene->mMeshes[i];
|
||||||
|
model->meshes[i] = std::make_shared<Mesh>(process_ai_mesh(mesh));
|
||||||
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_ai_node(aiNode* node, const aiScene* scene, Model* model)
|
void process_ai_node(aiNode* node, const aiScene* scene, Model* model)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < node->mNumMeshes; i++)
|
for (unsigned int i = 0; i < node->mNumChildren; i++) {
|
||||||
{
|
|
||||||
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
|
||||||
model->meshes.push_back(process_ai_mesh(mesh, scene, model));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh process_ai_mesh(aiMesh* aiMesh, const aiScene* scene, Model* model)
|
Mesh process_ai_mesh(const aiMesh* aiMesh)
|
||||||
{
|
{
|
||||||
auto positions = std::vector<float>(aiMesh->mNumVertices * 3);
|
auto positions = std::vector<float>(aiMesh->mNumVertices * 3);
|
||||||
auto uvs = std::vector<float>(aiMesh->mNumVertices * 2);
|
auto uvs = std::vector<float>(aiMesh->mNumVertices * 2);
|
||||||
@@ -92,3 +107,48 @@ Mesh process_ai_mesh(aiMesh* aiMesh, const aiScene* scene, Model* model)
|
|||||||
|
|
||||||
return {positions, uvs, normals, indices};
|
return {positions, uvs, normals, indices};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Material process_ai_material(aiMaterial *mat) {
|
||||||
|
aiString matName;
|
||||||
|
aiReturn ret = mat->Get(AI_MATKEY_NAME, matName);
|
||||||
|
if (ret != AI_SUCCESS) {
|
||||||
|
spdlog::error("Could not find material name");
|
||||||
|
}
|
||||||
|
|
||||||
|
aiColor3D ambientColor {0.f, 0.f, 0.f};
|
||||||
|
ret = mat->Get(AI_MATKEY_COLOR_DIFFUSE, ambientColor);
|
||||||
|
if (ret != AI_SUCCESS) {
|
||||||
|
spdlog::error("Could not find ambient color for material: {}", matName.C_Str());
|
||||||
|
ambientColor = {.3f, .3f, .3f};
|
||||||
|
}
|
||||||
|
|
||||||
|
aiColor3D diffuseColor {1.f, 1.f, 1.f};
|
||||||
|
ret = mat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuseColor);
|
||||||
|
if (ret != AI_SUCCESS) {
|
||||||
|
spdlog::error("Could not find diffuse color for material: {}", matName.C_Str());
|
||||||
|
diffuseColor = {1.f, 1.f, 1.f};
|
||||||
|
}
|
||||||
|
|
||||||
|
aiColor3D specularColor {1.f, 1.f, 1.f};
|
||||||
|
ret = mat->Get(AI_MATKEY_COLOR_SPECULAR, specularColor);
|
||||||
|
if (ret != AI_SUCCESS) {
|
||||||
|
spdlog::error("Could not find specular color for material: {}", matName.C_Str());
|
||||||
|
specularColor = {1.f, 1.f, 1.f};
|
||||||
|
}
|
||||||
|
|
||||||
|
float shininess = 32.f;
|
||||||
|
ret = mat->Get(AI_MATKEY_SHININESS, shininess);
|
||||||
|
if (ret != AI_SUCCESS) {
|
||||||
|
spdlog::error("Could not find shininess for material: {}", matName.C_Str());
|
||||||
|
shininess = 32.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Material material;
|
||||||
|
material.name = matName.C_Str();
|
||||||
|
material.phong.ambient = glm::vec3{ambientColor.r, ambientColor.g, ambientColor.b};
|
||||||
|
material.phong.diffuse = glm::vec3{diffuseColor.r, diffuseColor.g, diffuseColor.b};
|
||||||
|
material.phong.specular = glm::vec3{specularColor.r, specularColor.g, specularColor.b};
|
||||||
|
material.phong.shininess = shininess;
|
||||||
|
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
class ModelLoader
|
class ModelLoader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static std::unordered_map<std::string, std::shared_ptr<Model>> models;
|
||||||
|
|
||||||
static std::shared_ptr<Model> load_from_file(std::string_view _path);
|
static std::shared_ptr<Model> load_from_file(std::string_view _path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
97
src/ShaderLoader.cpp
Normal file
97
src/ShaderLoader.cpp
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
//
|
||||||
|
// Created by slinky on 5/1/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "ShaderLoader.h"
|
||||||
|
|
||||||
|
#include "glad/gl.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
void log_shader_compile_errors(GLuint shader, std::string_view shaderType);
|
||||||
|
void log_program_compile_errors(GLuint program);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<ShaderProgram>> ShaderLoader::shaders;
|
||||||
|
|
||||||
|
std::shared_ptr<ShaderProgram> ShaderLoader::load(std::string_view vertexPath, std::string_view fragmentPath)
|
||||||
|
{
|
||||||
|
std::string vertexSource;
|
||||||
|
std::string fragmentSource;
|
||||||
|
|
||||||
|
std::ifstream vertexFile {};
|
||||||
|
std::ifstream fragmentFile {};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
vertexFile.open(vertexPath.data());
|
||||||
|
fragmentFile.open(fragmentPath.data());
|
||||||
|
|
||||||
|
std::stringstream vertexSourceStream {};
|
||||||
|
vertexSourceStream << vertexFile.rdbuf();
|
||||||
|
vertexSource = vertexSourceStream.str();
|
||||||
|
|
||||||
|
std::stringstream fragmentSourceStream {};
|
||||||
|
fragmentSourceStream << fragmentFile.rdbuf();
|
||||||
|
fragmentSource = fragmentSourceStream.str();
|
||||||
|
|
||||||
|
vertexFile.close();
|
||||||
|
fragmentFile.close();
|
||||||
|
} catch (std::ifstream::failure& e) {
|
||||||
|
spdlog::error("Failed to load shader program {}, {}: {}", vertexPath, fragmentPath, std::string(e.what()).c_str());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int vertex;
|
||||||
|
unsigned int fragment;
|
||||||
|
|
||||||
|
vertex = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
const char* vertex_str = vertexSource.data();
|
||||||
|
glShaderSource(vertex, 1, &vertex_str, NULL);
|
||||||
|
glCompileShader(vertex);
|
||||||
|
log_shader_compile_errors(vertex, "vertex");
|
||||||
|
|
||||||
|
fragment = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
const char* frag_str = fragmentSource.data();
|
||||||
|
glShaderSource(fragment, 1, &frag_str, NULL);
|
||||||
|
glCompileShader(fragment);
|
||||||
|
log_shader_compile_errors(fragment, "fragment");
|
||||||
|
|
||||||
|
int shaderId = glCreateProgram();
|
||||||
|
|
||||||
|
glAttachShader(shaderId, vertex);
|
||||||
|
glAttachShader(shaderId, fragment);
|
||||||
|
glLinkProgram(shaderId);
|
||||||
|
log_program_compile_errors(shaderId);
|
||||||
|
|
||||||
|
glDeleteShader(vertex);
|
||||||
|
glDeleteShader(fragment);
|
||||||
|
|
||||||
|
return std::make_shared<ShaderProgram>(ShaderProgram(shaderId));
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_shader_compile_errors(GLuint shader, std::string_view shaderType)
|
||||||
|
{
|
||||||
|
GLint success;
|
||||||
|
GLchar infoLog[1024];
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
|
||||||
|
spdlog::error("Failed to compile {} shader: {}", shaderType, infoLog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_program_compile_errors(GLuint program)
|
||||||
|
{
|
||||||
|
GLint success;
|
||||||
|
GLchar infoLog[1024];
|
||||||
|
glGetProgramiv(program, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
glGetShaderInfoLog(program, 1024, NULL, infoLog);
|
||||||
|
spdlog::error("Failed to compile program: {}", infoLog);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/ShaderLoader.h
Normal file
19
src/ShaderLoader.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by slinky on 5/1/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef B_ENGINE_SHADERLOADER_H
|
||||||
|
#define B_ENGINE_SHADERLOADER_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "ShaderProgram.h"
|
||||||
|
|
||||||
|
class ShaderLoader {
|
||||||
|
public:
|
||||||
|
static std::unordered_map<std::string, std::shared_ptr<ShaderProgram>> shaders;
|
||||||
|
|
||||||
|
static std::shared_ptr<ShaderProgram> load(std::string_view vertexPath, std::string_view fragmentPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //B_ENGINE_SHADERLOADER_H
|
||||||
@@ -5,68 +5,8 @@
|
|||||||
#include "ShaderProgram.h"
|
#include "ShaderProgram.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "glad/gl.h"
|
#include <glad/gl.h>
|
||||||
#include "spdlog/spdlog.h"
|
|
||||||
|
|
||||||
void log_shader_compile_errors(GLuint shader, std::string_view shaderType);
|
|
||||||
void log_program_compile_errors(GLuint program);
|
|
||||||
|
|
||||||
std::shared_ptr<ShaderProgram> ShaderProgram::load(std::string_view vertexPath, std::string_view fragmentPath)
|
|
||||||
{
|
|
||||||
std::string vertexSource;
|
|
||||||
std::string fragmentSource;
|
|
||||||
|
|
||||||
std::ifstream vertexFile {};
|
|
||||||
std::ifstream fragmentFile {};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
vertexFile.open(vertexPath.data());
|
|
||||||
fragmentFile.open(fragmentPath.data());
|
|
||||||
|
|
||||||
ss << vertexFile.rdbuf();
|
|
||||||
vertexSource = ss.str();
|
|
||||||
ss.clear();
|
|
||||||
ss << fragmentFile.rdbuf();
|
|
||||||
fragmentSource = ss.str();
|
|
||||||
|
|
||||||
vertexFile.close();
|
|
||||||
fragmentFile.close();
|
|
||||||
} catch (std::ifstream::failure& e) {
|
|
||||||
spdlog::error("Failed to load shader program {}, {}: {}", vertexPath, fragmentPath, std::string(e.what()).c_str());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int vertex;
|
|
||||||
unsigned int fragment;
|
|
||||||
|
|
||||||
vertex = glCreateShader(GL_VERTEX_SHADER);
|
|
||||||
glShaderSource(vertex, 1, reinterpret_cast<const GLchar* const*>(vertexSource.data()), NULL);
|
|
||||||
glCompileShader(vertex);
|
|
||||||
log_shader_compile_errors(vertex, "vertex");
|
|
||||||
|
|
||||||
fragment = glCreateShader(GL_FRAGMENT_SHADER);
|
|
||||||
glShaderSource(fragment, 1, reinterpret_cast<const GLchar* const*>(fragmentSource.data()), NULL);
|
|
||||||
glCompileShader(fragment);
|
|
||||||
log_shader_compile_errors(fragment, "fragment");
|
|
||||||
|
|
||||||
ShaderProgram program;
|
|
||||||
program.id = glCreateProgram();
|
|
||||||
|
|
||||||
glAttachShader(program.id, vertex);
|
|
||||||
glAttachShader(program.id, fragment);
|
|
||||||
glLinkProgram(program.id);
|
|
||||||
log_program_compile_errors(program.id);
|
|
||||||
|
|
||||||
glDeleteShader(vertex);
|
|
||||||
glDeleteShader(fragment);
|
|
||||||
|
|
||||||
return std::make_shared<ShaderProgram>(program);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShaderProgram::bind()
|
void ShaderProgram::bind()
|
||||||
{
|
{
|
||||||
@@ -80,49 +20,26 @@ void ShaderProgram::unbind()
|
|||||||
|
|
||||||
void ShaderProgram::setFloat(std::string_view name, float value) const
|
void ShaderProgram::setFloat(std::string_view name, float value) const
|
||||||
{
|
{
|
||||||
|
glUniform1f(glGetUniformLocation(id, name.data()), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderProgram::setVec2(std::string_view name, const glm::vec2& value) const
|
void ShaderProgram::setInt(std::string_view name, int value) const
|
||||||
{
|
{
|
||||||
|
glUniform1i(glGetUniformLocation(id, name.data()), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderProgram::setVec3(std::string_view name, const glm::vec3& value) const
|
void ShaderProgram::setVec3(std::string_view name, const glm::vec3& value) const
|
||||||
{
|
{
|
||||||
|
glUniform3fv(glGetUniformLocation(id, name.data()), 1, &value[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderProgram::setVec4(std::string_view name, const glm::vec4& value) const
|
void ShaderProgram::setVec4(std::string_view name, const glm::vec4& value) const
|
||||||
{
|
{
|
||||||
|
glUniform4fv(glGetUniformLocation(id, name.data()), 1, &value[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderProgram::setMat4(std::string_view name, const glm::mat4& value) const
|
void ShaderProgram::setMat4(std::string_view name, const glm::mat4& value) const
|
||||||
{
|
{
|
||||||
|
glUniformMatrix4fv(glGetUniformLocation(id, name.data()), 1, GL_FALSE, &value[0][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_shader_compile_errors(GLuint shader, std::string_view shaderType)
|
|
||||||
{
|
|
||||||
GLint success;
|
|
||||||
GLchar infoLog[1024];
|
|
||||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
|
|
||||||
spdlog::error("Failed to compile {} shader: {}", shaderType, infoLog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void log_program_compile_errors(GLuint program)
|
|
||||||
{
|
|
||||||
GLint success;
|
|
||||||
GLchar infoLog[1024];
|
|
||||||
glGetProgramiv(program, GL_COMPILE_STATUS, &success);
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
glGetShaderInfoLog(program, 1024, NULL, infoLog);
|
|
||||||
spdlog::error("Failed to compile program: {}", infoLog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,13 +15,13 @@
|
|||||||
class ShaderProgram
|
class ShaderProgram
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<ShaderProgram> load(std::string_view vertexPath, std::string_view fragmentPath);
|
explicit ShaderProgram(GLuint id) : id(id) {}
|
||||||
|
|
||||||
void bind();
|
void bind();
|
||||||
void unbind();
|
static void unbind();
|
||||||
|
|
||||||
void setFloat(std::string_view name, float value) const;
|
void setFloat(std::string_view name, float value) const;
|
||||||
void setVec2(std::string_view name, const glm::vec2 &value) const;
|
void setInt(std::string_view name, int value) const;
|
||||||
void setVec3(std::string_view name, const glm::vec3 &value) const;
|
void setVec3(std::string_view name, const glm::vec3 &value) const;
|
||||||
void setMat4(std::string_view name, const glm::mat4 &mat) const;
|
void setMat4(std::string_view name, const glm::mat4 &mat) const;
|
||||||
void setVec4(std::string_view name, const glm::vec4 &value) const;
|
void setVec4(std::string_view name, const glm::vec4 &value) const;
|
||||||
|
|||||||
@@ -5,21 +5,21 @@
|
|||||||
#ifndef B_ENGINE_TEXTURE_H
|
#ifndef B_ENGINE_TEXTURE_H
|
||||||
#define B_ENGINE_TEXTURE_H
|
#define B_ENGINE_TEXTURE_H
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <glad/gl.h>
|
||||||
|
|
||||||
class Texture
|
class Texture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<Texture> load_from_file(std::string_view filePath);
|
Texture(unsigned int id, std::string_view filePath, int width, int height, int channels)
|
||||||
static std::shared_ptr<Texture> load_from_data(unsigned char* data, int width, int height, int channels);
|
: id(id), filePath(filePath), width(width), height(height), channels(channels) {}
|
||||||
|
|
||||||
Texture() = default;
|
~Texture() { glDeleteTextures(1, &id); }
|
||||||
~Texture();
|
|
||||||
|
|
||||||
void bind(unsigned int slot);
|
void bind() const {glBindTexture(GL_TEXTURE_2D, id);}
|
||||||
void unbind();
|
static void unbind() {glBindTexture(GL_TEXTURE_2D, 0);}
|
||||||
|
|
||||||
[[nodiscard]] int get_width() const { return width; }
|
[[nodiscard]] int get_width() const { return width; }
|
||||||
[[nodiscard]] int get_height() const { return height; }
|
[[nodiscard]] int get_height() const { return height; }
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//
|
//
|
||||||
// Created by lbmas on 4/29/2026.
|
// Created by slinky on 5/1/26.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "Texture.h"
|
#include "TextureLoader.h"
|
||||||
|
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
@@ -10,7 +10,9 @@
|
|||||||
|
|
||||||
#include "glad/gl.h"
|
#include "glad/gl.h"
|
||||||
|
|
||||||
std::shared_ptr<Texture> Texture::load_from_file(std::string_view filePath)
|
std::unordered_map<std::string, std::shared_ptr<Texture>> TextureLoader::textures;
|
||||||
|
|
||||||
|
std::shared_ptr<Texture> TextureLoader::load_from_file(std::string_view filePath)
|
||||||
{
|
{
|
||||||
int width, height, channels;
|
int width, height, channels;
|
||||||
unsigned char *data = stbi_load(filePath.data(), &width, &height, &channels, 0);
|
unsigned char *data = stbi_load(filePath.data(), &width, &height, &channels, 0);
|
||||||
@@ -20,9 +22,9 @@ std::shared_ptr<Texture> Texture::load_from_file(std::string_view filePath)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture texture = {};
|
unsigned int textureID = 0;
|
||||||
glGenTextures(1, &texture.id);
|
glGenTextures(1, &textureID);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture.id);
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
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_MAG_FILTER, GL_LINEAR);
|
||||||
@@ -36,18 +38,14 @@ std::shared_ptr<Texture> Texture::load_from_file(std::string_view filePath)
|
|||||||
|
|
||||||
stbi_image_free(data);
|
stbi_image_free(data);
|
||||||
|
|
||||||
texture.filePath = filePath;
|
return std::make_shared<Texture>(textureID, filePath, width, height, channels);
|
||||||
texture.width = width;
|
|
||||||
texture.height = height;
|
|
||||||
texture.channels = channels;
|
|
||||||
return std::make_shared<Texture>(texture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Texture> Texture::load_from_data(unsigned char* data, int width, int height, int channels)
|
std::shared_ptr<Texture> TextureLoader::load_from_data(unsigned char* data, int width, int height, int channels)
|
||||||
{
|
{
|
||||||
Texture texture = {};
|
unsigned int textureID = 0;
|
||||||
glGenTextures(1, &texture.id);
|
glGenTextures(1, &textureID);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture.id);
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
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_MAG_FILTER, GL_LINEAR);
|
||||||
@@ -59,24 +57,5 @@ std::shared_ptr<Texture> Texture::load_from_data(unsigned char* data, int width,
|
|||||||
glTexImage2D(GL_TEXTURE_2D, 0, (GLint)format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
|
glTexImage2D(GL_TEXTURE_2D, 0, (GLint)format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
|
||||||
texture.filePath = "";
|
return std::make_shared<Texture>(textureID, "memory", width, height, channels);
|
||||||
texture.width = width;
|
|
||||||
texture.height = height;
|
|
||||||
texture.channels = channels;
|
|
||||||
return std::make_shared<Texture>(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
Texture::~Texture()
|
|
||||||
{
|
|
||||||
glDeleteTextures(1, &id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Texture::bind(unsigned int slot)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Texture::unbind()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
21
src/TextureLoader.h
Normal file
21
src/TextureLoader.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// Created by slinky on 5/1/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef B_ENGINE_TEXTURELOADER_H
|
||||||
|
#define B_ENGINE_TEXTURELOADER_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "Texture.h"
|
||||||
|
|
||||||
|
class TextureLoader {
|
||||||
|
public:
|
||||||
|
static std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
|
||||||
|
|
||||||
|
static std::shared_ptr<Texture> load_from_file(std::string_view filePath);
|
||||||
|
static std::shared_ptr<Texture> load_from_data(unsigned char* data, int width, int height, int channels);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //B_ENGINE_TEXTURELOADER_H
|
||||||
80
src/main.cpp
80
src/main.cpp
@@ -11,8 +11,11 @@
|
|||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
|
#include "ModelLoader.h"
|
||||||
|
#include "ShaderLoader.h"
|
||||||
#include "ShaderProgram.h"
|
#include "ShaderProgram.h"
|
||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
|
#include "TextureLoader.h"
|
||||||
|
|
||||||
GLFWwindow* gWindow = nullptr;
|
GLFWwindow* gWindow = nullptr;
|
||||||
int gWindowWidth = 800;
|
int gWindowWidth = 800;
|
||||||
@@ -25,10 +28,6 @@ auto cameraPosition = glm::vec3{0, 0, 0};
|
|||||||
auto view = glm::mat4{0};
|
auto view = glm::mat4{0};
|
||||||
auto projection = glm::mat4{0};
|
auto projection = glm::mat4{0};
|
||||||
|
|
||||||
std::unordered_map<std::string, std::shared_ptr<Model>> gModels = {};
|
|
||||||
std::unordered_map<std::string, std::shared_ptr<Texture>> gTextures = {};
|
|
||||||
std::unordered_map<std::string, std::shared_ptr<ShaderProgram>> gShaders = {};
|
|
||||||
|
|
||||||
void glfw_error_callback(int error, const char* description);
|
void glfw_error_callback(int error, const char* description);
|
||||||
void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||||
void glfw_framebuffer_size_callback(GLFWwindow* window, int width, int height);
|
void glfw_framebuffer_size_callback(GLFWwindow* window, int width, int height);
|
||||||
@@ -37,6 +36,7 @@ void init_glfw();
|
|||||||
void create_main_window();
|
void create_main_window();
|
||||||
void load_gl();
|
void load_gl();
|
||||||
void init_camera();
|
void init_camera();
|
||||||
|
void loop();
|
||||||
|
|
||||||
std::shared_ptr<Model> load_model(std::string_view _path);
|
std::shared_ptr<Model> load_model(std::string_view _path);
|
||||||
|
|
||||||
@@ -55,26 +55,21 @@ int main() {
|
|||||||
|
|
||||||
// create a default texture
|
// create a default texture
|
||||||
unsigned char defaultDiffuseData[4] = {static_cast<unsigned char>(255), 255, 255, 255};
|
unsigned char defaultDiffuseData[4] = {static_cast<unsigned char>(255), 255, 255, 255};
|
||||||
gTextures["default_diffuse"] = Texture::load_from_data(reinterpret_cast<unsigned char*>(&defaultDiffuseData), 1, 1, 4);
|
TextureLoader::textures["default_diffuse"] = TextureLoader::load_from_data(reinterpret_cast<unsigned char*>(&defaultDiffuseData), 1, 1, 4);
|
||||||
|
|
||||||
// create a default specular map
|
// create a default specular map
|
||||||
unsigned char defaultSpecularData[4] = {static_cast<unsigned char>(128), 128, 128, 255};
|
unsigned char defaultSpecularData[4] = {static_cast<unsigned char>(128), 128, 128, 255};
|
||||||
gTextures["default_specular"] = Texture::load_from_data(reinterpret_cast<unsigned char*>(&defaultSpecularData), 1, 1, 4);
|
TextureLoader::textures["default_specular"] = TextureLoader::load_from_data(reinterpret_cast<unsigned char*>(&defaultSpecularData), 1, 1, 4);
|
||||||
|
|
||||||
gShaders["phong_shader"] = ShaderProgram::load("./resources/standard.frag", "./resources/standard.vert");
|
ShaderLoader::shaders["phong_shader"] = ShaderLoader::load("./resources/standard.vert", "./resources/standard.frag");
|
||||||
if (gShaders["phong_shader"] == nullptr)
|
if (ShaderLoader::shaders["phong_shader"] == nullptr)
|
||||||
{
|
{
|
||||||
std::exit(1);
|
std::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(gWindow)) {
|
ModelLoader::models["cube"] = ModelLoader::load_from_file("./resources/cube.obj");
|
||||||
glfwPollEvents();
|
|
||||||
|
|
||||||
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
loop();
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
glfwSwapBuffers(gWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwDestroyWindow(gWindow);
|
glfwDestroyWindow(gWindow);
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
@@ -153,7 +148,56 @@ void init_camera()
|
|||||||
projection = glm::perspective(glm::radians(75.f), aspectRatio, 0.1f, 100.0f);
|
projection = glm::perspective(glm::radians(75.f), aspectRatio, 0.1f, 100.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Model> load_model(std::string_view _path)
|
void loop() {
|
||||||
{
|
Texture* defaultDiffuse = TextureLoader::textures["default_diffuse"].get();
|
||||||
return std::make_shared<Model>();
|
Texture* defaultSpecular = TextureLoader::textures["default_specular"].get();
|
||||||
|
|
||||||
|
while (!glfwWindowShouldClose(gWindow)) {
|
||||||
|
auto modelMatrix = glm::identity<glm::mat4>();
|
||||||
|
glfwPollEvents();
|
||||||
|
|
||||||
|
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
ShaderProgram* shader = ShaderLoader::shaders["phong_shader"].get();
|
||||||
|
Model* model = ModelLoader::models["cube"].get();
|
||||||
|
|
||||||
|
if (shader && model) {
|
||||||
|
Material* mat = model->materials[0].get();
|
||||||
|
shader->bind();
|
||||||
|
|
||||||
|
shader->setMat4("projection", projection);
|
||||||
|
shader->setMat4("view", view);
|
||||||
|
shader->setMat4("model", modelMatrix);
|
||||||
|
|
||||||
|
shader->setVec3("viewPosition", cameraPosition);
|
||||||
|
|
||||||
|
if (mat) {
|
||||||
|
shader->setVec3("phongAmbient", mat->phong.ambient);
|
||||||
|
shader->setVec3("phongDiffuse", mat->phong.diffuse);
|
||||||
|
shader->setVec3("phongSpecular", mat->phong.specular);
|
||||||
|
shader->setFloat("phongShininess", mat->phong.shininess);
|
||||||
|
}
|
||||||
|
|
||||||
|
shader->setVec3("lightPosition", glm::vec3(5.f, 5.f, 5.f));
|
||||||
|
shader->setVec3("lightAmbient", glm::vec3{.1f, .1f, .1f});
|
||||||
|
shader->setVec3("lightDiffuse", glm::vec3{.8f, .8f, .8f});
|
||||||
|
shader->setVec3("lightSpecular", glm::vec3{1.f, 1.f, 1.f});
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
defaultDiffuse->bind();
|
||||||
|
shader->setInt("diffuse1", 0);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
defaultSpecular->bind();
|
||||||
|
shader->setInt("specular1", 1);
|
||||||
|
|
||||||
|
for (auto mesh: model->meshes) {
|
||||||
|
glBindVertexArray(mesh.get()->vao);
|
||||||
|
glDrawElements(GL_TRIANGLES, mesh->numIndices, GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwSwapBuffers(gWindow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user