17 Commits

43 changed files with 10232 additions and 269 deletions

176
.gitattributes vendored
View File

@@ -43,7 +43,7 @@
*.udk lock
*.upk lock
# Anything in `/RawContent` dir
/RowContent/**/* lfs
/RawContent/**/* lfs
# Common files
*.3ds lock
*.3DS lock
@@ -167,6 +167,8 @@
*.TAR lfs
*.tar.gz lfs
*.TAR.GZ lfs
*.tga lfs
*.TGA lfs
*.tif lfs
*.TIF lfs
*.tiff lfs
@@ -210,175 +212,3 @@
*.DYLIB 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
# 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.

View File

@@ -1,5 +0,0 @@
varying vec3 fcolor;
void main() {
gl_FragColor = vec4(fcolor, 1);
}

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.

View File

@@ -0,0 +1,68 @@
uniform int useTexture;
uniform sampler2D texSampler;
uniform int numLights;
uniform vec4 materialColor;
uniform float shininess;
uniform vec3 ambientLight;
struct Light {
vec4 vector;
vec3 color;
float intensity;
float linear_att;
};
uniform Light lights[10];
varying vec3 fcolor;
varying vec2 ftexcoord;
varying vec3 fnormal;
varying vec4 fposition;
void main() {
vec3 diffuseAccum = vec3(0.0, 0.0, 0.0);
vec3 specularAccum = vec3(0.0, 0.0, 0.0);
if (numLights > 0) {
diffuseAccum = ambientLight;
for (int i = 0; i < 10; i++) {
if (i >= numLights) break;
vec3 N = normalize(fnormal);
vec3 L = lights[i].vector.xyz;
float attenuation = 1.0;
if (lights[i].vector.w == 1.0) {
L = L - fposition.xyz;
float distance = length(L);
attenuation = 1.0 / (1.0 + lights[i].linear_att * distance);
}
L = normalize(L);
float NdotL = max(dot(N, L), 0.0);
diffuseAccum += NdotL * lights[i].color * lights[i].intensity * attenuation;
if (shininess > 0.0 && NdotL > 0.0) {
vec3 V = normalize(-fposition.xyz);
vec3 H = normalize(L + V);
float NdotH = max(dot(N, H), 0.0);
specularAccum += pow(NdotH, shininess) * attenuation * lights[i].color * lights[i].intensity;
}
}
}
vec4 fragmentColor;
if (useTexture == 1) {
fragmentColor = texture2D(texSampler, ftexcoord);
} else {
fragmentColor = materialColor;
}
if (numLights > 0) {
gl_FragColor = vec4(fragmentColor.rgb * diffuseAccum + specularAccum, fragmentColor.a);
} else {
gl_FragColor = fragmentColor;
}
}

19
data/shaders/vertex.glsl Normal file
View File

@@ -0,0 +1,19 @@
uniform mat4 mvp;
uniform mat4 modelView;
uniform mat4 normalMatrix;
attribute vec3 vpos;
attribute vec3 vcolor;
attribute vec2 vtexcoord;
attribute vec3 vnormal;
varying vec3 fcolor;
varying vec2 ftexcoord;
varying vec3 fnormal;
varying vec4 fposition;
void main() {
gl_Position = mvp * vec4(vpos, 1);
fcolor = vcolor;
ftexcoord = vtexcoord;
fnormal = vec3(normalMatrix * vec4(vnormal, 0.0));
fposition = modelView * vec4(vpos, 1);
}

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

Binary file not shown.

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

Binary file not shown.

View File

@@ -1,9 +0,0 @@
uniform mat4 mvp;
attribute vec3 vpos;
attribute vec3 vcolor;
varying vec3 fcolor;
void main() {
gl_Position = mvp * vec4(vpos, 1);
fcolor = vcolor;
}

7187
lib/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

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),
indices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
nullptr);
glEnableVertexAttribArray(0);
// Note: Vertex attributes are set up by Shader::setup_attribs() during rendering
// This allows the shader to dynamically query and set the correct attribute locations
Logger::info(sstr("Buffer created with ", vertices.size(),
" vertices and ", indices.size(), " indices"));

View File

