From b3981b90e44a098ca956822d8bf499147aafb13f Mon Sep 17 00:00:00 2001 From: ExilProductions Date: Wed, 23 Apr 2025 17:16:52 +0200 Subject: [PATCH] Refactor engine code --- .vscode/c_cpp_properties.json | 6 +- .vscode/settings.json | 16 +++- CMakeLists.txt | 16 ++-- {Ps1Engine => Engine}/loader/mesh.cpp | 54 +++++++++---- Engine/loader/mesh.h | 15 ++++ Engine/ps1engine.h | 2 + {Ps1Engine => Engine}/renderer/renderer.cpp | 89 ++++++++++++++------- {Ps1Engine => Engine}/renderer/renderer.h | 6 +- Ps1Engine/loader/mesh.h | 9 --- cube.cpp => examples/cube.cpp | 5 +- 10 files changed, 148 insertions(+), 70 deletions(-) rename {Ps1Engine => Engine}/loader/mesh.cpp (63%) create mode 100644 Engine/loader/mesh.h create mode 100644 Engine/ps1engine.h rename {Ps1Engine => Engine}/renderer/renderer.cpp (81%) rename {Ps1Engine => Engine}/renderer/renderer.h (89%) delete mode 100644 Ps1Engine/loader/mesh.h rename cube.cpp => examples/cube.cpp (98%) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index bdc0a60..ee967a9 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,9 +3,9 @@ { "name": "Linux", "includePath": [ - "${workspaceFolder}/Ps1Engine/renderer", - "${workspaceFolder}/Ps1Engine/loader", - "${workspaceFolder}/Ps1Engine", + "${workspaceFolder}/Engine/renderer", + "${workspaceFolder}/Engine/loader", + "${workspaceFolder}/Engine", "${workspaceFolder}/external/**", "/usr/include", "/usr/local/include" diff --git a/.vscode/settings.json b/.vscode/settings.json index a23afc8..3656822 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -63,6 +63,20 @@ "streambuf": "cpp", "cinttypes": "cpp", "typeinfo": "cpp", - "variant": "cpp" + "variant": "cpp", + "csignal": "cpp", + "strstream": "cpp", + "bitset": "cpp", + "condition_variable": "cpp", + "unordered_set": "cpp", + "expected": "cpp", + "mutex": "cpp", + "ranges": "cpp", + "semaphore": "cpp", + "shared_mutex": "cpp", + "stop_token": "cpp", + "thread": "cpp", + "typeindex": "cpp", + "valarray": "cpp" } } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 67885cb..dd87b53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,23 +8,25 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) # Include directories -include_directories(${CMAKE_SOURCE_DIR}/renderer) -include_directories(${CMAKE_SOURCE_DIR}/loader) +include_directories(${CMAKE_SOURCE_DIR}/Engine) +include_directories(${CMAKE_SOURCE_DIR}/Engine/renderer) +include_directories(${CMAKE_SOURCE_DIR}/Engine/loader) +include_directories(${CMAKE_SOURCE_DIR}/examples) include_directories(${CMAKE_SOURCE_DIR}/external/stb) # Source files set(SOURCES - ${CMAKE_SOURCE_DIR}/renderer/renderer.cpp - ${CMAKE_SOURCE_DIR}/loader/mesh.cpp - ${CMAKE_SOURCE_DIR}/../cube.cpp + ${CMAKE_SOURCE_DIR}/Engine/renderer/renderer.cpp + ${CMAKE_SOURCE_DIR}/Engine/loader/mesh.cpp + ${CMAKE_SOURCE_DIR}/examples/cube.cpp ) # Executable -add_executable(Ps1Engine ${SOURCES}) +add_executable(Engine ${SOURCES}) # Link libraries find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) find_package(glfw3 REQUIRED) -target_link_libraries(Ps1Engine OpenGL::GL GLEW::GLEW glfw) \ No newline at end of file +target_link_libraries(Engine OpenGL::GL GLEW::GLEW glfw) \ No newline at end of file diff --git a/Ps1Engine/loader/mesh.cpp b/Engine/loader/mesh.cpp similarity index 63% rename from Ps1Engine/loader/mesh.cpp rename to Engine/loader/mesh.cpp index db7eb61..e686f22 100644 --- a/Ps1Engine/loader/mesh.cpp +++ b/Engine/loader/mesh.cpp @@ -7,13 +7,13 @@ namespace fs = std::filesystem; -std::map load_mtl_colors(const std::string& mtl_path) +std::map load_mtl_materials(const std::string& mtl_path) { - std::map material_colors; + std::map materials; std::ifstream file(mtl_path); if (!file.is_open()) { std::cerr << "Warning: could not open MTL file: " << mtl_path << std::endl; - return material_colors; + return materials; } std::string line, current_mtl; @@ -24,21 +24,30 @@ std::map load_mtl_colors(const std::string& mtl_path) if (keyword == "newmtl") { ss >> current_mtl; + materials[current_mtl] = Material{Color(255, 255, 255), ""}; // Default white, no texture } else if (keyword == "Kd") { float r, g, b; ss >> r >> g >> b; - material_colors[current_mtl] = Color( - static_cast(r * 255), - static_cast(g * 255), - static_cast(b * 255) - ); + if (materials.count(current_mtl)) { + materials[current_mtl].color = Color( + static_cast(r * 255), + static_cast(g * 255), + static_cast(b * 255) + ); + } + } else if (keyword == "map_Kd") { + std::string texture_path; + ss >> texture_path; + if (materials.count(current_mtl)) { + materials[current_mtl].texture_path = texture_path; + } } } - return material_colors; + return materials; } -std::vector load_obj(const std::string& obj_path) +std::vector load_obj(const std::string& obj_path, Renderer* renderer) { std::ifstream file(obj_path); if (!file.is_open()) { @@ -47,7 +56,8 @@ std::vector load_obj(const std::string& obj_path) std::vector positions; std::vector texcoords; - std::map materials; + std::map materials; + std::map texture_map; std::vector triangles; std::string current_material = ""; @@ -100,9 +110,11 @@ std::vector load_obj(const std::string& obj_path) tri.uv2 = (t_idx[i + 1] >= 0 && t_idx[i + 1] < (int)texcoords.size()) ? texcoords[t_idx[i + 1]] : Vec2(0, 0); if (materials.count(current_material)) { - tri.color = materials[current_material]; + tri.color = materials[current_material].color; + tri.texture = texture_map[current_material]; } else { - tri.color = Color(255, 255, 255); // fallback white + tri.color = Color(255, 255, 255); // Fallback white + tri.texture = 0; // No texture } triangles.push_back(tri); @@ -111,11 +123,23 @@ std::vector load_obj(const std::string& obj_path) std::string mtl_file; ss >> mtl_file; fs::path mtl_path = base_path / mtl_file; - materials = load_mtl_colors(mtl_path.string()); + materials = load_mtl_materials(mtl_path.string()); + + // Load textures for all materials + for (const auto& mat_pair : materials) { + const std::string& mat_name = mat_pair.first; + const Material& mat = mat_pair.second; + if (!mat.texture_path.empty()) { + fs::path texture_full_path = base_path / mat.texture_path; + texture_map[mat_name] = renderer->load_texture(texture_full_path.string()); + } else { + texture_map[mat_name] = 0; // No texture + } + } } else if (keyword == "usemtl") { ss >> current_material; } } return triangles; -} +} \ No newline at end of file diff --git a/Engine/loader/mesh.h b/Engine/loader/mesh.h new file mode 100644 index 0000000..3d7008a --- /dev/null +++ b/Engine/loader/mesh.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include +#include "renderer.h" // includes Vec3, Vec2, Triangle, Color + +struct Material +{ + Color color; + std::string texture_path; +}; + +std::map load_mtl_materials(const std::string& mtl_path); +std::vector load_obj(const std::string& obj_path, Renderer* renderer); \ No newline at end of file diff --git a/Engine/ps1engine.h b/Engine/ps1engine.h new file mode 100644 index 0000000..58e2f1b --- /dev/null +++ b/Engine/ps1engine.h @@ -0,0 +1,2 @@ +#include +#include \ No newline at end of file diff --git a/Ps1Engine/renderer/renderer.cpp b/Engine/renderer/renderer.cpp similarity index 81% rename from Ps1Engine/renderer/renderer.cpp rename to Engine/renderer/renderer.cpp index fcdb8bd..3719ff1 100644 --- a/Ps1Engine/renderer/renderer.cpp +++ b/Engine/renderer/renderer.cpp @@ -1,6 +1,7 @@ #include "renderer.h" #include #include +#include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" @@ -50,7 +51,6 @@ Matrix4 matrix_multiply(const Matrix4 &a, const Matrix4 &b) Color convert_color(const Color &color) { - uint8_t r = (color.r >> 3) << 3; uint8_t g = (color.g >> 3) << 3; uint8_t b = (color.b >> 3) << 3; @@ -61,7 +61,6 @@ Renderer::Renderer(int width_, int height_, const std::string &title_) : width(width_), height(height_), title(title_), internal_width(320), internal_height(240) { - if (!glfwInit()) { throw std::runtime_error("Failed to initialize GLFW"); @@ -105,12 +104,11 @@ void Renderer::set_view_matrix(const Matrix4 &view) void Renderer::begin_frame() { - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void Renderer::render(const std::vector &triangles, GLuint texture) +void Renderer::render(const std::vector &triangles) { std::vector transformed_triangles; @@ -124,6 +122,7 @@ void Renderer::render(const std::vector &triangles, GLuint texture) t.uv1 = tri.uv1; t.uv2 = tri.uv2; t.color = tri.color; + t.texture = tri.texture; Vec3 edge1(t.v1.x - t.v0.x, t.v1.y - t.v0.y, t.v1.z - t.v0.z); Vec3 edge2(t.v2.x - t.v0.x, t.v2.y - t.v0.y, t.v2.z - t.v0.z); @@ -185,53 +184,81 @@ void Renderer::render(const std::vector &triangles, GLuint texture) screen_tri.uv1 = tri.uv1; screen_tri.uv2 = tri.uv2; screen_tri.color = convert_color(tri.color); + screen_tri.texture = tri.texture; screen_triangles.push_back(screen_tri); } - glBindTexture(GL_TEXTURE_2D, texture); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // Group triangles by texture + std::map> texture_groups; + for (const auto& tri : screen_triangles) + { + texture_groups[tri.texture].push_back(tri); + } glDisable(GL_BLEND); - for (const auto &tri : screen_triangles) + // Render each texture group + for (const auto& group : texture_groups) { + GLuint tex = group.first; + const std::vector& tris = group.second; - glBegin(GL_TRIANGLES); - - Color c = tri.color; - glColor3ub(c.r, c.g, c.b); - - glTexCoord2f(tri.uv0.x, tri.uv0.y); - glVertex3f(static_cast(tri.v0.x), static_cast(tri.v0.y), static_cast(tri.v0.z) / 32767.0f); - - glTexCoord2f(tri.uv1.x, tri.uv1.y); - glVertex3f(static_cast(tri.v1.x), static_cast(tri.v1.y), static_cast(tri.v1.z) / 32767.0f); - - glTexCoord2f(tri.uv2.x, tri.uv2.y); - glVertex3f(static_cast(tri.v2.x), static_cast(tri.v2.y), static_cast(tri.v2.z) / 32767.0f); - - glEnd(); - - if (rand() % 5 == 0) + if (tex != 0) + { + glBindTexture(GL_TEXTURE_2D, tex); + glEnable(GL_TEXTURE_2D); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else { glDisable(GL_TEXTURE_2D); - glColor3f(0.0f, 0.0f, 0.0f); - glBegin(GL_LINE_LOOP); + } + + for (const auto& tri : tris) + { + glBegin(GL_TRIANGLES); + Color c = tri.color; + glColor3ub(c.r, c.g, c.b); + + if (tex != 0) + { + glTexCoord2f(tri.uv0.x, tri.uv0.y); + } glVertex3f(static_cast(tri.v0.x), static_cast(tri.v0.y), static_cast(tri.v0.z) / 32767.0f); + + if (tex != 0) + { + glTexCoord2f(tri.uv1.x, tri.uv1.y); + } glVertex3f(static_cast(tri.v1.x), static_cast(tri.v1.y), static_cast(tri.v1.z) / 32767.0f); + + if (tex != 0) + { + glTexCoord2f(tri.uv2.x, tri.uv2.y); + } glVertex3f(static_cast(tri.v2.x), static_cast(tri.v2.y), static_cast(tri.v2.z) / 32767.0f); + glEnd(); - glEnable(GL_TEXTURE_2D); + + if (rand() % 5 == 0) + { + glDisable(GL_TEXTURE_2D); + glColor3f(0.0f, 0.0f, 0.0f); + glBegin(GL_LINE_LOOP); + glVertex3f(static_cast(tri.v0.x), static_cast(tri.v0.y), static_cast(tri.v0.z) / 32767.0f); + glVertex3f(static_cast(tri.v1.x), static_cast(tri.v1.y), static_cast(tri.v1.z) / 32767.0f); + glVertex3f(static_cast(tri.v2.x), static_cast(tri.v2.y), static_cast(tri.v2.z) / 32767.0f); + glEnd(); + if (tex != 0) glEnable(GL_TEXTURE_2D); + } } } } void Renderer::end_frame() { - glfwSwapBuffers(window); glfwPollEvents(); } @@ -307,4 +334,4 @@ GLuint Renderer::load_texture(const std::string &filepath) delete[] resized; return texture; -} +} \ No newline at end of file diff --git a/Ps1Engine/renderer/renderer.h b/Engine/renderer/renderer.h similarity index 89% rename from Ps1Engine/renderer/renderer.h rename to Engine/renderer/renderer.h index f4a8dc0..bb25284 100644 --- a/Ps1Engine/renderer/renderer.h +++ b/Engine/renderer/renderer.h @@ -36,6 +36,7 @@ struct Triangle Vec3 v0, v1, v2; Vec2 uv0, uv1, uv2; Color color; + GLuint texture; }; Vec3 matrix_multiply(const Matrix4 &mat, const Vec3 &v); @@ -60,10 +61,11 @@ public: ~Renderer(); void set_view_matrix(const Matrix4 &view); void begin_frame(); - void render(const std::vector &triangles, GLuint texture); + void render(const std::vector &triangles); void end_frame(); bool should_close(); GLuint load_texture(const std::string &filepath); + GLFWwindow *get_window() { return window; } }; -#endif +#endif \ No newline at end of file diff --git a/Ps1Engine/loader/mesh.h b/Ps1Engine/loader/mesh.h deleted file mode 100644 index becd447..0000000 --- a/Ps1Engine/loader/mesh.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include -#include -#include -#include "renderer.h" // includes Vec3, Vec2, Triangle, Color - -std::vector load_obj(const std::string& obj_path); -std::map load_mtl_colors(const std::string& mtl_path); diff --git a/cube.cpp b/examples/cube.cpp similarity index 98% rename from cube.cpp rename to examples/cube.cpp index d8ca46c..97405a4 100644 --- a/cube.cpp +++ b/examples/cube.cpp @@ -1,4 +1,4 @@ -#include "renderer.h" +#include #include #include #include @@ -283,10 +283,11 @@ int main() t.uv1 = tri.uv1; t.uv2 = tri.uv2; t.color = tri.color; + t.texture = texture; transformed_cube.push_back(t); } - renderer.render(transformed_cube, texture); + renderer.render(transformed_cube); renderer.end_frame(); }