├── .gitattributes ├── .gitignore ├── License.md ├── ProjectIW.sln ├── ProjectIW ├── Box.cpp ├── Box.h ├── Camera.cpp ├── Camera.h ├── ConstantsBuffer.cpp ├── ConstantsBuffer.h ├── DirectInput.cpp ├── DirectInput.h ├── Engine.cpp ├── Engine.h ├── GPUMesh.cpp ├── GPUMesh.h ├── General.h ├── GeometryShader.hlsl ├── IBO.cpp ├── IBO.h ├── InputController.cpp ├── InputController.h ├── LRUCache.hpp ├── MeshGeneration.cpp ├── MeshGeneration.h ├── NodeCache.cpp ├── NodeCache.h ├── NodeCreation.cpp ├── NodeCreation.h ├── Octree.cpp ├── Octree.h ├── OctreeNode.cpp ├── OctreeNode.h ├── PixelShader.hlsl ├── ProjectIW.vcxproj ├── ProjectIW.vcxproj.filters ├── QEFSolver.cpp ├── QEFSolver.h ├── RenderEngine.cpp ├── RenderEngine.h ├── SVD.cpp ├── SVD.h ├── Scene.cpp ├── Scene.h ├── Shader.cpp ├── Shader.h ├── ShaderConstants.h ├── ShaderGroup.cpp ├── ShaderGroup.h ├── ShaderLoader.cpp ├── ShaderLoader.h ├── SimpleMath.h ├── SimpleMath.inl ├── SimplexNoise.cpp ├── SimplexNoise.h ├── Tables.cpp ├── Tables.h ├── Task.h ├── TerrainChunk.cpp ├── TerrainChunk.h ├── ThreadPool.cpp ├── ThreadPool.h ├── Utils.cpp ├── VBO.cpp ├── VBO.h ├── Vertex.cpp ├── Vertex.h ├── VertexPositionColorNormal.cpp ├── VertexPositionColorNormal.h ├── VertexShader.hlsl ├── Window.cpp ├── Window.h ├── World.cpp ├── World.h ├── WorldNode.cpp ├── WorldNode.h ├── WorldProcessor.cpp ├── WorldProcessor.h ├── WorldTree.cpp ├── WorldTree.h └── WorldTypes.h └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 John 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ProjectIW.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProjectIW", "ProjectIW\ProjectIW.vcxproj", "{1DDE4CFE-542D-42BF-9CF1-9FBD2F8348B1}" 7 | EndProject 8 | Global 9 | GlobalSection(Performance) = preSolution 10 | HasPerformanceSessions = true 11 | EndGlobalSection 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|x64 = Debug|x64 14 | Debug|x86 = Debug|x86 15 | Release|x64 = Release|x64 16 | Release|x86 = Release|x86 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {1DDE4CFE-542D-42BF-9CF1-9FBD2F8348B1}.Debug|x64.ActiveCfg = Debug|x64 20 | {1DDE4CFE-542D-42BF-9CF1-9FBD2F8348B1}.Debug|x64.Build.0 = Debug|x64 21 | {1DDE4CFE-542D-42BF-9CF1-9FBD2F8348B1}.Debug|x86.ActiveCfg = Debug|Win32 22 | {1DDE4CFE-542D-42BF-9CF1-9FBD2F8348B1}.Debug|x86.Build.0 = Debug|Win32 23 | {1DDE4CFE-542D-42BF-9CF1-9FBD2F8348B1}.Release|x64.ActiveCfg = Release|x64 24 | {1DDE4CFE-542D-42BF-9CF1-9FBD2F8348B1}.Release|x64.Build.0 = Release|x64 25 | {1DDE4CFE-542D-42BF-9CF1-9FBD2F8348B1}.Release|x86.ActiveCfg = Release|Win32 26 | {1DDE4CFE-542D-42BF-9CF1-9FBD2F8348B1}.Release|x86.Build.0 = Release|Win32 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /ProjectIW/Box.cpp: -------------------------------------------------------------------------------- 1 | #include "Box.h" 2 | 3 | 4 | Box::Box() 5 | { 6 | } 7 | 8 | 9 | Box::~Box() 10 | { 11 | } -------------------------------------------------------------------------------- /ProjectIW/Box.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "General.h" 6 | 7 | using namespace DirectX; 8 | 9 | class Box 10 | { 11 | public: 12 | Box(); 13 | ~Box(); 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /ProjectIW/Camera.cpp: -------------------------------------------------------------------------------- 1 | #include "Camera.h" 2 | 3 | const XMVECTOR UnitXVector = XMVectorSet(1, 0, 0, 0); 4 | const XMVECTOR UnitYVector = XMVectorSet(0, 1, 0, 0); 5 | const XMVECTOR UnitZVector = XMVectorSet(0, 0, 1, 0); 6 | 7 | Camera::Camera(float aspectRatio) 8 | { 9 | rotationX = PI * 0.25f; 10 | rotationY = PI * 0.25f; 11 | ZeroMemory(&terrain_constants, sizeof(terrain_constants)); 12 | Rotation = XMMatrixRotationX(rotationY) * XMMatrixRotationY(rotationX); 13 | SetWorld(XMMatrixIdentity()); 14 | SetProjection(aspectRatio); 15 | 16 | this->SetPosition(XMFLOAT3(0, 1, 0), XMFLOAT3(0, 0, 0)); 17 | VectorPosition = XMVectorSet(0, 1, 0, 0); 18 | 19 | //SetView(XMMatrixLookAtLH(this->VectorPosition, this->VectorTarget, this->VectorUp)); 20 | 21 | terrain_buffer = new ConstantsBuffer(); 22 | terrain_buffer->Create(sizeof(terrain_constants), &terrain_constants); 23 | 24 | speed_multiplier = 0.0f; 25 | 26 | UpdateFirstPerson(true); 27 | } 28 | 29 | Camera::~Camera() 30 | { 31 | if (terrain_buffer) 32 | { 33 | delete terrain_buffer; 34 | terrain_buffer = 0; 35 | } 36 | } 37 | 38 | void Camera::SetPosition(XMFLOAT3& pos, XMFLOAT3& target) 39 | { 40 | if (&Position != &pos) 41 | memcpy(&Position, &pos, sizeof(pos)); 42 | if (&Target != &target) 43 | memcpy(&Target, &target, sizeof(target)); 44 | this->VectorPosition = XMVectorSet(pos.x, pos.y, pos.z, 1.0f); 45 | this->VectorTarget = XMVectorSet(target.x, target.y, target.z, 1.0f); 46 | this->VectorUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); 47 | SetView(XMMatrixLookAtLH(this->VectorPosition, this->VectorTarget, this->VectorUp)); 48 | } 49 | 50 | XMMATRIX Camera::GetWorld() 51 | { 52 | return World; 53 | } 54 | XMMATRIX Camera::GetView() 55 | { 56 | return View; 57 | } 58 | XMMATRIX Camera::GetProjection() 59 | { 60 | return Projection; 61 | } 62 | void Camera::SetWorld(XMMATRIX& m) 63 | { 64 | World = XMMatrixTranspose(m); 65 | terrain_constants.world = World; 66 | } 67 | void Camera::SetView(XMMATRIX& m) 68 | { 69 | View = XMMatrixTranspose(m); 70 | terrain_constants.view = View; 71 | } 72 | void Camera::SetProjection(XMMATRIX& m) 73 | { 74 | Projection = XMMatrixTranspose(m); 75 | terrain_constants.projection = Projection; 76 | } 77 | void Camera::SetProjection(float aspectRatio) 78 | { 79 | Projection = XMMatrixTranspose(XMMatrixPerspectiveFovLH(PI / 4.0f, aspectRatio, 0.01f, 10000.0f * 1000.0f)); 80 | terrain_constants.projection = Projection; 81 | } 82 | 83 | bool Camera::UpdateFirstPerson(bool update) 84 | { 85 | if (!update) 86 | { 87 | int deltaX = engine->input->CurrentDeltaX(); 88 | int deltaY = engine->input->CurrentDeltaY(); 89 | if (!deltaX && !deltaY) 90 | goto CheckKeys; 91 | rotationX += deltaX * 0.01f; 92 | rotationY += deltaY * 0.01f; 93 | Rotation = XMMatrixRotationX(rotationY) * XMMatrixRotationY(rotationX); 94 | } 95 | VectorUp = XMVector3Transform(UnitYVector, Rotation); 96 | update = true; 97 | 98 | CheckKeys: 99 | float speed = 0.25f; 100 | 101 | if (engine->input->CurrentKey(DIK_LSHIFT)) 102 | speed *= 5.0f; 103 | if (engine->input->CurrentKey(DIK_SPACE)) 104 | speed *= 20.0f; 105 | if (engine->input->CurrentKey(DIK_LCONTROL)) 106 | speed *= 20.0f; 107 | 108 | if (engine->input->CurrentKeyOnly(DIK_1)) 109 | speed_multiplier += 1.0f; 110 | if (engine->input->CurrentKeyOnly(DIK_2) && speed_multiplier >= 0.99f) 111 | speed_multiplier -= 1.0f; 112 | speed *= powf(2, speed_multiplier); 113 | 114 | if (engine->input->CurrentKey(DIK_W)) 115 | { 116 | VectorPosition = VectorPosition + XMVector3Transform(UnitZVector * speed, Rotation); 117 | update = true; 118 | } 119 | else if (engine->input->CurrentKey(DIK_S)) 120 | { 121 | VectorPosition = VectorPosition + XMVector3Transform(-UnitZVector * speed, Rotation); 122 | update = true; 123 | } 124 | if (engine->input->CurrentKey(DIK_A)) 125 | { 126 | VectorPosition = VectorPosition + XMVector3Transform(-UnitXVector * speed, Rotation); 127 | update = true; 128 | } 129 | else if (engine->input->CurrentKey(DIK_D)) 130 | { 131 | VectorPosition = VectorPosition + XMVector3Transform(UnitXVector * speed, Rotation); 132 | update = true; 133 | } 134 | if (engine->input->CurrentKey(DIK_Q)) 135 | { 136 | VectorPosition = VectorPosition + UnitYVector * speed; 137 | update = true; 138 | } 139 | else if (engine->input->CurrentKey(DIK_E)) 140 | { 141 | VectorPosition = VectorPosition + UnitYVector * -speed; 142 | update = true; 143 | } 144 | /*if (engine->input->CurrentKey(DIK_SPACE)) 145 | { 146 | VectorPosition = VectorPosition + XMVector3Transform(UnitYVector * speed, Rotation); 147 | update = true; 148 | }*/ 149 | 150 | if (!update) 151 | return false; 152 | Position = XMFLOAT3(XMVectorGetX(VectorPosition), XMVectorGetY(VectorPosition), XMVectorGetZ(VectorPosition)); 153 | VectorTarget = VectorPosition + XMVector3Transform(UnitZVector, Rotation); 154 | Target = XMFLOAT3(XMVectorGetX(VectorTarget), XMVectorGetY(VectorTarget), XMVectorGetZ(VectorTarget)); 155 | SetView(XMMatrixLookAtLH(this->VectorPosition, this->VectorTarget, this->VectorUp)); 156 | return true; 157 | } 158 | 159 | void Camera::SetShaderConstants() 160 | { 161 | terrain_buffer->SetData(&terrain_constants, 0, sizeof(terrain_constants)); 162 | } 163 | -------------------------------------------------------------------------------- /ProjectIW/Camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "General.h" 5 | #include "Engine.h" 6 | #include "ConstantsBuffer.h" 7 | #include "ShaderConstants.h" 8 | 9 | using namespace DirectX; 10 | 11 | class Camera 12 | { 13 | public: 14 | 15 | XMFLOAT3 Position; 16 | XMFLOAT3 Target; 17 | 18 | Camera(float aspect_ratio); 19 | ~Camera(); 20 | 21 | void SetPosition(XMFLOAT3&, XMFLOAT3&); 22 | XMMATRIX GetWorld(); 23 | XMMATRIX GetView(); 24 | XMMATRIX GetProjection(); 25 | void SetWorld(XMMATRIX& m); 26 | void SetView(XMMATRIX& m); 27 | void SetProjection(XMMATRIX& m); 28 | void SetProjection(float aspectRatio); 29 | 30 | bool UpdateFirstPerson(bool update = false); 31 | void SetShaderConstants(); 32 | 33 | inline ConstantsBuffer* GetTerrainBuffer() { return terrain_buffer; } 34 | 35 | private: 36 | ConstantsBuffer* terrain_buffer; 37 | BasicShaderConstants terrain_constants; 38 | 39 | XMVECTOR VectorPosition; 40 | XMVECTOR VectorTarget; 41 | XMVECTOR VectorUp; 42 | 43 | XMMATRIX World; 44 | XMMATRIX View; 45 | XMMATRIX Projection; 46 | 47 | XMMATRIX Rotation; 48 | float rotationX; 49 | float rotationY; 50 | 51 | float speed_multiplier; 52 | }; 53 | 54 | -------------------------------------------------------------------------------- /ProjectIW/ConstantsBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "ConstantsBuffer.h" 2 | 3 | ConstantsBuffer::ConstantsBuffer() 4 | { 5 | underlying_buffer = 0; 6 | } 7 | 8 | ConstantsBuffer::~ConstantsBuffer() 9 | { 10 | if (underlying_buffer) 11 | underlying_buffer->Release(); 12 | } 13 | 14 | HRESULT ConstantsBuffer::Create(UINT size, void* data) 15 | { 16 | ID3D11Device* device = engine->rendering->Device; 17 | if (!device) 18 | return -1; 19 | 20 | this->size = size; 21 | D3D11_BUFFER_DESC desc; 22 | ZeroMemory(&desc, sizeof(desc)); 23 | desc.ByteWidth = size; 24 | desc.Usage = D3D11_USAGE_DYNAMIC; 25 | desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 26 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 27 | desc.MiscFlags = 0; 28 | 29 | if (!data) 30 | return device->CreateBuffer(&desc, NULL, &underlying_buffer); 31 | 32 | D3D11_SUBRESOURCE_DATA r; 33 | r.pSysMem = data; 34 | r.SysMemPitch = 0; 35 | r.SysMemSlicePitch = 0; 36 | return device->CreateBuffer(&desc, &r, &underlying_buffer); 37 | } 38 | 39 | void ConstantsBuffer::SetData(void* data, UINT offset, UINT length) 40 | { 41 | ID3D11DeviceContext* context = engine->rendering->ImmediateContext; 42 | if (!context) 43 | return; 44 | 45 | D3D11_MAPPED_SUBRESOURCE resource; 46 | HRESULT hr = context->Map(underlying_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); 47 | memcpy(resource.pData, data, length); 48 | context->Unmap(underlying_buffer, 0); 49 | } 50 | 51 | void ConstantsBuffer::BindToShader(unsigned int index) 52 | { 53 | ID3D11DeviceContext* context = engine->rendering->ImmediateContext; 54 | if (!context) 55 | return; 56 | 57 | context->VSSetConstantBuffers(index, 1, &underlying_buffer); 58 | } 59 | 60 | void ConstantsBuffer::BindToPSShader(unsigned int index) 61 | { 62 | ID3D11DeviceContext* context = engine->rendering->ImmediateContext; 63 | if (!context) 64 | return; 65 | 66 | context->PSSetConstantBuffers(index, 1, &underlying_buffer); 67 | } 68 | -------------------------------------------------------------------------------- /ProjectIW/ConstantsBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Engine.h" 5 | 6 | class ConstantsBuffer 7 | { 8 | public: 9 | 10 | ConstantsBuffer(); 11 | ~ConstantsBuffer(); 12 | 13 | HRESULT Create(UINT size, void* init_data = 0); 14 | void SetData(void* data, UINT offsetInBytes, UINT length); 15 | void BindToShader(unsigned int index); 16 | void BindToPSShader(unsigned int index); 17 | 18 | inline ID3D11Buffer* GetUnderlyingBuffer() { return underlying_buffer; } 19 | 20 | private: 21 | ID3D11Buffer* underlying_buffer; 22 | unsigned int size; 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /ProjectIW/DirectInput.cpp: -------------------------------------------------------------------------------- 1 | #include "DirectInput.h" 2 | 3 | DirectInput::DirectInput(HINSTANCE hInstance) 4 | { 5 | this->hInstance = hInstance; 6 | Mouse = 0; 7 | Keyboard = 0; 8 | DIController = 0; 9 | } 10 | 11 | DirectInput::~DirectInput() 12 | { 13 | Dispose(); 14 | } 15 | 16 | bool DirectInput::Setup() 17 | { 18 | if (FAILED(DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DIController, NULL))) 19 | { 20 | MessageBox(0, "Failed to initialize direct input.", "Error", MB_ICONERROR); 21 | return false; 22 | } 23 | 24 | if (FAILED(DIController->CreateDevice(GUID_SysMouse, &Mouse, NULL))) 25 | { 26 | MessageBox(0, "Failed to create mouse.", "Error", MB_ICONERROR); 27 | return false; 28 | } 29 | Mouse->SetDataFormat(&c_dfDIMouse); 30 | Mouse->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); 31 | 32 | if (FAILED(DIController->CreateDevice(GUID_SysKeyboard, &Keyboard, NULL))) 33 | { 34 | MessageBox(0, "Failed to create keyboard.", "Error", MB_ICONERROR); 35 | return false; 36 | } 37 | Keyboard->SetDataFormat(&c_dfDIKeyboard); 38 | Keyboard->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_NOWINKEY | DISCL_FOREGROUND); 39 | 40 | return true; 41 | } 42 | 43 | void DirectInput::MouseState(DIMOUSESTATE* dest) 44 | { 45 | if (!Mouse) 46 | return; 47 | Mouse->Acquire(); 48 | if (FAILED(Mouse->GetDeviceState(sizeof(DIMOUSESTATE), dest))) 49 | MessageBox(0, "Failed to retrieve mouse state.", "Error", MB_ICONERROR); 50 | } 51 | 52 | void DirectInput::KeyboardState(BYTE* dest) 53 | { 54 | if (!Keyboard) 55 | return; 56 | Keyboard->Acquire(); 57 | if (FAILED(Keyboard->GetDeviceState(256, dest))) 58 | MessageBox(0, "Failed to retrieve keyboard state.", "Error", MB_ICONERROR); 59 | } 60 | 61 | void DirectInput::Dispose() 62 | { 63 | if (Mouse) 64 | Mouse->Unacquire(); 65 | if (Keyboard) 66 | Keyboard->Unacquire(); 67 | if (DIController) 68 | DIController->Release(); 69 | } 70 | -------------------------------------------------------------------------------- /ProjectIW/DirectInput.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "General.h" 5 | #include "Window.h" 6 | 7 | class DirectInput 8 | { 9 | public: 10 | 11 | IDirectInputDevice8* Mouse; 12 | IDirectInputDevice8* Keyboard; 13 | 14 | LPDIRECTINPUT8 DIController; 15 | 16 | DirectInput(HINSTANCE hInstance); 17 | ~DirectInput(); 18 | 19 | void MouseState(DIMOUSESTATE* dest); 20 | void KeyboardState(BYTE* dest); 21 | 22 | bool Setup(); 23 | void Dispose(); 24 | 25 | private: 26 | HINSTANCE hInstance; 27 | }; 28 | -------------------------------------------------------------------------------- /ProjectIW/Engine.cpp: -------------------------------------------------------------------------------- 1 | #include "Engine.h" 2 | 3 | 4 | Engine::Engine(HWND handle, HINSTANCE hInstance) 5 | { 6 | rendering = new RenderEngine(handle); 7 | input = new InputController(hInstance, handle); 8 | } 9 | 10 | 11 | Engine::~Engine(void) 12 | { 13 | delete input; 14 | delete rendering; 15 | } 16 | 17 | bool Engine::Setup() 18 | { 19 | if (!input->Setup()) 20 | return false; 21 | if (!rendering->Setup()) 22 | return false; 23 | return true; 24 | } 25 | 26 | void Engine::Loop() 27 | { 28 | MSG msg = { 0 }; 29 | while (msg.message != WM_QUIT) 30 | { 31 | if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) 32 | { 33 | TranslateMessage(&msg); 34 | DispatchMessage(&msg); 35 | } 36 | else 37 | { 38 | //SetCursorPos(400, 400); 39 | input->UpdateMousePosition(); 40 | input->Update(); 41 | rendering->Render(); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /ProjectIW/Engine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "General.h" 4 | #include "RenderEngine.h" 5 | #include "InputController.h" 6 | #include 7 | 8 | class Engine 9 | { 10 | public: 11 | RenderEngine* rendering; 12 | InputController* input; 13 | 14 | Engine(HWND handle, HINSTANCE hInstance); 15 | ~Engine(void); 16 | 17 | bool Setup(); 18 | void Loop(); 19 | 20 | private: 21 | }; 22 | -------------------------------------------------------------------------------- /ProjectIW/GPUMesh.cpp: -------------------------------------------------------------------------------- 1 | #include "GPUMesh.h" 2 | 3 | GPUMesh::GPUMesh() 4 | { 5 | } 6 | 7 | 8 | GPUMesh::~GPUMesh() 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /ProjectIW/GPUMesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class GPUMesh 4 | { 5 | public: 6 | GPUMesh(); 7 | ~GPUMesh(); 8 | }; 9 | 10 | -------------------------------------------------------------------------------- /ProjectIW/General.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define PI 3.1415926535897932384626433832795f 6 | #define CROSS(u, v) XMFLOAT3(u.y * v.z - u.z * v.y, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x) 7 | #define DOT(u, v) u.x * v.x + u.y * v.y + u.z * v.z 8 | #define ADD(u, v) XMFLOAT3(u.x + v.x, u.y + v.y, u.z + v.z) 9 | #define ABS(x) (x >= 0 ? x : -x); 10 | 11 | #define SDELETE(x) if(x){delete x;x=0;} 12 | #define SDELETEARRAY(x, size) for(int i=0;i output) 21 | { 22 | /* face normal */ 23 | float3 ea = input[1].pos - input[0].pos; 24 | float3 eb = input[2].pos - input[0].pos; 25 | float3 face_normal = normalize(cross(eb, ea)); 26 | for (uint i = 0; i < 3; i++) 27 | { 28 | GSOutput element = input[i]; 29 | 30 | const float C = 1.0f; 31 | const float far = 10000.0f * 1000.0f; 32 | const float FC = 1.0f / log(far*C + 1); 33 | element.pos.z = log(element.pos.w*C + 1)*FC * element.pos.w; 34 | 35 | element.norm_flat = face_normal; 36 | output.Append(element); 37 | } 38 | } -------------------------------------------------------------------------------- /ProjectIW/IBO.cpp: -------------------------------------------------------------------------------- 1 | #include "IBO.h" 2 | 3 | IBO::IBO(void* data, unsigned int size, bool modifiable) 4 | { 5 | this->buffer = 0; 6 | this->buffer_size = size; 7 | CreateBuffer(data, modifiable); 8 | } 9 | 10 | IBO::~IBO() 11 | { 12 | Dispose(); 13 | } 14 | 15 | void IBO::Dispose() 16 | { 17 | if (buffer) 18 | { 19 | buffer->Release(); 20 | buffer = 0; 21 | } 22 | } 23 | 24 | bool IBO::CreateBuffer(void* data, bool modifyable) 25 | { 26 | D3D11_BUFFER_DESC desc; 27 | ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC)); 28 | desc.Usage = (!modifyable ? D3D11_USAGE_DEFAULT : D3D11_USAGE_DYNAMIC); 29 | desc.ByteWidth = this->buffer_size; 30 | desc.BindFlags = D3D11_BIND_INDEX_BUFFER; 31 | desc.CPUAccessFlags = (!modifyable ? 0 : D3D11_CPU_ACCESS_WRITE); 32 | desc.MiscFlags = 0; 33 | 34 | D3D11_SUBRESOURCE_DATA resource; 35 | ZeroMemory(&resource, sizeof(D3D11_SUBRESOURCE_DATA)); 36 | resource.pSysMem = data; 37 | 38 | HRESULT hr = engine->rendering->Device->CreateBuffer(&desc, &resource, &buffer); 39 | if (FAILED(hr)) 40 | { 41 | MessageBox(NULL, "Failed to create index buffer.", "Error", MB_ICONERROR); 42 | return false; 43 | } 44 | 45 | return true; 46 | } 47 | 48 | void IBO::SetData(void* data, UINT offset, UINT length) 49 | { 50 | D3D11_MAPPED_SUBRESOURCE resource; 51 | engine->rendering->ImmediateContext->Map(buffer, 0, D3D11_MAP_WRITE, 0, &resource); 52 | memcpy((void*)((char*)resource.pData + offset), data, length); 53 | engine->rendering->ImmediateContext->Unmap(buffer, 0); 54 | } 55 | 56 | void IBO::Bind() 57 | { 58 | const UINT offset = 0; 59 | engine->rendering->ImmediateContext->IASetIndexBuffer(buffer, DXGI_FORMAT::DXGI_FORMAT_R32_UINT, 0); 60 | } -------------------------------------------------------------------------------- /ProjectIW/IBO.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "General.h" 6 | #include "Window.h" 7 | 8 | class IBO 9 | { 10 | public: 11 | 12 | IBO(void* data, unsigned int size, bool modifiable); 13 | ~IBO(); 14 | 15 | void SetData(void* data, UINT offset, UINT length); 16 | void Bind(); 17 | void Dispose(); 18 | 19 | inline ID3D11Buffer* GetBuffer() { return buffer; } 20 | inline UINT GetBufferSize() { return buffer_size; } 21 | 22 | private: 23 | UINT buffer_size; 24 | ID3D11Buffer* buffer = 0; 25 | 26 | bool CreateBuffer(void*, bool modifyable); 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /ProjectIW/InputController.cpp: -------------------------------------------------------------------------------- 1 | #include "InputController.h" 2 | 3 | InputController::InputController(HINSTANCE h, HWND hwnd) 4 | { 5 | direct_input = new DirectInput(h); 6 | lock_cursor = false; 7 | _hwnd = hwnd; 8 | } 9 | 10 | InputController::~InputController() 11 | { 12 | if (direct_input) 13 | delete direct_input; 14 | } 15 | 16 | bool InputController::Setup() 17 | { 18 | ZeroMemory(current_keys, sizeof(current_keys)); 19 | ZeroMemory(last_keys, sizeof(last_keys)); 20 | ZeroMemory(¤t_mouse, sizeof(current_mouse)); 21 | ZeroMemory(&last_mouse, sizeof(last_mouse)); 22 | ZeroMemory(&mouse_pos, sizeof(mouse_pos)); 23 | current_pos.x = current_pos.y = last_pos.x = last_pos.y = 0; 24 | return direct_input->Setup(); 25 | } 26 | 27 | void InputController::Update() 28 | { 29 | if (!direct_input) 30 | return; 31 | 32 | memcpy(last_keys, current_keys, sizeof(last_keys)); 33 | memcpy(&last_mouse, ¤t_mouse, sizeof(last_mouse)); 34 | direct_input->KeyboardState(current_keys); 35 | direct_input->MouseState(¤t_mouse); 36 | //if (CurrentKeyOnly(DIK_TAB)) 37 | // lock_cursor = !lock_cursor; 38 | 39 | 40 | current_scroll = total_scroll; 41 | total_scroll = 0; 42 | 43 | if (lock_cursor) 44 | { 45 | SetCursorPos(lock_point.x, lock_point.y); 46 | } 47 | } 48 | 49 | void InputController::UpdateMousePosition() 50 | { 51 | if (!direct_input) 52 | return; 53 | 54 | direct_input->MouseState(&mouse_pos); 55 | total_scroll += mouse_pos.lZ; 56 | last_pos.x = current_pos.x; 57 | last_pos.y = current_pos.y; 58 | GetCursorPos(¤t_pos); 59 | ScreenToClient(_hwnd, ¤t_pos); 60 | } 61 | -------------------------------------------------------------------------------- /ProjectIW/InputController.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "General.h" 4 | #include "DirectInput.h" 5 | 6 | class InputController 7 | { 8 | public: 9 | InputController(HINSTANCE, HWND hwnd); 10 | ~InputController(); 11 | bool Setup(); 12 | void UpdateMousePosition(); 13 | void Update(); 14 | 15 | //for these two functions, they originally just returned v & 0x80, but the compiler complained about 16 | //a performance hit due to implicitly casting an int to bool. now it returns v & 0x80 != 0 17 | inline bool CurrentKey(int k) { return (current_keys[k] & 0x80) != 0; } 18 | inline bool LastKey(int k) { return (last_keys[k] & 0x80) != 0; } 19 | inline bool CurrentKeyOnly(int k) { return CurrentKey(k) && !LastKey(k); } 20 | 21 | inline int CurrentDeltaX() { return mouse_pos.lX; } 22 | inline int CurrentDeltaY() { return mouse_pos.lY; } 23 | inline int LastDeltaX() { return last_mouse.lX; } 24 | inline int LastDeltaY() { return last_mouse.lY; } 25 | inline int CurrentX() { return current_pos.x; } 26 | inline int CurrentY() { return current_pos.y; } 27 | inline int LastX() { return last_pos.x; } 28 | inline int LastY() { return last_pos.y; } 29 | inline bool LeftButton() { return current_mouse.rgbButtons[0] != 0; } 30 | inline bool RightButton() { return current_mouse.rgbButtons[1] != 0; } 31 | inline bool MiddleButton() { return current_mouse.rgbButtons[2] != 0; } 32 | inline bool LeftButtonOnly() { return current_mouse.rgbButtons[0] != 0 && last_mouse.rgbButtons[0] == 0; } 33 | inline bool RightButtonOnly() { return current_mouse.rgbButtons[1] != 0 && last_mouse.rgbButtons[1] == 0; } 34 | inline int GetScroll() { return current_scroll; } 35 | 36 | inline void LockCursor() 37 | { 38 | if (lock_cursor) 39 | return; 40 | lock_cursor = true; 41 | ShowCursor(false); 42 | GetCursorPos(&lock_point); 43 | } 44 | inline void UnlockCursor() 45 | { 46 | if (!lock_cursor) 47 | return; 48 | lock_cursor = false; 49 | ShowCursor(true); 50 | SetCursorPos(lock_point.x, lock_point.y); 51 | } 52 | 53 | private: 54 | HWND _hwnd; 55 | DirectInput* direct_input; 56 | BYTE current_keys[256]; 57 | BYTE last_keys[256]; 58 | DIMOUSESTATE current_mouse; 59 | DIMOUSESTATE last_mouse; 60 | DIMOUSESTATE mouse_pos; 61 | bool lock_cursor; 62 | POINT current_pos; 63 | POINT last_pos; 64 | 65 | int current_scroll; 66 | int total_scroll; 67 | POINT lock_point; 68 | }; 69 | -------------------------------------------------------------------------------- /ProjectIW/LRUCache.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014, lamerman 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of lamerman nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | */ 30 | 31 | /* 32 | * File: lrucache.hpp 33 | * Author: Alexander Ponomarev 34 | * 35 | * Created on June 20, 2013, 5:09 PM 36 | */ 37 | 38 | //Personal note: some modifications here to fit my needs of popping items out of the list, as well as dealing with stranded ones at the end of the cache. 39 | 40 | #ifndef _LRUCACHE_HPP_INCLUDED_ 41 | #define _LRUCACHE_HPP_INCLUDED_ 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | namespace Utilities 49 | { 50 | 51 | template 52 | class lru_cache 53 | { 54 | public: 55 | typedef typename std::pair key_value_pair_t; 56 | typedef typename std::list::iterator list_iterator_t; 57 | 58 | lru_cache(size_t max_size) : 59 | _max_size(max_size) { 60 | } 61 | 62 | void put(const key_t& key, const value_t& value, value_t* oldest_out, value_t* duplicate_out) { 63 | auto it = _cache_items_map.find(key); 64 | _cache_items_list.push_front(key_value_pair_t(key, value)); 65 | if (it != _cache_items_map.end()) { 66 | *duplicate_out = it->second->second; 67 | _cache_items_list.erase(it->second); 68 | _cache_items_map.erase(it); 69 | } 70 | _cache_items_map[key] = _cache_items_list.begin(); 71 | 72 | if (_cache_items_map.size() > _max_size) { 73 | auto last = _cache_items_list.end(); 74 | last--; 75 | _cache_items_map.erase(last->first); 76 | *oldest_out = _cache_items_list.end()->second; 77 | _cache_items_list.pop_back(); 78 | } 79 | } 80 | 81 | const value_t& get(const key_t& key) { 82 | auto it = _cache_items_map.find(key); 83 | if (it == _cache_items_map.end()) { 84 | throw std::range_error("There is no such key in cache"); 85 | } 86 | else { 87 | _cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second); 88 | return it->second->second; 89 | } 90 | } 91 | 92 | const value_t get_and_remove(const key_t& key) { 93 | auto it = _cache_items_map.find(key); 94 | if (it == _cache_items_map.end()) { 95 | throw std::range_error("There is no such key in cache"); 96 | } 97 | else { 98 | value_t at = it->second->second; 99 | _cache_items_list.erase(it->second); 100 | _cache_items_map.erase(it); 101 | return at; 102 | } 103 | } 104 | 105 | const void remove(const key_t& key) { 106 | auto it = _cache_items_map.find(key); 107 | if (it == _cache_items_map.end()) { 108 | throw std::range_error("There is no such key in cache"); 109 | } 110 | else { 111 | _cache_items_list.erase(it->second); 112 | _cache_items_map.erase(it); 113 | } 114 | } 115 | 116 | bool exists(const key_t& key) const { 117 | return _cache_items_map.find(key) != _cache_items_map.end(); 118 | } 119 | 120 | size_t size() const { 121 | return _cache_items_map.size(); 122 | } 123 | 124 | std::list& get_items_list() { return _cache_items_list; } 125 | 126 | private: 127 | std::list _cache_items_list; 128 | std::unordered_map _cache_items_map; 129 | size_t _max_size; 130 | }; 131 | 132 | } // namespace lru 133 | 134 | #endif /* _LRUCACHE_HPP_INCLUDED_ */ 135 | -------------------------------------------------------------------------------- /ProjectIW/MeshGeneration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "MeshGeneration.h" 3 | #include "WorldNode.h" 4 | 5 | #define NUM_THREADS 4 6 | 7 | ThreadPool MeshGeneration::threadpool(NUM_THREADS); 8 | std::atomic MeshGeneration::shutdown = false; 9 | 10 | void MeshGeneration::AddNode(WorldNode* node) 11 | { 12 | assert(node->GetStage() == NODE_STAGE_CREATION || node->GetStage() == NODE_STAGE_MESH_WAITING); 13 | Task t = Task([node]() 14 | { 15 | MeshGeneration::ProcessNode(node); 16 | }, nullptr, TaskPriority::Low); 17 | 18 | threadpool.AddTask(t); 19 | } 20 | 21 | void MeshGeneration::ProcessNode(WorldNode* node) 22 | { 23 | // TODO: reuse terrain chunk for regenerating mesh 24 | assert(node != 0); 25 | assert(node->underlying_chunk == 0); 26 | 27 | if (!shutdown && !node->request_abandon) 28 | { 29 | node->SetStage(NODE_STAGE_MESH_GENERATING); 30 | 31 | if (node->IsLeaf()) 32 | { 33 | unsigned int scale = (unsigned int)log2(node->size / NODE_CHUNK_RESOLUTION); 34 | unsigned int mul = (unsigned int)pow(2, scale); 35 | 36 | TerrainChunk* chunk = new TerrainChunk(node->position, node->size / NODE_CHUNK_RESOLUTION); 37 | chunk->GenerateOctree(); 38 | chunk->GenerateMesh(); 39 | 40 | node->is_empty = chunk->IsEmpty(); 41 | node->underlying_chunk = chunk; 42 | } 43 | } 44 | node->SetStage(NODE_STAGE_READY); 45 | } 46 | 47 | void MeshGeneration::Quit() 48 | { 49 | threadpool.Quit(); 50 | } 51 | -------------------------------------------------------------------------------- /ProjectIW/MeshGeneration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "ThreadPool.h" 6 | #include "WorldTypes.h" 7 | 8 | /// 9 | /// This is the mesh generation stage of the pipeline. 10 | /// It's a background process that reads from a queue and updates mesh for dirty nodes. 11 | /// 12 | class MeshGeneration 13 | { 14 | public: 15 | /// 16 | /// Shuts the mesh generation down and forces it to stop generating mesh for new nodes. 17 | /// 18 | inline static void Shutdown() { shutdown = true; } 19 | 20 | 21 | /// 22 | /// Adds the node to the generation queue. 23 | /// 24 | /// The node to add. 25 | static void AddNode(WorldNode* node); 26 | 27 | /// 28 | /// Generates the mesh and sets the node to READY status once it's finished. 29 | /// 30 | /// The node to process. 31 | static void ProcessNode(WorldNode* node); 32 | 33 | static void Quit(); 34 | 35 | private: 36 | static ThreadPool threadpool; 37 | static std::atomic shutdown; 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /ProjectIW/NodeCache.cpp: -------------------------------------------------------------------------------- 1 | #include "NodeCache.h" 2 | #include "WorldNode.h" 3 | 4 | #define MAX_CACHED_NODES 1048576 5 | 6 | NodeCache::NodeCache() : stop_delete(false), cache(MAX_CACHED_NODES), delete_thread(&NodeCache::ProcessDeleteQueue, this) 7 | { 8 | } 9 | 10 | NodeCache::~NodeCache() 11 | { 12 | stop_delete = true; 13 | 14 | delete_condition.notify_all(); 15 | delete_thread.join(); 16 | 17 | 18 | // Cleanup the delete queue 19 | while (delete_queue.size() > 0) 20 | { 21 | WorldNode* node = delete_queue.front(); 22 | delete_queue.pop(); 23 | 24 | if (node) 25 | { 26 | int stage = false; 27 | do 28 | { 29 | stage = node->GetStage(); 30 | } while (stage == NODE_STAGE_MESH_WAITING || stage == NODE_STAGE_MESH_GENERATING); 31 | delete node; 32 | } 33 | } 34 | 35 | // Cleanup the cache 36 | auto it = cache.get_items_list().begin(); 37 | for (auto it = cache.get_items_list().begin(); it != cache.get_items_list().end(); ++it) 38 | { 39 | WorldNode* node = it->second; 40 | 41 | if (node) 42 | { 43 | int stage = 0; 44 | do 45 | { 46 | stage = node->GetStage().load(); 47 | } while (stage != NODE_STAGE_READY); 48 | delete node; 49 | } 50 | } 51 | } 52 | 53 | WorldNode* NodeCache::Find(int64_t hash, XMINT3 expected_pos, unsigned int expected_size) 54 | { 55 | if (MAX_CACHED_NODES == 0) 56 | return 0; 57 | 58 | WorldNode* node = 0; 59 | if (cache.exists(hash)) 60 | { 61 | node = cache.get(hash); 62 | 63 | if (node->position.x != expected_pos.x || node->position.y != expected_pos.y || node->position.z != expected_pos.z || node->size != expected_size) 64 | { 65 | node = 0; 66 | } 67 | else 68 | { 69 | cache.remove(hash); 70 | } 71 | } 72 | 73 | return node; 74 | } 75 | 76 | void NodeCache::Add(WorldNode* node) 77 | { 78 | if (!node || MAX_CACHED_NODES == 0) 79 | return; 80 | 81 | WorldNode* oldest = 0; 82 | WorldNode* duplicate = 0; 83 | cache.put(node->Hash(), node, &oldest, &duplicate); 84 | if (oldest || duplicate) 85 | { 86 | { 87 | std::unique_lock delete_lock(delete_mutex); 88 | if (oldest) 89 | { 90 | delete_queue.push(oldest); 91 | oldest->request_abandon = true; 92 | } 93 | if (duplicate) 94 | { 95 | delete_queue.push(duplicate); 96 | duplicate->request_abandon = true; 97 | } 98 | } 99 | delete_condition.notify_one(); 100 | } 101 | } 102 | 103 | void NodeCache::ProcessDeleteQueue() 104 | { 105 | while (!stop_delete) 106 | { 107 | { 108 | std::unique_lock lock(delete_mutex); 109 | while (!stop_delete && delete_queue.empty()) 110 | delete_condition.wait(lock); 111 | 112 | if (stop_delete) 113 | return; 114 | WorldNode* node = delete_queue.front(); 115 | delete_queue.pop(); 116 | 117 | // The node should always exist. 118 | // If it does, only delete it if it's not generating. If it is, re-add it to the delete queue for further processing. 119 | if (node) 120 | { 121 | int stage = node->GetStage(); 122 | if (stage == NODE_STAGE_READY) 123 | { 124 | // Unlock the lock so other threads aren't waiting on delete 125 | lock.unlock(); 126 | delete node; 127 | } 128 | else 129 | delete_queue.push(node); 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /ProjectIW/NodeCache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "LRUCache.hpp" 8 | #include "WorldTypes.h" 9 | 10 | using namespace Utilities; 11 | using namespace DirectX; 12 | 13 | /// 14 | /// This class handles creating, destroying, and retrieving world nodes, using a LRU system. 15 | /// When a node is being divided, it first looks here to try and find a previously-generated node, and returns and removes it from the cache if found. 16 | /// When nodes are grouped, their children are recursively added to the cache. 17 | /// This class also handles the deletion of world nodes. 18 | /// 19 | class NodeCache 20 | { 21 | public: 22 | NodeCache(); 23 | ~NodeCache(); 24 | 25 | WorldNode* Find(int64_t hash, XMINT3 expected_pos, unsigned int expected_size); 26 | void Add(WorldNode* node); 27 | 28 | private: 29 | void ProcessDeleteQueue(); 30 | 31 | std::mutex delete_mutex; 32 | 33 | std::queue delete_queue; 34 | std::condition_variable delete_condition; 35 | std::atomic stop_delete; 36 | 37 | lru_cache cache; 38 | 39 | // IMPORTANT! This thread MUST come after the mutexes 40 | std::thread delete_thread; 41 | }; 42 | 43 | -------------------------------------------------------------------------------- /ProjectIW/NodeCreation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "NodeCreation.h" 3 | #include "WorldNode.h" 4 | #include "MeshGeneration.h" 5 | #include "NodeCache.h" 6 | 7 | #define NUM_THREADS 1 8 | 9 | NodeCreation::NodeCreation() : threadpool(NUM_THREADS) 10 | { 11 | task_queue.reserve(16384); 12 | shutdown = false; 13 | } 14 | 15 | NodeCreation::~NodeCreation() 16 | { 17 | threadpool.Quit(); 18 | } 19 | 20 | void NodeCreation::Shutdown() 21 | { 22 | shutdown = true; 23 | } 24 | 25 | unsigned int NodeCreation::TransferBatch(std::vector& batch) 26 | { 27 | size_t count = batch.size(); 28 | if (count == 0) 29 | return 0; 30 | 31 | using namespace std::chrono; 32 | steady_clock::time_point start = high_resolution_clock::now(); 33 | 34 | //TODO: batch task creation for one single lock if necessary 35 | task_queue.clear(); 36 | for (size_t i = 0; i < count; i++) 37 | { 38 | DirtyNodeOutput& node = batch[i]; 39 | Task t([node, this]() 40 | { 41 | ProcessNode(node, &cache, shutdown); 42 | }, 43 | nullptr, TaskPriority::Low); 44 | task_queue.push_back(t); 45 | 46 | //threadpool.AddTask(t); 47 | } 48 | threadpool.AddTaskBatch(task_queue); 49 | 50 | microseconds elapsed = duration_cast(high_resolution_clock::now() - start); 51 | return (unsigned int)elapsed.count(); 52 | } 53 | 54 | 55 | void NodeCreation::ProcessNode(DirtyNodeOutput n, NodeCache* cache, std::atomic& shutdown) 56 | { 57 | assert(n.node != 0); 58 | assert(n.node->GetStage() == NODE_STAGE_CREATION || n.node->GetStage() == NODE_STAGE_SPLITTABLE); 59 | 60 | NodeOutputType type = n.type; 61 | WorldNode* node = n.node; 62 | WorldNode* child = 0; 63 | 64 | switch (type) 65 | { 66 | //If the node needs division, divide it and assign the world handles. 67 | case NODE_OUTPUT_DIVIDE: 68 | node->Divide(cache); 69 | 70 | for (size_t i = 0; i < 8; i++) 71 | { 72 | PassNodeToMeshGeneration(node->children[i]); 73 | } 74 | node->SetStage(NODE_STAGE_READY); 75 | break; 76 | 77 | case NODE_OUTPUT_GROUP: 78 | for (size_t i = 0; i < 8; i++) 79 | { 80 | child = node->children[i]; 81 | assert(child != 0); 82 | assert(!child->IsActive()); 83 | child->parent = 0; 84 | child->is_leaf = true; 85 | cache->Add(child); 86 | node->children[i] = 0; 87 | } 88 | 89 | node->Group(); 90 | node->SetStage(NODE_STAGE_READY); 91 | break; 92 | } 93 | 94 | } 95 | 96 | void NodeCreation::PassNodeToMeshGeneration(WorldNode* node) 97 | { 98 | //assert(node->GetStage() == NODE_STAGE_CREATION); 99 | // First determine if the node needs its mesh generated by checking the stage of it. 100 | // The only way for it to not be NODE_STAGE_CREATION is if it was a cached node. 101 | if (node->GetStage() != NODE_STAGE_CREATION) 102 | { 103 | // Make sure the stage is one of these 3. 104 | // Side note: order of checks matter here since GetStage is called each check. 105 | assert(node->GetStage() == NODE_STAGE_MESH_GENERATING || node->GetStage() == NODE_STAGE_MESH_WAITING || node->GetStage() == NODE_STAGE_READY); 106 | return; 107 | } 108 | 109 | node->SetStage(NODE_STAGE_MESH_WAITING); 110 | MeshGeneration::AddNode(node); 111 | } 112 | -------------------------------------------------------------------------------- /ProjectIW/NodeCreation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "WorldTypes.h" 6 | #include "ThreadPool.h" 7 | #include "NodeCache.h" 8 | 9 | /// 10 | /// This is the node creation stage of the world pipeline. 11 | /// It accepts a vector of DirtyNodeOutput containing nodes that either need to be divided or grouped and adds them to another queue, which is then processed to create/destroy nodes. 12 | /// 13 | class NodeCreation 14 | { 15 | public: 16 | NodeCreation(); 17 | ~NodeCreation(); 18 | 19 | /// 20 | /// Sets the shutdown flag to allow full grouping of nodes. 21 | /// 22 | void Shutdown(); 23 | 24 | /// 25 | /// Transfers the batch of dirty nodes to the processor to handle them. To be ran on same thread as WorldTree's initial processing. 26 | /// 27 | /// Batch of dirty nodes to be divided or grouped. 28 | /// The amount of time in us it took. 29 | unsigned int TransferBatch(std::vector& batch); 30 | 31 | /// 32 | /// Processes the node. 33 | /// 34 | /// The node to be divided or grouped. 35 | /// The list containing the last node. 36 | static void ProcessNode(DirtyNodeOutput n, NodeCache* cache, std::atomic& shutdown); 37 | 38 | /// 39 | /// Passes the node to the mesh generation stage. 40 | /// 41 | /// The node to pass. 42 | static void PassNodeToMeshGeneration(WorldNode* node); 43 | 44 | private: 45 | /// 46 | /// The threadpool that handles executing node divisions and groups. 47 | /// 48 | ThreadPool threadpool; 49 | 50 | /// 51 | /// The cache used for looking up previously-generated nodes. 52 | /// 53 | NodeCache cache; 54 | 55 | std::vector task_queue; 56 | std::atomic shutdown; 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /ProjectIW/Octree.cpp: -------------------------------------------------------------------------------- 1 | #include "Octree.h" 2 | 3 | namespace MDC 4 | { 5 | Octree::Octree() 6 | { 7 | } 8 | 9 | Octree::~Octree() 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ProjectIW/Octree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace MDC 4 | { 5 | class Octree 6 | { 7 | public: 8 | Octree(); 9 | ~Octree(); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /ProjectIW/OctreeNode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "General.h" 6 | #include "SimpleMath.h" 7 | #include "VertexPositionColorNormal.h" 8 | 9 | using namespace DirectX; 10 | using namespace DirectX::SimpleMath; 11 | 12 | namespace MDC 13 | { 14 | class OctreeNode 15 | { 16 | public: 17 | OctreeNode(); 18 | OctreeNode(XMINT3 position, unsigned short size, bool is_leaf, unsigned int scale); 19 | ~OctreeNode(); 20 | 21 | bool ConstructNodes(); 22 | bool ConstructLeaf(); 23 | void GenerateVertexBuffer(std::vector& vertices); 24 | 25 | void ProcessCell(std::vector& indexes, float threshold); 26 | static void ProcessFace(OctreeNode** nodes, int direction, std::vector& indexes, float threshold); 27 | static void ProcessEdge(OctreeNode** nodes, int direction, std::vector& indexes, float threshold); 28 | static void ProcessIndexes(OctreeNode** nodes, int direction, std::vector& indexes, float threshold); 29 | 30 | void ClusterCellBase(float error); 31 | void ClusterCell(float error); 32 | static void ClusterFace(OctreeNode** nodes, int direction, int& surface_index, std::vector& collected_vertices); 33 | static void ClusterEdge(OctreeNode** nodes, int direction, int& surface_index, std::vector& collected_vertices); 34 | static void ClusterIndexes(OctreeNode** nodes, int direction, int& max_surface_index, std::vector& collected_vertices); 35 | static void AssignSurface(std::vector& vertices, int from, int to); 36 | 37 | 38 | OctreeNode* children[8]; 39 | Vertex* vertices; 40 | 41 | XMINT3 position; 42 | int scale; 43 | int size; 44 | unsigned char child_index; 45 | bool is_leaf; 46 | unsigned char corners; 47 | unsigned char vertex_count; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /ProjectIW/PixelShader.hlsl: -------------------------------------------------------------------------------- 1 | static float3 light_dir = float3(0.4f, 1.0f, 0.1f); 2 | static float3 brown = float3(0.4375f, 0.375f, 0.25f); 3 | 4 | struct VSOutput 5 | { 6 | float4 pos : SV_POSITION; 7 | float3 norm : TEXCOORD0; 8 | nointerpolation float3 norm_flat : TEXCOORD1; 9 | float3 color : COLOR0; 10 | }; 11 | 12 | float4 main(VSOutput input) : SV_TARGET 13 | { 14 | float d = dot(normalize(light_dir), normalize(input.norm_flat)); 15 | d = (d + 1.0f) * 0.5f; 16 | float m = lerp(0.6f, 1, d); 17 | 18 | d = dot(normalize(light_dir), input.norm); 19 | d = (d + 1.0f) * 0.5f; 20 | float m2 = lerp(-0.1f, 0.15f, d); 21 | float m3 = lerp(0.6f, 1, d); 22 | 23 | //float3 base_color = brown; 24 | //base_color *= m; 25 | float3 base_color = (normalize(input.norm) * 0.5f + float3(.5, .5, .5)).xyz; 26 | float3 sun_color = float3(1.0f, 1.0f, 0.6f); 27 | sun_color *= m2; 28 | 29 | //return float4(input.color.xyz, 1.0f); 30 | return float4(base_color, 1.0f); 31 | } -------------------------------------------------------------------------------- /ProjectIW/ProjectIW.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {1DDE4CFE-542D-42BF-9CF1-9FBD2F8348B1} 23 | ProjectIW 24 | 8.1 25 | 26 | 27 | 28 | Application 29 | true 30 | v140 31 | MultiByte 32 | 33 | 34 | Application 35 | false 36 | v140 37 | true 38 | MultiByte 39 | 40 | 41 | Application 42 | true 43 | v140 44 | MultiByte 45 | 46 | 47 | Application 48 | false 49 | v140 50 | true 51 | MultiByte 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | $(IncludePath);$(DXSDK_DIR)Include 73 | $(LibraryPath);$(DXSDK_DIR)Lib\x86 74 | false 75 | 76 | 77 | $(IncludePath);$(DXSDK_DIR)Include 78 | $(LibraryPath);$(DXSDK_DIR)Lib\x86 79 | 80 | 81 | 82 | Level3 83 | Disabled 84 | false 85 | 86 | 87 | true 88 | D3D11.lib;d3dx11.lib;dinput8.lib;dxguid.lib;D3dcompiler.lib;%(AdditionalDependencies) 89 | true 90 | 91 | 92 | 93 | 94 | Level3 95 | Disabled 96 | true 97 | 98 | 99 | true 100 | true 101 | 102 | 103 | 104 | 105 | Level3 106 | MaxSpeed 107 | true 108 | true 109 | true 110 | 111 | 112 | true 113 | true 114 | true 115 | D3D11.lib;d3dx11.lib;dinput8.lib;dxguid.lib;D3dcompiler.lib;%(AdditionalDependencies) 116 | true 117 | 118 | 119 | 120 | 121 | Level3 122 | MaxSpeed 123 | true 124 | true 125 | true 126 | 127 | 128 | true 129 | true 130 | true 131 | true 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | Geometry 215 | 4.0 216 | Geometry 217 | 4.0 218 | Geometry 219 | 4.0 220 | Geometry 221 | 4.0 222 | 223 | 224 | Pixel 225 | Pixel 226 | Pixel 227 | Pixel 228 | 4.0 229 | 4.0 230 | 231 | 232 | Vertex 233 | Vertex 234 | Vertex 235 | Vertex 236 | 4.0 237 | 238 | 239 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /ProjectIW/ProjectIW.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {be3841b6-e111-4cfe-bdd9-7f0d7c54c3be} 18 | 19 | 20 | {6234cdcf-4355-43d8-8dd0-b9db3be8de48} 21 | 22 | 23 | {1a9f71bf-b612-4512-aeed-bdf202531f8d} 24 | 25 | 26 | {97a7e532-877d-4f6e-86c2-a465588a9726} 27 | 28 | 29 | {73a99ee7-5aee-4ee5-a1bf-ddeca5237fb3} 30 | 31 | 32 | {2eb2a3e7-c919-4dfb-8339-14ef4ac617b7} 33 | 34 | 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | Header Files 56 | 57 | 58 | Header Files 59 | 60 | 61 | Header Files 62 | 63 | 64 | Header Files 65 | 66 | 67 | Header Files 68 | 69 | 70 | Header Files 71 | 72 | 73 | Header Files 74 | 75 | 76 | Header Files\MDC 77 | 78 | 79 | Header Files\MDC 80 | 81 | 82 | Header Files\MDC 83 | 84 | 85 | Header Files 86 | 87 | 88 | Header Files 89 | 90 | 91 | Header Files 92 | 93 | 94 | Header Files 95 | 96 | 97 | Header Files 98 | 99 | 100 | Header Files\MDC 101 | 102 | 103 | Header Files 104 | 105 | 106 | Header Files\MDC 107 | 108 | 109 | Header Files\MDC 110 | 111 | 112 | Header Files 113 | 114 | 115 | Header Files 116 | 117 | 118 | Header Files 119 | 120 | 121 | Header Files 122 | 123 | 124 | Header Files\WorldPipeline 125 | 126 | 127 | Header Files\WorldPipeline 128 | 129 | 130 | Header Files\WorldPipeline 131 | 132 | 133 | Header Files\WorldPipeline 134 | 135 | 136 | Header Files\WorldPipeline 137 | 138 | 139 | Header Files\WorldPipeline 140 | 141 | 142 | Header Files\Utilities 143 | 144 | 145 | Header Files 146 | 147 | 148 | 149 | 150 | Source Files 151 | 152 | 153 | Source Files 154 | 155 | 156 | Source Files 157 | 158 | 159 | Source Files 160 | 161 | 162 | Source Files 163 | 164 | 165 | Source Files 166 | 167 | 168 | Source Files 169 | 170 | 171 | Source Files 172 | 173 | 174 | Source Files 175 | 176 | 177 | Source Files 178 | 179 | 180 | Source Files 181 | 182 | 183 | Source Files 184 | 185 | 186 | Source Files 187 | 188 | 189 | Source Files\MDC 190 | 191 | 192 | Source Files\MDC 193 | 194 | 195 | Source Files\MDC 196 | 197 | 198 | Source Files\MDC 199 | 200 | 201 | Source Files 202 | 203 | 204 | Source Files 205 | 206 | 207 | Source Files 208 | 209 | 210 | Source Files\MDC 211 | 212 | 213 | Source Files 214 | 215 | 216 | Source Files\MDC 217 | 218 | 219 | Source Files\MDC 220 | 221 | 222 | Source Files 223 | 224 | 225 | Source Files 226 | 227 | 228 | Source Files 229 | 230 | 231 | Source Files\WorldPipeline 232 | 233 | 234 | Source Files\WorldPipeline 235 | 236 | 237 | Source Files\WorldPipeline 238 | 239 | 240 | Source Files\WorldPipeline 241 | 242 | 243 | Source Files\WorldPipeline 244 | 245 | 246 | Source Files 247 | 248 | 249 | 250 | 251 | Header Files\MDC 252 | 253 | 254 | Header Files 255 | 256 | 257 | 258 | 259 | Shaders 260 | 261 | 262 | Shaders 263 | 264 | 265 | Shaders 266 | 267 | 268 | -------------------------------------------------------------------------------- /ProjectIW/QEFSolver.cpp: -------------------------------------------------------------------------------- 1 | #include "QEFSolver.h" 2 | #include 3 | 4 | namespace MDC 5 | { 6 | QEFData::QEFData() 7 | { 8 | this->clear(); 9 | } 10 | 11 | QEFData::QEFData(const float ata_00, const float ata_01, 12 | const float ata_02, const float ata_11, const float ata_12, 13 | const float ata_22, const float atb_x, const float atb_y, 14 | const float atb_z, const float btb, const float massPoint_x, 15 | const float massPoint_y, const float massPoint_z, 16 | const int numPoints) 17 | { 18 | this->set(ata_00, ata_01, ata_02, ata_11, ata_12, ata_22, atb_x, atb_y, 19 | atb_z, btb, massPoint_x, massPoint_y, massPoint_z, numPoints); 20 | } 21 | 22 | QEFData::QEFData(const QEFData &rhs) 23 | { 24 | this->set(rhs); 25 | } 26 | 27 | QEFData& QEFData::operator=(const QEFData& rhs) 28 | { 29 | this->set(rhs); 30 | return *this; 31 | } 32 | 33 | void QEFData::add(const QEFData &rhs) 34 | { 35 | this->ata_00 += rhs.ata_00; 36 | this->ata_01 += rhs.ata_01; 37 | this->ata_02 += rhs.ata_02; 38 | this->ata_11 += rhs.ata_11; 39 | this->ata_12 += rhs.ata_12; 40 | this->ata_22 += rhs.ata_22; 41 | this->atb_x += rhs.atb_x; 42 | this->atb_y += rhs.atb_y; 43 | this->atb_z += rhs.atb_z; 44 | this->btb += rhs.btb; 45 | this->massPoint_x += rhs.massPoint_x; 46 | this->massPoint_y += rhs.massPoint_y; 47 | this->massPoint_z += rhs.massPoint_z; 48 | this->numPoints += rhs.numPoints; 49 | } 50 | 51 | void QEFData::clear() 52 | { 53 | this->set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 54 | } 55 | 56 | void QEFData::set(const float ata_00, const float ata_01, 57 | const float ata_02, const float ata_11, const float ata_12, 58 | const float ata_22, const float atb_x, const float atb_y, 59 | const float atb_z, const float btb, const float massPoint_x, 60 | const float massPoint_y, const float massPoint_z, 61 | const int numPoints) 62 | { 63 | this->ata_00 = ata_00; 64 | this->ata_01 = ata_01; 65 | this->ata_02 = ata_02; 66 | this->ata_11 = ata_11; 67 | this->ata_12 = ata_12; 68 | this->ata_22 = ata_22; 69 | this->atb_x = atb_x; 70 | this->atb_y = atb_y; 71 | this->atb_z = atb_z; 72 | this->btb = btb; 73 | this->massPoint_x = massPoint_x; 74 | this->massPoint_y = massPoint_y; 75 | this->massPoint_z = massPoint_z; 76 | this->numPoints = numPoints; 77 | } 78 | 79 | void QEFData::set(const QEFData &rhs) 80 | { 81 | this->set(rhs.ata_00, rhs.ata_01, rhs.ata_02, rhs.ata_11, rhs.ata_12, 82 | rhs.ata_22, rhs.atb_x, rhs.atb_y, rhs.atb_z, rhs.btb, 83 | rhs.massPoint_x, rhs.massPoint_y, rhs.massPoint_z, 84 | rhs.numPoints); 85 | } 86 | 87 | QEFSolver::QEFSolver() : data(), ata(), atb(), massPoint(), x(), 88 | hasSolution(false) {} 89 | 90 | QEFSolver::QEFSolver(const QEFSolver& q) : data(), ata(), atb(), massPoint(), x(), 91 | hasSolution(false) 92 | { 93 | memcpy(this, &q, sizeof(q)); 94 | 95 | this->data.set(q.data); 96 | } 97 | 98 | static void normalize(float &nx, float &ny, float &nz) 99 | { 100 | Vec3 tmpv(nx, ny, nz); 101 | VecUtils::normalize(tmpv); 102 | nx = tmpv.x; 103 | ny = tmpv.y; 104 | nz = tmpv.z; 105 | } 106 | 107 | void QEFSolver::add(const float px, const float py, const float pz, 108 | float nx, float ny, float nz) 109 | { 110 | this->hasSolution = false; 111 | normalize(nx, ny, nz); 112 | this->data.ata_00 += nx * nx; 113 | this->data.ata_01 += nx * ny; 114 | this->data.ata_02 += nx * nz; 115 | this->data.ata_11 += ny * ny; 116 | this->data.ata_12 += ny * nz; 117 | this->data.ata_22 += nz * nz; 118 | const float dot = nx * px + ny * py + nz * pz; 119 | this->data.atb_x += dot * nx; 120 | this->data.atb_y += dot * ny; 121 | this->data.atb_z += dot * nz; 122 | this->data.btb += dot * dot; 123 | this->data.massPoint_x += px; 124 | this->data.massPoint_y += py; 125 | this->data.massPoint_z += pz; 126 | ++this->data.numPoints; 127 | } 128 | 129 | void QEFSolver::add(const Vec3 &p, const Vec3 &n) 130 | { 131 | this->add(p.x, p.y, p.z, n.x, n.y, n.z); 132 | } 133 | 134 | void QEFSolver::add(const QEFData &rhs) 135 | { 136 | this->hasSolution = false; 137 | this->data.add(rhs); 138 | } 139 | 140 | QEFData QEFSolver::getData() 141 | { 142 | return data; 143 | } 144 | 145 | float QEFSolver::getError() 146 | { 147 | if (!this->hasSolution) { 148 | throw std::runtime_error("illegal state"); 149 | } 150 | 151 | return this->getError(this->x); 152 | } 153 | 154 | float QEFSolver::getError(const Vec3 &pos) 155 | { 156 | if (!this->hasSolution) { 157 | this->setAta(); 158 | this->setAtb(); 159 | } 160 | 161 | Vec3 atax; 162 | MatUtils::vmul_symmetric(atax, this->ata, pos); 163 | return VecUtils::dot(pos, atax) - 2 * VecUtils::dot(pos, this->atb) 164 | + this->data.btb; 165 | } 166 | 167 | void QEFSolver::reset() 168 | { 169 | this->hasSolution = false; 170 | this->data.clear(); 171 | } 172 | 173 | void QEFSolver::setAta() 174 | { 175 | this->ata.setSymmetric(this->data.ata_00, this->data.ata_01, 176 | this->data.ata_02, this->data.ata_11, this->data.ata_12, 177 | this->data.ata_22); 178 | } 179 | 180 | void QEFSolver::setAtb() 181 | { 182 | this->atb.set(this->data.atb_x, this->data.atb_y, this->data.atb_z); 183 | } 184 | 185 | float QEFSolver::solve(Vec3 &outx, const float svd_tol, 186 | const int svd_sweeps, const float pinv_tol) 187 | { 188 | if (this->data.numPoints == 0) { 189 | throw std::invalid_argument("..."); 190 | } 191 | 192 | this->massPoint.set(this->data.massPoint_x, this->data.massPoint_y, 193 | this->data.massPoint_z); 194 | VecUtils::scale(this->massPoint, 1.0f / this->data.numPoints); 195 | this->setAta(); 196 | this->setAtb(); 197 | Vec3 tmpv; 198 | MatUtils::vmul_symmetric(tmpv, this->ata, this->massPoint); 199 | VecUtils::sub(this->atb, this->atb, tmpv); 200 | this->x.clear(); 201 | const float result = Svd::solveSymmetric(this->ata, this->atb, 202 | this->x, svd_tol, svd_sweeps, pinv_tol); 203 | if (isnan(result)) 204 | this->x.set(this->massPoint); 205 | else 206 | VecUtils::addScaled(this->x, 1, this->massPoint); 207 | this->setAtb(); 208 | outx.set(x); 209 | this->hasSolution = true; 210 | return result; 211 | } 212 | } -------------------------------------------------------------------------------- /ProjectIW/QEFSolver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "SimpleMath.h" 4 | #include "SVD.h" 5 | 6 | using namespace DirectX::SimpleMath; 7 | 8 | namespace MDC 9 | { 10 | struct QEFData 11 | { 12 | float ata_00, ata_01, ata_02, ata_11, ata_12, ata_22; 13 | float atb_x, atb_y, atb_z; 14 | float btb; 15 | float massPoint_x, massPoint_y, massPoint_z; 16 | int numPoints; 17 | 18 | QEFData(); 19 | 20 | QEFData(const float ata_00, const float ata_01, 21 | const float ata_02, const float ata_11, const float ata_12, 22 | const float ata_22, const float atb_x, const float atb_y, 23 | const float atb_z, const float btb, const float massPoint_x, 24 | const float massPoint_y, const float massPoint_z, 25 | const int numPoints); 26 | 27 | void add(const QEFData& rhs); 28 | 29 | void clear(); 30 | 31 | void set(const float ata_00, const float ata_01, 32 | const float ata_02, const float ata_11, const float ata_12, 33 | const float ata_22, const float atb_x, const float atb_y, 34 | const float atb_z, const float btb, const float massPoint_x, 35 | const float massPoint_y, const float massPoint_z, 36 | const int numPoints); 37 | 38 | void set(const QEFData& rhs); 39 | 40 | QEFData(const QEFData& rhs); 41 | QEFData &operator= (const QEFData& rhs); 42 | }; 43 | 44 | class QEFSolver 45 | { 46 | public: 47 | QEFSolver(); 48 | QEFSolver(const QEFSolver&); 49 | 50 | const Vec3& getMassPoint() const { return massPoint; } 51 | 52 | void add(const float px, const float py, const float pz, 53 | float nx, float ny, float nz); 54 | void add(const Vec3 &p, const Vec3 &n); 55 | void add(const QEFData &rhs); 56 | QEFData getData(); 57 | float getError(); 58 | float getError(const Vec3 &pos); 59 | void reset(); 60 | float solve(Vec3 &outx, const float svd_tol, 61 | const int svd_sweeps, const float pinv_tol); 62 | 63 | private: 64 | 65 | QEFData data; 66 | SMat3 ata; 67 | Vec3 atb, massPoint, x; 68 | bool hasSolution; 69 | 70 | void setAta(); 71 | void setAtb(); 72 | }; 73 | } 74 | -------------------------------------------------------------------------------- /ProjectIW/RenderEngine.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderEngine.h" 2 | #include "Scene.h" 3 | #include 4 | 5 | int BUFFER_WIDTH = 1280; 6 | int BUFFER_HEIGHT = 720; 7 | 8 | RenderEngine::RenderEngine(HWND handle) 9 | { 10 | this->windowHandle = handle; 11 | } 12 | 13 | RenderEngine::~RenderEngine(void) 14 | { 15 | Dispose(); 16 | } 17 | 18 | bool RenderEngine::Setup() 19 | { 20 | this->scene = 0; 21 | if (!SetupDevice()) 22 | return false; 23 | if (!SetupBuffer()) 24 | return false; 25 | if (!SetupDepthBuffer()) 26 | return false; 27 | if (!SetupRasterizerState()) 28 | return false; 29 | void* v = _aligned_malloc(sizeof(Scene), 16); 30 | this->scene = new (v)Scene(); 31 | if (!this->scene->Setup()) 32 | return false; 33 | 34 | return true; 35 | } 36 | 37 | bool RenderEngine::SetupDevice() 38 | { 39 | DXGI_SWAP_CHAIN_DESC desc; 40 | ZeroMemory(&desc, sizeof(desc)); 41 | desc.BufferCount = 1; 42 | desc.BufferDesc.Width = BUFFER_WIDTH; 43 | desc.BufferDesc.Height = BUFFER_HEIGHT; 44 | desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 45 | desc.BufferDesc.RefreshRate.Numerator = REFRESH_RATE; 46 | desc.BufferDesc.RefreshRate.Denominator = 1; 47 | desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 48 | desc.OutputWindow = this->windowHandle; 49 | desc.SampleDesc.Count = 1; 50 | desc.SampleDesc.Quality = 0; 51 | desc.Windowed = true; 52 | 53 | D3D_FEATURE_LEVEL FeatureLevelsRequested[3] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0 }; 54 | UINT numLevelsRequested = 1; 55 | D3D_FEATURE_LEVEL FeatureLevelsSupported; 56 | 57 | HRESULT hr = D3D11CreateDeviceAndSwapChain(0, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, FeatureLevelsRequested, 3, D3D11_SDK_VERSION, &desc, &SwapChain, &Device, &FeatureLevelsSupported, &ImmediateContext); 58 | if (FAILED(hr)) 59 | { 60 | MessageBox(0, std::to_string(hr).c_str(), "DIR", MB_OK); 61 | MessageBox(NULL, "Failed to create device.", "Error", 0); 62 | return false; 63 | } 64 | 65 | return true; 66 | } 67 | 68 | bool RenderEngine::SetupBuffer() 69 | { 70 | if (FAILED(SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&BackBuffer))) 71 | { 72 | MessageBox(NULL, "Failed to create back buffer.", "Error", 0); 73 | return false; 74 | } 75 | HRESULT hr = Device->CreateRenderTargetView(BackBuffer, NULL, &RenderTargetView); 76 | BackBuffer->Release(); 77 | if (FAILED(hr)) 78 | { 79 | MessageBox(NULL, "Failed to create render target view.", "Error", 0); 80 | return false; 81 | } 82 | 83 | ZeroMemory(&Viewport, sizeof(Viewport)); 84 | UpdateViewport(); 85 | 86 | return true; 87 | } 88 | 89 | bool RenderEngine::SetupDepthBuffer() 90 | { 91 | D3D11_TEXTURE2D_DESC desc; 92 | ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC)); 93 | desc.Width = BUFFER_WIDTH; 94 | desc.Height = BUFFER_HEIGHT; 95 | desc.MipLevels = 1; 96 | desc.ArraySize = 1; 97 | desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; 98 | desc.SampleDesc.Count = 1; 99 | desc.SampleDesc.Quality = 0; 100 | desc.Usage = D3D11_USAGE_DEFAULT; 101 | desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; 102 | desc.CPUAccessFlags = 0; 103 | desc.MiscFlags = 0; 104 | 105 | if (FAILED(Device->CreateTexture2D(&desc, NULL, &DepthBuffer))) 106 | { 107 | MessageBox(0, "Failed to create depth buffer.", "Error", MB_ICONERROR); 108 | return false; 109 | } 110 | if (FAILED(Device->CreateDepthStencilView(DepthBuffer, NULL, &DepthStencilView))) 111 | { 112 | MessageBox(0, "Failed to create depth stencil view.", "Error", MB_ICONERROR); 113 | return false; 114 | } 115 | 116 | return true; 117 | } 118 | 119 | bool RenderEngine::SetupRasterizerState() 120 | { 121 | D3D11_RASTERIZER_DESC rasterDesc; 122 | ZeroMemory(&rasterDesc, sizeof(rasterDesc)); 123 | rasterDesc.AntialiasedLineEnable = false; 124 | rasterDesc.CullMode = D3D11_CULL_NONE; 125 | rasterDesc.DepthBias = 0; 126 | rasterDesc.DepthBiasClamp = 0.0f; 127 | rasterDesc.DepthClipEnable = true; 128 | rasterDesc.FillMode = D3D11_FILL_SOLID; 129 | rasterDesc.FrontCounterClockwise = true; 130 | rasterDesc.MultisampleEnable = false; 131 | rasterDesc.ScissorEnable = false; 132 | rasterDesc.SlopeScaledDepthBias = 0.0f; 133 | 134 | if (FAILED(Device->CreateRasterizerState(&rasterDesc, &Rasterizer))) 135 | { 136 | MessageBox(0, "Failed to create rasterizer.", "Error", MB_ICONERROR); 137 | return false; 138 | } 139 | 140 | rasterDesc.FillMode = D3D11_FILL_WIREFRAME; 141 | rasterDesc.CullMode = D3D11_CULL_NONE; 142 | 143 | if (FAILED(Device->CreateRasterizerState(&rasterDesc, &WireframeRasterizer))) 144 | { 145 | MessageBox(0, "Failed to create rasterizer.", "Error", MB_ICONERROR); 146 | return false; 147 | } 148 | 149 | return true; 150 | } 151 | 152 | void RenderEngine::UpdateViewport() 153 | { 154 | Viewport.TopLeftX = 0; 155 | Viewport.TopLeftY = 0; 156 | Viewport.Width = (float)BUFFER_WIDTH; 157 | Viewport.Height = (float)BUFFER_HEIGHT; 158 | Viewport.MinDepth = 0.0f; 159 | Viewport.MaxDepth = 1.0f; 160 | ImmediateContext->RSSetViewports(1, &Viewport); 161 | //if (scene) 162 | // scene->UpdateCamera(); 163 | } 164 | 165 | void RenderEngine::Render() 166 | { 167 | //float color[4] = { 0.0f, 0.6f, 0.9f, 1.0f }; 168 | float color[4] = { 0.1f, 0.1f, 0.1f, 1.0f }; 169 | ImmediateContext->ClearRenderTargetView(RenderTargetView, color); 170 | ImmediateContext->ClearDepthStencilView(DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); 171 | ImmediateContext->OMSetRenderTargets(1, &RenderTargetView, DepthStencilView); 172 | 173 | ImmediateContext->RSSetState(Rasterizer); 174 | 175 | if (scene) 176 | { 177 | scene->Update(); 178 | scene->Render(); 179 | } 180 | 181 | SwapChain->Present(1, 0); 182 | } 183 | 184 | void RenderEngine::Dispose() 185 | { 186 | if (scene) 187 | { 188 | //delete scene; 189 | scene->~Scene(); 190 | _aligned_free(scene); 191 | } 192 | if (SwapChain) 193 | SwapChain->Release(); 194 | if (Device) 195 | Device->Release(); 196 | if (ImmediateContext) 197 | ImmediateContext->Release(); 198 | if (BackBuffer) 199 | BackBuffer->Release(); 200 | if (RenderTargetView) 201 | RenderTargetView->Release(); 202 | if (DepthBuffer) 203 | DepthBuffer->Release(); 204 | if (DepthStencilView) 205 | DepthStencilView->Release(); 206 | if (Rasterizer) 207 | Rasterizer->Release(); 208 | if (WireframeRasterizer) 209 | WireframeRasterizer->Release(); 210 | } 211 | -------------------------------------------------------------------------------- /ProjectIW/RenderEngine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "General.h" 5 | 6 | #define REFRESH_RATE 60 7 | 8 | class RenderEngine 9 | { 10 | public: 11 | ID3D11Device* Device = 0; 12 | IDXGISwapChain* SwapChain = 0; 13 | ID3D11DeviceContext* ImmediateContext = 0; 14 | ID3D11RasterizerState* Rasterizer = 0; 15 | ID3D11RasterizerState* WireframeRasterizer = 0; 16 | 17 | ID3D11Texture2D* BackBuffer = 0; 18 | ID3D11RenderTargetView* RenderTargetView = 0; 19 | ID3D11Texture2D* DepthBuffer = 0; 20 | ID3D11DepthStencilView* DepthStencilView = 0; 21 | 22 | D3D11_VIEWPORT Viewport; 23 | 24 | RenderEngine(HWND); 25 | ~RenderEngine(void); 26 | 27 | bool Setup(); 28 | void UpdateViewport(); 29 | void Render(); 30 | void Dispose(); 31 | 32 | private: 33 | HWND windowHandle; 34 | Scene* scene = 0; 35 | 36 | bool SetupDevice(); 37 | bool SetupBuffer(); 38 | bool SetupDepthBuffer(); 39 | bool SetupRasterizerState(); 40 | }; 41 | -------------------------------------------------------------------------------- /ProjectIW/SVD.cpp: -------------------------------------------------------------------------------- 1 | #include "SVD.h" 2 | #include 3 | 4 | namespace MDC 5 | { 6 | 7 | Mat3::Mat3() 8 | { 9 | this->clear(); 10 | } 11 | 12 | Mat3::Mat3(const float m00, const float m01, const float m02, 13 | const float m10, const float m11, const float m12, 14 | const float m20, const float m21, const float m22) 15 | { 16 | this->set(m00, m01, m02, m10, m11, m12, m20, m21, m22); 17 | } 18 | 19 | Mat3::Mat3(const Mat3 &rhs) 20 | { 21 | this->set(rhs); 22 | } 23 | 24 | void Mat3::clear() 25 | { 26 | this->set(0, 0, 0, 0, 0, 0, 0, 0, 0); 27 | } 28 | 29 | void Mat3::set(const float m00, const float m01, const float m02, 30 | const float m10, const float m11, const float m12, 31 | const float m20, const float m21, const float m22) 32 | { 33 | this->m00 = m00; 34 | this->m01 = m01; 35 | this->m02 = m02; 36 | this->m10 = m10; 37 | this->m11 = m11; 38 | this->m12 = m12; 39 | this->m20 = m20; 40 | this->m21 = m21; 41 | this->m22 = m22; 42 | } 43 | 44 | void Mat3::set(const Mat3 &rhs) 45 | { 46 | this->set(rhs.m00, rhs.m01, rhs.m02, rhs.m10, rhs.m11, rhs.m12, rhs.m20, 47 | rhs.m21, rhs.m22); 48 | } 49 | 50 | void Mat3::setSymmetric(const SMat3 &rhs) 51 | { 52 | this->setSymmetric(rhs.m00, rhs.m01, rhs.m02, rhs.m11, rhs.m12, rhs.m22); 53 | } 54 | 55 | void Mat3::setSymmetric(const float a00, const float a01, const float a02, 56 | const float a11, const float a12, const float a22) 57 | { 58 | this->set(a00, a01, a02, a01, a11, a12, a02, a12, a22); 59 | } 60 | 61 | SMat3::SMat3() 62 | { 63 | this->clear(); 64 | } 65 | 66 | SMat3::SMat3(const float m00, const float m01, const float m02, 67 | const float m11, const float m12, const float m22) 68 | { 69 | this->setSymmetric(m00, m01, m02, m11, m12, m22); 70 | } 71 | 72 | SMat3::SMat3(const SMat3 &rhs) 73 | { 74 | this->setSymmetric(rhs); 75 | } 76 | 77 | void SMat3::clear() 78 | { 79 | this->setSymmetric(0, 0, 0, 0, 0, 0); 80 | } 81 | 82 | void SMat3::setSymmetric(const SMat3 &rhs) 83 | { 84 | this->setSymmetric(rhs.m00, rhs.m01, rhs.m02, rhs.m11, rhs.m12, rhs.m22); 85 | } 86 | 87 | void SMat3::setSymmetric(const float a00, const float a01, const float a02, 88 | const float a11, const float a12, const float a22) 89 | { 90 | this->m00 = a00; 91 | this->m01 = a01; 92 | this->m02 = a02; 93 | this->m11 = a11; 94 | this->m12 = a12; 95 | this->m22 = a22; 96 | } 97 | 98 | Vec3::Vec3() : x(0), y(0), z(0) { } 99 | 100 | Vec3::Vec3(const Vec3 &rhs)// : Vec3() 101 | { 102 | this->set(rhs); 103 | } 104 | 105 | Vec3::Vec3(const float x, const float y, const float z)// : Vec3() 106 | { 107 | this->set(x, y, z); 108 | } 109 | 110 | void Vec3::clear() 111 | { 112 | this->set(0, 0, 0); 113 | } 114 | 115 | void Vec3::set(const float x, const float y, const float z) 116 | { 117 | this->x = x; 118 | this->y = y; 119 | this->z = z; 120 | } 121 | 122 | void Vec3::set(const Vec3 &rhs) 123 | { 124 | this->set(rhs.x, rhs.y, rhs.z); 125 | } 126 | 127 | float MatUtils::fnorm(const Mat3 &a) 128 | { 129 | return sqrt((a.m00 * a.m00) + (a.m01 * a.m01) + (a.m02 * a.m02) 130 | + (a.m10 * a.m10) + (a.m11 * a.m11) + (a.m12 * a.m12) 131 | + (a.m20 * a.m20) + (a.m21 * a.m21) + (a.m22 * a.m22)); 132 | } 133 | 134 | float MatUtils::fnorm(const SMat3 &a) 135 | { 136 | return sqrt((a.m00 * a.m00) + (a.m01 * a.m01) + (a.m02 * a.m02) 137 | + (a.m01 * a.m01) + (a.m11 * a.m11) + (a.m12 * a.m12) 138 | + (a.m02 * a.m02) + (a.m12 * a.m12) + (a.m22 * a.m22)); 139 | } 140 | 141 | float MatUtils::off(const Mat3 &a) 142 | { 143 | return sqrt((a.m01 * a.m01) + (a.m02 * a.m02) + (a.m10 * a.m10) 144 | + (a.m12 * a.m12) + (a.m20 * a.m20) + (a.m21 * a.m21)); 145 | } 146 | 147 | float MatUtils::off(const SMat3 &a) 148 | { 149 | return sqrt(2.0f * ((a.m01 * a.m01) + (a.m02 * a.m02) + (a.m12 * a.m12))); 150 | } 151 | 152 | void MatUtils::mmul(Mat3 &out, const Mat3 &a, const Mat3 &b) 153 | { 154 | out.set(a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20, 155 | a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21, 156 | a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22, 157 | a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20, 158 | a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21, 159 | a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22, 160 | a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20, 161 | a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21, 162 | a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22); 163 | } 164 | 165 | void MatUtils::mmul_ata(SMat3 &out, const Mat3 &a) 166 | { 167 | out.setSymmetric(a.m00 * a.m00 + a.m10 * a.m10 + a.m20 * a.m20, 168 | a.m00 * a.m01 + a.m10 * a.m11 + a.m20 * a.m21, 169 | a.m00 * a.m02 + a.m10 * a.m12 + a.m20 * a.m22, 170 | a.m01 * a.m01 + a.m11 * a.m11 + a.m21 * a.m21, 171 | a.m01 * a.m02 + a.m11 * a.m12 + a.m21 * a.m22, 172 | a.m02 * a.m02 + a.m12 * a.m12 + a.m22 * a.m22); 173 | } 174 | 175 | void MatUtils::transpose(Mat3 &out, const Mat3 &a) 176 | { 177 | out.set(a.m00, a.m10, a.m20, a.m01, a.m11, a.m21, a.m02, a.m12, a.m22); 178 | } 179 | 180 | void MatUtils::vmul(Vec3 &out, const Mat3 &a, const Vec3 &v) 181 | { 182 | out.x = (a.m00 * v.x) + (a.m01 * v.y) + (a.m02 * v.z); 183 | out.y = (a.m10 * v.x) + (a.m11 * v.y) + (a.m12 * v.z); 184 | out.z = (a.m20 * v.x) + (a.m21 * v.y) + (a.m22 * v.z); 185 | } 186 | 187 | void MatUtils::vmul_symmetric(Vec3 &out, const SMat3 &a, const Vec3 &v) 188 | { 189 | out.x = (a.m00 * v.x) + (a.m01 * v.y) + (a.m02 * v.z); 190 | out.y = (a.m01 * v.x) + (a.m11 * v.y) + (a.m12 * v.z); 191 | out.z = (a.m02 * v.x) + (a.m12 * v.y) + (a.m22 * v.z); 192 | } 193 | 194 | void VecUtils::addScaled(Vec3 &v, const float s, const Vec3 &rhs) 195 | { 196 | v.x += s * rhs.x; 197 | v.y += s * rhs.y; 198 | v.z += s * rhs.z; 199 | } 200 | 201 | float VecUtils::dot(const Vec3 &a, const Vec3 &b) 202 | { 203 | return a.x * b.x + a.y * b.y + a.z * b.z; 204 | } 205 | 206 | void VecUtils::normalize(Vec3 &v) 207 | { 208 | const float len2 = VecUtils::dot(v, v); 209 | 210 | if (fabs(len2) < 1e-12) { 211 | v.clear(); 212 | } 213 | else { 214 | VecUtils::scale(v, 1 / sqrt(len2)); 215 | } 216 | } 217 | 218 | void VecUtils::scale(Vec3 &v, const float s) 219 | { 220 | v.x *= s; 221 | v.y *= s; 222 | v.z *= s; 223 | } 224 | 225 | void VecUtils::sub(Vec3 &c, const Vec3 &a, const Vec3 &b) 226 | { 227 | const float v0 = a.x - b.x; 228 | const float v1 = a.y - b.y; 229 | const float v2 = a.z - b.z; 230 | c.x = v0; 231 | c.y = v1; 232 | c.z = v2; 233 | } 234 | 235 | void Givens::rot01_post(Mat3 &m, const float c, const float s) 236 | { 237 | const float m00 = m.m00, m01 = m.m01, m10 = m.m10, m11 = m.m11, m20 = m.m20, 238 | m21 = m.m21; 239 | m.set(c * m00 - s * m01, s * m00 + c * m01, m.m02, c * m10 - s * m11, 240 | s * m10 + c * m11, m.m12, c * m20 - s * m21, s * m20 + c * m21, m.m22); 241 | } 242 | 243 | void Givens::rot02_post(Mat3 &m, const float c, const float s) 244 | { 245 | const float m00 = m.m00, m02 = m.m02, m10 = m.m10, m12 = m.m12, 246 | m20 = m.m20, m22 = m.m22; 247 | m.set(c * m00 - s * m02, m.m01, s * m00 + c * m02, c * m10 - s * m12, m.m11, 248 | s * m10 + c * m12, c * m20 - s * m22, m.m21, s * m20 + c * m22); 249 | } 250 | 251 | void Givens::rot12_post(Mat3 &m, const float c, const float s) 252 | { 253 | const float m01 = m.m01, m02 = m.m02, m11 = m.m11, m12 = m.m12, 254 | m21 = m.m21, m22 = m.m22; 255 | m.set(m.m00, c * m01 - s * m02, s * m01 + c * m02, m.m10, c * m11 - s * m12, 256 | s * m11 + c * m12, m.m20, c * m21 - s * m22, s * m21 + c * m22); 257 | } 258 | 259 | static void calcSymmetricGivensCoefficients(const float a_pp, 260 | const float a_pq, const float a_qq, float &c, float &s) 261 | { 262 | if (a_pq == 0) { 263 | c = 1; 264 | s = 0; 265 | return; 266 | } 267 | 268 | const float tau = (a_qq - a_pp) / (2 * a_pq); 269 | const float stt = sqrt(1.0f + tau * tau); 270 | const float tan = 1.0f / ((tau >= 0) ? (tau + stt) : (tau - stt)); 271 | c = 1.0f / sqrt(1.f + tan * tan); 272 | s = tan * c; 273 | } 274 | 275 | void Schur2::rot01(SMat3 &m, float &c, float &s) 276 | { 277 | MDC::calcSymmetricGivensCoefficients(m.m00, m.m01, m.m11, c, s); 278 | const float cc = c * c; 279 | const float ss = s * s; 280 | const float mix = 2 * c * s * m.m01; 281 | m.setSymmetric(cc * m.m00 - mix + ss * m.m11, 0, c * m.m02 - s * m.m12, 282 | ss * m.m00 + mix + cc * m.m11, s * m.m02 + c * m.m12, m.m22); 283 | } 284 | 285 | void Schur2::rot02(SMat3 &m, float &c, float &s) 286 | { 287 | MDC::calcSymmetricGivensCoefficients(m.m00, m.m02, m.m22, c, s); 288 | const float cc = c * c; 289 | const float ss = s * s; 290 | const float mix = 2 * c * s * m.m02; 291 | m.setSymmetric(cc * m.m00 - mix + ss * m.m22, c * m.m01 - s * m.m12, 0, 292 | m.m11, s * m.m01 + c * m.m12, ss * m.m00 + mix + cc * m.m22); 293 | } 294 | 295 | void Schur2::rot12(SMat3 &m, float &c, float &s) 296 | { 297 | MDC::calcSymmetricGivensCoefficients(m.m11, m.m12, m.m22, c, s); 298 | const float cc = c * c; 299 | const float ss = s * s; 300 | const float mix = 2 * c * s * m.m12; 301 | m.setSymmetric(m.m00, c * m.m01 - s * m.m02, s * m.m01 + c * m.m02, 302 | cc * m.m11 - mix + ss * m.m22, 0, ss * m.m11 + mix + cc * m.m22); 303 | } 304 | 305 | static void rotate01(SMat3 &vtav, Mat3 &v) 306 | { 307 | if (vtav.m01 == 0) { 308 | return; 309 | } 310 | 311 | float c = 0, s = 0; 312 | Schur2::rot01(vtav, c, s); 313 | c = 0; s = 0; 314 | Givens::rot01_post(v, c, s); 315 | } 316 | 317 | static void rotate02(SMat3 &vtav, Mat3 &v) 318 | { 319 | if (vtav.m02 == 0) { 320 | return; 321 | } 322 | 323 | float c = 0, s = 0; 324 | Schur2::rot02(vtav, c, s); 325 | c = 0; s = 0; 326 | Givens::rot02_post(v, c, s); 327 | } 328 | 329 | static void rotate12(SMat3 &vtav, Mat3 &v) 330 | { 331 | if (vtav.m12 == 0) { 332 | return; 333 | } 334 | 335 | float c = 0, s = 0; 336 | Schur2::rot12(vtav, c, s); 337 | c = 0; s = 0; 338 | Givens::rot12_post(v, c, s); 339 | } 340 | 341 | void Svd::getSymmetricSvd(const SMat3 &a, SMat3 &vtav, Mat3 &v, 342 | const float tol, 343 | const int max_sweeps) 344 | { 345 | vtav.setSymmetric(a); 346 | v.set(1, 0, 0, 0, 1, 0, 0, 0, 1); 347 | const float delta = tol * MatUtils::fnorm(vtav); 348 | 349 | for (int i = 0; i < max_sweeps 350 | && MatUtils::off(vtav) > delta; ++i) { 351 | rotate01(vtav, v); 352 | rotate02(vtav, v); 353 | rotate12(vtav, v); 354 | } 355 | } 356 | 357 | static float calcError(const Mat3 &A, const Vec3 &x, 358 | const Vec3 &b) 359 | { 360 | Vec3 vtmp; 361 | MatUtils::vmul(vtmp, A, x); 362 | VecUtils::sub(vtmp, b, vtmp); 363 | return VecUtils::dot(vtmp, vtmp); 364 | } 365 | 366 | static float calcError(const SMat3 &origA, const Vec3 &x, 367 | const Vec3 &b) 368 | { 369 | Mat3 A; 370 | Vec3 vtmp; 371 | A.setSymmetric(origA); 372 | MatUtils::vmul(vtmp, A, x); 373 | VecUtils::sub(vtmp, b, vtmp); 374 | return VecUtils::dot(vtmp, vtmp); 375 | } 376 | 377 | static float pinv(const float x, const float tol) 378 | { 379 | return (fabs(x) < tol || fabs(1.0f / x) < tol) ? 0 : (1.0f / x); 380 | } 381 | 382 | void Svd::pseudoinverse(Mat3 &out, const SMat3 &d, const Mat3 &v, 383 | const float tol) 384 | { 385 | const float d0 = pinv(d.m00, tol), d1 = pinv(d.m11, tol), d2 = pinv(d.m22, 386 | tol); 387 | out.set(v.m00 * d0 * v.m00 + v.m01 * d1 * v.m01 + v.m02 * d2 * v.m02, 388 | v.m00 * d0 * v.m10 + v.m01 * d1 * v.m11 + v.m02 * d2 * v.m12, 389 | v.m00 * d0 * v.m20 + v.m01 * d1 * v.m21 + v.m02 * d2 * v.m22, 390 | v.m10 * d0 * v.m00 + v.m11 * d1 * v.m01 + v.m12 * d2 * v.m02, 391 | v.m10 * d0 * v.m10 + v.m11 * d1 * v.m11 + v.m12 * d2 * v.m12, 392 | v.m10 * d0 * v.m20 + v.m11 * d1 * v.m21 + v.m12 * d2 * v.m22, 393 | v.m20 * d0 * v.m00 + v.m21 * d1 * v.m01 + v.m22 * d2 * v.m02, 394 | v.m20 * d0 * v.m10 + v.m21 * d1 * v.m11 + v.m22 * d2 * v.m12, 395 | v.m20 * d0 * v.m20 + v.m21 * d1 * v.m21 + v.m22 * d2 * v.m22); 396 | } 397 | 398 | float Svd::solveSymmetric(const SMat3 &A, const Vec3 &b, Vec3 &x, 399 | const float svd_tol, const int svd_sweeps, const float pinv_tol) 400 | { 401 | Mat3 mtmp, pinv, V; 402 | SMat3 VTAV; 403 | 404 | Svd::getSymmetricSvd(A, VTAV, V, svd_tol, svd_sweeps); 405 | Svd::pseudoinverse(pinv, VTAV, V, pinv_tol); 406 | MatUtils::vmul(x, pinv, b); 407 | return MDC::calcError(A, x, b); 408 | } 409 | 410 | float 411 | LeastSquares::solveLeastSquares(const Mat3 &a, const Vec3 &b, Vec3 &x, 412 | const float svd_tol, const int svd_sweeps, const float pinv_tol) 413 | { 414 | Mat3 at; 415 | SMat3 ata; 416 | Vec3 atb; 417 | MatUtils::transpose(at, a); 418 | MatUtils::mmul_ata(ata, a); 419 | MatUtils::vmul(atb, at, b); 420 | return Svd::solveSymmetric(ata, atb, x, svd_tol, svd_sweeps, pinv_tol); 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /ProjectIW/SVD.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace MDC 4 | { 5 | class SMat3 6 | { 7 | public: 8 | float m00, m01, m02, m11, m12, m22; 9 | public: 10 | SMat3(); 11 | SMat3(const float m00, const float m01, const float m02, 12 | const float m11, const float m12, const float m22); 13 | void clear(); 14 | void setSymmetric(const float m00, const float m01, const float m02, 15 | const float m11, 16 | const float m12, const float m22); 17 | void setSymmetric(const SMat3 &rhs); 18 | private: 19 | SMat3(const SMat3 &rhs); 20 | SMat3 &operator=(const SMat3 &rhs); 21 | }; 22 | class Mat3 23 | { 24 | public: 25 | float m00, m01, m02, m10, m11, m12, m20, m21, m22; 26 | public: 27 | Mat3(); 28 | Mat3(const float m00, const float m01, const float m02, 29 | const float m10, const float m11, const float m12, 30 | const float m20, const float m21, const float m22); 31 | void clear(); 32 | void set(const float m00, const float m01, const float m02, 33 | const float m10, const float m11, const float m12, 34 | const float m20, const float m21, const float m22); 35 | void set(const Mat3 &rhs); 36 | void setSymmetric(const float a00, const float a01, const float a02, 37 | const float a11, const float a12, const float a22); 38 | void setSymmetric(const SMat3 &rhs); 39 | private: 40 | Mat3(const Mat3 &rhs); 41 | Mat3 &operator=(const Mat3 &rhs); 42 | }; 43 | class Vec3 44 | { 45 | public: 46 | float x, y, z; 47 | public: 48 | Vec3(); 49 | Vec3(const float x, const float y, const float z); 50 | void clear(); 51 | void set(const float x, const float y, const float z); 52 | void set(const Vec3 &rhs); 53 | private: 54 | Vec3(const Vec3 &rhs); 55 | Vec3 &operator=(const Vec3 &rhs); 56 | }; 57 | 58 | class MatUtils 59 | { 60 | public: 61 | static float fnorm(const Mat3 &a); 62 | static float fnorm(const SMat3 &a); 63 | static float off(const Mat3 &a); 64 | static float off(const SMat3 &a); 65 | 66 | public: 67 | static void mmul(Mat3 &out, const Mat3 &a, const Mat3 &b); 68 | static void mmul_ata(SMat3 &out, const Mat3 &a); 69 | static void transpose(Mat3 &out, const Mat3 &a); 70 | static void vmul(Vec3 &out, const Mat3 &a, const Vec3 &v); 71 | static void vmul_symmetric(Vec3 &out, const SMat3 &a, const Vec3 &v); 72 | }; 73 | class VecUtils 74 | { 75 | public: 76 | static void addScaled(Vec3 &v, const float s, const Vec3 &rhs); 77 | static float dot(const Vec3 &a, const Vec3 &b); 78 | static void normalize(Vec3 &v); 79 | static void scale(Vec3 &v, const float s); 80 | static void sub(Vec3 &c, const Vec3 &a, const Vec3 &b); 81 | }; 82 | class Givens 83 | { 84 | public: 85 | static void rot01_post(Mat3 &m, const float c, const float s); 86 | static void rot02_post(Mat3 &m, const float c, const float s); 87 | static void rot12_post(Mat3 &m, const float c, const float s); 88 | }; 89 | class Schur2 90 | { 91 | public: 92 | static void rot01(SMat3 &out, float &c, float &s); 93 | static void rot02(SMat3 &out, float &c, float &s); 94 | static void rot12(SMat3 &out, float &c, float &s); 95 | }; 96 | class Svd 97 | { 98 | public: 99 | static void getSymmetricSvd(const SMat3 &a, SMat3 &vtav, Mat3 &v, 100 | const float tol, const int max_sweeps); 101 | static void pseudoinverse(Mat3 &out, const SMat3 &d, const Mat3 &v, 102 | const float tol); 103 | static float solveSymmetric(const SMat3 &A, const Vec3 &b, Vec3 &x, 104 | const float svd_tol, const int svd_sweeps, const float pinv_tol); 105 | }; 106 | class LeastSquares 107 | { 108 | public: 109 | static float solveLeastSquares(const Mat3 &a, const Vec3 &b, Vec3 &x, 110 | const float svd_tol, const int svd_sweeps, const float pinv_tol); 111 | }; 112 | } 113 | -------------------------------------------------------------------------------- /ProjectIW/Scene.cpp: -------------------------------------------------------------------------------- 1 | #include "Scene.h" 2 | #include "VertexPositionColorNormal.h" 3 | #include "TerrainChunk.h" 4 | #include "WorldNode.h" 5 | #include "ShaderLoader.h" 6 | #include "ShaderGroup.h" 7 | #include "Camera.h" 8 | #include "Task.h" 9 | 10 | Scene::Scene() : world((int)pow(2, 16)) 11 | { 12 | terrain_shaders = 0; 13 | camera = 0; 14 | } 15 | 16 | Scene::~Scene() 17 | { 18 | world.Cleanup(); 19 | MeshGeneration::Quit(); 20 | 21 | if (terrain_shaders) 22 | { 23 | delete terrain_shaders; 24 | terrain_shaders = 0; 25 | } 26 | if (camera) 27 | { 28 | camera->~Camera(); 29 | _aligned_free(camera); 30 | camera = 0; 31 | } 32 | } 33 | 34 | bool Scene::Setup() 35 | { 36 | if (!SetupShaders()) 37 | return false; 38 | 39 | void* v = _aligned_malloc(sizeof(Camera), 16); 40 | this->camera = new (v)Camera((float)BUFFER_WIDTH / (float)BUFFER_HEIGHT); 41 | last_update_pos = Vector3(0, 0, 0); 42 | 43 | return true; 44 | } 45 | 46 | bool Scene::SetupShaders() 47 | { 48 | terrain_shaders = new ShaderGroup(L"VertexShader.cso", L"PixelShader.cso", L"GeometryShader.cso"); 49 | if (!terrain_shaders->IsValid()) 50 | return false; 51 | if (!terrain_shaders->CreateInputLayout(MDC::VertexPositionColorNormal::layout, MDC::VertexPositionColorNormal::num_elements)) 52 | return false; 53 | 54 | 55 | return true; 56 | } 57 | 58 | 59 | 60 | 61 | 62 | void Scene::Update() 63 | { 64 | UpdateWorld(); 65 | } 66 | 67 | void Scene::UpdateWorld() 68 | { 69 | Vector3 center = Vector3(camera->Position); 70 | if ((int)center.x == (int)last_update_pos.x && (int)center.y == (int)last_update_pos.y && (int)center.z == (int)last_update_pos.z) 71 | { 72 | last_update_pos = center; 73 | //return; 74 | } 75 | last_update_pos = center; 76 | 77 | world.Update(center); 78 | } 79 | 80 | void Scene::Render() 81 | { 82 | ID3D11DeviceContext* context = engine->rendering->ImmediateContext; 83 | 84 | camera->UpdateFirstPerson(); 85 | camera->SetShaderConstants(); 86 | 87 | context->VSSetShader(terrain_shaders->GetVertexShader(), 0, 0); 88 | context->GSSetShader(terrain_shaders->GetGeometryShader(), 0, 0); 89 | context->PSSetShader(terrain_shaders->GetPixelShader(), 0, 0); 90 | 91 | auto& nodes = world.GetRenderables(); 92 | for(auto n : nodes) 93 | { 94 | int stage = n->GetStage().load(); 95 | if (stage != NODE_STAGE_READY && stage != NODE_STAGE_SPLITTABLE) 96 | continue; 97 | TerrainChunk* octree = n->underlying_chunk; 98 | if (!octree || !octree->GetVBO() || !octree->GetIBO()) 99 | continue; 100 | octree->GetIBO()->Bind(); 101 | octree->GetVBO()->Bind(0); 102 | context->IASetInputLayout(terrain_shaders->GetInputLayout()); 103 | camera->GetTerrainBuffer()->BindToShader(0); 104 | 105 | context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 106 | context->DrawIndexed(octree->GetTriangleCount(), 0, 0); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /ProjectIW/Scene.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "General.h" 10 | #include "SimpleMath.h" 11 | #include "ThreadPool.h" 12 | #include "WorldProcessor.h" 13 | 14 | using namespace MDC; 15 | using namespace DirectX::SimpleMath; 16 | 17 | #define NUM_CHUNKS 8 18 | 19 | class Scene 20 | { 21 | public: 22 | Scene(); 23 | ~Scene(); 24 | 25 | bool Setup(); 26 | void Update(); 27 | void Render(); 28 | 29 | private: 30 | bool SetupShaders(); 31 | void UpdateWorld(); 32 | 33 | ShaderGroup* terrain_shaders; 34 | Camera* camera; 35 | Vector3 last_update_pos; 36 | 37 | WorldProcessor world; 38 | }; -------------------------------------------------------------------------------- /ProjectIW/Shader.cpp: -------------------------------------------------------------------------------- 1 | #include "Shader.h" 2 | 3 | 4 | Shader::Shader() 5 | { 6 | } 7 | 8 | 9 | Shader::~Shader() 10 | { 11 | } 12 | -------------------------------------------------------------------------------- /ProjectIW/Shader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "General.h" 4 | 5 | class Shader 6 | { 7 | public: 8 | Shader(); 9 | ~Shader(); 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /ProjectIW/ShaderConstants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | using namespace DirectX; 6 | 7 | __declspec(align(16)) 8 | struct BasicShaderConstants 9 | { 10 | XMMATRIX world; 11 | XMMATRIX view; 12 | XMMATRIX projection; 13 | }; 14 | -------------------------------------------------------------------------------- /ProjectIW/ShaderGroup.cpp: -------------------------------------------------------------------------------- 1 | #include "ShaderGroup.h" 2 | #include "Window.h" 3 | 4 | ShaderGroup::ShaderGroup(const WCHAR* vertex_name, const WCHAR* pixel_name, const WCHAR* geometry_name) 5 | { 6 | valid = LoadShader(vertex_name, pixel_name, geometry_name); 7 | } 8 | 9 | ShaderGroup::~ShaderGroup() 10 | { 11 | if (vertex_shader) 12 | { 13 | vertex_shader->Release(); 14 | vertex_shader = 0; 15 | } 16 | if (pixel_shader) 17 | { 18 | pixel_shader->Release(); 19 | pixel_shader = 0; 20 | } 21 | if (geometry_shader) 22 | { 23 | geometry_shader->Release(); 24 | geometry_shader = 0; 25 | } 26 | if (input_layout) 27 | { 28 | input_layout->Release(); 29 | input_layout = 0; 30 | } 31 | if (vertex_bytecode) 32 | { 33 | vertex_bytecode->Release(); 34 | vertex_bytecode = 0; 35 | } 36 | } 37 | 38 | bool ShaderGroup::LoadShader(const WCHAR* vertex_name, const WCHAR* pixel_name, const WCHAR* geometry_name) 39 | { 40 | vertex_shader = 0; 41 | pixel_shader = 0; 42 | geometry_shader = 0; 43 | input_layout = 0; 44 | vertex_bytecode = 0; 45 | 46 | if (!vertex_name && !pixel_name && !geometry_name) 47 | return false; 48 | 49 | if (vertex_name) 50 | { 51 | HRESULT hr = D3DReadFileToBlob(vertex_name, &vertex_bytecode); 52 | if (FAILED(hr)) 53 | return false; 54 | 55 | hr = engine->rendering->Device->CreateVertexShader(vertex_bytecode->GetBufferPointer(), vertex_bytecode->GetBufferSize(), 0, &vertex_shader); 56 | if (FAILED(hr)) 57 | return false; 58 | } 59 | 60 | if (pixel_name) 61 | { 62 | ID3DBlob* pixel_bytecode; 63 | HRESULT hr = D3DReadFileToBlob(pixel_name, &pixel_bytecode); 64 | if (FAILED(hr)) 65 | return false; 66 | 67 | hr = engine->rendering->Device->CreatePixelShader(pixel_bytecode->GetBufferPointer(), pixel_bytecode->GetBufferSize(), 0, &pixel_shader); 68 | if (FAILED(hr)) 69 | return false; 70 | } 71 | 72 | if (geometry_name) 73 | { 74 | ID3DBlob* geometry_bytecode; 75 | HRESULT hr = D3DReadFileToBlob(geometry_name, &geometry_bytecode); 76 | if (FAILED(hr)) 77 | return false; 78 | 79 | hr = engine->rendering->Device->CreateGeometryShader(geometry_bytecode->GetBufferPointer(), geometry_bytecode->GetBufferSize(), 0, &geometry_shader); 80 | if (FAILED(hr)) 81 | return false; 82 | } 83 | 84 | return true; 85 | } 86 | 87 | bool ShaderGroup::CreateInputLayout(D3D11_INPUT_ELEMENT_DESC* layout, int num_elements) 88 | { 89 | HRESULT hr = engine->rendering->Device->CreateInputLayout(layout, num_elements, vertex_bytecode->GetBufferPointer(), vertex_bytecode->GetBufferSize(), &input_layout); 90 | if (FAILED(hr)) 91 | { 92 | input_layout = 0; 93 | return false; 94 | } 95 | 96 | return true; 97 | } 98 | -------------------------------------------------------------------------------- /ProjectIW/ShaderGroup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class ShaderGroup 8 | { 9 | public: 10 | ShaderGroup(const WCHAR* vertex_name = 0, const WCHAR* pixel_name = 0, const WCHAR* geometry_name = 0); 11 | ~ShaderGroup(); 12 | 13 | inline ID3D11VertexShader* GetVertexShader() { return vertex_shader; } 14 | inline ID3D11PixelShader* GetPixelShader() { return pixel_shader; } 15 | inline ID3D11GeometryShader* GetGeometryShader() { return geometry_shader; } 16 | 17 | bool LoadShader(const WCHAR* vertex_name = 0, const WCHAR* pixel_name = 0, const WCHAR* geometry_name = 0); 18 | inline bool IsValid() { return valid; } 19 | inline ID3D11InputLayout* GetInputLayout() { return input_layout; } 20 | 21 | bool CreateInputLayout(D3D11_INPUT_ELEMENT_DESC* layout, int num_elements); 22 | 23 | private: 24 | ID3D11VertexShader* vertex_shader; 25 | ID3D11PixelShader* pixel_shader; 26 | ID3D11GeometryShader* geometry_shader; 27 | 28 | ID3D11InputLayout* input_layout; 29 | ID3DBlob* vertex_bytecode; 30 | bool valid; 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /ProjectIW/ShaderLoader.cpp: -------------------------------------------------------------------------------- 1 | #include "ShaderLoader.h" 2 | 3 | 4 | ShaderLoader::ShaderLoader(LPCSTR filename, const char* start, const char* version) 5 | { 6 | this->ByteCode = 0; 7 | Compile(filename, start, version); 8 | } 9 | 10 | ShaderLoader::ShaderLoader(LPCWSTR filename) 11 | { 12 | HRESULT hr = D3DReadFileToBlob(filename, &ByteCode); 13 | if (FAILED(hr)) 14 | { 15 | ByteCode = 0; 16 | } 17 | Error = 0; 18 | } 19 | 20 | ShaderLoader::~ShaderLoader(void) 21 | { 22 | 23 | } 24 | 25 | void ShaderLoader::Compile(LPCSTR filename, const char* start, const char* version) 26 | { 27 | D3DX11CompileFromFile(filename, 0, 0, start, version, 0, 0, 0, &ByteCode, &Error, 0); 28 | } -------------------------------------------------------------------------------- /ProjectIW/ShaderLoader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | class ShaderLoader 11 | { 12 | public: 13 | ID3DBlob* ByteCode; 14 | ID3D10Blob* Error; 15 | ShaderLoader(LPCSTR, const char*, const char*); 16 | ShaderLoader(LPCWSTR); 17 | ~ShaderLoader(void); 18 | 19 | void Compile(LPCSTR, const char*, const char*); 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /ProjectIW/SimplexNoise.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "General.h" 4 | #include "SimplexNoise.h" 5 | 6 | //#define FastFloor(x) (x > 0 ? (int) x : (int) x - 1) 7 | #define Mod(x, m) (x < 0 ? x % m + m : x % m) 8 | 9 | #define RSEED 1973418615 10 | //#define perm[x) (unsigned char)((x * RSEED >> 3 ^ (x & 0x7F)) & 0x7FFFFFFF) 11 | 12 | const unsigned int perm[512] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 13 | 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 14 | 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 15 | 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 16 | 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 17 | 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 18 | 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 19 | 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 20 | 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 21 | 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 22 | 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 23 | 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, 24 | 25 | 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 26 | 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 27 | 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 28 | 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 29 | 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 30 | 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 31 | 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 32 | 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 33 | 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 34 | 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 35 | 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 36 | 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 37 | 38 | }; 39 | 40 | float SimplexNoise::GenerateSimplexNoise(float x) 41 | { 42 | int i0 = FastFloor(x); 43 | int i1 = i0 + 1; 44 | float x0 = x - i0; 45 | float x1 = x0 - 1.0f; 46 | 47 | float n0, n1; 48 | 49 | float t0 = 1.0f - x0 * x0; 50 | t0 *= t0; 51 | n0 = t0 * t0 * grad(perm[i0 & 0xff], x0); 52 | 53 | float t1 = 1.0f - x1 * x1; 54 | t1 *= t1; 55 | n1 = t1 * t1 * grad(perm[i1 & 0xff], x1); 56 | // The maximum value of this noise is 8*(3/4)^4 = 2.53125 57 | // A factor of 0.395 scales to fit exactly within [-1,1] 58 | return 0.395f * (n0 + n1); 59 | } 60 | 61 | float SimplexNoise::GenerateSimplexNoise(float xin, float yin) 62 | { 63 | float const F2 = 0.3660254f; 64 | float const G2 = 0.2113249f; 65 | float n0, n1, n2; // Noise contributions from the three corners 66 | // Skew the input space to determine which simplex cell we're in 67 | float s = (xin + yin)*F2; // Hairy factor for 2D 68 | int i = FastFloor(xin + s); 69 | int j = FastFloor(yin + s); 70 | float t = (i + j)*G2; 71 | float X0 = i - t; // Unskew the cell origin back to (x,y) space 72 | float Y0 = j - t; 73 | float x0 = xin - X0; // The x,y distances from the cell origin 74 | float y0 = yin - Y0; 75 | // For the 2D case, the simplex shape is an equilateral triangle. 76 | // Determine which simplex we are in. 77 | int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords 78 | if (x0 > y0) 79 | { 80 | i1 = 1; // lower triangle, XY order: (0,0)->(1,0)->(1,1) 81 | j1 = 0; 82 | } 83 | else 84 | { 85 | i1 = 0; // upper triangle, YX order: (0,0)->(0,1)->(1,1) 86 | j1 = 1; 87 | } 88 | // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and 89 | // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where 90 | // c = (3-sqrt(3))/6 91 | float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords 92 | float y1 = y0 - j1 + G2; 93 | float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords 94 | float y2 = y0 - 1.0f + 2.0f * G2; 95 | // Work out the hashed gradient indices of the three simplex corners 96 | int ii = i & 255; 97 | int jj = j & 255; 98 | int gi0 = perm[ii + perm[jj]] % 12; 99 | int gi1 = perm[ii + i1 + perm[jj + j1]] % 12; 100 | int gi2 = perm[ii + 1 + perm[jj + 1]] % 12; 101 | // Calculate the contribution from the three corners 102 | float t0 = 0.5f - x0*x0 - y0*y0; 103 | if (t0 < 0) n0 = 0.0f; 104 | else 105 | { 106 | t0 *= t0; 107 | n0 = t0 * t0 * Dot(grad3[gi0], x0, y0, 0); // (x,y) of grad3 used for 2D gradient 108 | } 109 | float t1 = 0.5f - x1*x1 - y1*y1; 110 | if (t1 < 0) n1 = 0.0f; 111 | else 112 | { 113 | t1 *= t1; 114 | n1 = t1 * t1 * Dot(grad3[gi1], x1, y1, 0); 115 | } 116 | float t2 = 0.5f - x2*x2 - y2*y2; 117 | if (t2 < 0) n2 = 0.0f; 118 | else 119 | { 120 | t2 *= t2; 121 | n2 = t2 * t2 * Dot(grad3[gi2], x2, y2, 0); 122 | } 123 | // Add contributions from each corner to get the final noise value. 124 | // The result is scaled to return values in the interval [-1,1]. 125 | return 70.0f * (n0 + n1 + n2); 126 | } 127 | 128 | float SimplexNoise::GenerateSimplexNoise(float xin, float yin, int octaves, float pers) 129 | { 130 | if (octaves <= 0) 131 | return GenerateSimplexNoise(xin, yin); 132 | 133 | float max_amp = 0; 134 | float amp = 1; 135 | float noise = 0; 136 | float freq = 1.0f; 137 | 138 | for (int i = 0; i < octaves; i++) 139 | { 140 | noise += GenerateSimplexNoise(xin * freq, yin * freq) * amp; 141 | max_amp += amp; 142 | amp *= pers; 143 | freq *= 2.0f; 144 | } 145 | 146 | noise /= max_amp; 147 | return noise; 148 | } 149 | 150 | float SimplexNoise::GenerateSimplexNoise(float xin, float yin, float zin, int octaves, float pers) 151 | { 152 | if (octaves <= 0) 153 | return GenerateSimplexNoise(xin, yin); 154 | 155 | float max_amp = 0; 156 | float amp = 1; 157 | float freq = 1.0f; 158 | float noise = 0; 159 | 160 | for (int i = 0; i < octaves; i++) 161 | { 162 | noise += GenerateSimplexNoise(xin * freq, yin * freq, zin * freq) * amp; 163 | max_amp += amp; 164 | amp *= pers; 165 | freq *= 2.0f; 166 | } 167 | 168 | noise /= max_amp; 169 | return noise; 170 | } 171 | 172 | /*float SimplexNoise::GenerateSimplexNoise(float x, float y, float z) 173 | { 174 | float n0, n1, n2, n3; // Noise contributions from the four corners 175 | 176 | // Skew the input space to determine which simplex cell we're in 177 | float F3 = 1.0 / 3.0f; 178 | float s = (x + y + z)*F3; // Very nice and simple skew factor for 3D 179 | int i = FastFloor(x + s); 180 | int j = FastFloor(y + s); 181 | int k = FastFloor(z + s); 182 | 183 | float G3 = 1.0 / 6.0; // Very nice and simple unskew factor, too 184 | float t = (i + j + k)*G3; 185 | float X0 = i - t; // Unskew the cell origin back to (x,y,z) space 186 | float Y0 = j - t; 187 | float Z0 = k - t; 188 | float x0 = x - X0; // The x,y,z distances from the cell origin 189 | float y0 = y - Y0; 190 | float z0 = z - Z0; 191 | 192 | // For the 3D case, the simplex shape is a slightly irregular tetrahedron. 193 | // Determine which simplex we are in. 194 | int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords 195 | int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords 196 | 197 | if (x0 >= y0) { 198 | if (y0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // X Y Z order 199 | else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } // X Z Y order 200 | else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } // Z X Y order 201 | } 202 | else { // x0 y0) ? 32 : 0; 299 | int c2 = (x0 > z0) ? 16 : 0; 300 | int c3 = (y0 > z0) ? 8 : 0; 301 | int c4 = (x0 > w0) ? 4 : 0; 302 | int c5 = (y0 > w0) ? 2 : 0; 303 | int c6 = (z0 > w0) ? 1 : 0; 304 | int c = c1 + c2 + c3 + c4 + c5 + c6; 305 | 306 | int i1, j1, k1, l1; // The integer offsets for the second simplex corner 307 | int i2, j2, k2, l2; // The integer offsets for the third simplex corner 308 | int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner 309 | 310 | // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. 311 | // Many values of c will never occur, since e.g. x>y>z>w makes x= 3 ? 1 : 0; 316 | j1 = simplex[c][1] >= 3 ? 1 : 0; 317 | k1 = simplex[c][2] >= 3 ? 1 : 0; 318 | l1 = simplex[c][3] >= 3 ? 1 : 0; 319 | // The number 2 in the "simplex" array is at the second largest coordinate. 320 | i2 = simplex[c][0] >= 2 ? 1 : 0; 321 | j2 = simplex[c][1] >= 2 ? 1 : 0; 322 | k2 = simplex[c][2] >= 2 ? 1 : 0; 323 | l2 = simplex[c][3] >= 2 ? 1 : 0; 324 | // The number 1 in the "simplex" array is at the second smallest coordinate. 325 | i3 = simplex[c][0] >= 1 ? 1 : 0; 326 | j3 = simplex[c][1] >= 1 ? 1 : 0; 327 | k3 = simplex[c][2] >= 1 ? 1 : 0; 328 | l3 = simplex[c][3] >= 1 ? 1 : 0; 329 | // The fifth corner has all coordinate offsets = 1, so no need to look that up. 330 | 331 | float x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords 332 | float y1 = y0 - j1 + G4; 333 | float z1 = z0 - k1 + G4; 334 | float w1 = w0 - l1 + G4; 335 | float x2 = x0 - i2 + 2.0f*G4; // Offsets for third corner in (x,y,z,w) coords 336 | float y2 = y0 - j2 + 2.0f*G4; 337 | float z2 = z0 - k2 + 2.0f*G4; 338 | float w2 = w0 - l2 + 2.0f*G4; 339 | float x3 = x0 - i3 + 3.0f*G4; // Offsets for fourth corner in (x,y,z,w) coords 340 | float y3 = y0 - j3 + 3.0f*G4; 341 | float z3 = z0 - k3 + 3.0f*G4; 342 | float w3 = w0 - l3 + 3.0f*G4; 343 | float x4 = x0 - 1.0 + 4.0f*G4; // Offsets for last corner in (x,y,z,w) coords 344 | float y4 = y0 - 1.0 + 4.0f*G4; 345 | float z4 = z0 - 1.0 + 4.0f*G4; 346 | float w4 = w0 - 1.0 + 4.0f*G4; 347 | 348 | // Work out the hashed gradient indices of the five simplex corners 349 | int ii = i & 255; 350 | int jj = j & 255; 351 | int kk = k & 255; 352 | int ll = l & 255; 353 | int gi0 = perm[ii + perm[jj + perm[kk + perm[ll]]]] % 32; 354 | int gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]] % 32; 355 | int gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]] % 32; 356 | int gi3 = perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]] % 32; 357 | int gi4 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]] % 32; 358 | 359 | // Calculate the contribution from the five corners 360 | float t0 = 0.6f - x0*x0 - y0*y0 - z0*z0 - w0*w0; 361 | if (t0 < 0) n0 = 0.0; 362 | else { 363 | t0 *= t0; 364 | n0 = t0 * t0 * Dot(grad4[gi0], x0, y0, z0, w0); 365 | } 366 | 367 | float t1 = 0.6f - x1*x1 - y1*y1 - z1*z1 - w1*w1; 368 | if (t1 < 0) n1 = 0.0; 369 | else { 370 | t1 *= t1; 371 | n1 = t1 * t1 * Dot(grad4[gi1], x1, y1, z1, w1); 372 | } 373 | 374 | float t2 = 0.6f - x2*x2 - y2*y2 - z2*z2 - w2*w2; 375 | if (t2 < 0) n2 = 0.0; 376 | else { 377 | t2 *= t2; 378 | n2 = t2 * t2 * Dot(grad4[gi2], x2, y2, z2, w2); 379 | } 380 | 381 | float t3 = 0.6f - x3*x3 - y3*y3 - z3*z3 - w3*w3; 382 | if (t3 < 0) n3 = 0.0; 383 | else { 384 | t3 *= t3; 385 | n3 = t3 * t3 * Dot(grad4[gi3], x3, y3, z3, w3); 386 | } 387 | 388 | float t4 = 0.6f - x4*x4 - y4*y4 - z4*z4 - w4*w4; 389 | if (t4 < 0) n4 = 0.0; 390 | else { 391 | t4 *= t4; 392 | n4 = t4 * t4 * Dot(grad4[gi4], x4, y4, z4, w4); 393 | } 394 | 395 | // Sum up and scale the result to cover the range [-1,1] 396 | return 27.0 * (n0 + n1 + n2 + n3 + n4); 397 | } 398 | 399 | float SimplexNoise::SeamlessNoise(float x, float y, float dx, float dy, float xyOffset, int octaves, float pers) 400 | { 401 | if (octaves <= 0) 402 | return SeamlessNoise(x, y, dx, dy, xyOffset); 403 | 404 | float max_amp = 0; 405 | float amp = 1; 406 | float noise = 0; 407 | for (int i = 0; i < octaves; i++) 408 | { 409 | float nx = xyOffset + (float)cos(x * 2.0f * PI) * dx / (float)(2.0f * PI); 410 | float ny = xyOffset + (float)cos(y * 2.0f * PI) * dy / (float)(2.0f * PI); 411 | float nz = xyOffset + (float)sin(x * 2.0f * PI) * dx / (float)(2.0f * PI); 412 | float nw = xyOffset + (float)sin(y * 2.0f * PI) * dy / (float)(2.0f * PI); 413 | 414 | noise += GenerateSimplexNoise(nx, ny, nz, nw) * amp; 415 | 416 | max_amp += amp; 417 | amp *= pers; 418 | dx *= 2.0f; 419 | dy *= 2.0f; 420 | } 421 | 422 | //noise /= max_amp; 423 | 424 | return noise; 425 | } 426 | 427 | float SimplexNoise::SeamlessNoise(float x, float y, float dx, float dy, float xyOffset) 428 | { 429 | float s = x; 430 | float t = y; 431 | 432 | float nx = xyOffset + (float)cos(x * 2.0f * PI) * dx / (float)(2.0f * PI); 433 | float ny = xyOffset + (float)cos(y * 2.0f * PI) * dy / (float)(2.0f * PI); 434 | float nz = xyOffset + (float)sin(x * 2.0f * PI) * dx / (float)(2.0f * PI); 435 | float nw = xyOffset + (float)sin(y * 2.0f * PI) * dy / (float)(2.0f * PI); 436 | 437 | return GenerateSimplexNoise(nx, ny, nz, nw); 438 | } -------------------------------------------------------------------------------- /ProjectIW/SimplexNoise.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "General.h" 4 | #include 5 | 6 | extern const unsigned int perm[512]; 7 | static const int grad3[12][3] = { 8 | { 1, 1, 0 }, { -1, 1, 0 }, { 1, -1, 0 }, { -1, -1, 0 }, 9 | { 1, 0, 1 }, { -1, 0, 1 }, { 1, 0, -1 }, { -1, 0, -1 }, 10 | { 0, 1, 1 }, { 0, -1, 1 }, { 0, 1, -1 }, { 0, -1, -1 } 11 | }; 12 | static const int grad4[32][4] = { 13 | { 0, 1, 1, 1 }, { 0, 1, 1, -1 }, { 0, 1, -1, 1 }, { 0, 1, -1, -1 }, 14 | { 0, -1, 1, 1 }, { 0, -1, 1, -1 }, { 0, -1, -1, 1 }, { 0, -1, -1, -1 }, 15 | { 1, 0, 1, 1 }, { 1, 0, 1, -1 }, { 1, 0, -1, 1 }, { 1, 0, -1, -1 }, 16 | { -1, 0, 1, 1 }, { -1, 0, 1, -1 }, { -1, 0, -1, 1 }, { -1, 0, -1, -1 }, 17 | { 1, 1, 0, 1 }, { 1, 1, 0, -1 }, { 1, -1, 0, 1 }, { 1, -1, 0, -1 }, 18 | { -1, 1, 0, 1 }, { -1, 1, 0, -1 }, { -1, -1, 0, 1 }, { -1, -1, 0, -1 }, 19 | { 1, 1, 1, 0 }, { 1, 1, -1, 0 }, { 1, -1, 1, 0 }, { 1, -1, -1, 0 }, 20 | { -1, 1, 1, 0 }, { -1, 1, -1, 0 }, { -1, -1, 1, 0 }, { -1, -1, -1, 0 } 21 | }; 22 | static const int simplex[64][4] = { 23 | { 0, 1, 2, 3 }, { 0, 1, 3, 2 }, { 0, 0, 0, 0 }, { 0, 2, 3, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 1, 2, 3, 0 }, 24 | { 0, 2, 1, 3 }, { 0, 0, 0, 0 }, { 0, 3, 1, 2 }, { 0, 3, 2, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 1, 3, 2, 0 }, 25 | { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 26 | { 1, 2, 0, 3 }, { 0, 0, 0, 0 }, { 1, 3, 0, 2 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 2, 3, 0, 1 }, { 2, 3, 1, 0 }, 27 | { 1, 0, 2, 3 }, { 1, 0, 3, 2 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 2, 0, 3, 1 }, { 0, 0, 0, 0 }, { 2, 1, 3, 0 }, 28 | { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 29 | { 2, 0, 1, 3 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 3, 0, 1, 2 }, { 3, 0, 2, 1 }, { 0, 0, 0, 0 }, { 3, 1, 2, 0 }, 30 | { 2, 1, 0, 3 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 3, 1, 0, 2 }, { 0, 0, 0, 0 }, { 3, 2, 0, 1 }, { 3, 2, 1, 0 } 31 | }; 32 | 33 | class SimplexNoise 34 | { 35 | public: 36 | SimplexNoise(); 37 | ~SimplexNoise(); 38 | static float GenerateSimplexNoise(float x); 39 | static float GenerateSimplexNoise(float x, float y); 40 | static float GenerateSimplexNoise(float x, float y, int octaves, float pers); 41 | static float GenerateSimplexNoise(float x, float y, float z, int octaves, float pers); 42 | static float GenerateSimplexNoise(float x, float y, float z, float w); 43 | static float SeamlessNoise(float x, float y, float dx, float dy, float xyOffset, int octaves, float pers); 44 | static float SeamlessNoise(float x, float y, float dx, float dy, float xyOffset); 45 | inline static float GenerateSimplexNoise(float x, float y, float z) 46 | { 47 | { 48 | float n0, n1, n2, n3; // Noise contributions from the four corners 49 | 50 | // Skew the input space to determine which simplex cell we're in 51 | float F3 = 1.0f / 3.0f; 52 | float s = (x + y + z)*F3; // Very nice and simple skew factor for 3D 53 | int i = FastFloor(x + s); 54 | int j = FastFloor(y + s); 55 | int k = FastFloor(z + s); 56 | 57 | float G3 = 1.0f / 6.0f; // Very nice and simple unskew factor, too 58 | float t = (i + j + k)*G3; 59 | float X0 = i - t; // Unskew the cell origin back to (x,y,z) space 60 | float Y0 = j - t; 61 | float Z0 = k - t; 62 | float x0 = x - X0; // The x,y,z distances from the cell origin 63 | float y0 = y - Y0; 64 | float z0 = z - Z0; 65 | 66 | // For the 3D case, the simplex shape is a slightly irregular tetrahedron. 67 | // Determine which simplex we are in. 68 | int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords 69 | int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords 70 | 71 | if (x0 >= y0) { 72 | if (y0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // X Y Z order 73 | else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } // X Z Y order 74 | else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } // Z X Y order 75 | } 76 | else { // x0 4 | #include "SimpleMath.h" 5 | 6 | using namespace DirectX; 7 | using namespace DirectX::SimpleMath; 8 | 9 | namespace MDC 10 | { 11 | extern const int num_vertices[256]; 12 | extern const int edge_table[256][16]; 13 | 14 | extern const int corner_deltas[8]; 15 | extern const Vector3 corner_deltas_f[8]; 16 | extern const int edge_pairs[12][3]; 17 | 18 | extern const int cell_proc_edge_mask[6][5]; 19 | extern const int face_proc_face_mask[3][4][3]; 20 | extern const int face_proc_edge_mask[3][4][6]; 21 | extern const int edge_proc_edge_mask[3][2][5]; 22 | extern const int process_edge_mask[3][4]; 23 | 24 | extern const int external_edges[8][3]; 25 | extern const int internal_edges[8][9]; 26 | extern const int faces[6][4]; 27 | } -------------------------------------------------------------------------------- /ProjectIW/Task.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | enum TaskPriority { Low, Medium, High, Urgent }; 8 | 9 | class Task 10 | { 11 | public: 12 | inline Task() 13 | { 14 | } 15 | 16 | inline Task(function t_function, function t_callback, TaskPriority p) 17 | { 18 | task_function = t_function; 19 | callback_function = t_callback; 20 | priority = p; 21 | } 22 | 23 | inline ~Task() { } 24 | 25 | inline TaskPriority GetPriority() { return priority; } 26 | 27 | inline void Execute() { if (task_function != nullptr) task_function(); } 28 | inline void Callback() { if (callback_function != nullptr) callback_function(); } 29 | 30 | private: 31 | function task_function; 32 | function callback_function; 33 | 34 | TaskPriority priority; 35 | }; 36 | -------------------------------------------------------------------------------- /ProjectIW/TerrainChunk.cpp: -------------------------------------------------------------------------------- 1 | #include "TerrainChunk.h" 2 | #include "OctreeNode.h" 3 | #include "WorldTypes.h" 4 | 5 | namespace MDC 6 | { 7 | TerrainChunk::TerrainChunk(XMINT3 pos, unsigned int scale) 8 | { 9 | octree = new OctreeNode(pos, NODE_CHUNK_RESOLUTION, false, scale); 10 | vbo = 0; 11 | ibo = 0; 12 | empty = false; 13 | } 14 | 15 | TerrainChunk::~TerrainChunk() 16 | { 17 | if (octree) 18 | { 19 | delete octree; 20 | octree = 0; 21 | } 22 | if (vbo) 23 | { 24 | delete vbo; 25 | vbo = 0; 26 | } 27 | if (ibo) 28 | { 29 | delete ibo; 30 | ibo = 0; 31 | } 32 | } 33 | 34 | unsigned int TerrainChunk::GenerateOctree() 35 | { 36 | auto start = std::chrono::high_resolution_clock::now(); 37 | 38 | octree->ConstructNodes(); 39 | empty = octree->is_leaf; 40 | 41 | //octree->ClusterCellBase(0.0f); 42 | std::vector verts; 43 | octree->GenerateVertexBuffer(verts); 44 | if (verts.size() > 0) 45 | vbo = new VBO(&verts[0], sizeof(VertexPositionColorNormal) * verts.size(), sizeof(VertexPositionColorNormal), false); 46 | 47 | return (unsigned int)(std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start)).count(); 48 | } 49 | 50 | unsigned int TerrainChunk::GenerateMesh() 51 | { 52 | auto start = std::chrono::high_resolution_clock::now(); 53 | 54 | std::vector indexes; 55 | 56 | octree->ProcessCell(indexes, 0.0f); 57 | if (indexes.size() > 0) 58 | { 59 | if (!ibo) 60 | { 61 | ibo = new IBO(&indexes[0], sizeof(unsigned int) * indexes.size(), false); 62 | } 63 | else 64 | { 65 | ibo->SetData(&indexes[0], 0, sizeof(unsigned int) * indexes.size()); 66 | } 67 | } 68 | tri_count = indexes.size(); 69 | 70 | if (octree) 71 | { 72 | delete octree; 73 | octree = 0; 74 | } 75 | 76 | return (unsigned int)(std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start)).count(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ProjectIW/TerrainChunk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "General.h" 6 | #include "IBO.h" 7 | #include "VBO.h" 8 | 9 | using namespace DirectX; 10 | 11 | #define CHUNK_SIZE 32 12 | 13 | namespace MDC 14 | { 15 | class TerrainChunk 16 | { 17 | public: 18 | TerrainChunk(XMINT3 pos, unsigned int scale); 19 | ~TerrainChunk(); 20 | 21 | unsigned int GenerateOctree(); 22 | unsigned int GenerateMesh(); 23 | 24 | inline VBO* GetVBO() { return vbo; } 25 | inline IBO* GetIBO() { return ibo; } 26 | inline unsigned int GetTriangleCount() { return tri_count; } 27 | inline bool IsEmpty() { return empty; } 28 | 29 | private: 30 | OctreeNode* octree; 31 | VBO* vbo; 32 | IBO* ibo; 33 | unsigned int tri_count; 34 | bool empty; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /ProjectIW/ThreadPool.cpp: -------------------------------------------------------------------------------- 1 | #include "ThreadPool.h" 2 | 3 | ThreadPool::ThreadPool(int n_threads) 4 | { 5 | num_threads = n_threads; 6 | active = true; 7 | for (int i = 0; i < n_threads; i++) 8 | worker_threads.push_back(thread(&ThreadPool::ThreadWork, this)); 9 | } 10 | 11 | ThreadPool::~ThreadPool() 12 | { 13 | if (active) 14 | Quit(); 15 | 16 | } 17 | 18 | void ThreadPool::AddTask(Task t) 19 | { 20 | { 21 | std::unique_lock lock(queue_mutex); 22 | 23 | if (!active) 24 | return; 25 | task_queue.push_back(t); 26 | } 27 | 28 | condition.notify_one(); 29 | } 30 | 31 | void ThreadPool::AddTaskBatch(std::vector& batch) 32 | { 33 | if (batch.size() == 0) 34 | return; 35 | 36 | { 37 | std::unique_lock lock(queue_mutex); 38 | 39 | if (!active) 40 | return; 41 | task_queue.insert(task_queue.end(), batch.begin(), batch.end()); 42 | } 43 | 44 | condition.notify_one(); 45 | } 46 | 47 | void ThreadPool::ThreadWork() 48 | { 49 | //thanks to http://progsch.net/wordpress/?p=81 for a good idea on how to do this 50 | //note: there might be deactivating problems 51 | //TODO: fix if it becomes an issue 52 | Task t; 53 | while (active) 54 | { 55 | { 56 | std::unique_lock lock(queue_mutex); 57 | while (active && task_queue.empty()) 58 | condition.wait(lock); 59 | 60 | if (!active) 61 | return; 62 | t = task_queue.front(); 63 | task_queue.pop_front(); 64 | } 65 | 66 | if (!active) 67 | return; 68 | t.Execute(); 69 | if (!active) 70 | return; 71 | t.Callback(); 72 | } 73 | } 74 | 75 | void ThreadPool::Quit() 76 | { 77 | { 78 | std::unique_lock lock(queue_mutex); 79 | active = false; 80 | } 81 | condition.notify_all(); 82 | for (int i = 0; i < num_threads; i++) 83 | { 84 | worker_threads[i].join(); 85 | } 86 | } 87 | 88 | void ThreadPool::JoinAllAndAbort() 89 | { 90 | condition.notify_all(); 91 | for (int i = 0; i < num_threads; i++) 92 | { 93 | worker_threads[i].join(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /ProjectIW/ThreadPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "Task.h" 11 | 12 | using namespace std; 13 | 14 | class ThreadPool 15 | { 16 | public: 17 | ThreadPool(int n_threads); 18 | ~ThreadPool(); 19 | 20 | inline bool IsActive() { return active; } 21 | 22 | void AddTask(Task t); 23 | void AddTaskBatch(std::vector& batch); 24 | void ThreadWork(); 25 | void Quit(); 26 | void JoinAllAndAbort(); 27 | 28 | private: 29 | int num_threads; 30 | vector worker_threads; 31 | 32 | deque task_queue; 33 | mutex queue_mutex; 34 | condition_variable condition; 35 | 36 | atomic active; 37 | }; 38 | -------------------------------------------------------------------------------- /ProjectIW/Utils.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "General.h" 6 | 7 | using namespace DirectX; 8 | 9 | bool RayIntersectsTriangle(XMFLOAT3 rayDirection, XMFLOAT3 rayStart, XMFLOAT3 vertex1, XMFLOAT3 vertex2, XMFLOAT3 vertex3) 10 | { 11 | // Compute vectors along two edges of the triangle. 12 | XMFLOAT3 edge1, edge2; 13 | 14 | edge1 = ADD(vertex2, -vertex1); 15 | edge2 = ADD(vertex3, -vertex1); 16 | 17 | // Compute the determinant. 18 | XMFLOAT3 directionCrossEdge2; 19 | directionCrossEdge2 = CROSS(rayDirection, edge2); 20 | 21 | float determinant; 22 | determinant = DOT(edge1, directionCrossEdge2); 23 | 24 | // If the ray is parallel to the triangle plane, there is no collision. 25 | if (determinant > -FLT_EPSILON && determinant < FLT_EPSILON) 26 | { 27 | return false; 28 | } 29 | 30 | float inverseDeterminant = 1.0f / determinant; 31 | 32 | // Calculate the U parameter of the intersection point. 33 | XMFLOAT3 distanceVector; 34 | distanceVector = ADD(rayStart, -vertex1); 35 | 36 | float triangleU; 37 | triangleU = DOT(distanceVector, directionCrossEdge2); 38 | triangleU *= inverseDeterminant; 39 | 40 | // Make sure it is inside the triangle. 41 | if (triangleU < 0 || triangleU > 1) 42 | { 43 | return false; 44 | } 45 | 46 | // Calculate the V parameter of the intersection point. 47 | XMFLOAT3 distanceCrossEdge1; 48 | distanceCrossEdge1 = CROSS(distanceVector, edge1); 49 | 50 | float triangleV; 51 | triangleV = DOT(rayDirection, distanceCrossEdge1); 52 | triangleV *= inverseDeterminant; 53 | 54 | // Make sure it is inside the triangle. 55 | if (triangleV < 0 || triangleU + triangleV > 1) 56 | { 57 | return false; 58 | } 59 | 60 | // Compute the distance along the ray to the triangle. 61 | float rayDistance; 62 | rayDistance = DOT(edge2, distanceCrossEdge1); 63 | rayDistance *= inverseDeterminant; 64 | 65 | // Is the triangle behind the ray origin? 66 | if (rayDistance < 0) 67 | { 68 | return false; 69 | } 70 | 71 | return true; 72 | } -------------------------------------------------------------------------------- /ProjectIW/VBO.cpp: -------------------------------------------------------------------------------- 1 | #include "VBO.h" 2 | 3 | VBO::VBO(void* data, unsigned int size, unsigned int stride, bool modifiable) 4 | { 5 | this->buffer = 0; 6 | this->buffer_size = size; 7 | this->stride = stride; 8 | this->numElements = numElements; 9 | CreateBuffer(data, modifiable); 10 | } 11 | 12 | VBO::~VBO() 13 | { 14 | Dispose(); 15 | } 16 | 17 | void VBO::Dispose() 18 | { 19 | if (buffer) 20 | { 21 | buffer->Release(); 22 | buffer = 0; 23 | } 24 | } 25 | 26 | bool VBO::CreateBuffer(void* data, bool modifyable) 27 | { 28 | D3D11_BUFFER_DESC desc; 29 | ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC)); 30 | desc.Usage = (!modifyable ? D3D11_USAGE_DEFAULT : D3D11_USAGE_DYNAMIC); 31 | desc.ByteWidth = this->buffer_size; 32 | desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 33 | desc.CPUAccessFlags = (!modifyable ? 0 : D3D11_CPU_ACCESS_WRITE); 34 | desc.MiscFlags = 0; 35 | 36 | D3D11_SUBRESOURCE_DATA resource; 37 | ZeroMemory(&resource, sizeof(D3D11_SUBRESOURCE_DATA)); 38 | resource.pSysMem = data; 39 | 40 | HRESULT hr = engine->rendering->Device->CreateBuffer(&desc, &resource, &buffer); 41 | if (FAILED(hr)) 42 | { 43 | MessageBox(NULL, "Failed to create vertex buffer.", "Error", MB_ICONERROR); 44 | return false; 45 | } 46 | 47 | return true; 48 | } 49 | 50 | void VBO::SetData(void* data, UINT offset, UINT length) 51 | { 52 | D3D11_MAPPED_SUBRESOURCE resource; 53 | engine->rendering->ImmediateContext->Map(buffer, 0, D3D11_MAP_WRITE, 0, &resource); 54 | memcpy((void*)((char*)resource.pData + offset), data, length); 55 | engine->rendering->ImmediateContext->Unmap(buffer, 0); 56 | } 57 | 58 | void VBO::Bind(unsigned int slot) 59 | { 60 | const UINT offset = 0; 61 | engine->rendering->ImmediateContext->IASetVertexBuffers(slot, 1, &buffer, &stride, &offset); 62 | } -------------------------------------------------------------------------------- /ProjectIW/VBO.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "General.h" 6 | #include "Window.h" 7 | 8 | class VBO 9 | { 10 | public: 11 | 12 | VBO(void* data, unsigned int size, unsigned int stride, bool modifiable); 13 | ~VBO(); 14 | 15 | UINT GetBufferSize(); 16 | void SetData(void* data, UINT offset, UINT length); 17 | void Bind(unsigned int slot = 0); 18 | void Dispose(); 19 | 20 | inline ID3D11Buffer* GetBuffer() { return buffer; } 21 | 22 | private: 23 | UINT buffer_size; 24 | UINT stride; 25 | UINT numElements; 26 | ID3D11Buffer* buffer = 0; 27 | 28 | bool CreateBuffer(void*, bool modifyable); 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /ProjectIW/Vertex.cpp: -------------------------------------------------------------------------------- 1 | #include "Vertex.h" 2 | 3 | namespace MDC 4 | { 5 | Vertex::Vertex() : parent(0), index(-1), surface_index(-1), flags(0), position(Vector3(0, 0, 0)), normal(Vector3(0, 0, 0)), error(0), euler(0), in_cell(0) 6 | { 7 | ZeroMemory(eis, sizeof(int) * 12); 8 | } 9 | 10 | Vertex::~Vertex() 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ProjectIW/Vertex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "SimpleMath.h" 4 | #include "QEFSolver.h" 5 | 6 | using namespace DirectX::SimpleMath; 7 | 8 | namespace MDC 9 | { 10 | enum VertexFlags 11 | { 12 | NONE = 0, 13 | COLLAPSIBLE = 1, 14 | FACEPROP2 = 2 15 | }; 16 | 17 | class Vertex 18 | { 19 | public: 20 | Vertex(); 21 | ~Vertex(); 22 | 23 | QEFSolver qef; 24 | Vertex* parent; 25 | Vector3 position; 26 | Vector3 normal; 27 | 28 | unsigned int index; 29 | int surface_index; 30 | unsigned char flags; 31 | float error; 32 | int euler; 33 | int eis[12]; 34 | unsigned char in_cell; 35 | 36 | inline bool IsCollapsible() { return (flags & VertexFlags::COLLAPSIBLE) != 0; } 37 | inline bool IsManifold() { return euler == 1 && (flags & VertexFlags::FACEPROP2) != 0; } 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /ProjectIW/VertexPositionColorNormal.cpp: -------------------------------------------------------------------------------- 1 | #include "VertexPositionColorNormal.h" 2 | 3 | namespace MDC 4 | { 5 | D3D11_INPUT_ELEMENT_DESC VertexPositionColorNormal::layout[] = 6 | { 7 | { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 8 | { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 9 | { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /ProjectIW/VertexPositionColorNormal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "SimpleMath.h" 5 | 6 | using namespace DirectX::SimpleMath; 7 | 8 | namespace MDC 9 | { 10 | struct VertexPositionColorNormal 11 | { 12 | Vector3 position; 13 | Vector3 color; 14 | Vector3 normal; 15 | 16 | VertexPositionColorNormal() 17 | { 18 | position = Vector3(0, 0, 0); 19 | color = Vector3(0.3f, 0.5f, 0.7f); 20 | normal = Vector3(0, 0, 0); 21 | } 22 | 23 | VertexPositionColorNormal(Vector3 _position, Vector3 _normal) 24 | { 25 | position = Vector3(_position.x, _position.y, _position.z); 26 | color = Vector3(0.3f, 0.5f, 0.7f); 27 | normal = _normal; 28 | } 29 | 30 | static D3D11_INPUT_ELEMENT_DESC layout[]; 31 | static const unsigned int num_elements = 3; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /ProjectIW/VertexShader.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer WVP : register(b0) 2 | { 3 | float4x4 world; 4 | float4x4 view; 5 | float4x4 proj; 6 | }; 7 | 8 | struct VSOutput 9 | { 10 | float4 pos : SV_POSITION; 11 | float3 norm : TEXCOORD0; 12 | float3 norm_flat : TEXCOORD1; 13 | float3 color : COLOR0; 14 | }; 15 | 16 | static float3 light_dir = float3(0.4f, 1.0f, 0.1f); 17 | static float3 brown = float3(0.4375f, 0.375f, 0.25f); 18 | 19 | VSOutput main(float4 pos : POSITION, float3 norm : NORMAL0, float4 color : COLOR0) 20 | { 21 | VSOutput output; 22 | float4 world_pos = mul(pos, world); 23 | float4 view_pos = mul(world_pos, view); 24 | output.pos = mul(view_pos, proj); 25 | /*const float C = 0.1f; 26 | const float far = 10000.0f * 1000.0f; 27 | output.pos.z = log(C*output.pos.w + 1) / log(C*far + 1) * output.pos.w;*/ 28 | 29 | output.norm = normalize(norm); 30 | output.norm_flat = output.norm; 31 | output.color = color; 32 | return output; 33 | } -------------------------------------------------------------------------------- /ProjectIW/Window.cpp: -------------------------------------------------------------------------------- 1 | #include "Window.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | 9 | #ifdef _DEBUG 10 | #define _CRTDBG_MAP_ALLOC 11 | #include 12 | #include 13 | #endif 14 | 15 | Engine* engine; 16 | 17 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) 18 | { 19 | _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 20 | WNDCLASSEX wcex; 21 | 22 | wcex.cbSize = sizeof(WNDCLASSEX); 23 | wcex.style = CS_HREDRAW | CS_VREDRAW; 24 | wcex.lpfnWndProc = WndProc; 25 | wcex.cbClsExtra = 0; 26 | wcex.cbWndExtra = 0; 27 | wcex.hInstance = hInstance; 28 | wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); 29 | wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 30 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 31 | wcex.lpszMenuName = NULL; 32 | wcex.lpszClassName = WINDOW_CLASS; 33 | wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); 34 | 35 | if (!RegisterClassEx(&wcex)) 36 | { 37 | MessageBox(NULL, "Error registering class.", "Error", MB_ICONERROR); 38 | return 1; 39 | } 40 | 41 | RECT clientSize = { 0, 0, BUFFER_WIDTH, BUFFER_HEIGHT }; 42 | AdjustWindowRect(&clientSize, WS_OVERLAPPEDWINDOW, false); 43 | hwnd = CreateWindow(WINDOW_CLASS, WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, clientSize.right - clientSize.left, clientSize.bottom - clientSize.top, NULL, NULL, hInstance, NULL); 44 | if (!hwnd) 45 | { 46 | MessageBox(NULL, "Error creating window.", "Error", MB_ICONERROR); 47 | return 2; 48 | } 49 | 50 | 51 | ShowWindow(hwnd, nShowCmd); 52 | UpdateWindow(hwnd); 53 | 54 | engine = new Engine(hwnd, hInstance); 55 | if (!engine->Setup()) 56 | return 1; 57 | 58 | engine->Loop(); 59 | delete engine; 60 | 61 | #ifdef _DEBUG 62 | //Print out any memory leaks 63 | //_CrtDumpMemoryLeaks(); 64 | 65 | CHAR s[500]; 66 | GetCurrentDirectory(500, s); 67 | OutputDebugString(s); 68 | OutputDebugString("\nShutdown success.\n"); 69 | #endif 70 | 71 | return 0; 72 | } 73 | 74 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 75 | { 76 | switch (message) 77 | { 78 | case WM_KEYDOWN: 79 | if (wParam == VK_ESCAPE) 80 | PostQuitMessage(0); 81 | break; 82 | case WM_EXITSIZEMOVE: 83 | case WM_SIZE: 84 | if (engine && engine->rendering) 85 | { 86 | RECT rect; 87 | GetClientRect(hwnd, &rect); 88 | BUFFER_WIDTH = (int)rect.right - rect.left; 89 | BUFFER_HEIGHT = (int)rect.bottom - rect.top; 90 | engine->rendering->UpdateViewport(); 91 | } 92 | break; 93 | case WM_DESTROY: 94 | PostQuitMessage(0); 95 | break; 96 | default: 97 | 98 | break; 99 | } 100 | return DefWindowProc(hWnd, message, wParam, lParam); 101 | } 102 | 103 | int HandleMessages() 104 | { 105 | MSG msg; 106 | while (GetMessage(&msg, NULL, 0, 0)) 107 | { 108 | TranslateMessage(&msg); 109 | DispatchMessage(&msg); 110 | } 111 | 112 | return 0; 113 | } -------------------------------------------------------------------------------- /ProjectIW/Window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "General.h" 8 | #include "Engine.h" 9 | 10 | #define winstring LPCTSTR 11 | 12 | const TCHAR WINDOW_TITLE[] = _T("ProjectIW"); 13 | static TCHAR WINDOW_CLASS[] = _T("win32app"); 14 | static HWND hwnd; 15 | static HINSTANCE windowHInstance; 16 | 17 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd); 18 | LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 19 | int HandleMessages(); 20 | -------------------------------------------------------------------------------- /ProjectIW/World.cpp: -------------------------------------------------------------------------------- 1 | #include "World.h" 2 | #include "SimplexNoise.h" 3 | #include 4 | 5 | #define USE_PLANE 0 6 | #define USE_SPHERE 1 7 | #define USE_FRACTAL_2D 2 8 | #define USE_FRACTAL_3D 3 9 | #define USE_FRACTAL_SPHERE 4 10 | #define USE_HEIGHTMAP 5 11 | 12 | float World::global_size = 0.0f; 13 | float World::global_size_inverse = 0.0f; 14 | int World::sample_type = USE_HEIGHTMAP; 15 | float World::terrain_scale = 0.0005f; 16 | float World::terrain_height = 1024.0f; 17 | 18 | float fractal(double x, double y, int* out_iterations) 19 | { 20 | using namespace std::complex_literals; 21 | std::complex z(0, 0); 22 | std::complex C(x, y); 23 | const int max_iterations = 1024; 24 | int iterations = 0; 25 | for (; z.real() * z.real() + z.imag() * z.imag() < 4.0 && iterations < max_iterations; iterations++) 26 | { 27 | z = z * z + C; 28 | } 29 | 30 | float v = (float)iterations / (float)max_iterations; 31 | if (out_iterations) 32 | *out_iterations = iterations; 33 | return (1.0f - v) * 1.0f + v * (-1.0f); 34 | } 35 | 36 | void hypercomplex_multiply(double& x, double& y, double& z) 37 | { 38 | double pi = 3.14159265; 39 | double r = sqrt(x*x + y*y + z*z); 40 | double yang = atan2(sqrt(x*x + y*y), z); 41 | double zang = atan2(y, x); 42 | double newx = (r*r) * sin(yang * 2 + 0.5*pi) * cos(zang * 2 + pi); 43 | double newy = (r*r) * sin(yang * 2 + 0.5*pi) * sin(zang * 2 + pi); 44 | double newz = (r*r) * cos(yang * 2 + 0.5*pi); 45 | x = newx; 46 | y = newy; 47 | z = newz; 48 | } 49 | 50 | void hypercomplex_multiply2(float& x, float& y, float& z) 51 | { 52 | if (x == 0 && y == 0 && z == 0) 53 | return; 54 | float p = sqrt(x*x + y*y); 55 | float a = 1.0f - z*z / p*p; 56 | float newx = a * (x*x - y*y); 57 | float newy = a * (x*y + x*y); 58 | float newz = p*z + p*z; 59 | 60 | x = newx; 61 | y = newy; 62 | z = newz; 63 | } 64 | 65 | void hypercomplex_multiply3(float& x, float& y, float& z, float order) 66 | { 67 | if (x == 0 && y == 0 && z == 0) 68 | return; 69 | float r = sqrt(x*x + y*y + z*z); 70 | float theta = atan2(sqrt(x*x + y*y), z); 71 | float phi = atan2(y, x); 72 | 73 | float newx = pow(r, order) * sin(theta * order) * cos(phi * order); 74 | float newy = pow(r, order) * sin(theta * order) * sin(phi * order); 75 | float newz = pow(r, order) * cos(theta * order); 76 | 77 | x = newx; 78 | y = newy; 79 | z = newz; 80 | } 81 | 82 | void hypercomplex_multiply4(float p, float& x, float& y, float& z, float zr0, float& dr) 83 | { 84 | if (x == 0 && y == 0 && z == 0) 85 | return; 86 | 87 | float zo0 = asinf(z / zr0); 88 | float zi0 = atan2f(y, x); 89 | float zr = powf(zr0, p - 1.0f); 90 | float zo = zo0 * p; 91 | float zi = zi0*p; 92 | float czo = cosf(zo); 93 | 94 | dr = zr * dr * p + 1.0f; 95 | zr *= zr0; 96 | 97 | x = zr * czo * cosf(zi); 98 | y = zr * czo * sinf(zi); 99 | z = zr * sinf(zo); 100 | } 101 | 102 | float fractal(float init_x, float init_y, float init_z, int* out_iterations, int max_iterations = 12) 103 | { 104 | using namespace std::complex_literals; 105 | 106 | float z_x = init_x, z_y = init_y, z_z = init_z; 107 | float d_x = init_x, d_y = init_y, d_z = init_z; 108 | float dr = 1.0f; 109 | float r = sqrtf(z_x*z_x + z_y*z_y + z_z*z_z); 110 | float md = 10000.0f; 111 | const float power = 8.0f; 112 | const int clr_iterations = 2; 113 | const float bailout = 4.0f; 114 | 115 | for (int i = 0; i < max_iterations; i++) 116 | { 117 | //hypercomplex_multiply2(z_x, z_y, z_z); 118 | hypercomplex_multiply3(z_x, z_y, z_z, 8); 119 | //hypercomplex_multiply4(power, z_x, z_y, z_z, r, dr); 120 | z_x += init_x; 121 | z_y += init_y; 122 | z_z += init_z; 123 | 124 | r = sqrtf(z_x*z_x + z_y*z_y + z_z*z_z); 125 | 126 | if (r > bailout) 127 | break; 128 | } 129 | 130 | float distance = 0.5f * r * log(r) / sqrtf(d_x * d_x + d_y * d_y + d_z * d_z); 131 | return -distance; 132 | 133 | 134 | /*for (; z_x*z_x + z_y*z_y + z_z*z_z < 2.0 && iterations < max_iterations; iterations++) 135 | { 136 | hypercomplex_multiply3(z_x, z_y, z_z, 8); 137 | z_x += init_x; 138 | z_y += init_y; 139 | z_z += init_z; 140 | } 141 | 142 | float v = (float)iterations / (float)max_iterations; 143 | float mag = (float)(z_x*z_x + z_y*z_y + z_z*z_z); 144 | if (out_iterations) 145 | *out_iterations = iterations; 146 | 147 | return mag - (float)max_iterations / 2.0f;*/ 148 | } 149 | 150 | float fractal_sphere(float init_x, float init_y, float init_z, int* out_iterations, int max_iterations = 4) 151 | { 152 | float z_x = init_x, z_y = init_y, z_z = init_z; 153 | float d_x = init_x, d_y = init_y, d_z = init_z; 154 | const float scale = 2.0f; 155 | float k = scale; 156 | float d = -10000.0f; 157 | float d1 = 0, r = 0, md = 100000.0f, cd = 0.0f; 158 | const float sphere_holes = 4.0f; 159 | const float sphere_scale = 2.05f; 160 | 161 | for (int i = 0; i < max_iterations; i++) 162 | { 163 | float new_x = fmodf(init_x * k, sphere_holes) - 0.5f * sphere_holes; 164 | float new_y = fmodf(init_y * k, sphere_holes) - 0.5f * sphere_holes; 165 | float new_z = fmodf(init_z * k, sphere_holes) - 0.5f * sphere_holes; 166 | r = sqrtf(new_x*new_x + new_y*new_y + new_z*new_z); 167 | 168 | d1 = (sphere_scale - r) / k; 169 | k *= scale; 170 | 171 | d = max(d, d1); 172 | } 173 | 174 | return -d; 175 | } 176 | 177 | float World::Sample(DirectX::XMINT3 pos, int scale) 178 | { 179 | return Sample((float)pos.x, (float)pos.y, (float)pos.z, scale); 180 | } 181 | 182 | float World::Sample(Vector3 pos, int scale) 183 | { 184 | return Sample(pos.x, pos.y, pos.z, scale); 185 | } 186 | 187 | float World::Sample(float x, float y, float z, int level) 188 | { 189 | float dx, dy, dz, n; 190 | 191 | switch (sample_type) 192 | { 193 | case USE_PLANE: 194 | return y; 195 | 196 | case USE_SPHERE: 197 | return Sphere(x, y, z); 198 | 199 | case USE_FRACTAL_2D: 200 | if (y < 0 || y > 0) 201 | return 1; 202 | dx = x / global_size; 203 | dz = z / global_size; 204 | return fractal(dx, dz, 0); 205 | 206 | case USE_FRACTAL_3D: 207 | dx = x / global_size; 208 | dy = y / global_size; 209 | dz = z / global_size; 210 | return fractal(dx, dy, dz, 0); 211 | 212 | case USE_FRACTAL_SPHERE: 213 | dx = x / global_size; 214 | dy = y / global_size; 215 | dz = z / global_size; 216 | return fractal_sphere(dx, dy, dz, 0); 217 | 218 | case USE_HEIGHTMAP: 219 | n = Noise(x, z, terrain_scale, 4); 220 | return y - n * terrain_height - terrain_height * 0.5f; 221 | 222 | default: // plane 223 | return y; 224 | } 225 | 226 | float scale = 65535.0f; 227 | const float kernel[7] = { 0.00598f, 0.060626f, 0.241843f, 0.383103f, 0.241843f, 0.060626f, 0.00598f, }; 228 | int index = 0; 229 | if (level < 3) 230 | index = scale; 231 | for (int i = max(0, level - 3); i < level + 3; i++) 232 | { 233 | float weight = kernel[i]; 234 | float new_x = x; 235 | index++; 236 | } 237 | 238 | //return base; 239 | //return y - Noise(x, z, 0.015f, 4) * range * 0.2f - range * 0.15f; 240 | //return y - Noise(x, y, z, 0.01f, 4) * 128.0f - 64.0f; 241 | 242 | return SimplexNoise::GenerateSimplexNoise(x, y, z); 243 | 244 | //return y; 245 | //return Sphere(x, y, z); 246 | //return Cube(x, y, z); 247 | //if (y < 1) 248 | // return -1; 249 | //return 1; 250 | //float scaley = 1.0f * 16.0f; 251 | //return y - Noise(x, 0, z) * scaley - scaley; 252 | //float n = Noise(x, y, z, 0.005f, 2); 253 | //return n; 254 | //return y - (Noise(x, 0, z) + n) * 16.0f - 16.0f; 255 | //return Cube(x / range, y / range, z / range); 256 | 257 | //float rocks = Noise(x, y, z, 0.1f, 4) * 0.5f; 258 | //int octaves = max(1, (256 - scale) / 4); 259 | //float base = y / range * 4.0f - Noise(x, z, 1.0f / range, 16); 260 | //float true_scale = powf(2, (float)scale); 261 | //float base = Noise(x, z, 1 / range * scale, 1); 262 | //base = y / range * 4.0f - base; 263 | /*if(scale <= 8) 264 | base += Noise(x + 80000.0f, y + 80000.0f, z + 80000.0f, 1.0f / range * 8.0f, 1) / 2.0f; 265 | if(scale <= 4) 266 | base += Noise(x + 40000.0f, y + 40000.0f, z + 40000.0f, 1.0f / range * 16.0f, 1) / 4.0f; 267 | if (scale <= 2) 268 | base += Noise(x + 20000.0f, y + 20000.0f, z + 20000.0f, 1.0f / range * 32.0f, 1) / 8.0f*/ 269 | } 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | float World::Noise(float x, float y, float z) 287 | { 288 | const float scale = 0.04f; 289 | x *= scale; 290 | y *= scale; 291 | z *= scale; 292 | 293 | return SimplexNoise::GenerateSimplexNoise(x, y, z); 294 | } 295 | 296 | float World::Noise(float x, float y, float z, float scale, int octaves) 297 | { 298 | x *= scale; 299 | y *= scale; 300 | z *= scale; 301 | 302 | return SimplexNoise::GenerateSimplexNoise(x, y, z, octaves, 0.5f); 303 | } 304 | 305 | float World::Noise(float x, float z, float scale, int octaves) 306 | { 307 | x *= scale; 308 | z *= scale; 309 | 310 | return SimplexNoise::GenerateSimplexNoise(x, z, octaves, 0.5f); 311 | } 312 | 313 | float World::Sphere(float x, float y, float z) 314 | { 315 | const float r = global_size / 2.0f; 316 | float origin[3] = { 0, 0, 0 }; 317 | float dx = x - origin[0]; 318 | float dy = y - origin[1]; 319 | float dz = z - origin[2]; 320 | 321 | return dx*dx + dy*dy + dz*dz - r*r; 322 | //Vector3 v(x, y, z); 323 | //Vector3 o(0, 0, 0); 324 | //return (v - o).LengthSquared() - r *r; 325 | } 326 | 327 | float World::Cube(float x, float y, float z) 328 | { 329 | const float r = 224288.0f; 330 | Vector3 pos(x + r, y + r, z + r); 331 | Vector3 o(r, r, r); 332 | Vector3 local = pos - o; 333 | Vector3 d = Vector3(abs(local.x), abs(local.y), abs(local.z)) - o; 334 | float m = max(d.x, max(d.y, d.z)); 335 | return min(m, d.Length()); 336 | } 337 | 338 | Vector3 World::GetIntersection(const Vector3 p1, const Vector3 p2, float d1, float d2) 339 | { 340 | return p1 + (Vector3)((p2 - p1) / (d2 - d1)) * (-d1); 341 | } 342 | 343 | Vector3 World::GetIntersection(const Vector3 pt0, const Vector3 pt1, int quality) 344 | { 345 | float iso_value = 0.0f; 346 | 347 | Vector3 p0 = pt0; 348 | float v0 = Sample(pt0, 1); 349 | Vector3 p1 = pt1; 350 | float v1 = Sample(pt1, 1); 351 | if (v1 == v0) 352 | return pt0; 353 | 354 | float alpha = (0.0f - v0) / (v1 - v0); 355 | 356 | Vector3 pos = p0 + (p1 - p0) * alpha; 357 | 358 | float val = Sample(pos, 1); 359 | 360 | if (fabsf(iso_value - val) < 0.0000001f || quality == 0) 361 | return pos; 362 | 363 | if (val < 0.0f) 364 | { 365 | if (v0 > 0.0f) 366 | pos = GetIntersection(pos, pt0, quality - 1); 367 | else if (v1 > 0.0f) 368 | pos = GetIntersection(pos, pt1, quality - 1); 369 | } 370 | else if (val > 0.0f) 371 | { 372 | if (v0 < 0.0f) 373 | pos = GetIntersection(pt0, pos, quality - 1); 374 | else if (v1 < 0.0f) 375 | pos = GetIntersection(pt1, pos, quality - 1); 376 | } 377 | 378 | return pos; 379 | } 380 | 381 | Vector3 World::GetNormal(Vector3 v, int scale) 382 | { 383 | /* A smaller h than this causes normals to have issues */ 384 | if (sample_type == USE_SPHERE) 385 | { 386 | v.Normalize(); 387 | return v; 388 | } 389 | float h = 0.1f; 390 | /*if (ImageData != null) 391 | { 392 | v = new Vector3((int)Math.Round(v.X), (int)Math.Round(v.Y), (int)Math.Round(v.Z)); 393 | h = 1.0f; 394 | }*/ 395 | float dxp = Sample(Vector3(v.x + h, v.y, v.z), scale); 396 | float dxm = Sample(Vector3(v.x - h, v.y, v.z), scale); 397 | float dyp = Sample(Vector3(v.x, v.y + h, v.z), scale); 398 | float dym = Sample(Vector3(v.x, v.y - h, v.z), scale); 399 | float dzp = Sample(Vector3(v.x, v.y, v.z + h), scale); 400 | float dzm = Sample(Vector3(v.x, v.y, v.z - h), scale); 401 | //Vector3 gradient = new Vector3(map[x + 1, y] - map[x - 1, y], map[x, y + 1] - map[x, y - 1]); 402 | Vector3 gradient = Vector3(dxp - dxm, dyp - dym, dzp - dzm); 403 | gradient.Normalize(); 404 | return gradient; 405 | } 406 | 407 | Vector3 World::GetColor(Vector3 pos) 408 | { 409 | Vector3 out; 410 | return Vector3(0.2f, 0.5f, 1.0f); 411 | const double range = pow(2.0, 22); 412 | //x /= range; y /= range; z /= range; 413 | double dx = (double)pos.x / (double)range; 414 | double dz = (double)pos.z / (double)range; 415 | int iterations; 416 | fractal(dx, dz, &iterations); 417 | 418 | float i = (float)iterations; 419 | out.x = i / 1024.0f; 420 | out.y = 0; 421 | out.z = 1.0f - i / 1024.0f; 422 | 423 | return out; 424 | } 425 | -------------------------------------------------------------------------------- /ProjectIW/World.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "SimpleMath.h" 4 | 5 | using namespace DirectX::SimpleMath; 6 | 7 | class World 8 | { 9 | public: 10 | static float Sample(DirectX::XMINT3 pos, int scale); 11 | static float Sample(Vector3 pos, int scale); 12 | static float Sample(float x, float y, float z, int scale); 13 | static float Noise(float x, float y, float z); 14 | static float Noise(float x, float y, float z, float scale, int octaves); 15 | static float Noise(float x, float z, float scale, int octaves); 16 | static Vector3 GetIntersection(const Vector3 p1, const Vector3 p2, float d1, float d2); 17 | static Vector3 GetIntersection(const Vector3 p1, const Vector3 p2, int quality); 18 | static float Sphere(float x, float y, float z); 19 | static float Cube(float x, float y, float z); 20 | static Vector3 GetNormal(Vector3 pos, int scale); 21 | static Vector3 GetColor(Vector3 pos); 22 | 23 | static float global_size; 24 | static float global_size_inverse; 25 | static int sample_type; 26 | static float terrain_scale; 27 | static float terrain_height; 28 | }; 29 | -------------------------------------------------------------------------------- /ProjectIW/WorldNode.cpp: -------------------------------------------------------------------------------- 1 | #include "WorldNode.h" 2 | #include "NodeCache.h" 3 | 4 | WorldNode::WorldNode() : WorldNode(1, XMINT3(0, 0, 0)) 5 | { 6 | } 7 | 8 | WorldNode::WorldNode(unsigned int size, XMINT3 pos) 9 | { 10 | Initialize(size, pos); 11 | } 12 | 13 | WorldNode::~WorldNode() 14 | { 15 | //if (!in_delete_queue) 16 | // SDELETEARRAY(children, 8); 17 | 18 | SDELETE(underlying_chunk); 19 | for (size_t i = 0; i < 8; i++) 20 | { 21 | assert(children[i] == 0); 22 | } 23 | } 24 | 25 | void WorldNode::Initialize(unsigned int size, XMINT3 pos) 26 | { 27 | this->node_stage = 0; 28 | this->size = size; 29 | this->position = pos; 30 | this->underlying_chunk = 0; 31 | this->parent = 0; 32 | this->is_leaf = true; 33 | this->is_empty = false; 34 | this->is_active = false; 35 | this->grouped_children = false; 36 | this->request_abandon = false; 37 | for (int i = 0; i < 8; i++) 38 | children[i] = 0; 39 | } 40 | 41 | int64_t WorldNode::Hash() 42 | { 43 | return Hash(position, size); 44 | } 45 | 46 | int64_t WorldNode::Hash(XMINT3 position, unsigned int size) 47 | { 48 | assert(sizeof(double) == sizeof(int64_t)); 49 | 50 | float c_x = (float)position.x + 1.0f / (float)size; 51 | float c_y = (float)position.y + 1.0f / (float)size; 52 | float c_z = (float)position.z + 1.0f / (float)size; 53 | 54 | const float p1 = 73856093.0f; 55 | const float p2 = 19349663.0f; 56 | const float p3 = 83492791.0f; 57 | 58 | double a = c_x * p1; 59 | double b = c_y * p2; 60 | double c = c_z * p3; 61 | 62 | int64_t i = *reinterpret_cast(&a); 63 | int64_t j = *reinterpret_cast(&b); 64 | int64_t k = *reinterpret_cast(&c); 65 | 66 | return i ^ j ^ k; 67 | } 68 | 69 | void WorldNode::SetAsLeaf() 70 | { 71 | } 72 | 73 | void WorldNode::Divide(NodeCache* cache) 74 | { 75 | is_leaf = false; 76 | 77 | int child_size = size / 2; 78 | WorldNode* child_pool = 0; 79 | 80 | bool cached_found = false; 81 | for (size_t i = 0; i < 8; i++) 82 | { 83 | XMINT3 child_pos = XMINT3(position.x + i / 4 * child_size, position.y + i % 4 / 2 * child_size, position.z + i % 2 * child_size); 84 | WorldNode* cached_node = cache->Find(Hash(child_pos, child_size), child_pos, child_size); 85 | if (cached_node) 86 | { 87 | // If we found the cached node, just assign it. There's no need to process it further because it's either being processed in the pipeline already, or it's ready. 88 | cached_node->request_abandon = false; 89 | cached_node->parent = this; 90 | children[i] = cached_node; 91 | cached_found = true; 92 | } 93 | } 94 | 95 | if (!cached_found) 96 | { 97 | //child_pool = new WorldNode[8]; 98 | //this->grouped_children = true; 99 | } 100 | 101 | for (int i = 0; i < 8; i++) 102 | { 103 | if (children[i]) 104 | { 105 | children[i]->parent = this; 106 | assert(children[i]->GetStage() != 0); 107 | continue; 108 | } 109 | 110 | XMINT3 child_pos = XMINT3(position.x + i / 4 * child_size, position.y + i % 4 / 2 * child_size, position.z + i % 2 * child_size); 111 | 112 | if (!cached_found) 113 | { 114 | // We set the node stage to CREATION here to ensure the node doesn't divide before having its set to generate. 115 | WorldNode* child = new WorldNode(child_size, child_pos); 116 | child->node_stage = NODE_STAGE_CREATION; 117 | child->parent = this; 118 | children[i] = child; 119 | //children[i] = child_pool + i; 120 | } 121 | else 122 | { 123 | WorldNode* child = new WorldNode(child_size, child_pos); 124 | child->node_stage = NODE_STAGE_CREATION; 125 | child->parent = this; 126 | children[i] = child; 127 | } 128 | } 129 | } 130 | 131 | bool WorldNode::Group() 132 | { 133 | is_leaf = true; 134 | return false; 135 | } 136 | 137 | void WorldNode::GetLeaves(std::vector& collection) 138 | { 139 | if (is_leaf && underlying_chunk) 140 | { 141 | collection.push_back(underlying_chunk); 142 | return; 143 | } 144 | 145 | for (int i = 0; i < 8; i++) 146 | { 147 | if (children[i]) 148 | { 149 | children[i]->GetLeaves(collection); 150 | } 151 | } 152 | } 153 | 154 | void WorldNode::DeleteChildren() 155 | { 156 | for (int i = 0; i < 8; i++) 157 | { 158 | if (children[i]) 159 | { 160 | children[i]->DeleteChildren(); 161 | delete children[i]; 162 | children[i] = 0; 163 | } 164 | } 165 | } 166 | 167 | WorldNode* WorldNode::GetNodeFromPos(Vector3 pos, bool prefer_parent) 168 | { 169 | return GetNodeFromPos(XMINT3((int)pos.x, (int)pos.y, (int)pos.z), prefer_parent); 170 | } 171 | 172 | WorldNode* WorldNode::GetNodeFromPos(XMINT3 source, bool prefer_parent) 173 | { 174 | if (source.x < position.x || source.y < position.y || source.z < position.z || source.x >= position.x + size || source.y >= position.y + size || source.z >= position.z + size) 175 | return 0; 176 | if (underlying_chunk) 177 | return this; 178 | 179 | XMINT3 difference = XMINT3(source.x - position.x, source.y - position.y, source.z - position.z); 180 | int dx = difference.x / (size / 2); 181 | int dy = difference.y / (size / 2); 182 | int dz = difference.z / (size / 2); 183 | int index = dx * 4 + dy * 2 + dz; 184 | if (children[index]) 185 | { 186 | if (children[index]->IsLeaf() && prefer_parent) 187 | return this; 188 | return children[index]->GetNodeFromPos(source); 189 | } 190 | return this; 191 | } 192 | 193 | Vector3 WorldNode::GetCenter() 194 | { 195 | Vector3 p((float)(position.x + size / 2), (float)(position.y + size / 2), (float)(position.z + size / 2)); 196 | return p; 197 | } 198 | -------------------------------------------------------------------------------- /ProjectIW/WorldNode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "SimpleMath.h" 8 | #include "General.h" 9 | #include "TerrainChunk.h" 10 | #include "WorldTypes.h" 11 | 12 | using namespace DirectX; 13 | using namespace DirectX::SimpleMath; 14 | using namespace MDC; 15 | 16 | class WorldNode 17 | { 18 | public: 19 | WorldNode(); 20 | WorldNode(unsigned int size, XMINT3 pos); 21 | ~WorldNode(); 22 | 23 | void Initialize(unsigned int size, XMINT3 pos); 24 | 25 | /// 26 | /// Hashes this instance. 27 | /// 28 | /// 29 | /// See http://www.beosil.com/download/CollisionDetectionHashing_VMV03.pdf for details on the algorithm. 30 | /// 31 | /// The hash of this node. 32 | int64_t Hash(); 33 | 34 | /// 35 | /// Hashes an input 3D vector and size, which are expected from a node. 36 | /// 37 | /// 38 | /// See http://www.beosil.com/download/CollisionDetectionHashing_VMV03.pdf for details on the algorithm. 39 | /// 40 | /// The hash of the position and size. 41 | static int64_t Hash(XMINT3 pos, unsigned int size); 42 | 43 | void SetAsLeaf(); 44 | 45 | /// 46 | /// Divides the node and creates children, using the cache to find pre-generated nodes if possible. 47 | /// 48 | /// The node cache containing previously-generated nodes. 49 | void Divide(NodeCache* cache); 50 | 51 | bool Group(); 52 | void GetLeaves(std::vector& collection); 53 | void DeleteChildren(); 54 | WorldNode* GetNodeFromPos(Vector3 pos, bool prefer_parent = false); 55 | WorldNode* GetNodeFromPos(XMINT3 pos, bool prefer_parent = false); 56 | Vector3 GetCenter(); 57 | 58 | inline std::atomic& IsLeaf() { return is_leaf; } 59 | inline std::atomic& GetStage() { return node_stage; } 60 | inline void SetStage(int stage) { node_stage = stage; } 61 | inline bool IsActive() { return is_active; } 62 | inline void SetActive(bool b) { is_active = b; } 63 | 64 | int size; 65 | XMINT3 position; 66 | bool grouped_children; 67 | WorldNode* children[8]; 68 | WorldNode* parent; 69 | std::atomic is_leaf; 70 | std::atomic request_abandon; 71 | bool is_empty; 72 | bool has_dirty_children; 73 | bool is_active; 74 | 75 | /// 76 | /// The node stage represents what stage in the pipeline it's in. 77 | /// See MeshTypes.WorldNodeStages for reference. 78 | /// TODO: possible change to an atomic enum after further research ensures they're treated as ints are 79 | /// 80 | std::atomic node_stage; 81 | 82 | /// 83 | /// The underlying chunk containing the mesh. 84 | /// This shouldn't need locking because its access depends on what node_stage returns, which is lock-free and thread-safe. 85 | /// For example, underlying_chunk is only used for rendering if the stage is READY or SPLITTABLE, and the stage is only set to that after the chunk is assigned. 86 | /// 87 | TerrainChunk* underlying_chunk; 88 | }; 89 | -------------------------------------------------------------------------------- /ProjectIW/WorldProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "WorldProcessor.h" 2 | #include "World.h" 3 | 4 | WorldProcessor::WorldProcessor(unsigned int res) : main_tree(res), node_creation() 5 | { 6 | } 7 | 8 | WorldProcessor::~WorldProcessor() 9 | { 10 | } 11 | 12 | void WorldProcessor::Cleanup() 13 | { 14 | MeshGeneration::Shutdown(); 15 | node_creation.Shutdown(); 16 | main_tree.Shutdown(); 17 | Vector3 pos(0, 0, 0); 18 | while (!main_tree.CanExit()) 19 | { 20 | main_tree.Update(pos); 21 | node_creation.TransferBatch(main_tree.GetDirtyNodes()); 22 | } 23 | 24 | } 25 | 26 | unsigned int WorldProcessor::Update(Vector3 pos) 27 | { 28 | unsigned int total_time = 0; 29 | 30 | total_time += main_tree.Update(pos); 31 | total_time += node_creation.TransferBatch(main_tree.GetDirtyNodes()); 32 | 33 | return total_time; 34 | } -------------------------------------------------------------------------------- /ProjectIW/WorldProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "WorldTree.h" 4 | #include "NodeCreation.h" 5 | #include "MeshGeneration.h" 6 | 7 | /// 8 | /// This controls the entire world pipeline. 9 | /// 10 | class WorldProcessor 11 | { 12 | public: 13 | WorldProcessor(unsigned int res); 14 | ~WorldProcessor(); 15 | 16 | /// 17 | /// Cleans up the world in the intended order. 18 | /// 19 | void Cleanup(); 20 | 21 | /// 22 | /// Begins the world pipeline stage, starting with WorldTree. 23 | /// 24 | /// The camera's position. 25 | /// How long the entire pipeline took on this thread. 26 | unsigned int Update(Vector3 pos); 27 | 28 | inline std::vector& GetRenderables() { return main_tree.GetRenderables(); } 29 | 30 | private: 31 | WorldTree main_tree; 32 | NodeCreation node_creation; 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /ProjectIW/WorldTree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "WorldTree.h" 3 | #include "MeshGeneration.h" 4 | #include "World.h" 5 | 6 | #define DEFAULT_BUFFER_SIZE 65536 7 | 8 | WorldTree::WorldTree(unsigned int default_res) 9 | { 10 | World::global_size = (float)default_res; 11 | World::global_size_inverse = 1.0f / (float)default_res; 12 | this->shutdown = false; 13 | this->default_res = default_res; 14 | this->renderables.reserve(DEFAULT_BUFFER_SIZE); 15 | this->output_buffer.reserve(DEFAULT_BUFFER_SIZE); 16 | Setup(); 17 | } 18 | 19 | WorldTree::~WorldTree() 20 | { 21 | assert(tree.IsLeaf()); 22 | 23 | } 24 | 25 | void WorldTree::Shutdown() 26 | { 27 | shutdown = true; 28 | } 29 | 30 | /// 31 | /// Process is as follows: 32 | /// -Create the octree 33 | /// -Move the main node right to the MeshGeneration stage 34 | /// After the main mesh is created, the update stage should pick it up as a node to be divided, just like any normal node. 35 | /// 36 | void WorldTree::Setup() 37 | { 38 | tree.Initialize(this->default_res, XMINT3(-(int)(this->default_res / 2), -(int)(this->default_res / 2), -(int)(this->default_res / 2))); 39 | tree.SetStage(NODE_STAGE_MESH_WAITING); 40 | tree.SetActive(true); 41 | renderables.push_back(&tree); 42 | 43 | MeshGeneration::AddNode(&tree); 44 | } 45 | 46 | unsigned int WorldTree::Update(Vector3 camera_pos) 47 | { 48 | using namespace std::chrono; 49 | steady_clock::time_point start = high_resolution_clock::now(); 50 | 51 | output_buffer.clear(); 52 | //renderables.clear(); 53 | 54 | //temp_process_queue.push_back(&tree); 55 | IterateTree(camera_pos); 56 | 57 | microseconds elapsed = duration_cast(high_resolution_clock::now() - start); 58 | return (unsigned int)elapsed.count(); 59 | } 60 | 61 | 62 | void WorldTree::IterateTree(Vector3 camera_pos) 63 | { 64 | WorldNode* n = 0; 65 | unsigned int index = 0; 66 | size_t size = renderables.size(); 67 | 68 | for (size_t i = 0; i < size; i++) 69 | { 70 | WorldNode* n = renderables[i]; 71 | assert(n != 0); 72 | assert(n->IsActive()); 73 | 74 | // This is only true if the parent node was grouped and this node is being processed afterwards for some reason 75 | /*if (!n->IsActive()) 76 | { 77 | renderables.erase(renderables.begin() + i--); 78 | size--; 79 | continue; 80 | }*/ 81 | 82 | //assert(n->IsActive()); 83 | // Get the stage and make sure we stick with it throughout the process here 84 | int stage = n->GetStage().load(); 85 | 86 | if (n->IsLeaf()) 87 | { 88 | if (n->parent && stage == NODE_STAGE_READY && NodeNeedsGrouping(n->parent, camera_pos)) 89 | { 90 | n->SetActive(false); 91 | renderables.erase(renderables.begin() + i--); 92 | if (!n->parent->IsActive()) 93 | AddNodeToRenderables(n->parent); 94 | else 95 | size--; 96 | assert(size == renderables.size()); 97 | continue; 98 | //size++; 99 | } 100 | 101 | // If the node doesn't have ready mesh, there's nothing further to do with it 102 | if (stage != NODE_STAGE_READY && stage != NODE_STAGE_SPLITTABLE) 103 | { 104 | continue; 105 | } 106 | 107 | // Check if the node is in a restful state and if it needs to be divided 108 | if (stage == NODE_STAGE_READY && NodeNeedsDivision(n, camera_pos)) 109 | { 110 | DirtyNodeOutput dirty; 111 | dirty.node = n; 112 | dirty.type = NODE_OUTPUT_DIVIDE; 113 | 114 | // We set the stage to splittable because it's ready and to-be enqueued in the NodeCreation stage 115 | n->SetStage(NODE_STAGE_SPLITTABLE); 116 | output_buffer.push_back(dirty); 117 | } 118 | 119 | // The node has mesh, so render it 120 | //AddNodeToRenderables(n); 121 | } 122 | else if (stage == NODE_STAGE_READY) // Node is not a leaf 123 | { 124 | if (NodeNeedsGrouping(n, camera_pos)) 125 | { 126 | if (stage == NODE_STAGE_READY) 127 | { 128 | DirtyNodeOutput dirty; 129 | dirty.node = n; 130 | dirty.type = NODE_OUTPUT_GROUP; 131 | bool can_group = true; 132 | 133 | for (size_t i = 0; i < 8; i++) 134 | { 135 | if (n->children[i]) 136 | { 137 | if (n->children[i]->IsActive()) 138 | { 139 | can_group = false; 140 | break; 141 | } 142 | //n->children[i]->SetActive(false); 143 | //assert(!n->children[i]->IsActive()); 144 | //n->children[i]->SetActive(false); 145 | } 146 | } 147 | if (!can_group) 148 | continue; 149 | 150 | // We set the stage to splittable because it's ready and to-be enqueued in the NodeCreation stage 151 | n->SetStage(NODE_STAGE_SPLITTABLE); 152 | output_buffer.push_back(dirty); 153 | } 154 | 155 | // At this point, the node has to be the highest possible level to be collapsed, so it's safe to add it to the renderables. 156 | //AddNodeToRenderables(n); 157 | //size++; 158 | 159 | continue; 160 | } 161 | 162 | bool all_renderable = true; 163 | for (size_t i = 0; i < 8; i++) 164 | { 165 | WorldNode* child = n->children[i]; 166 | assert(child != 0); 167 | 168 | int child_stage = child->GetStage(); 169 | if (child_stage != NODE_STAGE_READY && child_stage != NODE_STAGE_SPLITTABLE) 170 | { 171 | all_renderable = false; 172 | break; 173 | } 174 | } 175 | 176 | if (all_renderable) 177 | { 178 | n->SetActive(false); 179 | renderables.erase(renderables.begin() + i--); 180 | for (size_t i = 0; i < 8; i++) 181 | { 182 | WorldNode* child = n->children[i]; 183 | assert(child != 0); 184 | 185 | AddNodeToRenderables(child); 186 | //renderables.push_back(child); 187 | } 188 | size += 7; 189 | } 190 | else 191 | { 192 | assert(n->IsActive()); 193 | /*if (!n->IsActive()) // Should not ever be false 194 | { 195 | AddNodeToRenderables(n); 196 | size++; 197 | }*/ 198 | } 199 | } 200 | } 201 | } 202 | 203 | bool WorldTree::NodeNeedsDivision(WorldNode* n, Vector3 camera_pos) 204 | { 205 | if (shutdown) 206 | return false; 207 | assert(n != 0); 208 | assert(n->IsLeaf()); 209 | 210 | if (n->size <= NODE_CHUNK_RESOLUTION) 211 | return false; 212 | 213 | // We use raw floats here because Vector3 causes resource contention 214 | float n_x = (float)(n->position.x + n->size / 2) - camera_pos.x; 215 | float n_y = (float)(n->position.y + n->size / 2) - camera_pos.y; 216 | float n_z = (float)(n->position.z + n->size / 2) - camera_pos.z; 217 | 218 | float distance = sqrtf(n_x * n_x + n_y * n_y + n_z * n_z); 219 | return distance < (float)(n->size * 2); 220 | } 221 | 222 | bool WorldTree::NodeNeedsGrouping(WorldNode* n, Vector3 camera_pos) 223 | { 224 | assert(n != 0); 225 | assert(!n->IsLeaf()); 226 | 227 | if (n->GetStage() != NODE_STAGE_READY) 228 | return false; 229 | 230 | //Vector3 node_center = Vector3((float)(n->position.x + n->size / 2), (float)(n->position.y + n->size / 2), (float)(n->position.z + n->size / 2)); 231 | 232 | if (!shutdown) 233 | { 234 | // We use raw floats here because Vector3 causes resource contention 235 | float n_x = (float)(n->position.x + n->size / 2) - camera_pos.x; 236 | float n_y = (float)(n->position.y + n->size / 2) - camera_pos.y; 237 | float n_z = (float)(n->position.z + n->size / 2) - camera_pos.z; 238 | 239 | float distance = sqrtf(n_x * n_x + n_y * n_y + n_z * n_z); 240 | if (!(distance >= (float)(n->size) * 2.5f)) 241 | return false; 242 | } 243 | 244 | for (size_t i = 0; i < 8; i++) 245 | { 246 | int stage = n->children[i]->GetStage(); 247 | if ((n->children[i] && !n->children[i]->IsLeaf()) || stage == NODE_STAGE_CREATION || stage == NODE_STAGE_SPLITTABLE) 248 | return false; 249 | } 250 | 251 | return true; 252 | } 253 | 254 | void WorldTree::AddNodeToRenderables(WorldNode* n) 255 | { 256 | assert(n != 0); 257 | assert(!n->IsActive()); 258 | 259 | n->SetActive(true); 260 | renderables.push_back(n); 261 | } 262 | -------------------------------------------------------------------------------- /ProjectIW/WorldTree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "WorldTypes.h" 7 | #include "WorldNode.h" 8 | 9 | /// 10 | /// This is the initial step in the world pipeline. 11 | /// 12 | class WorldTree 13 | { 14 | public: 15 | WorldTree(unsigned int default_res); 16 | ~WorldTree(); 17 | 18 | /// 19 | /// Cleans up. This is to be called manually. 20 | /// 21 | void Shutdown(); 22 | 23 | /// 24 | /// Navigates through the tree and collects which nodes need dividing, need grouping, and are ready to be rendered. 25 | /// 26 | /// The camera's position. 27 | /// 28 | /// The amount of time in us it took. 29 | /// 30 | unsigned int Update(Vector3 camera_pos); 31 | 32 | inline std::vector& GetDirtyNodes() { return output_buffer; } 33 | inline std::vector& GetRenderables() { return renderables; } 34 | inline bool CanExit() { return tree.IsLeaf() && renderables.size() <= 1; } 35 | 36 | private: 37 | /// 38 | /// Creates the octree. 39 | /// 40 | void Setup(); 41 | 42 | /// 43 | /// Iterates through tree and builds up a list of nodes that need to be divided, need to be grouped, or can be rendered. 44 | /// 45 | /// The camera position. 46 | void IterateTree(Vector3 camera_pos); 47 | 48 | /// 49 | /// Determines whether or not a node needs to be divided. 50 | /// 51 | /// The node to check. 52 | /// The camera's position. 53 | /// True if node needs to be divided, false if otherwise. 54 | bool NodeNeedsDivision(WorldNode* n, Vector3 camera_pos); 55 | 56 | /// 57 | /// Determines whether or not a node needs to be grouped. 58 | /// 59 | /// The node to check. 60 | /// The camera's position. 61 | /// True if the node needs to be grouped, false if otherwise. 62 | bool NodeNeedsGrouping(WorldNode* n, Vector3 camera_pos); 63 | 64 | /// 65 | /// Adds the node to renderables. 66 | /// 67 | /// The node to add. 68 | void AddNodeToRenderables(WorldNode* n); 69 | 70 | unsigned int default_res; 71 | WorldNode tree; 72 | std::vector temp_process_queue; 73 | std::vector output_buffer; 74 | std::vector renderables; 75 | 76 | bool shutdown; 77 | 78 | //std::vector renderables_2; 79 | }; 80 | 81 | -------------------------------------------------------------------------------- /ProjectIW/WorldTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class WorldNode; 6 | class NodeCache; 7 | 8 | namespace MDC 9 | { 10 | class TerrainChunk; 11 | } 12 | 13 | enum NodeOutputType 14 | { 15 | NODE_OUTPUT_DIVIDE = 0, 16 | NODE_OUTPUT_GROUP = 1 17 | }; 18 | struct DirtyNodeOutput 19 | { 20 | NodeOutputType type; 21 | WorldNode* node; 22 | }; 23 | 24 | /// 25 | /// The possible node stages. 26 | /// 0 = unspecified 27 | /// 1 = in the NodeCreation stage to be split or grouped 28 | /// 2 = in the MeshGeneration queue waiting to be processed 29 | /// 3 = in the MeshGeneration stage and being generated 30 | /// 4 = fully complete and ready to render as a leaf node 31 | /// 5 = in the NodeCreation stage with full mesh 32 | /// 33 | /// 34 | /// There are 2 mesh stages simply for debugging purposes. 35 | /// 36 | enum WorldNodeStages 37 | { 38 | NODE_STAGE_UNSPECIFIED = 0, 39 | NODE_STAGE_CREATION = 1, 40 | NODE_STAGE_MESH_WAITING = 2, 41 | NODE_STAGE_MESH_GENERATING = 3, 42 | NODE_STAGE_READY = 4, 43 | NODE_STAGE_SPLITTABLE = 5 44 | }; 45 | 46 | // Uniform resolution of a chunk 47 | #define NODE_CHUNK_RESOLUTION 8 48 | //How many chunks to have before a LOD split 49 | #define NODE_LOD_THRESHOLD 1.0f -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ProjectIW 2 | Infinite world using MDC 3 | --------------------------------------------------------------------------------