@@ -9,14 +9,21 @@
#include "buffer.h"
#include "camera.h"
#include "light.h"
#include "logger.h"
#include "material.h"
#include "mesh.h"
#include "model.h"
#include "shader.h"
#include "state.h"
#include "texture.h"
#include "vertex.h"
#include "world.h"
// Instance variables
std::shared_ptr<Light> point_light;
// Constants
constexpr int screen_width = 800;
constexpr int screen_height = 600;
constexpr double fps_limit = 1.0 / 60.0;
@@ -83,8 +90,8 @@ void Engine::initialize()
// Initialize default shader
Logger::info("Loading default shaders...");
state::default_shader =
std::make_shared<Shader>("data/vertex.glsl", "data/fragment.glsl");
state::default_shader = std::make_shared<Shader>(
"data/shaders/vertex.glsl", "data/shaders/fragment.glsl");
if (std::strlen(state::default_shader->error()) > 0) {
Logger::error(sstr("Failed to initialize shaders: ",
state::default_shader->error()));
@@ -109,7 +116,7 @@ void Engine::run()
const double now = glfwGetTime();
const double delta_time = now - last_update_time_;
process_input();
process_input(delta_time);
update(delta_time);
if (now - last_frame_time_ >= fps_limit) {
@@ -138,11 +145,13 @@ void Engine::setup()
// Create world
world_ = std::make_unique<World>();
world_->set_ambient(glm::vec3(0.2f, 0.2f, 0.2f));
Logger::info("World created");
// Create camera
camera_ = std::make_shared<Camera>();
camera_->set_position(glm::vec3(0.0f, 0.0f, 6.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_projection(
glm::perspective(glm::radians(45.0f),
static_cast<float>(screen_width_)
@@ -153,31 +162,50 @@ void Engine::setup()
world_->add_entity(camera_);
Logger::info("Camera created and added to world");
// Create triangle mesh
std::vector<Vertex> vertices = {
{{0.0f, 0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}},
{{-0.5f, -0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}},
{{0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}}};
std::vector<uint16_t> indices = {0, 1, 2};
auto buffer = std::make_shared<Buffer>(vertices, indices);
mesh_ = std::make_shared<Mesh>();
mesh_->add_buffer(buffer);
Logger::info(sstr("Mesh created with ", vertices.size(),
" vertices and ", indices.size(), " indices"));
// Create 9 models in a 3x3 grid
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
auto model = std::make_shared<Model>(mesh_);
model->set_position(
glm::vec3(-3.0f + static_cast<float>(col) * 3.0f,
0.0f, static_cast<float>(-row) * 3.0f));
models_.push_back(model);
world_->add_entity(model);
}
// Load the box_stack model
auto box_stack_mesh = Mesh::load("data/models/box_stack.obj");
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");
}
Logger::info(sstr("Created ", models_.size(), " models in scene"));
// Load the gunslinger model
auto gunslinger_mesh = Mesh::load("data/models/gunslinger.obj");
if (gunslinger_mesh) {
auto gunslinger_model =
std::make_shared<Model>(gunslinger_mesh);
gunslinger_model->set_position(glm::vec3(2.0f, 0.0f, 0.0f));
gunslinger_model->set_rotation(
glm::vec3(0.0f, glm::radians(-30.0f), 0.0f));
gunslinger_model->set_scale(glm::vec3(0.1f, 0.1f, 0.1f));
models_.push_back(gunslinger_model);
world_->add_entity(gunslinger_model);
Logger::info("Gunslinger model loaded and added to world");
}
// Create directional light
auto directional_light = std::make_shared<Light>();
directional_light->set_type(Light::Type::DIRECTIONAL);
directional_light->set_color(glm::vec3(1.0f, 1.0f, 1.0f));
directional_light->set_intensity(1.0f);
directional_light->set_position(glm::normalize(
glm::vec3(1.0f, 1.0f, 1.0f))); // Use position as direction
world_->add_entity(directional_light);
Logger::info("Directional light created and added to world");
// Create point light
point_light = std::make_shared<Light>();
point_light->set_type(Light::Type::POINT);
point_light->set_color(glm::vec3(1.0f, 0.0f, 0.0f));
point_light->set_intensity(2.0f);
point_light->set_linear_attenuation(0.2f);
point_light->set_position(glm::vec3(5.0f, 0.0f, 0.0f));
world_->add_entity(point_light);
Logger::info("Point light created and added to world");
Logger::info("Scene setup complete");
}
@@ -187,20 +215,52 @@ void Engine::start()
// 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();
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)
{
// Update angle for rotation
angle_ += 32.0 * delta_time;
// Update angle for orbiting light
angle_ += 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));
// Make point light orbit around the model
if (point_light) {
constexpr float radius = 7.5f;
point_light->set_position(glm::vec3(radius * cos(angle_), 2.0f,
radius * sin(angle_)));
}
// Update world

View File

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

56
src/light.cpp Normal file
View File

@@ -0,0 +1,56 @@
#include "light.h"
#include "../lib/glm/gtc/matrix_transform.hpp"
#include "shader.h"
#include "state.h"
Light::Light()
: Entity()
, type_(Type::DIRECTIONAL)
, color_(1.0f, 1.0f, 1.0f)
, intensity_(1.0f)
, linear_attenuation_(0.0f)
{
}
void Light::prepare(int index, std::shared_ptr<Shader>& shader) const
{
if (!shader)
return;
// Build uniform names for this light index
std::string light_vector =
"lights[" + std::to_string(index) + "].vector";
std::string light_color = "lights[" + std::to_string(index) + "].color";
std::string light_intensity =
"lights[" + std::to_string(index) + "].intensity";
std::string light_linear_att =
"lights[" + std::to_string(index) + "].linear_att";
// Get uniform locations
int vector_loc = shader->uniform_location(light_vector.c_str());
int color_loc = shader->uniform_location(light_color.c_str());
int intensity_loc = shader->uniform_location(light_intensity.c_str());
int linear_att_loc = shader->uniform_location(light_linear_att.c_str());
// Calculate light vector in view space
glm::vec4 light_vector_view;
if (type_ == Type::DIRECTIONAL) {
// For directional lights, w = 0
glm::vec3 direction =
glm::normalize(position_); // Use position as direction
light_vector_view =
state::view_matrix * glm::vec4(direction, 0.0f);
} else {
// For point lights, w = 1
light_vector_view =
state::view_matrix * glm::vec4(position_, 1.0f);
}
// Set uniforms
Shader::set_vec4(vector_loc, light_vector_view);
Shader::set_vec3(color_loc, color_);
Shader::set_float(intensity_loc, intensity_);
Shader::set_float(linear_att_loc, linear_attenuation_);
}

67
src/light.h Normal file
View File

@@ -0,0 +1,67 @@
#ifndef LIGHT_H_
#define LIGHT_H_
#include <memory>
#include "../lib/glm/glm.hpp"
#include "entity.h"
class Shader;
class Light : public Entity {
public:
enum class Type {
DIRECTIONAL,
POINT
};
Light();
~Light() override = default;
[[nodiscard]] Type type() const
{
return type_;
}
void set_type(Type type)
{
type_ = type;
}
[[nodiscard]] const glm::vec3& color() const
{
return color_;
}
void set_color(const glm::vec3& color)
{
color_ = color;
}
[[nodiscard]] float intensity() const
{
return intensity_;
}
void set_intensity(float intensity)
{
intensity_ = intensity;
}
[[nodiscard]] float linear_attenuation() const
{
return linear_attenuation_;
}
void set_linear_attenuation(float att)
{
linear_attenuation_ = att;
}
void prepare(int index, std::shared_ptr<Shader>& shader) const;
private:
Type type_;
glm::vec3 color_;
float intensity_;
float linear_attenuation_;
};
#endif // LIGHT_H_

View File

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

99
src/material.cpp Normal file
View File

@@ -0,0 +1,99 @@
#include "material.h"
#include "../lib/glm/glm.hpp"
#include "../lib/glm/gtc/matrix_transform.hpp"
#include "light.h"
#include "shader.h"
#include "state.h"
#include "texture.h"
Material::Material(const std::shared_ptr<Texture>& tex,
const std::shared_ptr<Shader>& shader)
: shader_(shader)
, texture_(tex)
, color_(1.0f, 1.0f, 1.0f, 1.0f)
, shininess_(0)
{
}
const std::shared_ptr<Shader>& Material::shader() const
{
return shader_ ? shader_ : state::default_shader;
}
std::shared_ptr<Shader>& Material::shader()
{
return shader_ ? shader_ : state::default_shader;
}
void Material::set_shader(const std::shared_ptr<Shader>& shader)
{
shader_ = shader;
}
void Material::prepare()
{
// Activate shader
std::shared_ptr<Shader> active_shader = shader();
if (!active_shader)
return;
active_shader->use();
// Set uniform variables
const glm::mat4 mvp =
state::projection_matrix * state::view_matrix * state::model_matrix;
const int mvp_loc = active_shader->uniform_location("mvp");
Shader::set_mat4(mvp_loc, mvp);
// Set ModelView matrix
const glm::mat4 model_view = state::view_matrix * state::model_matrix;
const int model_view_loc = active_shader->uniform_location("modelView");
Shader::set_mat4(model_view_loc, model_view);
// Set Normal matrix (transpose of inverse of ModelView)
const glm::mat4 normal_matrix =
glm::transpose(glm::inverse(model_view));
const int normal_matrix_loc =
active_shader->uniform_location("normalMatrix");
Shader::set_mat4(normal_matrix_loc, normal_matrix);
// Set material properties
const int material_color_loc =
active_shader->uniform_location("materialColor");
Shader::set_vec4(material_color_loc, color_);
const int shininess_loc = active_shader->uniform_location("shininess");
Shader::set_float(shininess_loc, static_cast<float>(shininess_));
// Set ambient light
const int ambient_loc = active_shader->uniform_location("ambientLight");
Shader::set_vec3(ambient_loc, state::ambient);
// Set number of lights
const int num_lights_loc = active_shader->uniform_location("numLights");
Shader::set_int(num_lights_loc, static_cast<int>(state::lights.size()));
// Prepare each light
for (size_t i = 0; i < state::lights.size(); ++i) {
state::lights[i]->prepare(static_cast<int>(i), active_shader);
}
// Set texture-related uniforms
const int use_texture_loc =
active_shader->uniform_location("useTexture");
if (texture_) {
Shader::set_int(use_texture_loc, 1);
const int sampler_loc =
active_shader->uniform_location("texSampler");
Shader::set_int(sampler_loc, 0); // Texture unit 0
} else {
Shader::set_int(use_texture_loc, 0);
}
// Bind texture if available
if (texture_) {
texture_->bind();
}
}

57
src/material.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef MATERIAL_H_
#define MATERIAL_H_
#include <memory>
#include "../lib/glm/glm.hpp"
class Shader;
class Texture;
class Material {
public:
Material(const std::shared_ptr<Texture>& tex = nullptr,
const std::shared_ptr<Shader>& shader = nullptr);
~Material() = default;
[[nodiscard]] const std::shared_ptr<Shader>& shader() const;
[[nodiscard]] std::shared_ptr<Shader>& shader();
void set_shader(const std::shared_ptr<Shader>& shader);
[[nodiscard]] const std::shared_ptr<Texture>& texture() const
{
return texture_;
}
void set_texture(const std::shared_ptr<Texture>& tex)
{
texture_ = tex;
}
[[nodiscard]] const glm::vec4& color() const
{
return color_;
}
void set_color(const glm::vec4& color)
{
color_ = color;
}
[[nodiscard]] uint8_t shininess() const
{
return shininess_;
}
void set_shininess(uint8_t shininess)
{
shininess_ = shininess;
}
void prepare();
private:
std::shared_ptr<Shader> shader_;
std::shared_ptr<Texture> texture_;
glm::vec4 color_;
uint8_t shininess_;
};
#endif // MATERIAL_H_

View File

@@ -1,33 +1,202 @@
#include "mesh.h"
#include <filesystem>
#include <string>
#include <unordered_map>
#include "../lib/tiny_obj_loader.h"
#include "buffer.h"
#include "logger.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];
}
// Normal
vertex.normal = glm::vec3(0.0f, 0.0f, 1.0f);
if (idx.normal_index >= 0) {
vertex.normal.x = attrib.normals[3 * idx.normal_index + 0];
vertex.normal.y = attrib.normals[3 * idx.normal_index + 1];
vertex.normal.z = attrib.normals[3 * idx.normal_index + 2];
}
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,
const std::shared_ptr<Shader>& shader)
const Material& material)
{
buffers_.push_back(buffer);
shaders_.push_back(shader);
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()
{
// Calculate MVP matrix
glm::mat4 mvp = state::projection_matrix * state::view_matrix
* state::model_matrix;
// Draw each buffer with its shader
// Draw each buffer with its material
for (size_t i = 0; i < buffers_.size(); ++i) {
// Use buffer's shader if available, otherwise use default
// shader
std::shared_ptr<Shader> shader =
shaders_[i] ? shaders_[i] : state::default_shader;
if (shader) {
shader->use();
int mvpLoc = shader->uniform_location("mvp");
Shader::set_mat4(mvpLoc, mvp);
buffers_[i]->draw(*shader);
}
materials_[i].prepare();
buffers_[i]->draw(*materials_[i].shader());
}
}

View File

@@ -4,6 +4,8 @@
#include <memory>
#include <vector>
#include "material.h"
class Buffer;
class Shader;
@@ -12,8 +14,12 @@ public:
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,
const std::shared_ptr<Shader>& shader = nullptr);
const Material& material);
[[nodiscard]] size_t num_buffers() const
{
@@ -28,11 +34,20 @@ public:
return buffers_[index];
}
[[nodiscard]] const Material& material(size_t index) const
{
return materials_[index];
}
[[nodiscard]] Material& material(size_t index)
{
return materials_[index];
}
void draw();
private:
std::vector<std::shared_ptr<Buffer>> buffers_;
std::vector<std::shared_ptr<Shader>> shaders_;
std::vector<Material> materials_;
};
#endif // MESH_H_

