13 Commits

25 changed files with 2391 additions and 270 deletions

176
.gitattributes vendored
View File

@@ -43,7 +43,7 @@
*.udk lock *.udk lock
*.upk lock *.upk lock
# Anything in `/RawContent` dir # Anything in `/RawContent` dir
/RowContent/**/* lfs /RawContent/**/* lfs
# Common files # Common files
*.3ds lock *.3ds lock
*.3DS lock *.3DS lock
@@ -167,6 +167,8 @@
*.TAR lfs *.TAR lfs
*.tar.gz lfs *.tar.gz lfs
*.TAR.GZ lfs *.TAR.GZ lfs
*.tga lfs
*.TGA lfs
*.tif lfs *.tif lfs
*.TIF lfs *.TIF lfs
*.tiff lfs *.tiff lfs
@@ -210,175 +212,3 @@
*.DYLIB lfs *.DYLIB lfs
*.pdb lfs *.pdb lfs
*.PDB lfs *.PDB lfs
*.locres filter=lfs diff=lfs merge=lfs -text
*.locmeta filter=lfs diff=lfs merge=lfs -text
*.ico filter=lfs diff=lfs merge=lfs -text
*.uasset filter=lfs diff=lfs merge=lfs -text
*.umap filter=lfs diff=lfs merge=lfs -text
*.udk filter=lfs diff=lfs merge=lfs -text
*.upk filter=lfs diff=lfs merge=lfs -text
*.3DS filter=lfs diff=lfs merge=lfs -text
*.ABC filter=lfs diff=lfs merge=lfs -text
*.AEP filter=lfs diff=lfs merge=lfs -text
*.AFDESIGN filter=lfs diff=lfs merge=lfs -text
*.AFPHOTO filter=lfs diff=lfs merge=lfs -text
*.AI filter=lfs diff=lfs merge=lfs -text
*.AIF filter=lfs diff=lfs merge=lfs -text
*.AVI filter=lfs diff=lfs merge=lfs -text
*.BANK filter=lfs diff=lfs merge=lfs -text
*.BGEO filter=lfs diff=lfs merge=lfs -text
*.BIN filter=lfs diff=lfs merge=lfs -text
*.BLEND filter=lfs diff=lfs merge=lfs -text
*.BMP filter=lfs diff=lfs merge=lfs -text
*.BPOLY filter=lfs diff=lfs merge=lfs -text
*.C4D filter=lfs diff=lfs merge=lfs -text
*.DOC filter=lfs diff=lfs merge=lfs -text
*.DOCX filter=lfs diff=lfs merge=lfs -text
*.DWG filter=lfs diff=lfs merge=lfs -text
*.DXF filter=lfs diff=lfs merge=lfs -text
*.EXR filter=lfs diff=lfs merge=lfs -text
*.FBX filter=lfs diff=lfs merge=lfs -text
*.GEO filter=lfs diff=lfs merge=lfs -text
*.GI filter=lfs diff=lfs merge=lfs -text
*.GI2 filter=lfs diff=lfs merge=lfs -text
*.GIF filter=lfs diff=lfs merge=lfs -text
*.GLB filter=lfs diff=lfs merge=lfs -text
*.GLTF filter=lfs diff=lfs merge=lfs -text
*.HDR filter=lfs diff=lfs merge=lfs -text
*.HIP filter=lfs diff=lfs merge=lfs -text
*.HIPLC filter=lfs diff=lfs merge=lfs -text
*.HIPNC filter=lfs diff=lfs merge=lfs -text
*.JPEG filter=lfs diff=lfs merge=lfs -text
*.JPG filter=lfs diff=lfs merge=lfs -text
*.MA filter=lfs diff=lfs merge=lfs -text
*.MAX filter=lfs diff=lfs merge=lfs -text
*.MB filter=lfs diff=lfs merge=lfs -text
*.MOV filter=lfs diff=lfs merge=lfs -text
*.MP3 filter=lfs diff=lfs merge=lfs -text
*.MP4 filter=lfs diff=lfs merge=lfs -text
*.MPEG filter=lfs diff=lfs merge=lfs -text
*.MPG filter=lfs diff=lfs merge=lfs -text
*.OBJ filter=lfs diff=lfs merge=lfs -text
*.PDF filter=lfs diff=lfs merge=lfs -text
*.PFM filter=lfs diff=lfs merge=lfs -text
*.PIC filter=lfs diff=lfs merge=lfs -text
*.PMB filter=lfs diff=lfs merge=lfs -text
*.PNG filter=lfs diff=lfs merge=lfs -text
*.POLY filter=lfs diff=lfs merge=lfs -text
*.PPT filter=lfs diff=lfs merge=lfs -text
*.PPTX filter=lfs diff=lfs merge=lfs -text
*.PROFRAW filter=lfs diff=lfs merge=lfs -text
*.PRPROJ filter=lfs diff=lfs merge=lfs -text
*.PSB filter=lfs diff=lfs merge=lfs -text
*.PSD filter=lfs diff=lfs merge=lfs -text
*.RAR filter=lfs diff=lfs merge=lfs -text
*.RAT filter=lfs diff=lfs merge=lfs -text
*.RIB filter=lfs diff=lfs merge=lfs -text
*.SKETCH filter=lfs diff=lfs merge=lfs -text
*.STL filter=lfs diff=lfs merge=lfs -text
*.TAR filter=lfs diff=lfs merge=lfs -text
*.TAR.GZ filter=lfs diff=lfs merge=lfs -text
*.TIF filter=lfs diff=lfs merge=lfs -text
*.TIFF filter=lfs diff=lfs merge=lfs -text
*.TMP filter=lfs diff=lfs merge=lfs -text
*.UEXP filter=lfs diff=lfs merge=lfs -text
*.USD filter=lfs diff=lfs merge=lfs -text
*.USDC filter=lfs diff=lfs merge=lfs -text
*.USDZ filter=lfs diff=lfs merge=lfs -text
*.VDB filter=lfs diff=lfs merge=lfs -text
*.VOX filter=lfs diff=lfs merge=lfs -text
*.WAV filter=lfs diff=lfs merge=lfs -text
*.XCF filter=lfs diff=lfs merge=lfs -text
*.XLS filter=lfs diff=lfs merge=lfs -text
*.XLSX filter=lfs diff=lfs merge=lfs -text
*.ZIP filter=lfs diff=lfs merge=lfs -text
*.3ds filter=lfs diff=lfs merge=lfs -text
*.abc filter=lfs diff=lfs merge=lfs -text
*.aep filter=lfs diff=lfs merge=lfs -text
*.afdesign filter=lfs diff=lfs merge=lfs -text
*.afphoto filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
*.aif filter=lfs diff=lfs merge=lfs -text
*.avi filter=lfs diff=lfs merge=lfs -text
*.bank filter=lfs diff=lfs merge=lfs -text
*.bgeo filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text
*.bpoly filter=lfs diff=lfs merge=lfs -text
*.c4d filter=lfs diff=lfs merge=lfs -text
*.doc filter=lfs diff=lfs merge=lfs -text
*.docx filter=lfs diff=lfs merge=lfs -text
*.dwg filter=lfs diff=lfs merge=lfs -text
*.dxf filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.geo filter=lfs diff=lfs merge=lfs -text
*.gi filter=lfs diff=lfs merge=lfs -text
*.gi2 filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.glb filter=lfs diff=lfs merge=lfs -text
*.gltf filter=lfs diff=lfs merge=lfs -text
*.hdr filter=lfs diff=lfs merge=lfs -text
*.hip filter=lfs diff=lfs merge=lfs -text
*.hiplc filter=lfs diff=lfs merge=lfs -text
*.hipnc filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.ma filter=lfs diff=lfs merge=lfs -text
*.max filter=lfs diff=lfs merge=lfs -text
*.mb filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mpeg filter=lfs diff=lfs merge=lfs -text
*.mpg filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.pfm filter=lfs diff=lfs merge=lfs -text
*.pic filter=lfs diff=lfs merge=lfs -text
*.pmb filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.poly filter=lfs diff=lfs merge=lfs -text
*.ppt filter=lfs diff=lfs merge=lfs -text
*.pptx filter=lfs diff=lfs merge=lfs -text
*.profraw filter=lfs diff=lfs merge=lfs -text
*.prproj filter=lfs diff=lfs merge=lfs -text
*.psb filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.rar filter=lfs diff=lfs merge=lfs -text
*.rat filter=lfs diff=lfs merge=lfs -text
*.rib filter=lfs diff=lfs merge=lfs -text
*.sketch filter=lfs diff=lfs merge=lfs -text
*.stl filter=lfs diff=lfs merge=lfs -text
*.tar filter=lfs diff=lfs merge=lfs -text
*.tar.gz filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.tiff filter=lfs diff=lfs merge=lfs -text
*.tmp filter=lfs diff=lfs merge=lfs -text
*.uexp filter=lfs diff=lfs merge=lfs -text
*.usd filter=lfs diff=lfs merge=lfs -text
*.usdc filter=lfs diff=lfs merge=lfs -text
*.usdz filter=lfs diff=lfs merge=lfs -text
*.vdb filter=lfs diff=lfs merge=lfs -text
*.vox filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.xcf filter=lfs diff=lfs merge=lfs -text
*.xls filter=lfs diff=lfs merge=lfs -text
*.xlsx filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.a filter=lfs diff=lfs merge=lfs -text
*.A filter=lfs diff=lfs merge=lfs -text
*.lib filter=lfs diff=lfs merge=lfs -text
*.LIB filter=lfs diff=lfs merge=lfs -text
*.exe filter=lfs diff=lfs merge=lfs -text
*.EXE filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.DLL filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.SO filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text
*.DYLIB filter=lfs diff=lfs merge=lfs -text
*.pdb filter=lfs diff=lfs merge=lfs -text
*.PDB filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text

