Compare commits
14 Commits
assignment
...
assignment
| Author | SHA1 | Date | |
|---|---|---|---|
| 50a4f56e75 | |||
| c34d3f803f | |||
| 3b96b5008e | |||
| 9f0f8667ec | |||
| 58c761cb99 | |||
| 2d5f145c34 | |||
| 0931f3ce91 | |||
| 97606d398c | |||
| c30419899d | |||
| c1a5be6d90 | |||
| cf725c4c69 | |||
| d084ce8799 | |||
| 95275f9183 | |||
| 9124618ab6 |
176
.gitattributes
vendored
176
.gitattributes
vendored
@@ -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
8
.gitignore
vendored
@@ -90,5 +90,9 @@ Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# Build directory
|
||||
Build/
|
||||
**/Build/
|
||||
build/
|
||||
**/build/
|
||||
|
||||
# Asset directory
|
||||
!data/
|
||||
!data/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
35
data/models/box_stack.mtl
Normal file
35
data/models/box_stack.mtl
Normal 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
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
BIN
data/models/front.png
(Stored with Git LFS)
Normal file
Binary file not shown.
32
data/models/gunslinger.mtl
Normal file
32
data/models/gunslinger.mtl
Normal 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
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
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
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
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
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
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
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
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
BIN
data/models/top.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -1,12 +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) {
|
||||
gl_FragColor = texture2D(texSampler, ftexcoord);
|
||||
fragmentColor = texture2D(texSampler, ftexcoord);
|
||||
} else {
|
||||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
fragmentColor = materialColor;
|
||||
}
|
||||
|
||||
if (numLights > 0) {
|
||||
gl_FragColor = vec4(fragmentColor.rgb * diffuseAccum + specularAccum, fragmentColor.a);
|
||||
} else {
|
||||
gl_FragColor = fragmentColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +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);
|
||||
}
|
||||
2029
lib/tiny_obj_loader.h
Normal file
2029
lib/tiny_obj_loader.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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"));
|
||||
|
||||
167
src/engine.cpp
167
src/engine.cpp
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "buffer.h"
|
||||
#include "camera.h"
|
||||
#include "light.h"
|
||||
#include "logger.h"
|
||||
#include "material.h"
|
||||
#include "mesh.h"
|
||||
@@ -19,6 +20,10 @@
|
||||
#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;
|
||||
@@ -111,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) {
|
||||
@@ -140,11 +145,12 @@ 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 at position (0, 1, 3) with -20 degrees X rotation
|
||||
// Create 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_projection(
|
||||
glm::perspective(glm::radians(45.0f),
|
||||
@@ -156,78 +162,49 @@ void Engine::setup()
|
||||
world_->add_entity(camera_);
|
||||
Logger::info("Camera created and added to world");
|
||||
|
||||
// Load textures
|
||||
auto top_texture = Texture::load("data/textures/top.png");
|
||||
auto front_texture = Texture::load("data/textures/front.png");
|
||||
// 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");
|
||||
}
|
||||
|
||||
// Create cube mesh with two buffers
|
||||
mesh_ = std::make_shared<Mesh>();
|
||||
// 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");
|
||||
}
|
||||
|
||||
// Buffer 1: Top and bottom faces
|
||||
std::vector<Vertex> top_bottom_vertices = {
|
||||
// Top face (y = 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}},
|
||||
// Bottom face (y = -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}}};
|
||||
std::vector<uint16_t> top_bottom_indices = {// Top face
|
||||
0, 1, 2, 0, 2, 3,
|
||||
// Bottom face
|
||||
4, 6, 5, 4, 7, 6};
|
||||
// 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");
|
||||
|
||||
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);
|
||||
// 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");
|
||||
}
|
||||
@@ -238,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
|
||||
|
||||
@@ -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
56
src/light.cpp
Normal 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
67
src/light.h
Normal 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_
|
||||
15
src/main.cpp
15
src/main.cpp
@@ -1,9 +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/stb_image.h"
|
||||
#include "../lib/stb_image.h"
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "../lib/tiny_obj_loader.h"
|
||||
|
||||
#include "engine.h"
|
||||
|
||||
@@ -15,5 +18,9 @@ int main()
|
||||
engine.run();
|
||||
engine.destroy();
|
||||
|
||||
// _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
|
||||
// _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
|
||||
// _CrtDumpMemoryLeaks();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
#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)
|
||||
: shader_(shader)
|
||||
, texture_(tex)
|
||||
, color_(1.0f, 1.0f, 1.0f, 1.0f)
|
||||
, shininess_(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -42,6 +47,39 @@ void Material::prepare()
|
||||
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");
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "../lib/glm/glm.hpp"
|
||||
|
||||
class Shader;
|
||||
class Texture;
|
||||
|
||||
@@ -25,11 +27,31 @@ public:
|
||||
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_
|
||||
|
||||
182
src/mesh.cpp
182
src/mesh.cpp
@@ -1,7 +1,141 @@
|
||||
#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 Material& material)
|
||||
@@ -10,6 +144,54 @@ void Mesh::add_buffer(const std::shared_ptr<Buffer>& buffer,
|
||||
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()
|
||||
{
|
||||
// Draw each buffer with its material
|
||||
|
||||
@@ -7,12 +7,17 @@
|
||||
#include "material.h"
|
||||
|
||||
class Buffer;
|
||||
class Shader;
|
||||
|
||||
class Mesh {
|
||||
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 Material& material);
|
||||
|
||||
|
||||
@@ -73,6 +73,14 @@ void Shader::setup_attribs() const
|
||||
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
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
#define STATE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "../lib/glm/glm.hpp"
|
||||
|
||||
class Shader;
|
||||
class Light;
|
||||
|
||||
namespace state {
|
||||
|
||||
@@ -12,6 +14,8 @@ 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
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "../lib/glew/GL/glew.h"
|
||||
#include "../lib/glfw/glfw3.h"
|
||||
#include "../lib/stb/stb_image.h"
|
||||
#include "../lib/stb_image.h"
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ 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_
|
||||
|
||||
@@ -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
|
||||
|
||||
14
src/world.h
14
src/world.h
@@ -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_
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
<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" />
|
||||
@@ -180,6 +181,7 @@
|
||||
<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" />
|
||||
|
||||
Reference in New Issue
Block a user