Initial commit - some engine bugs stopping compiling

This commit is contained in:
Will
2026-03-29 15:52:42 +01:00
commit 3d573a200e
361 changed files with 332759 additions and 0 deletions

350
src/ResourceManager.cpp Normal file
View File

@@ -0,0 +1,350 @@
// src/ResourceManager.cpp
#include "ResourceManager.h"
#include "Shader.h"
#include "Mesh.h"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <unordered_set>
#include <algorithm>
// Static member definitions
std::unordered_map<std::string, std::shared_ptr<Shader>> ResourceManager::shaders_;
std::unordered_map<std::string, std::shared_ptr<Texture>> ResourceManager::textures_;
std::unordered_map<std::string, std::shared_ptr<Mesh>> ResourceManager::meshes_;
bool ResourceManager::hot_reload_enabled_ = false;
std::unordered_map<std::string, std::filesystem::file_time_type> ResourceManager::shader_timestamps_;
std::unordered_map<std::string, std::filesystem::path> ResourceManager::shader_paths_;
std::unordered_map<std::string, std::filesystem::file_time_type> ResourceManager::texture_timestamps_;
std::unordered_map<std::string, std::filesystem::path> ResourceManager::texture_paths_;
std::expected<std::shared_ptr<Shader>, std::string>
ResourceManager::LoadShader(const std::string& name,
const std::filesystem::path& vert,
const std::filesystem::path& frag) {
try {
auto shader = std::make_shared<Shader>(vert, frag);
if (!shader->IsValid()) {
return std::unexpected("Shader compilation/linking failed: " + name);
}
shaders_[name] = shader;
if (hot_reload_enabled_) {
shader_timestamps_[name] = std::filesystem::last_write_time(vert);
shader_paths_[name] = vert;
}
return shader;
} catch (const std::exception& e) {
return std::unexpected(std::string("Exception loading shader ") + name + ": " + e.what());
}
}
std::expected<std::shared_ptr<Shader>, std::string>
ResourceManager::LoadShader(const std::string& name,
const std::filesystem::path& vert,
const std::filesystem::path& geom,
const std::filesystem::path& frag) {
try {
auto shader = std::make_shared<Shader>(vert, geom, frag);
if (!shader->IsValid()) {
return std::unexpected("Shader compilation/linking failed: " + name);
}
shaders_[name] = shader;
if (hot_reload_enabled_) {
shader_timestamps_[name] = std::filesystem::last_write_time(vert);
shader_paths_[name] = vert;
}
return shader;
} catch (const std::exception& e) {
return std::unexpected(std::string("Exception loading shader ") + name + ": " + e.what());
}
}
std::shared_ptr<Shader> ResourceManager::GetShader(const std::string& name) {
auto it = shaders_.find(name);
return (it != shaders_.end()) ? it->second : nullptr;
}
std::expected<std::shared_ptr<Texture>, std::string>
ResourceManager::LoadTexture(const std::string& name,
const std::filesystem::path& path,
bool generate_mipmaps) {
try {
// TODO: Replace this stub with actual texture loading
// auto texture = std::make_shared<Texture>(path, generate_mipmaps);
// if (!texture->IsValid()) {
// return std::unexpected("Texture loading failed: " + name);
// }
// textures_[name] = texture;
if (hot_reload_enabled_) {
texture_timestamps_[name] = std::filesystem::last_write_time(path);
texture_paths_[name] = path;
}
// For now, return error since texture loading is not implemented
return std::unexpected("Texture loading not implemented");
} catch (const std::exception& e) {
return std::unexpected(std::string("Exception loading texture ") + name + ": " + e.what());
}
}
std::shared_ptr<Texture> ResourceManager::GetTexture(const std::string& name) {
auto it = textures_.find(name);
return (it != textures_.end()) ? it->second : nullptr;
}
void ResourceManager::RegisterMesh(const std::string& name, std::shared_ptr<Mesh> mesh) {
meshes_[name] = std::move(mesh);
}
std::shared_ptr<Mesh> ResourceManager::GetMesh(const std::string& name) {
auto it = meshes_.find(name);
return (it != meshes_.end()) ? it->second : nullptr;
}
void ResourceManager::ClearShaders() {
shaders_.clear();
shader_timestamps_.clear();
shader_paths_.clear();
}
void ResourceManager::ClearTextures() {
textures_.clear();
texture_timestamps_.clear();
texture_paths_.clear();
}
void ResourceManager::ClearMeshes() {
meshes_.clear();
}
void ResourceManager::ClearAll() {
ClearShaders();
ClearTextures();
ClearMeshes();
}
void ResourceManager::PrintResourceInfo() {
std::cout << "Shaders: " << shaders_.size()
<< ", Textures: " << textures_.size()
<< ", Meshes: " << meshes_.size() << "\n";
}
bool ResourceManager::HasShader(const std::string& name) {
return shaders_.count(name) > 0;
}
bool ResourceManager::HasTexture(const std::string& name) {
return textures_.count(name) > 0;
}
bool ResourceManager::HasMesh(const std::string& name) {
return meshes_.count(name) > 0;
}
void ResourceManager::LoadShadersFromDirectory(const std::filesystem::path& dir) {
if (!std::filesystem::exists(dir) || !std::filesystem::is_directory(dir)) {
std::cerr << "Directory does not exist: " << dir << "\n";
return;
}
std::unordered_map<std::string, std::filesystem::path> vert_files;
std::unordered_map<std::string, std::filesystem::path> frag_files;
std::unordered_map<std::string, std::filesystem::path> geom_files;
// Collect shader files by base name
for (const auto& entry : std::filesystem::directory_iterator(dir)) {
if (!entry.is_regular_file()) continue;
auto path = entry.path();
auto base_name = path.stem().string();
auto extension = path.extension().string();
if (extension == ".vert") {
vert_files[base_name] = path;
} else if (extension == ".frag") {
frag_files[base_name] = path;
} else if (extension == ".geom") {
geom_files[base_name] = path;
}
}
// Match and load shader pairs/triplets
for (const auto& [base_name, vert_path] : vert_files) {
auto frag_it = frag_files.find(base_name);
if (frag_it != frag_files.end()) {
auto geom_it = geom_files.find(base_name);
if (geom_it != geom_files.end()) {
// Load with geometry shader
auto result = LoadShader(base_name, vert_path, geom_it->second, frag_it->second);
if (result) {
std::cout << "Loaded shader with geometry: " << base_name << "\n";
} else {
std::cerr << "Failed to load shader " << base_name << ": " << result.error() << "\n";
}
} else {
// Load without geometry shader
auto result = LoadShader(base_name, vert_path, frag_it->second);
if (result) {
std::cout << "Loaded shader: " << base_name << "\n";
} else {
std::cerr << "Failed to load shader " << base_name << ": " << result.error() << "\n";
}
}
}
}
}
void ResourceManager::LoadTexturesFromDirectory(const std::filesystem::path& dir) {
if (!std::filesystem::exists(dir) || !std::filesystem::is_directory(dir)) {
std::cerr << "Directory does not exist: " << dir << "\n";
return;
}
// Common image extensions using unordered_set instead of set
std::unordered_set<std::string> image_extensions = {".png", ".jpg", ".jpeg", ".bmp", ".tga", ".dds"};
for (const auto& entry : std::filesystem::directory_iterator(dir)) {
if (!entry.is_regular_file()) continue;
auto path = entry.path();
auto extension = path.extension().string();
// Convert to lowercase for comparison
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
if (image_extensions.count(extension)) {
auto name = path.stem().string();
auto result = LoadTexture(name, path);
if (result) {
std::cout << "Loaded texture: " << name << "\n";
} else {
std::cerr << "Failed to load texture " << name << ": " << result.error() << "\n";
}
}
}
}
void ResourceManager::ReloadShader(const std::string& name) {
auto shader_it = shaders_.find(name);
if (shader_it == shaders_.end()) {
std::cerr << "Cannot reload shader: " << name << " not found\n";
return;
}
auto path_it = shader_paths_.find(name);
if (path_it == shader_paths_.end()) {
std::cerr << "Cannot reload shader: " << name << " path not stored\n";
return;
}
try {
// Determine fragment shader path (assume same base name, different extension)
auto vert_path = path_it->second;
auto frag_path = vert_path;
frag_path.replace_extension(".frag");
// Check if geometry shader exists
auto geom_path = vert_path;
geom_path.replace_extension(".geom");
if (std::filesystem::exists(geom_path)) {
// Reload with geometry shader
auto new_shader = std::make_shared<Shader>(vert_path, geom_path, frag_path);
if (new_shader->IsValid()) {
shaders_[name] = new_shader;
shader_timestamps_[name] = std::filesystem::last_write_time(vert_path);
std::cout << "Reloaded shader with geometry: " << name << "\n";
} else {
std::cerr << "Failed to reload shader with geometry: " << name << "\n";
}
} else {
// Reload without geometry shader
auto new_shader = std::make_shared<Shader>(vert_path, frag_path);
if (new_shader->IsValid()) {
shaders_[name] = new_shader;
shader_timestamps_[name] = std::filesystem::last_write_time(vert_path);
std::cout << "Reloaded shader: " << name << "\n";
} else {
std::cerr << "Failed to reload shader: " << name << "\n";
}
}
} catch (const std::exception& e) {
std::cerr << "Exception reloading shader " << name << ": " << e.what() << "\n";
}
}
void ResourceManager::ReloadTexture(const std::string& name) {
auto texture_it = textures_.find(name);
if (texture_it == textures_.end()) {
std::cerr << "Cannot reload texture: " << name << " not found\n";
return;
}
auto path_it = texture_paths_.find(name);
if (path_it == texture_paths_.end()) {
std::cerr << "Cannot reload texture: " << name << " path not stored\n";
return;
}
try {
// TODO: Replace this with actual texture reloading
// auto new_texture = std::make_shared<Texture>(path_it->second);
// if (new_texture->IsValid()) {
// textures_[name] = new_texture;
// texture_timestamps_[name] = std::filesystem::last_write_time(path_it->second);
// std::cout << "Reloaded texture: " << name << "\n";
// } else {
// std::cerr << "Failed to reload texture: " << name << "\n";
// }
// For now, just update timestamp
texture_timestamps_[name] = std::filesystem::last_write_time(path_it->second);
std::cout << "Texture reload placeholder for: " << name << "\n";
} catch (const std::exception& e) {
std::cerr << "Exception reloading texture " << name << ": " << e.what() << "\n";
}
}
void ResourceManager::CheckForChanges() {
if (!hot_reload_enabled_) return;
// Check for shader changes
for (const auto& [name, shader] : shaders_) {
auto path_it = shader_paths_.find(name);
if (path_it == shader_paths_.end()) continue;
try {
auto current = std::filesystem::last_write_time(path_it->second);
auto stored_it = shader_timestamps_.find(name);
if (stored_it != shader_timestamps_.end() && current != stored_it->second) {
std::cout << "Detected change in shader: " << name << "\n";
ReloadShader(name);
}
} catch (const std::filesystem::filesystem_error& e) {
std::cerr << "Error checking shader file " << name << ": " << e.what() << "\n";
}
}
// Check for texture changes
for (const auto& [name, texture] : textures_) {
auto path_it = texture_paths_.find(name);
if (path_it == texture_paths_.end()) continue;
try {
auto current = std::filesystem::last_write_time(path_it->second);
auto stored_it = texture_timestamps_.find(name);
if (stored_it != texture_timestamps_.end() && current != stored_it->second) {
std::cout << "Detected change in texture: " << name << "\n";
ReloadTexture(name);
texture_timestamps_[name] = current;
}
} catch (const std::filesystem::filesystem_error& e) {
std::cerr << "Error checking texture file " << name << ": " << e.what() << "\n";
}
}
}