8
.gitignore vendored
View File

@@ -90,5 +90,9 @@ Mkfile.old
dkms.conf dkms.conf
# Build directory # Build directory
Build/ build/
**/Build/ **/build/
# Asset directory
!data/
!data/**

View File

@@ -1,3 +1,3 @@
# U-Tad: 3D Programming # U-Tad - 3D Programming
"3D Programming" subject assignments from the U-Tad's Master Degree in Video Game Programming. "3D Programming" subject assignments from the U-Tad's Master Degree in Video Game Programming.

35
data/models/box_stack.mtl Normal file
View File

@@ -0,0 +1,35 @@
# Blender MTL File: 'box_stack.blend'
# Material Count: 3
newmtl mat_bot
Ns 96.078431
Ka 0.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Ka top.png
newmtl mat_mid
Ns 96.078431
Ka 0.600000 0.600000 0.000000
Kd 0.640000 0.640000 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Ka front.png
newmtl mat_top
Ns 96.078431
Ka 1.000000 0.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Ka top.png

BIN
data/models/box_stack.obj (Stored with Git LFS) Normal file

Binary file not shown.

BIN
data/models/front.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@@ -0,0 +1,32 @@
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# File Created: 21.07.2015 23:00:44
newmtl revolver
Ns 30.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.5500 0.5500 0.5500
Kd 0.5500 0.5500 0.5500
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000
map_Ka revolver_dfs.tga
map_Kd revolver_dfs.tga
map_bump revolver_nrm.tga
bump revolver_nrm.tga
newmtl gunslinger
Ns 30.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.5500 0.5500 0.5500
Kd 0.5500 0.5500 0.5500
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000
map_Ka gunslinger_dfs.tga
map_Kd gunslinger_dfs.tga

BIN
data/models/gunslinger.obj (Stored with Git LFS) Normal file

Binary file not shown.

BIN
data/models/gunslinger_dfs.bmp (Stored with Git LFS) Normal file

Binary file not shown.

BIN
data/models/gunslinger_dfs.tga (Stored with Git LFS) Normal file

Binary file not shown.

BIN
data/models/gunslinger_nrm.tga (Stored with Git LFS) Normal file

Binary file not shown.

BIN
data/models/gunslinger_spc.tga (Stored with Git LFS) Normal file

Binary file not shown.

BIN
data/models/revolver_dfs.tga (Stored with Git LFS) Normal file

Binary file not shown.

BIN
data/models/revolver_nrm.tga (Stored with Git LFS) Normal file

Binary file not shown.

BIN
data/models/revolver_spc.tga (Stored with Git LFS) Normal file

Binary file not shown.

BIN
data/models/top.png (Stored with Git LFS) Normal file

Binary file not shown.

2029
lib/tiny_obj_loader.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -27,9 +27,8 @@ Buffer::Buffer(const std::vector<Vertex>& vertices,
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t),
indices.data(), GL_STATIC_DRAW); indices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), // Note: Vertex attributes are set up by Shader::setup_attribs() during rendering
nullptr); // This allows the shader to dynamically query and set the correct attribute locations
glEnableVertexAttribArray(0);
Logger::info(sstr("Buffer created with ", vertices.size(), Logger::info(sstr("Buffer created with ", vertices.size(),
" vertices and ", indices.size(), " indices")); " vertices and ", indices.size(), " indices"));

View File

@@ -111,7 +111,7 @@ void Engine::run()
const double now = glfwGetTime(); const double now = glfwGetTime();
const double delta_time = now - last_update_time_; const double delta_time = now - last_update_time_;
process_input(); process_input(delta_time);
update(delta_time); update(delta_time);
if (now - last_frame_time_ >= fps_limit) { if (now - last_frame_time_ >= fps_limit) {
@@ -142,9 +142,9 @@ void Engine::setup()
world_ = std::make_unique<World>(); world_ = std::make_unique<World>();
Logger::info("World created"); Logger::info("World created");
// Create camera at position (0, 1, 3) with -20 degrees X rotation // Create camera
camera_ = std::make_shared<Camera>(); camera_ = std::make_shared<Camera>();
camera_->set_position(glm::vec3(0.0f, 1.0f, 3.0f)); camera_->set_position(glm::vec3(0.0f, 4.0f, 12.0f));
camera_->set_rotation(glm::vec3(glm::radians(-20.0f), 0.0f, 0.0f)); camera_->set_rotation(glm::vec3(glm::radians(-20.0f), 0.0f, 0.0f));
camera_->set_projection( camera_->set_projection(
glm::perspective(glm::radians(45.0f), glm::perspective(glm::radians(45.0f),
@@ -156,78 +156,29 @@ void Engine::setup()
world_->add_entity(camera_); world_->add_entity(camera_);
Logger::info("Camera created and added to world"); Logger::info("Camera created and added to world");
// Load textures // Load the box_stack model
auto top_texture = Texture::load("data/textures/top.png"); auto box_stack_mesh = Mesh::load("data/models/box_stack.obj");
auto front_texture = Texture::load("data/textures/front.png"); if (box_stack_mesh) {
auto box_stack_model = std::make_shared<Model>(box_stack_mesh);
box_stack_model->set_position(glm::vec3(-2.0f, -1.25f, 0.0f));
models_.push_back(box_stack_model);
world_->add_entity(box_stack_model);
Logger::info("Box stack model loaded and added to world");
}
// Create cube mesh with two buffers // Load the gunslinger model
mesh_ = std::make_shared<Mesh>(); auto gunslinger_mesh = Mesh::load("data/models/gunslinger.obj");
if (gunslinger_mesh) {
// Buffer 1: Top and bottom faces auto gunslinger_model =
std::vector<Vertex> top_bottom_vertices = { std::make_shared<Model>(gunslinger_mesh);
// Top face (y = 0.5) gunslinger_model->set_position(glm::vec3(2.0f, 0.0f, 0.0f));
{{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}}, gunslinger_model->set_rotation(
{{0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}}, glm::vec3(0.0f, glm::radians(-30.0f), 0.0f));
{{0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}}, gunslinger_model->set_scale(glm::vec3(0.1f, 0.1f, 0.1f));
{{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}, models_.push_back(gunslinger_model);
// Bottom face (y = -0.5) world_->add_entity(gunslinger_model);
{{-0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}}, Logger::info("Gunslinger model loaded and added to world");
{{0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}}, }
{{0.5f, -0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
{{-0.5f, -0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}};
std::vector<uint16_t> top_bottom_indices = {// Top face
0, 1, 2, 0, 2, 3,
// Bottom face
4, 6, 5, 4, 7, 6};
auto top_bottom_buffer =
std::make_shared<Buffer>(top_bottom_vertices, top_bottom_indices);
Material top_material(top_texture);
mesh_->add_buffer(top_bottom_buffer, top_material);
// Buffer 2: Front, back, left, right faces
std::vector<Vertex> side_vertices = {
// Front face (z = 0.5)
{{-0.5f, -0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}},
{{0.5f, -0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}},
{{0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
{{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
// Back face (z = -0.5)
{{-0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}},
{{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
{{0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
{{0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}},
// Left face (x = -0.5)
{{-0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}},
{{-0.5f, -0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}},
{{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
{{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
// Right face (x = 0.5)
{{0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}},
{{0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
{{0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
{{0.5f, -0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}}};
std::vector<uint16_t> side_indices = {// Front face
0, 1, 2, 0, 2, 3,
// Back face
4, 5, 6, 4, 6, 7,
// Left face
8, 9, 10, 8, 10, 11,
// Right face
12, 13, 14, 12, 14, 15};
auto side_buffer =
std::make_shared<Buffer>(side_vertices, side_indices);
Material side_material(front_texture);
mesh_->add_buffer(side_buffer, side_material);
Logger::info("Cube mesh created with two buffers");
// Create model at origin
auto model = std::make_shared<Model>(mesh_);
model->set_position(glm::vec3(0.0f, 0.0f, 0.0f));
models_.push_back(model);
world_->add_entity(model);
Logger::info("Scene setup complete"); Logger::info("Scene setup complete");
} }
@@ -238,22 +189,44 @@ void Engine::start()
// Can be used for initialization that needs the scene to be ready // Can be used for initialization that needs the scene to be ready
} }
void Engine::process_input() void Engine::process_input(const double delta_time)
{ {
glfwPollEvents(); glfwPollEvents();
if (!camera_) {
return;
}
constexpr float camera_speed = 7.5f;
glm::vec3 forward = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 right = glm::vec3(1.0f, 0.0f, 0.0f);
glm::mat4 rotation = glm::mat4(1.0f);
rotation = glm::rotate(rotation, camera_->rotation().y,
glm::vec3(0.0f, 1.0f, 0.0f));
rotation = glm::rotate(rotation, camera_->rotation().x,
glm::vec3(1.0f, 0.0f, 0.0f));
forward = glm::vec3(rotation * glm::vec4(forward, 0.0f));
right = glm::vec3(rotation * glm::vec4(right, 0.0f));
const float movement = camera_speed * static_cast<float>(delta_time);
if (glfwGetKey(window_, GLFW_KEY_UP) == GLFW_PRESS) {
camera_->set_position(camera_->position() + forward * movement);
}
if (glfwGetKey(window_, GLFW_KEY_DOWN) == GLFW_PRESS) {
camera_->set_position(camera_->position() - forward * movement);
}
if (glfwGetKey(window_, GLFW_KEY_LEFT) == GLFW_PRESS) {
camera_->set_position(camera_->position() - right * movement);
}
if (glfwGetKey(window_, GLFW_KEY_RIGHT) == GLFW_PRESS) {
camera_->set_position(camera_->position() + right * movement);
}
} }
void Engine::update(const double delta_time) void Engine::update(const double delta_time)
{ {
// Update angle for rotation
angle_ += 32.0 * delta_time;
// Update rotation for all models
for (auto& model : models_) {
model->set_rotation(glm::vec3(
0.0f, glm::radians(static_cast<float>(angle_)), 0.0f));
}
// Update world // Update world
world_->update(static_cast<float>(delta_time)); world_->update(static_cast<float>(delta_time));
} }

View File

@@ -25,7 +25,7 @@ private:
// Lifecycle methods // Lifecycle methods
void setup(); void setup();
void start(); void start();
void process_input(); void process_input(const double delta_time);
void update(const double delta_time); void update(const double delta_time);
void render(); void render();

View File

@@ -1,9 +1,12 @@
/*#ifdef _MSC_VER // #ifdef _MSC_VER
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") // #pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#endif*/ // #endif
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "../lib/stb/stb_image.h" #include "../lib/stb_image.h"
#define TINYOBJLOADER_IMPLEMENTATION
#include "../lib/tiny_obj_loader.h"
#include "engine.h" #include "engine.h"
@@ -15,5 +18,9 @@ int main()
engine.run(); engine.run();
engine.destroy(); engine.destroy();
// _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
// _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
// _CrtDumpMemoryLeaks();
return 0; return 0;
} }