View File

@@ -10,11 +10,11 @@
#include "logger.h"
#include "vertex.h"
Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath)
Shader::Shader(const std::string& vertex_path, const std::string& fragment_path)
{
const uint32_t vshader = compile_shader(GL_VERTEX_SHADER, vertexPath);
const uint32_t vshader = compile_shader(GL_VERTEX_SHADER, vertex_path);
const uint32_t fshader =
compile_shader(GL_FRAGMENT_SHADER, fragmentPath);
compile_shader(GL_FRAGMENT_SHADER, fragment_path);
if (vshader == 0 || fshader == 0) {
program_id_ = 0;
@@ -65,6 +65,22 @@ void Shader::setup_attribs() const
loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<const void*>(offsetof(Vertex, color)));
}
loc = glGetAttribLocation(program_id_, "vtexcoord");
if (loc != -1) {
glEnableVertexAttribArray(loc);
glVertexAttribPointer(
loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<const void*>(offsetof(Vertex, tex_coord)));
}
loc = glGetAttribLocation(program_id_, "vnormal");
if (loc != -1) {
glEnableVertexAttribArray(loc);
glVertexAttribPointer(
loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<const void*>(offsetof(Vertex, normal)));
}
}
int Shader::uniform_location(const char* key) const
@@ -141,9 +157,8 @@ uint32_t Shader::compile_shader(uint32_t type, const std::string& source_path)
char buffer[1024];
glGetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
error_ = buffer;
Logger::error(
sstr("Shader compilation failed (", shader_type_name, "): ",
buffer));
Logger::error(sstr("Shader compilation failed (",
shader_type_name, "): ", buffer));
glDeleteShader(shader);
return 0;
}

