25 Commits

Author SHA1 Message Date
c34d3f803f chore: fix gitattributes 2025-10-14 02:37:33 +02:00
3b96b5008e fix: gitattributes 2025-10-14 02:36:38 +02:00
9f0f8667ec fix: gitignore and upload .obj files 2025-10-14 02:32:27 +02:00
58c761cb99 chore: add tga to git attribtues 2025-10-14 02:31:42 +02:00
2d5f145c34 chore: fix gitignure capitalization 2025-10-14 02:13:34 +02:00
0931f3ce91 doc: update readme 2025-10-14 02:12:01 +02:00
97606d398c fix: drawing issue 2025-10-13 21:22:35 +02:00
c30419899d fix: texture prasing 2025-10-13 20:56:26 +02:00
c1a5be6d90 fix: rotation 2025-10-13 20:12:46 +02:00
cf725c4c69 refactor: mesh load method 2025-10-13 19:59:29 +02:00
d084ce8799 feat: load obj 2025-10-13 19:47:21 +02:00
95275f9183 chore: add mem leaks checks 2025-10-13 19:28:22 +02:00
9124618ab6 feat: add assignment 4 resources and tinyobjloader lib 2025-10-13 19:26:49 +02:00
1089861aa3 feat: implement libraries in main 2025-10-13 18:25:55 +02:00
49219fc597 feat: assignment 3 2025-10-13 18:23:01 +02:00
db6e548476 feat: add assignment 3 files 2025-10-13 17:51:00 +02:00
22c46053c0 chore: change build dir name 2025-10-13 17:33:13 +02:00
41c9b68eb9 feat: add logger class 2025-10-13 17:30:05 +02:00
74a0bfca41 refactor: state into namespace 2025-10-13 17:17:28 +02:00
4e2c62aaf4 feat: engine class 2025-10-13 16:51:07 +02:00
f1a24f576b style: naming convention 2025-10-13 16:22:57 +02:00
f981cee4e0 feat: assignment 2 2025-10-13 15:04:53 +02:00
986e31dbef style: apply clang format 2025-10-13 14:39:27 +02:00
253bc47a5f fix: working dir 2025-10-13 13:45:09 +02:00
e07cdefacc chore: change sln dir 2025-10-13 13:36:58 +02:00
56 changed files with 10961 additions and 451 deletions

56
.clang-format Normal file
View File

@@ -0,0 +1,56 @@
Language: Cpp
BasedOnStyle: LLVM
AccessModifierOffset: -8
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveDeclarations: Consecutive
AlignConsecutiveMacros: Consecutive
AlignEscapedNewlines: Left
AlignOperands: DontAlign
AlignTrailingComments: Always
AllowShortBlocksOnASingleLine: Never
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: None
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakInheritanceList: AfterColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakStringLiterals: false
ColumnLimit: 80
Cpp11BracedListStyle: true
EmptyLineBeforeAccessModifier: Always
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 8
InsertNewlineAtEOF: true
InsertTrailingCommas: None
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
PackConstructorInitializers: NextLineOnly
PointerAlignment: Left
SortIncludes: Never
SpaceBeforeCaseColon: false
TabWidth: 8
UseTab: Always

64
.clang-tidy Normal file
View File

