Refactor engine code

This commit is contained in:
ExilProductions
2025-04-23 17:16:52 +02:00
parent 5ccf861eaa
commit b3981b90e4
10 changed files with 148 additions and 70 deletions

View File

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

16
.vscode/settings.json vendored
View File

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

View File

@@ -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)
target_link_libraries(Engine OpenGL::GL GLEW::GLEW glfw)

View File

@@ -7,13 +7,13 @@
namespace fs = std::filesystem;
std::map<std::string, Color> load_mtl_colors(const std::string& mtl_path)
std::map<std::string, Material> load_mtl_materials(const std::string& mtl_path)
{
std::map<std::string, Color> material_colors;
std::map<std::string, Material> 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<std::string, Color> 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<uint8_t>(r * 255),
static_cast<uint8_t>(g * 255),
static_cast<uint8_t>(b * 255)
);
if (materials.count(current_mtl)) {
materials[current_mtl].color = Color(
static_cast<uint8_t>(r * 255),
static_cast<uint8_t>(g * 255),
static_cast<uint8_t>(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<Triangle> load_obj(const std::string& obj_path)
std::vector<Triangle> load_obj(const std::string& obj_path, Renderer* renderer)
{
std::ifstream file(obj_path);
if (!file.is_open()) {
@@ -47,7 +56,8 @@ std::vector<Triangle> load_obj(const std::string& obj_path)
std::vector<Vec3> positions;
std::vector<Vec2> texcoords;
std::map<std::string, Color> materials;
std::map<std::string, Material> materials;
std::map<std::string, GLuint> texture_map;
std::vector<Triangle> triangles;
std::string current_material = "";
@@ -100,9 +110,11 @@ std::vector<Triangle> 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,7 +123,19 @@ std::vector<Triangle> 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;
}

15
Engine/loader/mesh.h Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
#include <string>
#include <vector>
#include <map>
#include "renderer.h" // includes Vec3, Vec2, Triangle, Color
struct Material
{
Color color;
std::string texture_path;
};
std::map<std::string, Material> load_mtl_materials(const std::string& mtl_path);
std::vector<Triangle> load_obj(const std::string& obj_path, Renderer* renderer);

2
Engine/ps1engine.h Normal file
View File

@@ -0,0 +1,2 @@
#include <renderer.h>
#include <mesh.h>

View File

@@ -1,6 +1,7 @@
#include "renderer.h"
#include <stdexcept>
#include <algorithm>
#include <map>
#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<Triangle> &triangles, GLuint texture)
void Renderer::render(const std::vector<Triangle> &triangles)
{
std::vector<Triangle> transformed_triangles;
@@ -124,6 +122,7 @@ void Renderer::render(const std::vector<Triangle> &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<Triangle> &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<GLuint, std::vector<Triangle>> 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<Triangle>& 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<float>(tri.v0.x), static_cast<float>(tri.v0.y), static_cast<float>(tri.v0.z) / 32767.0f);
glTexCoord2f(tri.uv1.x, tri.uv1.y);
glVertex3f(static_cast<float>(tri.v1.x), static_cast<float>(tri.v1.y), static_cast<float>(tri.v1.z) / 32767.0f);
glTexCoord2f(tri.uv2.x, tri.uv2.y);
glVertex3f(static_cast<float>(tri.v2.x), static_cast<float>(tri.v2.y), static_cast<float>(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<float>(tri.v0.x), static_cast<float>(tri.v0.y), static_cast<float>(tri.v0.z) / 32767.0f);
if (tex != 0)
{
glTexCoord2f(tri.uv1.x, tri.uv1.y);
}
glVertex3f(static_cast<float>(tri.v1.x), static_cast<float>(tri.v1.y), static_cast<float>(tri.v1.z) / 32767.0f);
if (tex != 0)
{
glTexCoord2f(tri.uv2.x, tri.uv2.y);
}
glVertex3f(static_cast<float>(tri.v2.x), static_cast<float>(tri.v2.y), static_cast<float>(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<float>(tri.v0.x), static_cast<float>(tri.v0.y), static_cast<float>(tri.v0.z) / 32767.0f);
glVertex3f(static_cast<float>(tri.v1.x), static_cast<float>(tri.v1.y), static_cast<float>(tri.v1.z) / 32767.0f);
glVertex3f(static_cast<float>(tri.v2.x), static_cast<float>(tri.v2.y), static_cast<float>(tri.v2.z) / 32767.0f);
glEnd();
if (tex != 0) glEnable(GL_TEXTURE_2D);
}
}
}
}
void Renderer::end_frame()
{
glfwSwapBuffers(window);
glfwPollEvents();
}

View File

@@ -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<Triangle> &triangles, GLuint texture);
void render(const std::vector<Triangle> &triangles);
void end_frame();
bool should_close();
GLuint load_texture(const std::string &filepath);
GLFWwindow *get_window() { return window; }
};
#endif

View File

@@ -1,9 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include <map>
#include "renderer.h" // includes Vec3, Vec2, Triangle, Color
std::vector<Triangle> load_obj(const std::string& obj_path);
std::map<std::string, Color> load_mtl_colors(const std::string& mtl_path);

View File

@@ -1,4 +1,4 @@
#include "renderer.h"
#include <ps1engine.h>
#include <iostream>
#include <vector>
#include <cmath>
@@ -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();
}