View File

@@ -2,16 +2,20 @@
#define STATE_H_
#include <memory>
#include <vector>
#include "../lib/glm/glm.hpp"
class Shader;
class Light;
namespace state {
inline std::shared_ptr<Shader> default_shader = nullptr;
inline glm::mat4 projection_matrix = glm::mat4(1.0f);
inline glm::mat4 view_matrix = glm::mat4(1.0f);
inline glm::mat4 model_matrix = glm::mat4(1.0f);
inline std::shared_ptr<Shader> default_shader = nullptr;
inline glm::mat4 projection_matrix = glm::mat4(1.0f);
inline glm::mat4 view_matrix = glm::mat4(1.0f);
inline glm::mat4 model_matrix = glm::mat4(1.0f);
inline std::vector<std::shared_ptr<Light>> lights;
inline glm::vec3 ambient = glm::vec3(0.0f, 0.0f, 0.0f);
} // namespace state

81
src/texture.cpp Normal file
View File

@@ -0,0 +1,81 @@
#include "texture.h"
#include <algorithm>
#include "../lib/glew/GL/glew.h"
#include "../lib/glfw/glfw3.h"
#include "../lib/stb_image.h"
#include "logger.h"
Texture::Texture(uint32_t id, const glm::ivec2& size)
: id_(id), size_(size)
{
}
Texture::~Texture()
{
if (id_ != 0) {
glDeleteTextures(1, &id_);
Logger::info(sstr("Texture ", id_, " destroyed"));
}
}
std::shared_ptr<Texture> Texture::load(const char* filename)
{
Logger::info(sstr("Loading texture: ", filename));
// Load image
int width, height, channels;
stbi_uc* pixels =
stbi_load(filename, &width, &height, &channels, STBI_rgb_alpha);
if (!pixels) {
Logger::error(sstr("Failed to load texture: ", filename, " - ",
stbi_failure_reason()));
return nullptr;
}
// Flip image vertically (OpenGL expects bottom row first)
const int row_size = width * 4; // 4 channels (RGBA)
auto* row_buffer = new stbi_uc[row_size];
for (int y = 0; y < height / 2; ++y) {
stbi_uc* row1 = pixels + y * row_size;
stbi_uc* row2 = pixels + (height - 1 - y) * row_size;
std::copy(row1, row1 + row_size, row_buffer);
std::copy(row2, row2 + row_size, row1);
std::copy(row_buffer, row_buffer + row_size, row2);
}
delete[] row_buffer;
// Generate OpenGL texture
GLuint texture_id;
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
// Upload texture data
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, pixels);
// Set trilinear filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Generate mipmaps
glGenerateMipmap(GL_TEXTURE_2D);
// Free image data
stbi_image_free(pixels);
Logger::info(sstr("Texture loaded successfully: ", filename, " (",
width, "x", height, ", ", channels, " channels)"));
return std::shared_ptr<Texture>(
new Texture(texture_id, glm::ivec2(width, height)));
}
void Texture::bind() const
{
glBindTexture(GL_TEXTURE_2D, id_);
}