@@ -0,0 +1,64 @@
---
# C++ Core Guidelines style (CppCoreGuidelines)
Checks: >
cppcoreguidelines-*,
readability-identifier-naming,
readability-*,
modernize-*,
performance-*,
bugprone-*,
-modernize-use-trailing-return-type,
-readability-magic-numbers,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-pro-type-reinterpret-cast
CheckOptions:
# C++ Core Guidelines: Types use PascalCase
- { key: readability-identifier-naming.ClassCase, value: CamelCase }
- { key: readability-identifier-naming.StructCase, value: CamelCase }
- { key: readability-identifier-naming.EnumCase, value: CamelCase }
- { key: readability-identifier-naming.UnionCase, value: CamelCase }
# C++ Core Guidelines: Functions use snake_case (STL style)
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
- { key: readability-identifier-naming.MethodCase, value: lower_case }
# Member variables: snake_case with trailing underscore
- { key: readability-identifier-naming.PrivateMemberCase, value: lower_case }
- { key: readability-identifier-naming.PrivateMemberSuffix, value: '_' }
- { key: readability-identifier-naming.ProtectedMemberCase, value: lower_case }
- { key: readability-identifier-naming.ProtectedMemberSuffix, value: '_' }
- { key: readability-identifier-naming.PublicMemberCase, value: lower_case }
# Parameters and local variables: snake_case
- { key: readability-identifier-naming.ParameterCase, value: lower_case }
- { key: readability-identifier-naming.VariableCase, value: lower_case }
- { key: readability-identifier-naming.LocalVariableCase, value: lower_case }
# Constants and macros: UPPER_CASE
- { key: readability-identifier-naming.ConstantCase, value: UPPER_CASE }
- { key: readability-identifier-naming.ConstexprVariableCase, value: UPPER_CASE }
- { key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE }
- { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE }
# Global variables: snake_case (Core Guidelines: avoid globals when possible)
- { key: readability-identifier-naming.GlobalVariableCase, value: lower_case }
# Namespaces: snake_case
- { key: readability-identifier-naming.NamespaceCase, value: lower_case }
# Template parameters: PascalCase (following STL conventions)
- { key: readability-identifier-naming.TypeTemplateParameterCase, value: CamelCase }
- { key: readability-identifier-naming.ValueTemplateParameterCase, value: lower_case }
# Type aliases: PascalCase (modern C++ style with 'using')
- { key: readability-identifier-naming.TypeAliasCase, value: CamelCase }
# Function size limits
- { key: readability-function-size.LineThreshold, value: 100 }
- { key: readability-function-size.StatementThreshold, value: 50 }
WarningsAsErrors: ''
HeaderFilterRegex: 'src/.*\.h$'
FormatStyle: file

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.

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,12 @@
uniform int useTexture;
uniform sampler2D texSampler;
varying vec3 fcolor;
varying vec2 ftexcoord;
void main() {
if (useTexture == 1) {
gl_FragColor = texture2D(texSampler, ftexcoord);
} else {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
}

View File

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

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.

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

@@ -1,71 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="glfw">
<UniqueIdentifier>{422e20da-2cf0-4bda-9833-a89b7ab453a1}</UniqueIdentifier>
</Filter>
<Filter Include="glew">
<UniqueIdentifier>{296e1ba9-28bc-4e0b-8d4e-413551edca96}</UniqueIdentifier>
</Filter>
<Filter Include="Shaders">
<UniqueIdentifier>{0628083b-a31c-4825-822c-11b6f933e7bd}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\lib\glfw\glfw3.h">
<Filter>glfw</Filter>
</ClInclude>
<ClInclude Include="..\lib\glfw\glfw3native.h">
<Filter>glfw</Filter>
</ClInclude>
<ClInclude Include="..\lib\glew\GL\glew.h">
<Filter>glew</Filter>
</ClInclude>
<ClInclude Include="..\src\vertex.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\shader.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\buffer.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\lib\glew\glew.c">
<Filter>glew</Filter>
</ClCompile>
<ClCompile Include="..\src\vertex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\shader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\buffer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\data\fragment.glsl">
<Filter>Shaders</Filter>
</None>
<None Include="..\data\vertex.glsl">
<Filter>Shaders</Filter>
</None>
</ItemGroup>
</Project>

View File

@@ -1,14 +1,15 @@
#include "buffer.h" #include "buffer.h"
#include <vector> #include <vector>
#include <iostream>
#include "../lib/glew/GL/glew.h" #include "../lib/glew/GL/glew.h"
#include "../lib/glfw/glfw3.h" #include "../lib/glfw/glfw3.h"
#include "logger.h"
#include "vertex.h" #include "vertex.h"
Buffer::Buffer(const std::vector<Vertex>& vertices, const std::vector<uint16_t>& indices) Buffer::Buffer(const std::vector<Vertex>& vertices,
const std::vector<uint16_t>& indices)
{ {
index_count_ = static_cast<GLsizei>(indices.size()); index_count_ = static_cast<GLsizei>(indices.size());
@@ -19,13 +20,18 @@ Buffer::Buffer(const std::vector<Vertex>& vertices, const std::vector<uint16_t>&
glBindVertexArray(vao_); glBindVertexArray(vao_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_); glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex),
vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.data(), GL_STATIC_DRAW); 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); // Note: Vertex attributes are set up by Shader::setup_attribs() during rendering
glEnableVertexAttribArray(0); // 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"));
} }
Buffer::~Buffer() Buffer::~Buffer()
@@ -33,13 +39,14 @@ Buffer::~Buffer()
glDeleteVertexArrays(1, &vao_); glDeleteVertexArrays(1, &vao_);
glDeleteBuffers(1, &vbo_); glDeleteBuffers(1, &vbo_);
glDeleteBuffers(1, &ebo_); glDeleteBuffers(1, &ebo_);
Logger::info("Buffer destroyed");
} }
void Buffer::Draw(const Shader& shader) const void Buffer::draw(const Shader& shader) const
{ {
glBindVertexArray(vao_); glBindVertexArray(vao_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_); glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_);
shader.SetupAttribs(); shader.setup_attribs();
glDrawElements(GL_TRIANGLES, index_count_, GL_UNSIGNED_SHORT, nullptr); glDrawElements(GL_TRIANGLES, index_count_, GL_UNSIGNED_SHORT, nullptr);
} }

View File