View File

@@ -1,15 +1,189 @@
#include "mesh.h" #include "mesh.h"
#include <filesystem>
#include <string>
#include <unordered_map>
#include "../lib/tiny_obj_loader.h"
#include "buffer.h" #include "buffer.h"
#include "logger.h"
#include "material.h" #include "material.h"
#include "shader.h"
#include "state.h"
#include "texture.h"
#include "vertex.h"
// Helper structures and functions for OBJ loading
namespace {
struct LoadContext {
std::string base_dir;
std::unordered_map<std::string, std::shared_ptr<Texture>> texture_cache;
const std::vector<tinyobj::material_t>* materials;
const std::shared_ptr<Shader>& shader;
};
Vertex create_vertex(const tinyobj::attrib_t& attrib,
const tinyobj::index_t& idx)
{
Vertex vertex;
// Position
if (idx.vertex_index >= 0) {
vertex.position.x = attrib.vertices[3 * idx.vertex_index + 0];
vertex.position.y = attrib.vertices[3 * idx.vertex_index + 1];
vertex.position.z = attrib.vertices[3 * idx.vertex_index + 2];
}
// Color (default to white)
vertex.color = glm::vec3(1.0f, 1.0f, 1.0f);
// Texture coordinates
vertex.tex_coord = glm::vec2(0.0f, 0.0f);
if (idx.texcoord_index >= 0) {
vertex.tex_coord.x = attrib.texcoords[2 * idx.texcoord_index + 0];
vertex.tex_coord.y = attrib.texcoords[2 * idx.texcoord_index + 1];
}
return vertex;
}
void process_shape(const tinyobj::shape_t& shape,
const tinyobj::attrib_t& attrib,
std::vector<Vertex>& out_vertices,
std::vector<uint16_t>& out_indices)
{
// Process all indices - create one vertex per index
for (size_t i = 0; i < shape.mesh.indices.size(); ++i) {
const tinyobj::index_t& idx = shape.mesh.indices[i];
Vertex vertex = create_vertex(attrib, idx);
out_vertices.push_back(vertex);
out_indices.push_back(
static_cast<uint16_t>(out_vertices.size() - 1));
}
}
std::shared_ptr<Texture> load_material_texture(int material_id,
LoadContext& context)
{
if (material_id < 0
|| material_id >= static_cast<int>(context.materials->size())) {
return nullptr;
}
const auto& mat = (*context.materials)[material_id];
std::string texture_name = mat.diffuse_texname;
// Try ambient texture if diffuse is not available
if (texture_name.empty()) {
texture_name = mat.ambient_texname;
}
if (texture_name.empty()) {
return nullptr;
}
// Check cache first
auto it = context.texture_cache.find(texture_name);
if (it != context.texture_cache.end()) {
return it->second;
}
// Load texture
std::string texture_path = context.base_dir + texture_name;
auto texture = Texture::load(texture_path.c_str());
if (texture) {
context.texture_cache[texture_name] = texture;
Logger::info(sstr("Loaded texture: ", texture_path));
} else {
Logger::warn(sstr("Failed to load texture: ", texture_path));
}
return texture;
}
void create_buffer_for_shape(const tinyobj::shape_t& shape,
const std::vector<Vertex>& vertices,
const std::vector<uint16_t>& indices,
LoadContext& context,
std::shared_ptr<Mesh>& mesh)
{
auto buffer = std::make_shared<Buffer>(vertices, indices);
// Use first material ID from the shape
int material_id = -1;
if (!shape.mesh.material_ids.empty() && shape.mesh.material_ids[0] >= 0) {
material_id = shape.mesh.material_ids[0];
}
auto texture = load_material_texture(material_id, context);
auto material_shader =
context.shader ? context.shader : state::default_shader;
Material mat(texture, material_shader);
mesh->add_buffer(buffer, mat);
}
} // namespace
void Mesh::add_buffer(const std::shared_ptr<Buffer>& buffer, void Mesh::add_buffer(const std::shared_ptr<Buffer>& buffer,
const Material& material) const Material& material)
{ {
buffers_.push_back(buffer); buffers_.push_back(buffer);
materials_.push_back(material); materials_.push_back(material);
} }
std::shared_ptr<Mesh> Mesh::load(const char* filename,
const std::shared_ptr<Shader>& shader)
{
Logger::info(sstr("Loading mesh from: ", filename));
// Load OBJ file
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
std::filesystem::path obj_path(filename);
std::string base_dir = obj_path.parent_path().string();
if (!base_dir.empty()) {
base_dir += "/";
}
if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename,
base_dir.c_str())) {
Logger::error(
sstr("Failed to load OBJ file: ", filename, " - ", err));
return nullptr;
}
if (!err.empty()) {
Logger::warn(sstr("TinyObjLoader warning: ", err));
}
// Setup load context
LoadContext context{base_dir, {}, &materials, shader};
// Process each shape
auto mesh = std::make_shared<Mesh>();
for (const auto& shape : shapes) {
Logger::info(sstr("Processing shape: ", shape.name));
std::vector<Vertex> vertices;
std::vector<uint16_t> indices;
process_shape(shape, attrib, vertices, indices);
create_buffer_for_shape(shape, vertices, indices, context, mesh);
}
Logger::info(sstr("Mesh loaded successfully with ", mesh->num_buffers(),
" buffers"));
return mesh;
}
void Mesh::draw() void Mesh::draw()
{ {
// Draw each buffer with its material // Draw each buffer with its material

View File

@@ -7,12 +7,17 @@
#include "material.h" #include "material.h"
class Buffer; class Buffer;
class Shader;
class Mesh { class Mesh {
public: public:
Mesh() = default; Mesh() = default;
~Mesh() = default; ~Mesh() = default;
static std::shared_ptr<Mesh>
load(const char* filename,
const std::shared_ptr<Shader>& shader = nullptr);
void add_buffer(const std::shared_ptr<Buffer>& buffer, void add_buffer(const std::shared_ptr<Buffer>& buffer,
const Material& material); const Material& material);

View File

@@ -4,7 +4,7 @@
#include "../lib/glew/GL/glew.h" #include "../lib/glew/GL/glew.h"
#include "../lib/glfw/glfw3.h" #include "../lib/glfw/glfw3.h"
#include "../lib/stb/stb_image.h" #include "../lib/stb_image.h"
#include "logger.h" #include "logger.h"