35
src/texture.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef TEXTURE_H_
#define TEXTURE_H_
#include <cstdint>
#include <memory>
#include <string>
#include "../lib/glm/glm.hpp"
class Texture {
public:
Texture() = delete;
~Texture();
static std::shared_ptr<Texture> load(const char* filename);
[[nodiscard]] uint32_t id() const
{
return id_;
}
[[nodiscard]] const glm::ivec2& size() const
{
return size_;
}
void bind() const;
private:
Texture(uint32_t id, const glm::ivec2& size);
uint32_t id_;
glm::ivec2 size_;
};
#endif // TEXTURE_H_

View File

@@ -6,6 +6,8 @@
struct Vertex {
glm::vec3 position{0.0f, 0.0f, 0.0f};
glm::vec3 color{0.0f, 0.0f, 0.0f};
glm::vec2 tex_coord{0.0f, 0.0f};
glm::vec3 normal{0.0f, 0.0f, 0.0f};
};
#endif // VERTEX_H_

View File

@@ -4,7 +4,9 @@
#include "camera.h"
#include "entity.h"
#include "light.h"
#include "logger.h"
#include "state.h"
void World::add_entity(const std::shared_ptr<Entity>& entity)
{
@@ -17,10 +19,20 @@ void World::add_entity(const std::shared_ptr<Entity>& entity)
cameras_.push_back(camera);
Logger::info(sstr("Camera added to world (total cameras: ",
cameras_.size(), ")"));
} else {
Logger::info(sstr("Entity added to world (total entities: ",
entities_.size(), ")"));
return;
}
// Check if entity is a light
std::shared_ptr<Light> light = std::dynamic_pointer_cast<Light>(entity);
if (light) {
lights_.push_back(light);
Logger::info(sstr("Light added to world (total lights: ",
lights_.size(), ")"));
return;
}
Logger::info(sstr(
"Entity added to world (total entities: ", entities_.size(), ")"));
}
void World::remove_entity(const std::shared_ptr<Entity>& entity)
@@ -43,6 +55,16 @@ void World::remove_entity(const std::shared_ptr<Entity>& entity)
Logger::info("Camera removed from world");
}
}
// Check if entity is a light and remove from lights list
std::shared_ptr<Light> light = std::dynamic_pointer_cast<Light>(entity);
if (light) {
auto lightIt = std::find(lights_.begin(), lights_.end(), light);
if (lightIt != lights_.end()) {
lights_.erase(lightIt);
Logger::info("Light removed from world");
}
}
}
void World::update(float delta_time)
@@ -54,6 +76,10 @@ void World::update(float delta_time)
void World::draw()
{
// Update state with world lighting information
state::ambient = ambient_;
state::lights = lights_;
// Draw for each camera
for (auto& camera : cameras_) {
// Prepare the camera (sets viewport, projection, view, clears

View File

@@ -4,8 +4,11 @@
#include <memory>
#include <vector>
#include "../lib/glm/glm.hpp"
class Entity;
class Camera;
class Light;
class World {
public:
@@ -27,12 +30,23 @@ public:
return entities_[index];
}
[[nodiscard]] const glm::vec3& ambient() const
{
return ambient_;
}
void set_ambient(const glm::vec3& ambient)
{
ambient_ = ambient;
}
void update(float delta_time);
void draw();
private:
std::vector<std::shared_ptr<Entity>> entities_;
std::vector<std::shared_ptr<Camera>> cameras_;
std::vector<std::shared_ptr<Light>> lights_;
glm::vec3 ambient_{0.0f, 0.0f, 0.0f};
};
#endif // WORLD_H_

View File

@@ -159,15 +159,19 @@
<ClInclude Include="lib\glew\GL\glew.h" />
<ClInclude Include="lib\glfw\glfw3.h" />
<ClInclude Include="lib\glfw\glfw3native.h" />
<ClInclude Include="lib\stb\stb_image.h" />
<ClInclude Include="src\buffer.h" />
<ClInclude Include="src\camera.h" />
<ClInclude Include="src\engine.h" />
<ClInclude Include="src\entity.h" />
<ClInclude Include="src\light.h" />
<ClInclude Include="src\logger.h" />
<ClInclude Include="src\material.h" />
<ClInclude Include="src\mesh.h" />
<ClInclude Include="src\model.h" />
<ClInclude Include="src\shader.h" />
<ClInclude Include="src\state.h" />
<ClInclude Include="src\texture.h" />
<ClInclude Include="src\vertex.h" />
<ClInclude Include="src\world.h" />
</ItemGroup>
@@ -177,17 +181,20 @@
<ClCompile Include="src\camera.cpp" />
<ClCompile Include="src\engine.cpp" />
<ClCompile Include="src\entity.cpp" />
<ClCompile Include="src\light.cpp" />
<ClCompile Include="src\logger.cpp" />
<ClCompile Include="src\main.cpp" />
<ClCompile Include="src\material.cpp" />
<ClCompile Include="src\mesh.cpp" />
<ClCompile Include="src\model.cpp" />
<ClCompile Include="src\shader.cpp" />
<ClCompile Include="src\texture.cpp" />
<ClCompile Include="src\vertex.cpp" />
<ClCompile Include="src\world.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="data\fragment.glsl" />
<None Include="data\vertex.glsl" />
<None Include="data\shaders\fragment.glsl" />
<None Include="data\shaders\vertex.glsl" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -19,6 +19,9 @@
<Filter Include="glew">
<UniqueIdentifier>{296e1ba9-28bc-4e0b-8d4e-413551edca96}</UniqueIdentifier>
</Filter>
<Filter Include="stb">
<UniqueIdentifier>{e3c5a7f2-1d4b-4a9c-8f2e-9b5c8d7a6e4f}</UniqueIdentifier>
</Filter>
<Filter Include="Shaders">
<UniqueIdentifier>{0628083b-a31c-4825-822c-11b6f933e7bd}</UniqueIdentifier>
</Filter>
@@ -33,6 +36,9 @@
<ClInclude Include="lib\glew\GL\glew.h">
<Filter>glew</Filter>
</ClInclude>
<ClInclude Include="lib\stb\stb_image.h">
<Filter>stb</Filter>
</ClInclude>
<ClInclude Include="src\vertex.h">
<Filter>Source Files</Filter>
</ClInclude>
@@ -66,6 +72,12 @@
<ClInclude Include="src\logger.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\material.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\texture.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\main.cpp">
@@ -104,12 +116,18 @@
<ClCompile Include="src\logger.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\material.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\texture.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="data\fragment.glsl">
<None Include="data\shaders\fragment.glsl">
<Filter>Shaders</Filter>
</None>
<None Include="data\vertex.glsl">
<None Include="data\shaders\vertex.glsl">
<Filter>Shaders</Filter>
</None>
</ItemGroup>