@@ -10,10 +10,11 @@
class Buffer { class Buffer {
public: public:
Buffer(const std::vector<Vertex>& vertices, const std::vector<uint16_t>& indices); Buffer(const std::vector<Vertex>& vertices,
const std::vector<uint16_t>& indices);
~Buffer(); ~Buffer();
void Draw(const Shader& shader) const; void draw(const Shader& shader) const;
private: private:
uint32_t vao_, vbo_, ebo_; uint32_t vao_, vbo_, ebo_;

41
src/camera.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "camera.h"
#include "state.h"
#include "../lib/glew/GL/glew.h"
#include "../lib/glm/gtc/matrix_transform.hpp"
Camera::Camera()
: projection_(glm::mat4(1.0f))
, viewport_(0, 0, 800, 600)
, clear_color_(0.0f, 0.0f, 0.0f)
{
}
void Camera::prepare()
{
// Set projection matrix
state::projection_matrix = projection_;
// Calculate view matrix
// For a camera, we need the inverse transformation:
// View = inverse(Translation * Rotation)
// Which is: Rotation^-1 * Translation^-1
glm::mat4 view = glm::mat4(1.0f);
// Inverse rotation (rotate in opposite direction)
view = glm::rotate(view, -rotation_.z, glm::vec3(0.0f, 0.0f, 1.0f));
view = glm::rotate(view, -rotation_.y, glm::vec3(0.0f, 1.0f, 0.0f));
view = glm::rotate(view, -rotation_.x, glm::vec3(1.0f, 0.0f, 0.0f));
// Inverse translation (translate in opposite direction)
view = glm::translate(view, -position_);
state::view_matrix = view;
// Set viewport
glViewport(viewport_.x, viewport_.y, viewport_.z, viewport_.w);
glScissor(viewport_.x, viewport_.y, viewport_.z, viewport_.w);
// Set clear color and clear buffers
glClearColor(clear_color_.r, clear_color_.g, clear_color_.b, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

46
src/camera.h Normal file
View File

@@ -0,0 +1,46 @@
#ifndef CAMERA_H_
#define CAMERA_H_
#include "entity.h"
#include "../lib/glm/glm.hpp"
class Camera : public Entity {
public:
Camera();
[[nodiscard]] const glm::mat4& projection() const
{
return projection_;
}
void set_projection(const glm::mat4& proj)
{
projection_ = proj;
}
[[nodiscard]] const glm::ivec4& viewport() const
{
return viewport_;
}
void set_viewport(const glm::ivec4& vp)
{
viewport_ = vp;
}
[[nodiscard]] const glm::vec3& clear_color() const
{
return clear_color_;
}
void set_clear_color(const glm::vec3& color)
{
clear_color_ = color;
}
void prepare();
private:
glm::mat4 projection_;
glm::ivec4 viewport_;
glm::vec3 clear_color_;
};
#endif // CAMERA_H_

247
src/engine.cpp Normal file
View File

@@ -0,0 +1,247 @@
#include "engine.h"
#include <vector>
#include "../lib/glew/GL/glew.h"
#include "../lib/glfw/glfw3.h"
#include "../lib/glm/glm.hpp"
#include "../lib/glm/gtc/matrix_transform.hpp"
#include "buffer.h"
#include "camera.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"
constexpr int screen_width = 800;
constexpr int screen_height = 600;
constexpr double fps_limit = 1.0 / 60.0;
Engine::Engine()
: window_(nullptr)
, screen_width_(screen_width)
, screen_height_(screen_height)
, last_update_time_(0.0)
, last_frame_time_(0.0)
, angle_(0.0)
{
Logger::info("Engine created");
}
Engine::~Engine()
{
Logger::info("Engine destroyed");
destroy();
}
void Engine::initialize()
{
Logger::info("Initializing engine...");
// Initialize GLFW
if (!glfwInit()) {
Logger::error("Failed to initialize GLFW");
return;
}
Logger::info("GLFW initialized successfully");
glfwWindowHint(GLFW_RESIZABLE, false);
glfwWindowHint(GLFW_SAMPLES, 8);
// Create window
window_ = glfwCreateWindow(screen_width_, screen_height_,
"Daniel Poveda", nullptr, nullptr);
if (window_ == nullptr) {
Logger::error("Failed to create OpenGL window");
glfwTerminate();
return;
}
glfwMakeContextCurrent(window_);
// Enable OpenGL features
glEnable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
Logger::info(
sstr("OpenGL initialized, version: ",
reinterpret_cast<const char*>(glGetString(GL_VERSION))));
// Initialize GLEW
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (err != GLEW_OK) {
Logger::error(sstr(
"Failed to initialize GLEW: ",
reinterpret_cast<const char*>(glewGetErrorString(err))));
glfwTerminate();
return;
}
// Initialize default shader
Logger::info("Loading default shaders...");
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()));
} else {
Logger::info("Default shaders loaded successfully");
}
Logger::info("Engine initialization complete");
}
void Engine::run()
{
Logger::info("Starting game loop...");
setup();
start();
last_update_time_ = glfwGetTime();
last_frame_time_ = glfwGetTime();
while (is_running()) {
const double now = glfwGetTime();
const double delta_time = now - last_update_time_;
process_input(delta_time);
update(delta_time);
if (now - last_frame_time_ >= fps_limit) {
render();
last_frame_time_ = now;
}
last_update_time_ = now;
}
Logger::info("Game loop ended");
}
void Engine::destroy()
{
if (window_) {
Logger::info("Shutting down engine...");
glfwTerminate();
window_ = nullptr;
Logger::info("Engine shutdown complete");
}
}
void Engine::setup()
{
Logger::info("Setting up scene...");
// Create world
world_ = std::make_unique<World>();
Logger::info("World created");
// Create camera
camera_ = std::make_shared<Camera>();
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_)
/ static_cast<float>(screen_height_),
0.1f, 100.0f));
camera_->set_viewport(glm::ivec4(0, 0, screen_width_, screen_height_));
camera_->set_clear_color(glm::vec3(0.1f, 0.1f, 0.1f));
world_->add_entity(camera_);
Logger::info("Camera created and added to world");
// 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");
}
// 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");
}
Logger::info("Scene setup complete");
}
void Engine::start()
{
// Called once after setup, before the main loop
// Can be used for initialization that needs the scene to be ready
}
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 world
world_->update(static_cast<float>(delta_time));
}
void Engine::render()
{
// Draw world
world_->draw();
// Swap buffers
glfwSwapBuffers(window_);
}
bool Engine::is_running() const
{
return window_ && !glfwWindowShouldClose(window_)
&& !glfwGetKey(window_, GLFW_KEY_ESCAPE);
}

