Huge stuff. camera, input manager (mouse + keyboard), can move around scene now
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 4.1)
|
cmake_minimum_required(VERSION 4.1)
|
||||||
project(b_engine VERSION 0.0.1 LANGUAGES CXX C)
|
project(b_engine VERSION 0.0.2 LANGUAGES CXX C)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
@@ -26,17 +26,27 @@ add_executable(${PROJECT_NAME}
|
|||||||
src/Mesh.h
|
src/Mesh.h
|
||||||
src/Model.cpp
|
src/Model.cpp
|
||||||
src/Model.h
|
src/Model.h
|
||||||
src/Material.cpp
|
|
||||||
src/Material.h
|
src/Material.h
|
||||||
src/ModelLoader.cpp
|
src/ModelManager.cpp
|
||||||
src/ModelLoader.h
|
src/ModelManager.h
|
||||||
src/ShaderProgram.cpp
|
src/ShaderProgram.cpp
|
||||||
src/ShaderProgram.h
|
src/ShaderProgram.h
|
||||||
src/Texture.h
|
src/Texture.h
|
||||||
src/TextureLoader.cpp
|
src/TextureManager.cpp
|
||||||
src/TextureLoader.h
|
src/TextureManager.h
|
||||||
src/ShaderManager.cpp
|
src/ShaderManager.cpp
|
||||||
src/ShaderManager.h)
|
src/ShaderManager.h
|
||||||
|
src/FreeCamera.cpp
|
||||||
|
src/FreeCamera.h
|
||||||
|
src/InputManager.cpp
|
||||||
|
src/InputManager.h)
|
||||||
|
|
||||||
|
add_custom_target(copy_resources
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/resources"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/resources"
|
||||||
|
COMMENT "Copying resources..."
|
||||||
|
)
|
||||||
|
|
||||||
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})
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Ke 0.0 0.0 0.0
|
|||||||
Ni 1.450000
|
Ni 1.450000
|
||||||
d 1.000000
|
d 1.000000
|
||||||
illum 2
|
illum 2
|
||||||
map_Kd backpack/diffuse.jpg
|
map_Kd diffuse.jpg
|
||||||
map_Bump backpack/normal.png
|
map_Bump normal.png
|
||||||
map_Ks backpack/specular.jpg
|
map_Ks specular.jpg
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ in vec3 Position;
|
|||||||
in vec2 TexCoord;
|
in vec2 TexCoord;
|
||||||
in vec3 Normal;
|
in vec3 Normal;
|
||||||
|
|
||||||
uniform sampler2D diffuse;
|
uniform sampler2D diffuseMap;
|
||||||
|
uniform sampler2D specularMap;
|
||||||
|
|
||||||
uniform vec3 viewPosition;
|
uniform vec3 viewPosition;
|
||||||
|
|
||||||
@@ -15,22 +16,30 @@ uniform vec3 phongDiffuse;
|
|||||||
uniform vec3 phongSpecular;
|
uniform vec3 phongSpecular;
|
||||||
uniform float phongShininess;
|
uniform float phongShininess;
|
||||||
|
|
||||||
|
uniform vec3 lightPosition;
|
||||||
uniform vec3 lightDirection;
|
uniform vec3 lightDirection;
|
||||||
uniform vec3 lightAmbient;
|
uniform vec3 lightAmbient;
|
||||||
uniform vec3 lightDiffuse;
|
uniform vec3 lightDiffuse;
|
||||||
uniform vec3 lightSpecular;
|
uniform vec3 lightSpecular;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 diffuseColor = texture(diffuse, TexCoord);
|
vec3 diffuseColor = texture(diffuseMap, TexCoord).rgb;
|
||||||
|
vec3 specularColor = texture(specularMap, TexCoord).rgb;
|
||||||
|
|
||||||
vec3 norm = normalize(Normal);
|
vec3 norm = normalize(Normal);
|
||||||
vec3 lightDir = normalize(-lightDirection);
|
vec3 lightDir = normalize(-lightDirection);
|
||||||
|
vec3 viewDir = normalize(viewPosition - Position);
|
||||||
|
|
||||||
vec3 ambient = phongAmbient * vec3(diffuseColor);
|
vec3 ambient = lightAmbient * (diffuseColor * phongAmbient);
|
||||||
|
|
||||||
float diffImpact = max(dot(norm, lightDir), 0.0);
|
float diffImpact = max(dot(norm, lightDir), 0.0);
|
||||||
vec3 diffuse = (phongDiffuse * vec3(diffuseColor)) * diffImpact;
|
vec3 diffuse = lightDiffuse * (diffImpact * diffuseColor * phongDiffuse);
|
||||||
|
|
||||||
vec3 result = ambient + diffuse;
|
vec3 reflectDir = reflect(-lightDir, norm);
|
||||||
|
float effectiveShininess = max(phongShininess, 1.0);
|
||||||
|
float spec = pow(max(dot(viewDir, reflectDir), 0.0), effectiveShininess);
|
||||||
|
vec3 specular = lightSpecular * (spec * specularColor * phongSpecular);
|
||||||
|
|
||||||
|
vec3 result = ambient + diffuse + specular;
|
||||||
FragColor = vec4(result, 1.0);
|
FragColor = vec4(result, 1.0);
|
||||||
}
|
}
|
||||||
99
src/FreeCamera.cpp
Normal file
99
src/FreeCamera.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
//
|
||||||
|
// Created by slinky on 5/3/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "FreeCamera.h"
|
||||||
|
|
||||||
|
#include "glm/ext/matrix_transform.hpp"
|
||||||
|
#include "glm/ext/matrix_clip_space.hpp"
|
||||||
|
|
||||||
|
FreeCamera::FreeCamera(const glm::vec3 &pos, float pitch, float yaw, float aspectRatio) : _position(pos), _yaw(yaw), _pitch(pitch), _aspectRatio(aspectRatio) {
|
||||||
|
update_camera_vectors();
|
||||||
|
update_view();
|
||||||
|
update_projection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::mat4& FreeCamera::view() const {
|
||||||
|
return _view;
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::mat4& FreeCamera::projection() const {
|
||||||
|
return _projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::vec3& FreeCamera::position() const {
|
||||||
|
return _position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeCamera::rotate_pitch(float offset) {
|
||||||
|
_pitch += offset;
|
||||||
|
|
||||||
|
if (_pitch < MIN_PITCH) {
|
||||||
|
_pitch = MIN_PITCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pitch > MAX_PITCH) {
|
||||||
|
_pitch = MAX_PITCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_camera_vectors();
|
||||||
|
update_view();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeCamera::rotate_yaw(float offset) {
|
||||||
|
_yaw += offset;
|
||||||
|
update_camera_vectors();
|
||||||
|
update_view();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeCamera::move(CAMERA_MOVEMENT direction, float offset) {
|
||||||
|
glm::vec3 finalDirection = {};
|
||||||
|
|
||||||
|
switch (direction) {
|
||||||
|
case FORWARD:
|
||||||
|
finalDirection = front;
|
||||||
|
break;
|
||||||
|
case BACKWARD:
|
||||||
|
finalDirection = -front;
|
||||||
|
break;
|
||||||
|
case LEFT:
|
||||||
|
finalDirection = -right;
|
||||||
|
break;
|
||||||
|
case RIGHT:
|
||||||
|
finalDirection = right;
|
||||||
|
break;
|
||||||
|
case UP:
|
||||||
|
finalDirection = up;
|
||||||
|
break;
|
||||||
|
case DOWN:
|
||||||
|
finalDirection = -up;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalDirection = glm::normalize(finalDirection);
|
||||||
|
_position += finalDirection * offset;
|
||||||
|
_view = glm::lookAt(_position, _position + front, up);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeCamera::update_aspect_ratio(float aspectRatio) {
|
||||||
|
_aspectRatio = aspectRatio;
|
||||||
|
_projection = glm::perspective(glm::radians(75.f), _aspectRatio, 0.1f, 100.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeCamera::update_camera_vectors() {
|
||||||
|
front = {};
|
||||||
|
front.x = cos(glm::radians(_yaw)) * cos(glm::radians(_pitch));
|
||||||
|
front.y = sin(glm::radians(_pitch));
|
||||||
|
front.z = sin(glm::radians(_yaw)) * cos(glm::radians(_pitch));
|
||||||
|
|
||||||
|
right = glm::normalize(glm::cross(front, WORLD_UP));
|
||||||
|
up = glm::normalize(glm::cross(right, front));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeCamera::update_projection() {
|
||||||
|
_projection = glm::perspective(glm::radians(75.f), _aspectRatio, 0.1f, 100.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeCamera::update_view() {
|
||||||
|
_view = glm::lookAt(_position, _position + front, up);
|
||||||
|
}
|
||||||
61
src/FreeCamera.h
Normal file
61
src/FreeCamera.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
//
|
||||||
|
// Created by slinky on 5/3/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef B_ENGINE_CAMERA_H
|
||||||
|
#define B_ENGINE_CAMERA_H
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
constexpr float MAX_PITCH = 89.f;
|
||||||
|
constexpr float MIN_PITCH = -89.f;
|
||||||
|
|
||||||
|
constexpr glm::vec3 WORLD_UP = {0.0f, 1.0f, 0.0f};
|
||||||
|
|
||||||
|
enum CAMERA_MOVEMENT {
|
||||||
|
FORWARD,
|
||||||
|
BACKWARD,
|
||||||
|
LEFT,
|
||||||
|
RIGHT,
|
||||||
|
UP,
|
||||||
|
DOWN,
|
||||||
|
};
|
||||||
|
|
||||||
|
class FreeCamera {
|
||||||
|
public:
|
||||||
|
FreeCamera() = default;
|
||||||
|
FreeCamera(const glm::vec3 &pos, float pitch, float yaw, float aspectRatio);
|
||||||
|
|
||||||
|
[[nodiscard]] const glm::mat4& projection() const;
|
||||||
|
[[nodiscard]] const glm::mat4& view() const;
|
||||||
|
[[nodiscard]] const glm::vec3& position() const;
|
||||||
|
|
||||||
|
void update_aspect_ratio(float aspectRatio);
|
||||||
|
void rotate_yaw(float offset);
|
||||||
|
void rotate_pitch(float offset);
|
||||||
|
|
||||||
|
void move(CAMERA_MOVEMENT direction, float offset);
|
||||||
|
private:
|
||||||
|
void update_camera_vectors();
|
||||||
|
void update_projection();
|
||||||
|
void update_view();
|
||||||
|
|
||||||
|
glm::vec3 _position{};
|
||||||
|
|
||||||
|
glm::vec3 front{};
|
||||||
|
glm::vec3 up{};
|
||||||
|
glm::vec3 right{};
|
||||||
|
|
||||||
|
glm::mat4 _view{};
|
||||||
|
glm::mat4 _projection{};
|
||||||
|
|
||||||
|
float _yaw = 0;
|
||||||
|
float _pitch = 0;
|
||||||
|
|
||||||
|
float _aspectRatio = 0;
|
||||||
|
|
||||||
|
float _sensitivity = 0.1f;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //B_ENGINE_CAMERA_H
|
||||||
118
src/InputManager.cpp
Normal file
118
src/InputManager.cpp
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
//
|
||||||
|
// Created by slinky on 5/3/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "InputManager.h"
|
||||||
|
|
||||||
|
bool InputManager::mouseInit = false;
|
||||||
|
float InputManager::lastMousePositionX = 0;
|
||||||
|
float InputManager::lastMousePositionY = 0;
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<InputAction>> InputManager::registeredActions = {};
|
||||||
|
|
||||||
|
static bool currentKeyStatesData[512] = {};
|
||||||
|
bool* InputManager::currentKeyStates = currentKeyStatesData;
|
||||||
|
|
||||||
|
static bool previousKeyStatesData[512] = {};
|
||||||
|
bool* InputManager::previousKeyStates = previousKeyStatesData;
|
||||||
|
|
||||||
|
std::vector<MouseDeltaCallback> InputManager::mouse_listeners = {};
|
||||||
|
|
||||||
|
void InputManager::mouse_pos_callback(GLFWwindow *window, double x, double y) {
|
||||||
|
const auto xpos = static_cast<float>(x);
|
||||||
|
const auto ypos = static_cast<float>(y);
|
||||||
|
|
||||||
|
if (!mouseInit) {
|
||||||
|
lastMousePositionX = xpos;
|
||||||
|
lastMousePositionY = ypos;
|
||||||
|
mouseInit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float xOff = xpos - lastMousePositionX;
|
||||||
|
float yOff = lastMousePositionY - ypos;
|
||||||
|
|
||||||
|
lastMousePositionX = xpos;
|
||||||
|
lastMousePositionY = ypos;
|
||||||
|
|
||||||
|
for (const auto& cb : mouse_listeners) {
|
||||||
|
cb(xOff, yOff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputManager::add_mouse_listener(MouseDeltaCallback callback) {
|
||||||
|
mouse_listeners.push_back(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputManager::key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
||||||
|
if (action == GLFW_REPEAT) return;
|
||||||
|
|
||||||
|
set_key_state(key, action == GLFW_PRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputManager::generate_input_action(std::string_view actionName, std::initializer_list<InputRequirement> requirements) {
|
||||||
|
if (registeredActions.contains(actionName.data())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputAction action;
|
||||||
|
for (const auto& requirement : requirements) {
|
||||||
|
action.requirements.push_back(requirement);
|
||||||
|
}
|
||||||
|
const std::string key = actionName.data();
|
||||||
|
registeredActions[key] = std::make_unique<InputAction>(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputManager::check_action_performed(std::string_view actionName) {
|
||||||
|
if (!registeredActions.contains(actionName.data())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputAction* action = registeredActions[actionName.data()].get();
|
||||||
|
|
||||||
|
if (!action) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto&[key, state] : action->requirements) {
|
||||||
|
switch (state) {
|
||||||
|
case KEY_DOWN:
|
||||||
|
if (!key_down(key))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case KEY_HELD:
|
||||||
|
if (!key_held(key))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case KEY_PRESSED:
|
||||||
|
if (!key_pressed(key))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case KEY_RELEASED:
|
||||||
|
if (!key_released(key))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputManager::key_down(int key) {
|
||||||
|
return currentKeyStatesData[key];
|
||||||
|
}
|
||||||
|
bool InputManager::key_up(int key) {
|
||||||
|
return !currentKeyStatesData[key];
|
||||||
|
}
|
||||||
|
bool InputManager::key_pressed(int key) {
|
||||||
|
return !previousKeyStatesData[key] && currentKeyStatesData[key];
|
||||||
|
}
|
||||||
|
bool InputManager::key_released(int key) {
|
||||||
|
return previousKeyStatesData[key] && !currentKeyStatesData[key];
|
||||||
|
}
|
||||||
|
bool InputManager::key_held(int key) {
|
||||||
|
return previousKeyStatesData[key] && currentKeyStatesData[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputManager::set_key_state(int key, bool state) {
|
||||||
|
previousKeyStatesData[key] = currentKeyStatesData[key];
|
||||||
|
currentKeyStatesData[key] = state;
|
||||||
|
}
|
||||||
61
src/InputManager.h
Normal file
61
src/InputManager.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
//
|
||||||
|
// Created by slinky on 5/3/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef B_ENGINE_INPUTMANAGER_H
|
||||||
|
#define B_ENGINE_INPUTMANAGER_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
|
using MouseDeltaCallback = std::function<void(float, float)>;
|
||||||
|
|
||||||
|
enum KeyState {
|
||||||
|
KEY_PRESSED,
|
||||||
|
KEY_HELD,
|
||||||
|
KEY_DOWN,
|
||||||
|
KEY_RELEASED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InputRequirement {
|
||||||
|
int key;
|
||||||
|
KeyState state;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InputAction {
|
||||||
|
std::vector<InputRequirement> requirements{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class InputManager {
|
||||||
|
public:
|
||||||
|
static bool mouseInit;
|
||||||
|
static float lastMousePositionX;
|
||||||
|
static float lastMousePositionY;
|
||||||
|
|
||||||
|
static bool* currentKeyStates;
|
||||||
|
static bool* previousKeyStates;
|
||||||
|
|
||||||
|
static std::unordered_map<std::string, std::unique_ptr<InputAction>> registeredActions;
|
||||||
|
|
||||||
|
static void mouse_pos_callback(GLFWwindow* window, double x, double y);
|
||||||
|
static void add_mouse_listener(MouseDeltaCallback callback);
|
||||||
|
|
||||||
|
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||||
|
static void generate_input_action(std::string_view actionName, std::initializer_list<InputRequirement> requirements);
|
||||||
|
static bool check_action_performed(std::string_view actionName);
|
||||||
|
|
||||||
|
static bool key_pressed(int key);
|
||||||
|
static bool key_held(int key);
|
||||||
|
static bool key_released(int key);
|
||||||
|
static bool key_down(int key);
|
||||||
|
static bool key_up(int key);
|
||||||
|
private:
|
||||||
|
static std::vector<MouseDeltaCallback> mouse_listeners;
|
||||||
|
static void set_key_state(int key, bool state);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //B_ENGINE_INPUTMANAGER_H
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by lbmas on 4/28/2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Material.h"
|
|
||||||
@@ -8,7 +8,6 @@ Mesh::Mesh(const std::vector<float> &positions, const std::vector<float> &uvs, c
|
|||||||
ebo = 0;
|
ebo = 0;
|
||||||
numIndices = indices.size();
|
numIndices = indices.size();
|
||||||
|
|
||||||
|
|
||||||
// positions
|
// positions
|
||||||
GLuint positionVbo = 0;
|
GLuint positionVbo = 0;
|
||||||
glGenBuffers(1, &positionVbo);
|
glGenBuffers(1, &positionVbo);
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ public:
|
|||||||
const std::vector<float>& normals,
|
const std::vector<float>& normals,
|
||||||
const std::vector<unsigned int>& indices);
|
const std::vector<unsigned int>& indices);
|
||||||
|
|
||||||
GLuint vao;
|
GLuint vao = 0;
|
||||||
GLuint ebo;
|
GLuint ebo = 0;
|
||||||
unsigned int numIndices;
|
unsigned int numIndices = 0;
|
||||||
|
unsigned int materialId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //B_ENGINE_MESH_H
|
#endif //B_ENGINE_MESH_H
|
||||||
@@ -7,15 +7,13 @@
|
|||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include "Mesh.h"
|
#include "Mesh.h"
|
||||||
#include "Material.h"
|
#include "Material.h"
|
||||||
|
|
||||||
class Model
|
struct Model
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
static std::shared_ptr<Model> load_from_file(std::string_view filename);
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Mesh>> meshes;
|
std::vector<std::shared_ptr<Mesh>> meshes;
|
||||||
std::vector<std::shared_ptr<Material>> materials;
|
std::vector<std::shared_ptr<Material>> materials;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#include "ModelLoader.h"
|
#include "ModelManager.h"
|
||||||
|
|
||||||
#include <assimp/Importer.hpp>
|
#include <assimp/Importer.hpp>
|
||||||
#include <assimp/postprocess.h>
|
#include <assimp/postprocess.h>
|
||||||
@@ -12,15 +12,17 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "TextureLoader.h"
|
#include "TextureManager.h"
|
||||||
#include "glm/ext/matrix_transform.hpp"
|
#include "glm/ext/matrix_transform.hpp"
|
||||||
|
|
||||||
std::unordered_map<std::string, std::shared_ptr<Model>> ModelLoader::models;
|
std::unordered_map<std::string, std::shared_ptr<Model>> ModelManager::models;
|
||||||
|
|
||||||
void process_ai_mesh(aiMesh* aiMesh, const aiScene* scene, glm::mat4 transform, Mesh& mesh);
|
void process_ai_mesh(aiMesh* aiMesh, const aiScene* scene, glm::mat4 transform, Mesh& mesh);
|
||||||
void process_ai_node(aiNode* node, const aiScene* scene, glm::mat4 transform, Model* model);
|
void process_ai_node(aiNode* node, const aiScene* scene, glm::mat4 transform, Model* model);
|
||||||
|
|
||||||
void process_ai_material(aiMaterial* aiMat, const aiScene* scene, Material& mat);
|
void process_ai_material(aiMaterial* aiMat, const aiScene* scene, Material& mat, const std::filesystem::path& modelDirectory);
|
||||||
|
void process_ai_material_diffuse(const aiMaterial *aiMat, Material& mat, const std::filesystem::path& modelDirectory);
|
||||||
|
void process_ai_material_specular(const aiMaterial *aiMat, Material& mat, const std::filesystem::path& modelDirectory);
|
||||||
|
|
||||||
auto zUpMatrix = glm::mat4(
|
auto zUpMatrix = glm::mat4(
|
||||||
1.0f, 0.0f, 0.0f, 0.0f, // Column 0
|
1.0f, 0.0f, 0.0f, 0.0f, // Column 0
|
||||||
@@ -29,7 +31,7 @@ auto zUpMatrix = glm::mat4(
|
|||||||
0.0f, 0.0f, 0.0f, 1.0f // Column 3
|
0.0f, 0.0f, 0.0f, 1.0f // Column 3
|
||||||
);
|
);
|
||||||
|
|
||||||
std::shared_ptr<Model> ModelLoader::load_from_file(std::string_view _path, bool zUp)
|
std::shared_ptr<Model> ModelManager::load_from_file(std::string_view _path, bool zUp)
|
||||||
{
|
{
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
|
|
||||||
@@ -46,6 +48,16 @@ std::shared_ptr<Model> ModelLoader::load_from_file(std::string_view _path, bool
|
|||||||
|
|
||||||
auto model = std::make_shared<Model>();
|
auto model = std::make_shared<Model>();
|
||||||
|
|
||||||
|
std::filesystem::path modelPath = {_path};
|
||||||
|
|
||||||
|
model->materials.resize(scene->mNumMaterials);
|
||||||
|
for (unsigned int i = 0; i < scene->mNumMaterials; i++) {
|
||||||
|
aiMaterial* aiMat = scene->mMaterials[i];
|
||||||
|
Material mat{};
|
||||||
|
process_ai_material(aiMat, scene, mat, modelPath.parent_path());
|
||||||
|
model->materials[i] = std::make_shared<Material>(mat);
|
||||||
|
}
|
||||||
|
|
||||||
auto transform = glm::identity<glm::mat4>();
|
auto transform = glm::identity<glm::mat4>();
|
||||||
if (zUp) {
|
if (zUp) {
|
||||||
transform = zUpMatrix;
|
transform = zUpMatrix;
|
||||||
@@ -58,20 +70,16 @@ std::shared_ptr<Model> ModelLoader::load_from_file(std::string_view _path, bool
|
|||||||
|
|
||||||
void process_ai_node(aiNode* node, const aiScene* scene, glm::mat4 transform, Model* model)
|
void process_ai_node(aiNode* node, const aiScene* scene, glm::mat4 transform, Model* model)
|
||||||
{
|
{
|
||||||
auto m = node->mTransformation;
|
const auto t = node->mTransformation;
|
||||||
transform = transform * glm::mat4(m.a1, m.a2, m.a3, m.a4, m.b1, m.b2, m.b3, m.b4, m.c1, m.c2, m.c3, m.c4, m.d1, m.d2, m.d3, m.d4);
|
transform = transform * glm::mat4(t.a1, t.a2, t.a3, t.a4, t.b1, t.b2, t.b3, t.b4, t.c1, t.c2, t.c3, t.c4, t.d1, t.d2, t.d3, t.d4);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < node->mNumMeshes; i++)
|
for (unsigned int i = 0; i < node->mNumMeshes; i++)
|
||||||
{
|
{
|
||||||
aiMesh* aiMesh = scene->mMeshes[node->mMeshes[i]];
|
aiMesh* aiMesh = scene->mMeshes[node->mMeshes[i]];
|
||||||
Mesh mesh{};
|
Mesh mesh{};
|
||||||
|
mesh.materialId = aiMesh->mMaterialIndex;
|
||||||
process_ai_mesh(aiMesh, scene, transform, mesh);
|
process_ai_mesh(aiMesh, scene, transform, mesh);
|
||||||
model->meshes.push_back(std::make_shared<Mesh>(mesh));
|
model->meshes.push_back(std::make_shared<Mesh>(mesh));
|
||||||
|
|
||||||
aiMaterial* aiMat = scene->mMaterials[aiMesh->mMaterialIndex];
|
|
||||||
Material mat{};
|
|
||||||
process_ai_material(aiMat, scene, mat);
|
|
||||||
model->materials.push_back(std::make_shared<Material>(mat));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < node->mNumChildren; i++)
|
for (unsigned int i = 0; i < node->mNumChildren; i++)
|
||||||
@@ -130,7 +138,7 @@ void process_ai_mesh(aiMesh* aiMesh, const aiScene* scene, glm::mat4 transform,
|
|||||||
mesh = {positions, uvs, normals, indices};
|
mesh = {positions, uvs, normals, indices};
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_ai_material(aiMaterial* aiMat, const aiScene* scene, Material& mat) {
|
void process_ai_material(aiMaterial* aiMat, const aiScene* scene, Material& mat, const std::filesystem::path& modelDirectory) {
|
||||||
aiString matName;
|
aiString matName;
|
||||||
aiReturn ret = aiMat->Get(AI_MATKEY_NAME, matName);
|
aiReturn ret = aiMat->Get(AI_MATKEY_NAME, matName);
|
||||||
if (ret != AI_SUCCESS) {
|
if (ret != AI_SUCCESS) {
|
||||||
@@ -167,14 +175,8 @@ void process_ai_material(aiMaterial* aiMat, const aiScene* scene, Material& mat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now grab the textures, first diffuse
|
// now grab the textures, first diffuse
|
||||||
for (unsigned int i = 0; i < aiMat->GetTextureCount(aiTextureType_DIFFUSE); i++) {
|
process_ai_material_diffuse(aiMat, mat, modelDirectory);
|
||||||
aiString textureName;
|
process_ai_material_specular(aiMat, mat, modelDirectory);
|
||||||
aiMat->GetTexture(aiTextureType_DIFFUSE, i, &textureName);
|
|
||||||
|
|
||||||
if (!TextureLoader::textures.contains(textureName.C_Str())) {
|
|
||||||
TextureLoader::textures[textureName.C_Str()] = TextureLoader::load_from_file(textureName.C_Str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mat.name = matName.C_Str();
|
mat.name = matName.C_Str();
|
||||||
mat.phong.ambient = glm::vec3{ambientColor.r, ambientColor.g, ambientColor.b};
|
mat.phong.ambient = glm::vec3{ambientColor.r, ambientColor.g, ambientColor.b};
|
||||||
@@ -182,3 +184,69 @@ void process_ai_material(aiMaterial* aiMat, const aiScene* scene, Material& mat)
|
|||||||
mat.phong.specular = glm::vec3{specularColor.r, specularColor.g, specularColor.b};
|
mat.phong.specular = glm::vec3{specularColor.r, specularColor.g, specularColor.b};
|
||||||
mat.phong.shininess = shininess;
|
mat.phong.shininess = shininess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void process_ai_material_diffuse(const aiMaterial *aiMat, Material& mat, const std::filesystem::path& modelDirectory) {
|
||||||
|
aiString aiTextureName;
|
||||||
|
aiMat->GetTexture(aiTextureType_DIFFUSE, 0, &aiTextureName);
|
||||||
|
std::string textureName = aiTextureName.C_Str();
|
||||||
|
|
||||||
|
if (textureName.empty()) {
|
||||||
|
mat.diffuse = TextureManager::textures["default_diffuse"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto textureFilename = std::filesystem::path(textureName).filename();
|
||||||
|
const auto texturePath = modelDirectory / textureFilename;
|
||||||
|
|
||||||
|
const std::string finalTextureName = textureFilename.string();
|
||||||
|
if (TextureManager::textures.contains(finalTextureName)) {
|
||||||
|
mat.diffuse = TextureManager::textures[finalTextureName];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::filesystem::exists(texturePath)) {
|
||||||
|
const auto texture = TextureManager::load_from_file(texturePath.string());
|
||||||
|
if (!texture) {
|
||||||
|
mat.diffuse = TextureManager::textures["default_diffuse"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureManager::textures[finalTextureName] = texture;
|
||||||
|
mat.diffuse = texture;
|
||||||
|
} else {
|
||||||
|
mat.diffuse = TextureManager::textures["default_diffuse"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_ai_material_specular(const aiMaterial *aiMat, Material& mat, const std::filesystem::path& modelDirectory) {
|
||||||
|
aiString aiTextureName;
|
||||||
|
aiMat->GetTexture(aiTextureType_SPECULAR, 0, &aiTextureName);
|
||||||
|
std::string textureName = aiTextureName.C_Str();
|
||||||
|
|
||||||
|
if (textureName.empty()) {
|
||||||
|
mat.specular = TextureManager::textures["default_specular"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto textureFilename = std::filesystem::path(textureName).filename();
|
||||||
|
const auto texturePath = modelDirectory / textureFilename;
|
||||||
|
|
||||||
|
const std::string finalTextureName = textureFilename.string();
|
||||||
|
if (TextureManager::textures.contains(finalTextureName)) {
|
||||||
|
mat.specular = TextureManager::textures[finalTextureName];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::filesystem::exists(texturePath)) {
|
||||||
|
const auto texture = TextureManager::load_from_file(texturePath.string());
|
||||||
|
if (!texture) {
|
||||||
|
mat.specular = TextureManager::textures["default_specular"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureManager::textures[finalTextureName] = texture;
|
||||||
|
mat.specular = texture;
|
||||||
|
} else {
|
||||||
|
mat.specular = TextureManager::textures["default_specular"];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
|
|
||||||
class ModelLoader
|
class ModelManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::unordered_map<std::string, std::shared_ptr<Model>> models;
|
static std::unordered_map<std::string, std::shared_ptr<Model>> models;
|
||||||
@@ -16,6 +16,9 @@ public:
|
|||||||
Texture(unsigned int id, std::string_view filePath, int width, int height, int channels)
|
Texture(unsigned int id, std::string_view filePath, int width, int height, int channels)
|
||||||
: id(id), filePath(filePath), width(width), height(height), channels(channels) {}
|
: id(id), filePath(filePath), width(width), height(height), channels(channels) {}
|
||||||
|
|
||||||
|
Texture(const Texture&) = delete;
|
||||||
|
Texture& operator=(const Texture&) = delete;
|
||||||
|
|
||||||
~Texture() { glDeleteTextures(1, &id); }
|
~Texture() { glDeleteTextures(1, &id); }
|
||||||
|
|
||||||
void bind() const {glBindTexture(GL_TEXTURE_2D, id);}
|
void bind() const {glBindTexture(GL_TEXTURE_2D, id);}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Created by slinky on 5/1/26.
|
// Created by slinky on 5/1/26.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "TextureLoader.h"
|
#include "TextureManager.h"
|
||||||
|
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
#include "glad/gl.h"
|
#include "glad/gl.h"
|
||||||
|
|
||||||
std::unordered_map<std::string, std::shared_ptr<Texture>> TextureLoader::textures;
|
std::unordered_map<std::string, std::shared_ptr<Texture>> TextureManager::textures;
|
||||||
|
|
||||||
std::shared_ptr<Texture> TextureLoader::load_from_file(std::string_view filePath)
|
std::shared_ptr<Texture> TextureManager::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);
|
||||||
@@ -41,7 +41,7 @@ std::shared_ptr<Texture> TextureLoader::load_from_file(std::string_view filePath
|
|||||||
return std::make_shared<Texture>(textureID, filePath, width, height, channels);
|
return std::make_shared<Texture>(textureID, filePath, width, height, channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Texture> TextureLoader::load_from_data(unsigned char* data, int width, int height, int channels)
|
std::shared_ptr<Texture> TextureManager::load_from_data(unsigned char* data, int width, int height, int channels)
|
||||||
{
|
{
|
||||||
unsigned int textureID = 0;
|
unsigned int textureID = 0;
|
||||||
glGenTextures(1, &textureID);
|
glGenTextures(1, &textureID);
|
||||||
@@ -2,15 +2,15 @@
|
|||||||
// Created by slinky on 5/1/26.
|
// Created by slinky on 5/1/26.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef B_ENGINE_TEXTURELOADER_H
|
#ifndef B_ENGINE_TEXTUREMANAGER_H
|
||||||
#define B_ENGINE_TEXTURELOADER_H
|
#define B_ENGINE_TEXTUREMANAGER_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
|
|
||||||
class TextureLoader {
|
class TextureManager {
|
||||||
public:
|
public:
|
||||||
static std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
|
static std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
|
||||||
|
|
||||||
@@ -18,4 +18,4 @@ public:
|
|||||||
static std::shared_ptr<Texture> load_from_data(unsigned char* data, int width, int height, int channels);
|
static std::shared_ptr<Texture> load_from_data(unsigned char* data, int width, int height, int channels);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //B_ENGINE_TEXTURELOADER_H
|
#endif //B_ENGINE_TEXTUREMANAGER_H
|
||||||
207
src/main.cpp
207
src/main.cpp
@@ -8,14 +8,16 @@
|
|||||||
#include "glm/ext/matrix_transform.hpp"
|
#include "glm/ext/matrix_transform.hpp"
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "FreeCamera.h"
|
||||||
|
#include "InputManager.h"
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
#include "ModelLoader.h"
|
#include "ModelManager.h"
|
||||||
#include "ShaderManager.h"
|
#include "ShaderManager.h"
|
||||||
#include "ShaderProgram.h"
|
#include "ShaderProgram.h"
|
||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
#include "TextureLoader.h"
|
#include "TextureManager.h"
|
||||||
|
|
||||||
GLFWwindow* gWindow = nullptr;
|
GLFWwindow* gWindow = nullptr;
|
||||||
int gWindowWidth = 800;
|
int gWindowWidth = 800;
|
||||||
@@ -24,9 +26,11 @@ int gWindowHeight = 600;
|
|||||||
int glVersionMajor = 0;
|
int glVersionMajor = 0;
|
||||||
int glVersionMinor = 0;
|
int glVersionMinor = 0;
|
||||||
|
|
||||||
auto cameraPosition = glm::vec3{0, 0, 0};
|
float gAspectRatio = 0.f;
|
||||||
auto view = glm::mat4{0};
|
|
||||||
auto projection = glm::mat4{0};
|
float gMouseSensitivity = 0.1f;
|
||||||
|
|
||||||
|
FreeCamera gCamera {};
|
||||||
|
|
||||||
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);
|
||||||
@@ -36,10 +40,16 @@ void init_glfw();
|
|||||||
void create_main_window();
|
void create_main_window();
|
||||||
void load_gl();
|
void load_gl();
|
||||||
void init_camera();
|
void init_camera();
|
||||||
|
void load_default_textures();
|
||||||
|
void load_shaders();
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
std::shared_ptr<Model> load_model(std::string_view _path);
|
std::shared_ptr<Model> load_model(std::string_view _path);
|
||||||
|
|
||||||
|
auto xAxis = glm::vec3{1.f, 0.f, 0.f};
|
||||||
|
auto yAxis = glm::vec3{0.f, 1.f, 0.f};
|
||||||
|
auto zAxis = glm::vec3{0.f, 0.f, 1.f};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
spdlog::info("b_engine start");
|
spdlog::info("b_engine start");
|
||||||
|
|
||||||
@@ -49,30 +59,33 @@ int main() {
|
|||||||
|
|
||||||
load_gl();
|
load_gl();
|
||||||
|
|
||||||
stbi_set_flip_vertically_on_load(true);
|
|
||||||
|
|
||||||
init_camera();
|
init_camera();
|
||||||
|
|
||||||
// create a default texture
|
stbi_set_flip_vertically_on_load(true);
|
||||||
unsigned char defaultDiffuseData[4] = {static_cast<unsigned char>(255), 255, 255, 255};
|
|
||||||
TextureLoader::textures["default_diffuse"] = TextureLoader::load_from_data(reinterpret_cast<unsigned char*>(&defaultDiffuseData), 1, 1, 4);
|
|
||||||
|
|
||||||
// create a default specular map
|
load_default_textures();
|
||||||
unsigned char defaultSpecularData[4] = {static_cast<unsigned char>(128), 128, 128, 255};
|
|
||||||
TextureLoader::textures["default_specular"] = TextureLoader::load_from_data(reinterpret_cast<unsigned char*>(&defaultSpecularData), 1, 1, 4);
|
|
||||||
|
|
||||||
ShaderManager::shaders["phong_shader"] = ShaderManager::load("./resources/standard.vert", "./resources/standard.frag");
|
load_shaders();
|
||||||
if (ShaderManager::shaders["phong_shader"] == nullptr)
|
|
||||||
{
|
|
||||||
std::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*ModelLoader::models["cube"] = ModelLoader::load_from_file("./resources/cube.obj", true);*/
|
InputManager::generate_input_action("move_forward", {{GLFW_KEY_W, KEY_DOWN}});
|
||||||
ModelLoader::models["backpack"] = ModelLoader::load_from_file("./resources/backpack/backpack.obj");
|
InputManager::generate_input_action("move_backward", {{GLFW_KEY_S, KEY_DOWN}});
|
||||||
/*ModelLoader::models["male"] = ModelLoader::load_from_file("./resources/male.obj");*/
|
InputManager::generate_input_action("move_right", {{GLFW_KEY_D, KEY_DOWN}});
|
||||||
|
InputManager::generate_input_action("move_left", {{GLFW_KEY_A, KEY_DOWN}});
|
||||||
|
|
||||||
|
InputManager::generate_input_action("exit_application", {{GLFW_KEY_ESCAPE, KEY_DOWN}});
|
||||||
|
|
||||||
|
spdlog::info("loading models");
|
||||||
|
ModelManager::models["cube"] = ModelManager::load_from_file("./resources/cube.obj");
|
||||||
|
ModelManager::models["backpack"] = ModelManager::load_from_file("./resources/backpack/backpack.obj");
|
||||||
|
ModelManager::models["male"] = ModelManager::load_from_file("./resources/male.obj");
|
||||||
|
spdlog::info("done");
|
||||||
|
|
||||||
loop();
|
loop();
|
||||||
|
|
||||||
|
ShaderManager::shaders.clear();
|
||||||
|
TextureManager::textures.clear();
|
||||||
|
ModelManager::models.clear();
|
||||||
|
|
||||||
glfwDestroyWindow(gWindow);
|
glfwDestroyWindow(gWindow);
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
|
|
||||||
@@ -83,14 +96,10 @@ void glfw_error_callback(int error, const char* description) {
|
|||||||
spdlog::error("glfw error: {}", description);
|
spdlog::error("glfw error: {}", description);
|
||||||
}
|
}
|
||||||
|
|
||||||
void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
|
||||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
|
||||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void glfw_framebuffer_size_callback(GLFWwindow *window, int width, int height) {
|
void glfw_framebuffer_size_callback(GLFWwindow *window, int width, int height) {
|
||||||
glViewport(0, 0, width, height);
|
glViewport(0, 0, width, height);
|
||||||
|
gAspectRatio = (float)width / (float)height;
|
||||||
|
gCamera.update_aspect_ratio(gAspectRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_glfw()
|
void init_glfw()
|
||||||
@@ -103,13 +112,14 @@ void init_glfw()
|
|||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
glfwWindowHint(GLFW_SAMPLES, 4);
|
||||||
|
|
||||||
glfwSetErrorCallback(glfw_error_callback);
|
glfwSetErrorCallback(glfw_error_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_main_window()
|
void create_main_window()
|
||||||
{
|
{
|
||||||
gWindow = glfwCreateWindow(gWindowWidth, gWindowHeight, "b_engine v0.0.1", nullptr, nullptr);
|
gWindow = glfwCreateWindow(gWindowWidth, gWindowHeight, "b_engine v0.0.2", nullptr, nullptr);
|
||||||
if (!gWindow) {
|
if (!gWindow) {
|
||||||
spdlog::error("failed to create glfw window");
|
spdlog::error("failed to create glfw window");
|
||||||
std::exit(1);
|
std::exit(1);
|
||||||
@@ -117,8 +127,12 @@ void create_main_window()
|
|||||||
|
|
||||||
glfwMakeContextCurrent(gWindow);
|
glfwMakeContextCurrent(gWindow);
|
||||||
|
|
||||||
glfwSetKeyCallback(gWindow, glfw_key_callback);
|
glfwSetKeyCallback(gWindow, InputManager::key_callback);
|
||||||
|
glfwSetCursorPosCallback(gWindow, InputManager::mouse_pos_callback);
|
||||||
|
|
||||||
glfwSetFramebufferSizeCallback(gWindow, glfw_framebuffer_size_callback);
|
glfwSetFramebufferSizeCallback(gWindow, glfw_framebuffer_size_callback);
|
||||||
|
|
||||||
|
glfwSetInputMode(gWindow, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_gl()
|
void load_gl()
|
||||||
@@ -132,63 +146,131 @@ void load_gl()
|
|||||||
{
|
{
|
||||||
int fbWidth, fbHeight;
|
int fbWidth, fbHeight;
|
||||||
glfwGetFramebufferSize(gWindow, &fbWidth, &fbHeight);
|
glfwGetFramebufferSize(gWindow, &fbWidth, &fbHeight);
|
||||||
glViewport(0, 0, fbWidth, fbHeight);
|
gAspectRatio = (float)fbWidth / (float)fbHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_MULTISAMPLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_camera()
|
void init_camera() {
|
||||||
{
|
gCamera = {{5.f, 5.f, 5.f}, 0, 0, gAspectRatio};
|
||||||
cameraPosition = glm::vec3{10, 0, 10};
|
gCamera.rotate_yaw(-135.f);
|
||||||
auto cameraTarget = glm::vec3{0, 0, 0};
|
gCamera.rotate_pitch(-35.f);
|
||||||
|
|
||||||
view = glm::lookAt(cameraPosition, cameraTarget, glm::vec3(0.0f, 1.0f, 0.0f));
|
InputManager::add_mouse_listener([](float xoff, float yoff) {
|
||||||
|
gCamera.rotate_yaw(xoff * gMouseSensitivity);
|
||||||
|
gCamera.rotate_pitch(yoff * gMouseSensitivity);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
float aspectRatio = static_cast<float>(gWindowWidth) / static_cast<float>(gWindowHeight);
|
void load_default_textures() {
|
||||||
projection = glm::perspective(glm::radians(75.f), aspectRatio, 0.1f, 100.0f);
|
spdlog::info("creating default textures");
|
||||||
|
unsigned char defaultDiffuseData[4] = {static_cast<unsigned char>(255), 255, 255, 255};
|
||||||
|
TextureManager::textures["default_diffuse"] = TextureManager::load_from_data(reinterpret_cast<unsigned char*>(&defaultDiffuseData), 1, 1, 4);
|
||||||
|
|
||||||
|
unsigned char defaultSpecularData[4] = {static_cast<unsigned char>(64), 64, 64, 255};
|
||||||
|
TextureManager::textures["default_specular"] = TextureManager::load_from_data(reinterpret_cast<unsigned char*>(&defaultSpecularData), 1, 1, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_shaders() {
|
||||||
|
spdlog::info("compiling shaders");
|
||||||
|
ShaderManager::shaders["phong_shader"] = ShaderManager::load("./resources/standard.vert", "./resources/standard.frag");
|
||||||
|
if (ShaderManager::shaders["phong_shader"] == nullptr)
|
||||||
|
{
|
||||||
|
spdlog::error("failed to compile phong shader");
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
Texture* defaultDiffuse = TextureLoader::textures["default_diffuse"].get();
|
std::shared_ptr<Texture> defaultDiffuse = TextureManager::textures["default_diffuse"];
|
||||||
Texture* defaultSpecular = TextureLoader::textures["default_specular"].get();
|
std::shared_ptr<Texture> defaultSpecular = TextureManager::textures["default_specular"];
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(gWindow)) {
|
|
||||||
auto model = glm::identity<glm::mat4>();
|
auto model = glm::identity<glm::mat4>();
|
||||||
// model = glm::translate(model, glm::vec3(0, -5.f, 0));
|
|
||||||
// model = glm::scale(model, glm::vec3(.5f, .5f, .5f));
|
|
||||||
glfwPollEvents();
|
|
||||||
|
|
||||||
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
|
|
||||||
ShaderProgram* shader = ShaderManager::shaders["phong_shader"].get();
|
ShaderProgram* shader = ShaderManager::shaders["phong_shader"].get();
|
||||||
|
|
||||||
const Model* cube = ModelLoader::models["cube"].get();
|
const auto cube = ModelManager::models["cube"];
|
||||||
const Model* backpack = ModelLoader::models["backpack"].get();
|
const auto backpack = ModelManager::models["backpack"];
|
||||||
const Model* male = ModelLoader::models["male"].get();
|
const auto male = ModelManager::models["male"];
|
||||||
|
|
||||||
if (shader) {
|
const auto& activeModel = backpack;
|
||||||
Material* mat = backpack->materials[0].get();
|
|
||||||
|
while (!glfwWindowShouldClose(gWindow)) {
|
||||||
|
glfwPollEvents();
|
||||||
|
|
||||||
|
// check inputs
|
||||||
|
if (InputManager::check_action_performed("exit_application")) {
|
||||||
|
glfwSetWindowShouldClose(gWindow, true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InputManager::check_action_performed("move_forward")) {
|
||||||
|
gCamera.move(CAMERA_MOVEMENT::FORWARD, .05);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InputManager::check_action_performed("move_backward")) {
|
||||||
|
gCamera.move(CAMERA_MOVEMENT::BACKWARD, .05);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InputManager::check_action_performed("move_left")) {
|
||||||
|
gCamera.move(CAMERA_MOVEMENT::LEFT, .05);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InputManager::check_action_performed("move_right")) {
|
||||||
|
gCamera.move(CAMERA_MOVEMENT::RIGHT, .05);
|
||||||
|
}
|
||||||
|
|
||||||
|
// gl frame prep
|
||||||
|
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
// draw the stuff
|
||||||
|
if (shader && activeModel) {
|
||||||
shader->bind();
|
shader->bind();
|
||||||
|
|
||||||
shader->setMat4("projection", projection);
|
shader->setMat4("projection", gCamera.projection());
|
||||||
shader->setMat4("view", view);
|
shader->setMat4("view", gCamera.view());
|
||||||
shader->setMat4("model", model);
|
shader->setMat4("model", model);
|
||||||
|
|
||||||
shader->setVec3("viewPosition", cameraPosition);
|
shader->setVec3("viewPosition", gCamera.position());
|
||||||
|
|
||||||
shader->setVec3("phongAmbient", glm::vec3(0.3f, 0.3f, 0.3f));
|
shader->setVec3("lightPosition", glm::vec3{-2.f, 0, 2.0f});
|
||||||
shader->setVec3("phongDiffuse", glm::vec3(0.8f, 0.8f, 0.8f));
|
shader->setVec3("lightDirection", glm::vec3(1, -1, -1));
|
||||||
shader->setVec3("phongSpecular", glm::vec3(1.0f, 1.0f, 1.0f));
|
|
||||||
shader->setFloat("phongShininess", 32.0f);
|
|
||||||
|
|
||||||
shader->setVec3("lightDirection", glm::vec3(-.5f, -.5f, -.5f));
|
|
||||||
shader->setVec3("lightAmbient", glm::vec3(0.3f, 0.3f, 0.3f));
|
shader->setVec3("lightAmbient", glm::vec3(0.3f, 0.3f, 0.3f));
|
||||||
shader->setVec3("lightDiffuse", glm::vec3(1.0f, 1.0f, 1.0f));
|
shader->setVec3("lightDiffuse", glm::vec3(0.5f, 0.5f, 0.5f));
|
||||||
shader->setVec3("lightSpecular", glm::vec3(1.0f, 1.0f, 1.0f));
|
shader->setVec3("lightSpecular", glm::vec3(1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
for (const auto& mesh: backpack->meshes) {
|
for (const auto& mesh: activeModel->meshes) {
|
||||||
|
unsigned int materialId = mesh->materialId;
|
||||||
|
if (materialId >= activeModel->materials.size()) {
|
||||||
|
materialId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<Material> mat = activeModel->materials[1];
|
||||||
|
|
||||||
|
shader->setVec3("phongAmbient", mat->phong.ambient);
|
||||||
|
shader->setVec3("phongDiffuse", mat->phong.diffuse);
|
||||||
|
shader->setVec3("phongSpecular", mat->phong.specular);
|
||||||
|
shader->setFloat("phongShininess", mat->phong.shininess);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
auto diffuse = mat->diffuse;
|
||||||
|
if (!diffuse) {
|
||||||
|
diffuse = defaultDiffuse;
|
||||||
|
}
|
||||||
|
diffuse->bind();
|
||||||
|
shader->setInt("diffuseMap", 0);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
auto specular = mat->specular;
|
||||||
|
if (!specular) {
|
||||||
|
specular = defaultSpecular;
|
||||||
|
}
|
||||||
|
specular->bind();
|
||||||
|
shader->setInt("specularMap", 1);
|
||||||
|
|
||||||
glBindVertexArray(mesh.get()->vao);
|
glBindVertexArray(mesh.get()->vao);
|
||||||
glDrawElements(GL_TRIANGLES, mesh->numIndices, GL_UNSIGNED_INT, 0);
|
glDrawElements(GL_TRIANGLES, mesh->numIndices, GL_UNSIGNED_INT, 0);
|
||||||
}
|
}
|
||||||
@@ -197,6 +279,7 @@ void loop() {
|
|||||||
ShaderProgram::unbind();
|
ShaderProgram::unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gl end frame stuff
|
||||||
glfwSwapBuffers(gWindow);
|
glfwSwapBuffers(gWindow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user