51
src/engine.h Normal file
View File

@@ -0,0 +1,51 @@
#ifndef ENGINE_H_
#define ENGINE_H_
#include <memory>
#include <vector>
#include "../lib/glew/GL/glew.h"
#include "../lib/glfw/glfw3.h"
class World;
class Camera;
class Model;
class Mesh;
class Engine {
public:
Engine();
~Engine();
void initialize();
void run();
void destroy();
private:
// Lifecycle methods
void setup();
void start();
void process_input(const double delta_time);
void update(const double delta_time);
void render();
[[nodiscard]] bool is_running() const;
// Window and OpenGL
GLFWwindow* window_;
int screen_width_;
int screen_height_;
// Game objects
std::unique_ptr<World> world_;
std::shared_ptr<Camera> camera_;
std::vector<std::shared_ptr<Model>> models_;
std::shared_ptr<Mesh> mesh_;
// Game loop timing
double last_update_time_;
double last_frame_time_;
double angle_;
};
#endif // ENGINE_H_

13
src/entity.cpp Normal file
View File

@@ -0,0 +1,13 @@
#include "entity.h"
Entity::Entity()
: position_(0.0f, 0.0f, 0.0f)
, rotation_(0.0f, 0.0f, 0.0f)
, scale_(1.0f, 1.0f, 1.0f)
{
}
void Entity::move(const glm::vec3& vec)
{
position_ += vec;
}

55
src/entity.h Normal file
View File

@@ -0,0 +1,55 @@
#ifndef ENTITY_H_
#define ENTITY_H_
#include "../lib/glm/glm.hpp"
class Entity {
public:
Entity();
virtual ~Entity() = default;
[[nodiscard]] const glm::vec3& position() const
{
return position_;
}
void set_position(const glm::vec3& pos)
{
position_ = pos;
}
[[nodiscard]] const glm::vec3& rotation() const
{
return rotation_;
}
void set_rotation(const glm::vec3& rot)
{
rotation_ = rot;
}
[[nodiscard]] const glm::vec3& scale() const
{
return scale_;
}
void set_scale(const glm::vec3& scale)
{
scale_ = scale;
}
void move(const glm::vec3& vec);
virtual void update(const float delta_time)
{
// ...
}
virtual void draw()
{
// ...
}
protected:
glm::vec3 position_;
glm::vec3 rotation_;
glm::vec3 scale_;
};
#endif // ENTITY_H_

57
src/logger.cpp Normal file
View File

@@ -0,0 +1,57 @@
#include "logger.h"
#include <chrono>
#include <iostream>
namespace {
std::string current_datetime_string()
{
auto now = std::chrono::system_clock::now();
auto now_time_t = std::chrono::system_clock::to_time_t(now);
struct tm now_tm {};
#ifdef _WIN32
localtime_s(&now_tm, &now_time_t);
#else
localtime_r(&now_time_t, &now_tm);
#endif
char buffer[30];
std::strftime(buffer, sizeof(buffer) / sizeof(char), "%Y-%m-%d %H:%M:%S",
&now_tm);
return std::string{buffer};
}
} // namespace
void Logger::info(const std::string& message)
{
LogEntry entry;
entry.type = LogType::info;
entry.message =
"[" + current_datetime_string() + "] [INFO]: " + message;
std::cout << "\x1B[32m" << entry.message << "\033[0m" << std::endl;
messages_.push_back(entry);
}
void Logger::warn(const std::string& message)
{
LogEntry entry;
entry.type = LogType::warn;
entry.message =
"[" + current_datetime_string() + "] [WARN]: " + message;
std::cout << "\x1B[93m" << entry.message << "\033[0m" << std::endl;
messages_.push_back(entry);
}
void Logger::error(const std::string& message)
{
LogEntry entry;
entry.type = LogType::error;
entry.message = "[" + current_datetime_string() + "] [ERROR]: " + message;
std::cerr << "\x1B[91m" << entry.message << "\033[0m" << std::endl;
messages_.push_back(entry);
}

48
src/logger.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef LOGGER_H_
#define LOGGER_H_
#include <sstream>
#include <string>
#include <vector>
// Utility: Concatenate any types into a string
template <typename... Args>
std::string sstr(Args&&... args)
{
std::ostringstream stream;
stream << std::dec;
((stream << args), ...);
return stream.str();
}
// Log types
enum class LogType {
info = 0,
warn,
error
};
// Log entry structure
struct LogEntry {
LogType type{LogType::info};
std::string message{};
};
// Logger class
class Logger {
public:
static void info(const std::string& message);
static void warn(const std::string& message);
static void error(const std::string& message);
[[nodiscard]] static const std::vector<LogEntry>& messages()
{
return messages_;
}
static void clear() { messages_.clear(); }
private:
inline static std::vector<LogEntry> messages_{};
};
#endif // LOGGER_H_

View File

@@ -1,118 +1,26 @@
/*#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
#include "../lib/stb_image.h"
#include <iostream> #define TINYOBJLOADER_IMPLEMENTATION
#include <vector> #include "../lib/tiny_obj_loader.h"
#include "../lib/glew/GL/glew.h" #include "engine.h"
#include "../lib/glfw/glfw3.h"
#include "../lib/glm/glm.hpp"
#include "../lib/glm/gtc/matrix_transform.hpp"
#include "vertex.h" int main()
#include "shader.h" {
#include "buffer.h" Engine engine;
#define SCREEN_WIDTH 800 engine.initialize();
#define SCREEN_HEIGHT 600 engine.run();
engine.destroy();
int main() { // _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
// Initialize OpenGL // _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
if (!glfwInit()) { // _CrtDumpMemoryLeaks();
std::cerr << "Failed to initialize glfw\n";
return 1;
}
glfwWindowHint(GLFW_RESIZABLE, false);
glfwWindowHint(GLFW_SAMPLES, 8);
//glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
//glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* win = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Daniel Poveda", nullptr, nullptr);
if (win == nullptr) {
std::cerr << "Failed to create opengl window\n";
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(win);
glEnable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
std::cout << "OpenGL initialized, version: " << glGetString(GL_VERSION) << "\n";
// Initialize GLEW
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (err != GLEW_OK) {
std::cerr << "Failed to initialize GLEW: " << glewGetErrorString(err) << "\n";
glfwTerminate();
return 1;
}
// Logic
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 };
Buffer buffer(vertices, indices);
Shader shader("data/vertex.glsl", "data/fragment.glsl");
if (std::strlen(shader.getError()) > 0) {
std::cerr << "Failed to initialize shaders: " << shader.getError() << "\n";
}
glm::mat4 projection = glm::perspective(glm::radians(45.0f), static_cast<float>(SCREEN_WIDTH) / SCREEN_HEIGHT, 0.1f, 100.0f);
//glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 6));
glm::mat4 view = glm::lookAt(glm::vec3(0, 0, 6), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
// main loop
double angle = 0.0;
double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(win) && !glfwGetKey(win, GLFW_KEY_ESCAPE)) {
// Delta
double delta_time = glfwGetTime() - lastTime;
lastTime = glfwGetTime();
// Reset window
int screenWidth, screenHeight;
glfwGetWindowSize(win, &screenWidth, &screenHeight);
glViewport(0, 0, screenWidth, screenHeight);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.Use();
// Logic
angle += 32.0 * delta_time;
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
glm::mat4 model = glm::translate(glm::mat4(1.0), glm::vec3(-3.0f + static_cast<float>(col) * 3.0f, 0.0f, static_cast<float>(-row) * 3.0f));
model = glm::rotate(model, glm::radians(static_cast<float>(angle)), glm::vec3(0, 1, 0));
glm::mat4 mvp = projection * view * model;
Shader::setMat4(shader.getLocation("mvp"), mvp);
buffer.Draw(shader);
}
}
// Refresh screen
glfwSwapBuffers(win);
glfwPollEvents();
}
// Shutdown
glfwTerminate();
return 0; return 0;
} }

61
src/material.cpp Normal file
View File

@@ -0,0 +1,61 @@
#include "material.h"
#include "../lib/glm/glm.hpp"
#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)
{
}
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 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();
}
}

35
src/material.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef MATERIAL_H_
#define MATERIAL_H_
#include <memory>
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;
}
void prepare();
private:
std::shared_ptr<Shader> shader_;
std::shared_ptr<Texture> texture_;
};
#endif // MATERIAL_H_

194
src/mesh.cpp Normal file
View File

@@ -0,0 +1,194 @@
#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];
}
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)
{
buffers_.push_back(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
for (size_t i = 0; i < buffers_.size(); ++i) {
materials_[i].prepare();
buffers_[i]->draw(*materials_[i].shader());
}
}

53
src/mesh.h Normal file
View File

@@ -0,0 +1,53 @@
#ifndef MESH_H_
#define MESH_H_
#include <memory>
#include <vector>
#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);
[[nodiscard]] size_t num_buffers() const
{
return buffers_.size();
}
[[nodiscard]] const std::shared_ptr<Buffer>& buffer(size_t index) const
{
return buffers_[index];
}
[[nodiscard]] std::shared_ptr<Buffer>& buffer(size_t index)
{
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<Material> materials_;
};
#endif // MESH_H_

35
src/model.cpp Normal file
View File

@@ -0,0 +1,35 @@
#include "model.h"
#include "mesh.h"
#include "state.h"
#include "../lib/glm/gtc/matrix_transform.hpp"
Model::Model(const std::shared_ptr<Mesh>& mesh)
: mesh_(mesh)
{
}
void Model::draw()
{
if (!mesh_)
return;
// Build model matrix: Translation * Rotation * Scale
glm::mat4 model = glm::mat4(1.0f);
// Translation
model = glm::translate(model, position_);
// Rotation (applying X, Y, Z rotations)
model = glm::rotate(model, rotation_.x, glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, rotation_.y, glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, rotation_.z, glm::vec3(0.0f, 0.0f, 1.0f));
// Scale
model = glm::scale(model, scale_);
// Set the model matrix in state
state::model_matrix = model;
// Draw the mesh
mesh_->draw();
}

19
src/model.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef MODEL_H_
#define MODEL_H_
#include "entity.h"
#include <memory>
class Mesh;
class Model : public Entity {
public:
Model(const std::shared_ptr<Mesh>& mesh);
virtual void draw() override;
private:
std::shared_ptr<Mesh> mesh_;
};
#endif // MODEL_H_

View File

@@ -1,19 +1,20 @@
#include "shader.h" #include "shader.h"
#include <vector>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <iostream> #include <vector>
#include "../lib/glew/GL/glew.h" #include "../lib/glew/GL/glew.h"
#include "../lib/glfw/glfw3.h" #include "../lib/glfw/glfw3.h"
#include "logger.h"
#include "vertex.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 = CompileShader(GL_VERTEX_SHADER, vertexPath); const uint32_t vshader = compile_shader(GL_VERTEX_SHADER, vertex_path);
const uint32_t fshader = CompileShader(GL_FRAGMENT_SHADER, fragmentPath); const uint32_t fshader =
compile_shader(GL_FRAGMENT_SHADER, fragment_path);
if (vshader == 0 || fshader == 0) { if (vshader == 0 || fshader == 0) {
program_id_ = 0; program_id_ = 0;
@@ -30,7 +31,8 @@ Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath)
glGetProgramiv(program_id_, GL_LINK_STATUS, &ret); glGetProgramiv(program_id_, GL_LINK_STATUS, &ret);
if (ret == GL_FALSE) { if (ret == GL_FALSE) {
char buffer[1024]; char buffer[1024];
glGetProgramInfoLog(program_id_, sizeof(buffer), nullptr, buffer); glGetProgramInfoLog(program_id_, sizeof(buffer), nullptr,
buffer);
error_ = buffer; error_ = buffer;
glDeleteProgram(program_id_); glDeleteProgram(program_id_);
program_id_ = 0; program_id_ = 0;
@@ -40,67 +42,80 @@ Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath)
glDeleteShader(fshader); glDeleteShader(fshader);
} }
void Shader::Use() const void Shader::use() const
{ {
if (program_id_ != 0) if (program_id_ != 0)
glUseProgram(program_id_); glUseProgram(program_id_);
} }
void Shader::SetupAttribs() const void Shader::setup_attribs() const
{ {
int loc = glGetAttribLocation(program_id_, "vpos"); int loc = glGetAttribLocation(program_id_, "vpos");
if (loc != -1) { if (loc != -1) {
glEnableVertexAttribArray(loc); glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const void*>(offsetof(Vertex, position))); glVertexAttribPointer(
loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<const void*>(offsetof(Vertex, position)));
} }
loc = glGetAttribLocation(program_id_, "vcolor"); loc = glGetAttribLocation(program_id_, "vcolor");
if (loc != -1) { if (loc != -1) {
glEnableVertexAttribArray(loc); glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const void*>(offsetof(Vertex, color))); glVertexAttribPointer(
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)));
} }
} }
int Shader::getLocation(const char* key) const int Shader::uniform_location(const char* key) const
{ {
return glGetUniformLocation(program_id_, key); return glGetUniformLocation(program_id_, key);
} }
void Shader::setInt(int loc, int value) void Shader::set_int(int loc, int value)
{ {
if (loc != -1) if (loc != -1)
glUniform1i(loc, value); glUniform1i(loc, value);
} }
void Shader::setFloat(int loc, float value) void Shader::set_float(int loc, float value)
{ {
if (loc != -1) if (loc != -1)
glUniform1f(loc, value); glUniform1f(loc, value);
} }
void Shader::setVec3(int loc, const glm::vec3& value) void Shader::set_vec3(int loc, const glm::vec3& value)
{ {
if (loc != -1) if (loc != -1)
glUniform3fv(loc, 1, &value[0]); glUniform3fv(loc, 1, &value[0]);
} }
void Shader::setVec4(int loc, const glm::vec4& value) void Shader::set_vec4(int loc, const glm::vec4& value)
{ {
if (loc != -1) if (loc != -1)
glUniform4fv(loc, 1, &value[0]); glUniform4fv(loc, 1, &value[0]);
} }
void Shader::setMat4(int loc, const glm::mat4& value) void Shader::set_mat4(int loc, const glm::mat4& value)
{ {
if (loc != -1) if (loc != -1)
glUniformMatrix4fv(loc, 1, GL_FALSE, &value[0][0]); glUniformMatrix4fv(loc, 1, GL_FALSE, &value[0][0]);
} }
std::string Shader::ReadShaderFile(const std::string& filename) std::string Shader::read_shader_file(const std::string& filename)
{ {
std::ifstream file(filename); std::ifstream file(filename);
if (!file) { if (!file) {
error_ = "Failed to open shader file: " + filename + "\n"; error_ = "Failed to open shader file: " + filename;
Logger::error(sstr("Failed to open shader file: ", filename));
return std::string{0}; return std::string{0};
} }
@@ -109,13 +124,18 @@ std::string Shader::ReadShaderFile(const std::string& filename)
return buffer.str(); return buffer.str();
} }
uint32_t Shader::CompileShader(uint32_t type, const std::string& source_path) uint32_t Shader::compile_shader(uint32_t type, const std::string& source_path)
{ {
std::string source = ReadShaderFile(source_path); const char* shader_type_name =
//std::cout << "SHADER FILE: " << source << "\n"; (type == GL_VERTEX_SHADER) ? "vertex" : "fragment";
std::string source = read_shader_file(source_path);
if (source.empty()) if (source.empty())
return 0; return 0;
Logger::info(
sstr("Compiling ", shader_type_name, " shader: ", source_path));
const uint32_t shader = glCreateShader(type); const uint32_t shader = glCreateShader(type);
const char* shader_code = source.c_str(); const char* shader_code = source.c_str();
@@ -129,9 +149,12 @@ uint32_t Shader::CompileShader(uint32_t type, const std::string& source_path)
char buffer[1024]; char buffer[1024];
glGetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer); glGetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
error_ = buffer; error_ = buffer;
Logger::error(sstr("Shader compilation failed (",
shader_type_name, "): ", buffer));
glDeleteShader(shader); glDeleteShader(shader);
return 0; return 0;
} }
Logger::info(sstr(shader_type_name, " shader compiled successfully"));
return shader; return shader;
} }

View File

@@ -9,29 +9,35 @@
class Shader { class Shader {
public: public:
Shader(const std::string& vertex_path, const std::string& fragment_path); Shader(const std::string& vertex_path,
const std::string& fragment_path);
void Use() const; void use() const;
void SetupAttribs() const; void setup_attribs() const;
uint32_t getId() const { return program_id_; } [[nodiscard]] uint32_t id() const
const char* getError() const { return error_.c_str(); } {
return program_id_;
}
[[nodiscard]] const char* error() const
{
return error_.c_str();
}
int getLocation(const char* key) const; [[nodiscard]] int uniform_location(const char* key) const;
static void setInt(int loc, int value); static void set_int(int loc, int value);
static void setFloat(int loc, float value); static void set_float(int loc, float value);
static void setVec3(int loc, const glm::vec3& value); static void set_vec3(int loc, const glm::vec3& value);
static void setVec4(int loc, const glm::vec4& value); static void set_vec4(int loc, const glm::vec4& value);
static void setMat4(int loc, const glm::mat4& value); static void set_mat4(int loc, const glm::mat4& value);
private: private:
uint32_t program_id_; uint32_t program_id_;
std::string error_; std::string error_;
std::string ReadShaderFile(const std::string& filename); std::string read_shader_file(const std::string& filename);
uint32_t CompileShader(uint32_t type, const std::string& source_path); uint32_t compile_shader(uint32_t type, const std::string& source_path);
}; };
#endif // SHADER_H_ #endif // SHADER_H_

18
src/state.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef STATE_H_
#define STATE_H_
#include <memory>
#include "../lib/glm/glm.hpp"
class Shader;
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);
} // namespace state
#endif // STATE_H_

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

@@ -4,8 +4,9 @@
#include "../lib/glm/glm.hpp" #include "../lib/glm/glm.hpp"
struct Vertex { struct Vertex {
glm::vec3 position{ 0.0f, 0.0f, 0.0f }; glm::vec3 position{0.0f, 0.0f, 0.0f};
glm::vec3 color{ 0.0f, 0.0f, 0.0f }; glm::vec3 color{0.0f, 0.0f, 0.0f};
glm::vec2 tex_coord{0.0f, 0.0f};
}; };
#endif // VERTEX_H_ #endif // VERTEX_H_

68
src/world.cpp Normal file
View File

@@ -0,0 +1,68 @@
#include "world.h"
#include <algorithm>
#include "camera.h"
#include "entity.h"
#include "logger.h"
void World::add_entity(const std::shared_ptr<Entity>& entity)
{
entities_.push_back(entity);
// Check if entity is a camera
std::shared_ptr<Camera> camera =
std::dynamic_pointer_cast<Camera>(entity);
if (camera) {
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(), ")"));
}
}
void World::remove_entity(const std::shared_ptr<Entity>& entity)
{
// Remove from entities list
auto it = std::find(entities_.begin(), entities_.end(), entity);
if (it != entities_.end()) {
entities_.erase(it);
Logger::info("Entity removed from world");
}
// Check if entity is a camera and remove from cameras list
std::shared_ptr<Camera> camera =
std::dynamic_pointer_cast<Camera>(entity);
if (camera) {
auto camIt =
std::find(cameras_.begin(), cameras_.end(), camera);
if (camIt != cameras_.end()) {
cameras_.erase(camIt);
Logger::info("Camera removed from world");
}
}
}
void World::update(float delta_time)
{
for (auto& entity : entities_) {
entity->update(delta_time);
}
}
void World::draw()
{
// Draw for each camera
for (auto& camera : cameras_) {
// Prepare the camera (sets viewport, projection, view, clears
// screen)
camera->prepare();
// Draw all entities
for (auto& entity : entities_) {
entity->draw();
}
}
}

38
src/world.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef WORLD_H_
#define WORLD_H_
#include <memory>
#include <vector>
class Entity;
class Camera;
class World {
public:
World() = default;
void add_entity(const std::shared_ptr<Entity>& entity);
void remove_entity(const std::shared_ptr<Entity>& entity);
[[nodiscard]] size_t num_entities() const
{
return entities_.size();
}
[[nodiscard]] const std::shared_ptr<Entity>& entity(size_t index) const
{
return entities_[index];
}
[[nodiscard]] std::shared_ptr<Entity>& entity(size_t index)
{
return entities_[index];
}
void update(float delta_time);
void draw();
private:
std::vector<std::shared_ptr<Entity>> entities_;
std::vector<std::shared_ptr<Camera>> cameras_;
};
#endif // WORLD_H_

View File

@@ -72,20 +72,20 @@
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup /> <PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)Build\$(Platform)\$(Configuration)\</OutDir> <OutDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)Build\obj\$(Platform)\$(Configuration)\</IntDir> <IntDir>$(SolutionDir)build\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)Build\$(Platform)\$(Configuration)\</OutDir> <OutDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)Build\obj\$(Platform)\$(Configuration)\</IntDir> <IntDir>$(SolutionDir)build\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)Build\$(Platform)\$(Configuration)\</OutDir> <OutDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)Build\obj\$(Platform)\$(Configuration)\</IntDir> <IntDir>$(SolutionDir)build\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)Build\$(Platform)\$(Configuration)\</OutDir> <OutDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)Build\obj\$(Platform)\$(Configuration)\</IntDir> <IntDir>$(SolutionDir)build\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
@@ -93,12 +93,12 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>../lib/glew</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>lib/glew</AdditionalIncludeDirectories>
<PreprocessorDefinitions>GLEW_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>GLEW_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalLibraryDirectories>../lib/glfw</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>lib/glfw</AdditionalLibraryDirectories>
<AdditionalDependencies>glfw3.win32.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>glfw3.win32.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@@ -108,12 +108,12 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>../lib/glew</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>lib/glew</AdditionalIncludeDirectories>
<PreprocessorDefinitions>GLEW_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>GLEW_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalLibraryDirectories>../lib/glfw</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>lib/glfw</AdditionalLibraryDirectories>
<AdditionalDependencies>glfw3.win64.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>glfw3.win64.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@@ -125,14 +125,14 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>../lib/glew</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>lib/glew</AdditionalIncludeDirectories>
<PreprocessorDefinitions>GLEW_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>GLEW_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>../lib/glfw</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>lib/glfw</AdditionalLibraryDirectories>
<AdditionalDependencies>glfw3.win32.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>glfw3.win32.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@@ -144,35 +144,55 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>../lib/glew</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>lib/glew</AdditionalIncludeDirectories>
<PreprocessorDefinitions>GLEW_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>GLEW_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>../lib/glfw</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>lib/glfw</AdditionalLibraryDirectories>
<AdditionalDependencies>glfw3.win64.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>glfw3.win64.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\lib\glew\GL\glew.h" /> <ClInclude Include="lib\glew\GL\glew.h" />
<ClInclude Include="..\lib\glfw\glfw3.h" /> <ClInclude Include="lib\glfw\glfw3.h" />
<ClInclude Include="..\lib\glfw\glfw3native.h" /> <ClInclude Include="lib\glfw\glfw3native.h" />
<ClInclude Include="..\src\buffer.h" /> <ClInclude Include="lib\stb\stb_image.h" />
<ClInclude Include="..\src\shader.h" /> <ClInclude Include="src\buffer.h" />
<ClInclude Include="..\src\vertex.h" /> <ClInclude Include="src\camera.h" />
<ClInclude Include="src\engine.h" />
<ClInclude Include="src\entity.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> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\lib\glew\glew.c" /> <ClCompile Include="lib\glew\glew.c" />
<ClCompile Include="..\src\buffer.cpp" /> <ClCompile Include="src\buffer.cpp" />
<ClCompile Include="..\src\main.cpp" /> <ClCompile Include="src\camera.cpp" />
<ClCompile Include="..\src\shader.cpp" /> <ClCompile Include="src\engine.cpp" />
<ClCompile Include="..\src\vertex.cpp" /> <ClCompile Include="src\entity.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>
<ItemGroup> <ItemGroup>
<None Include="..\data\fragment.glsl" /> <None Include="data\shaders\fragment.glsl" />
<None Include="..\data\vertex.glsl" /> <None Include="data\shaders\vertex.glsl" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

134
ugine3d.vcxproj.filters Normal file
View File

@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="glfw">
<UniqueIdentifier>{422e20da-2cf0-4bda-9833-a89b7ab453a1}</UniqueIdentifier>
</Filter>
<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>
</ItemGroup>
<ItemGroup>
<ClInclude Include="lib\glfw\glfw3.h">
<Filter>glfw</Filter>
</ClInclude>
<ClInclude Include="lib\glfw\glfw3native.h">
<Filter>glfw</Filter>
</ClInclude>
<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>
<ClInclude Include="src\shader.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\buffer.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\state.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\mesh.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\entity.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\model.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\camera.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\world.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\engine.h">
<Filter>Source Files</Filter>
</ClInclude>
<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">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="lib\glew\glew.c">
<Filter>glew</Filter>
</ClCompile>
<ClCompile Include="src\vertex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\shader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\buffer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\mesh.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\entity.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\model.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\camera.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\world.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\engine.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<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\shaders\fragment.glsl">
<Filter>Shaders</Filter>
</None>
<None Include="data\shaders\vertex.glsl">
<Filter>Shaders</Filter>
</None>
</ItemGroup>
</Project>

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerWorkingDirectory>..</LocalDebuggerWorkingDirectory> <LocalDebuggerWorkingDirectory>$(ProjectDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerWorkingDirectory>..</LocalDebuggerWorkingDirectory> <LocalDebuggerWorkingDirectory>$(ProjectDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerWorkingDirectory>..</LocalDebuggerWorkingDirectory> <LocalDebuggerWorkingDirectory>$(ProjectDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerWorkingDirectory>..</LocalDebuggerWorkingDirectory> <LocalDebuggerWorkingDirectory>$(ProjectDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
</Project> </Project>