summaryrefslogtreecommitdiff
path: root/demo/ocean_vessel.cpp
diff options
context:
space:
mode:
authorJason Maskell <[email protected]>2016-05-09 10:39:54 +0200
committerJason Maskell <[email protected]>2016-05-09 10:39:54 +0200
commit79b3462799c28af8ba586349bd671b1b56e72353 (patch)
tree3b06e36c390254c0dc7f3733a0d32af213d87293 /demo/ocean_vessel.cpp
downloadarchived-waveworks-archive-79b3462799c28af8ba586349bd671b1b56e72353.tar.xz
archived-waveworks-archive-79b3462799c28af8ba586349bd671b1b56e72353.zip
Initial commit with PS4 and XBone stuff trimmed.
Diffstat (limited to 'demo/ocean_vessel.cpp')
-rw-r--r--demo/ocean_vessel.cpp1590
1 files changed, 1590 insertions, 0 deletions
diff --git a/demo/ocean_vessel.cpp b/demo/ocean_vessel.cpp
new file mode 100644
index 0000000..6b57724
--- /dev/null
+++ b/demo/ocean_vessel.cpp
@@ -0,0 +1,1590 @@
+// This code contains NVIDIA Confidential Information and is disclosed
+// under the Mutual Non-Disclosure Agreement.
+//
+// Notice
+// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
+// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless
+// expressly authorized by NVIDIA. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright � 2008- 2013 NVIDIA Corporation. All rights reserved.
+//
+// NVIDIA Corporation and its licensors retain all intellectual property and proprietary
+// rights in and to this software and related documentation and any modifications thereto.
+// Any use, reproduction, disclosure or distribution of this software and related
+// documentation without an express license agreement from NVIDIA Corporation is
+// strictly prohibited.
+//
+
+#include "DXUT.h"
+#include "ocean_vessel.h"
+#include "ocean_hull_profile.h"
+#include "ocean_hull_sensors.h"
+#include "ocean_env.h"
+#include "ocean_smoke.h"
+#include "ocean_psm.h"
+#include "ocean_surface_heights.h"
+
+#include "GFSDK_WaveWorks.h"
+#include "GFSDK_WaveWorks_D3D_Util.h"
+#include "DXUTcamera.h"
+
+#include <tchar.h>
+
+#pragma warning(disable:4127)
+
+const float kAccelerationDueToGravity = 9.81f;
+const float kDensityOfWater = 1000.f;
+const float kMaximumFractionalCornerError = 0.0001f; // 100ppm
+const float kMaxSimulationTimeStep = 0.02f;
+
+const float kSpotlightClipNear = 0.1f;
+const float kSpotlightClipFar = 200.0f;
+
+extern HRESULT LoadFile(LPCTSTR FileName, ID3DXBuffer** ppBuffer);
+extern HRESULT CreateTextureFromFileSRGB(
+ ID3D11Device* pDevice,
+ LPCTSTR pSrcFile,
+ ID3D11Resource** ppTexture);
+
+inline bool operator!=(const D3DVERTEXELEMENT9& lhs, const D3DVERTEXELEMENT9& rhs) {
+ return lhs.Stream != rhs.Stream ||
+ lhs.Offset != rhs.Offset ||
+ lhs.Type != rhs.Type ||
+ lhs.Method != rhs.Method ||
+ lhs.Usage != rhs.Usage ||
+ lhs.UsageIndex != rhs.UsageIndex;
+}
+
+namespace {
+
+ float sqr(float x) { return x * x; }
+
+ D3DXVECTOR3 D3DXVec3Min(const D3DXVECTOR3& lhs, const D3DXVECTOR3& rhs) {
+ return D3DXVECTOR3(min(lhs.x,rhs.x), min(lhs.y,rhs.y), min(lhs.z,rhs.z));
+ }
+
+ D3DXVECTOR3 D3DXVec3Max(const D3DXVECTOR3& lhs, const D3DXVECTOR3& rhs) {
+ return D3DXVECTOR3(max(lhs.x,rhs.x), max(lhs.y,rhs.y), max(lhs.z,rhs.z));
+ }
+}
+
+HRESULT BoatMesh::CreateInputLayout(ID3D11Device* pd3dDevice,
+ UINT iMesh, UINT iVB,
+ const void *pShaderBytecodeWithInputSignature, SIZE_T BytecodeLength,
+ ID3D11InputLayout** pIL
+ )
+{
+ // Translate from D3D9 decl...
+ SDKMESH_VERTEX_BUFFER_HEADER* pVBHeader = m_pVertexBufferArray + m_pMeshArray[ iMesh ].VertexBuffers[iVB];
+
+ D3D11_INPUT_ELEMENT_DESC vertex_layout[MAX_VERTEX_ELEMENTS];
+ UINT num_layout_elements = 0;
+ const D3DVERTEXELEMENT9 d3d9_decl_end = D3DDECL_END();
+ while(pVBHeader->Decl[num_layout_elements] != d3d9_decl_end) {
+
+ const D3DVERTEXELEMENT9& d3d9_decl_element = pVBHeader->Decl[num_layout_elements];
+ D3D11_INPUT_ELEMENT_DESC& d3d11_layout_element = vertex_layout[num_layout_elements];
+
+ // Translate usage
+ switch(d3d9_decl_element.Usage) {
+ case D3DDECLUSAGE_POSITION: d3d11_layout_element.SemanticName = "POSITION"; break;
+ case D3DDECLUSAGE_NORMAL: d3d11_layout_element.SemanticName = "NORMAL"; break;
+ case D3DDECLUSAGE_TEXCOORD: d3d11_layout_element.SemanticName = "TEXCOORD"; break;
+ case D3DDECLUSAGE_COLOR: d3d11_layout_element.SemanticName = "COLOR"; break;
+ default:
+ return E_FAIL; // Whoops, this usage not handled yet!
+ }
+
+ // Translate usage index
+ d3d11_layout_element.SemanticIndex = d3d9_decl_element.UsageIndex;
+
+ // Translate type
+ switch(d3d9_decl_element.Type) {
+ case D3DDECLTYPE_FLOAT1: d3d11_layout_element.Format = DXGI_FORMAT_R32_FLOAT; break;
+ case D3DDECLTYPE_FLOAT2: d3d11_layout_element.Format = DXGI_FORMAT_R32G32_FLOAT; break;
+ case D3DDECLTYPE_FLOAT3: d3d11_layout_element.Format = DXGI_FORMAT_R32G32B32_FLOAT; break;
+ case D3DDECLTYPE_FLOAT4: d3d11_layout_element.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; break;
+ case D3DDECLTYPE_D3DCOLOR: d3d11_layout_element.Format = DXGI_FORMAT_R8G8B8A8_UNORM; break;
+ default:
+ return E_FAIL; // Whoops, this format not handled yet!
+ }
+
+ // Translate stream
+ d3d11_layout_element.InputSlot = d3d9_decl_element.Stream;
+
+ // Translate offset
+ d3d11_layout_element.AlignedByteOffset = d3d9_decl_element.Offset;
+
+ // No instancing
+ d3d11_layout_element.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
+ d3d11_layout_element.InstanceDataStepRate = 0;
+
+ ++num_layout_elements;
+ }
+
+ return pd3dDevice->CreateInputLayout(vertex_layout, num_layout_elements, pShaderBytecodeWithInputSignature, BytecodeLength, pIL);
+}
+
+OceanVessel::OceanVessel(OceanVesselDynamicState* pDynamicState) :
+ m_pDynamicState(pDynamicState)
+{
+ m_MeshFileName = NULL;
+ m_pMesh = NULL;
+ m_pLayout = NULL;
+
+ m_pFX = NULL;
+ m_pRenderToSceneTechnique = NULL;
+ m_pRenderToShadowMapTechnique = NULL;
+ m_pRenderToHullProfileTechnique = NULL;
+ m_pRenderQuadToUITechnique = NULL;
+ m_pRenderQuadToCrackFixTechnique = NULL;
+ m_pWireframeOverrideTechnique = NULL;
+
+ m_pMatWorldViewProjVariable = NULL;
+ m_pMatWorldVariable = NULL;
+ m_pMatWorldViewVariable = NULL;
+ m_pTexDiffuseVariable = NULL;
+ m_pTexRustMapVariable = NULL;
+ m_pTexRustVariable = NULL;
+ m_pTexBumpVariable = NULL;
+ m_pDiffuseColorVariable = NULL;
+ m_pLightDirectionVariable = NULL;
+ m_pLightColorVariable = NULL;
+ m_pAmbientColorVariable = NULL;
+
+ m_pSpotlightNumVariable = NULL;
+ m_pSpotlightPositionVariable = NULL;
+ m_pSpotLightAxisAndCosAngleVariable = NULL;
+ m_pSpotlightColorVariable = NULL;
+ m_pSpotlightShadowMatrixVar = NULL;
+ m_pSpotlightShadowResourceVar = NULL;
+
+ m_pLightningPositionVariable = NULL;
+ m_pLightningColorVariable = NULL;
+
+ m_pFogExponentVariable = NULL;
+
+ m_pWhiteTextureSRV = NULL;
+ m_pRustMapSRV = NULL;
+ m_pRustSRV = NULL;
+ m_pBumpSRV = NULL;
+
+ m_pHullProfileSRV[0] = NULL;
+ m_pHullProfileSRV[1] = NULL;
+ m_pHullProfileRTV[0] = NULL;
+ m_pHullProfileRTV[1] = NULL;
+ m_pHullProfileDSV = NULL;
+
+ m_pd3dDevice = DXUTGetD3D11Device();
+
+ m_HeightDrag = 1.f;
+ m_PitchDrag = 2.f;
+ m_YawDrag = 1.f;
+ m_YawCoefficient = 1.f;
+ m_RollDrag = 1.f;
+
+ m_Length = 30.f;
+ m_CameraHeightAboveWater = 6.f;
+ m_CameraLongitudinalOffset = 5.f;
+ m_MetacentricHeight = 1.f;
+ m_LongitudinalCOM = -7.f;
+ m_MassMult = 0.5f;
+ m_PitchInertiaMult = 0.2f;
+ m_RollInertiaMult = 0.3f;
+
+ m_InitialPitch = 0.0438f;
+ m_InitialHeight = -0.75f;
+
+ m_HullProfileTextureWH = 512;
+
+ m_DiffuseGamma = 3.f;
+
+ m_FunnelLongitudinalOffset = 0.f;
+ m_FunnelHeightAboveWater = 6.f;
+ m_FunnelMouthSize = D3DXVECTOR2(1.f,1.f);
+
+ m_NumSmokeParticles = 4096;
+ m_SmokeParticleEmitRate = FLOAT(m_NumSmokeParticles)/10.f;
+ m_SmokeParticleEmitMinVelocity = 1.f;
+ m_SmokeParticleEmitMaxVelocity = 1.f;
+ m_SmokeParticleMinBuoyancy = 0.f;
+ m_SmokeParticleMaxBuoyancy = 1.f;
+ m_SmokeParticleCoolingRate = 0.f;
+ m_SmokeParticleEmitSpread = 0.f;
+ m_SmokeParticleBeginSize = 1.f;
+ m_SmokeParticleEndSize = 1.f;
+ m_SmokeWindDrag = 1.f;
+ m_SmokePSMBoundsFadeMargin = 0.1f;
+ m_SmokeWindNoiseLevel = 2.f;
+ m_SmokeWindNoiseSpatialScale = 1.f;
+ m_SmokeWindNoiseTimeScale = 1.f;
+ m_SmokeTint = D3DXVECTOR3( 1.f, 1.f, 1.f);
+ m_SmokeShadowOpacity = 1.f;
+ m_SmokeTextureFileName = NULL;
+ m_pSmoke = NULL;
+
+ m_PSMRes = 512;
+ m_PSMMinCorner = D3DXVECTOR3(-1.f,-1.f,-1.f);
+ m_PSMMaxCorner = D3DXVECTOR3( 1.f, 1.f, 1.f);
+ m_pPSM = NULL;
+
+ m_NumSurfaceHeightSamples = 1000;
+ m_pSurfaceHeights = NULL;
+
+ m_pHullSensors = NULL;
+}
+
+OceanVessel::~OceanVessel()
+{
+ SAFE_DELETE(m_pHullSensors);
+ SAFE_DELETE(m_pSurfaceHeights);
+ SAFE_DELETE_ARRAY(m_SmokeTextureFileName);
+ SAFE_DELETE(m_pSmoke);
+ SAFE_DELETE(m_pPSM);
+ SAFE_DELETE_ARRAY(m_MeshFileName);
+ SAFE_RELEASE(m_pHullProfileSRV[0]);
+ SAFE_RELEASE(m_pHullProfileSRV[1]);
+ SAFE_RELEASE(m_pHullProfileRTV[0]);
+ SAFE_RELEASE(m_pHullProfileRTV[1]);
+ SAFE_RELEASE(m_pHullProfileDSV);
+ SAFE_RELEASE(m_pRustMapSRV);
+ SAFE_RELEASE(m_pRustSRV);
+ SAFE_RELEASE(m_pBumpSRV);
+ SAFE_RELEASE(m_pWhiteTextureSRV);
+
+ SAFE_DELETE(m_pMesh);
+ SAFE_RELEASE(m_pLayout);
+ SAFE_RELEASE(m_pFX);
+
+ m_SpotlightsShadows.clear();
+}
+
+HRESULT OceanVessel::init(LPCTSTR cfg_string, bool allow_smoke)
+{
+ HRESULT hr = S_OK;
+
+ // Parse the cfg file
+ V_RETURN(parseConfig(cfg_string));
+
+ // Load the mesh
+ SAFE_DELETE(m_pMesh);
+ m_pMesh = new BoatMesh();
+ V_RETURN(m_pMesh->Create(m_pd3dDevice, m_MeshFileName));
+
+ // Get the bounding box and figure out the scale needed to achieve the desired length,
+ // then figure out the other dims
+ UINT num_meshes = m_pMesh->GetNumMeshes();
+ if(0 == num_meshes)
+ return E_FAIL;
+
+ m_bbExtents = m_pMesh->GetMeshBBoxExtents(0);
+ m_bbCentre = m_pMesh->GetMeshBBoxCenter(0);
+ FLOAT meshRenderScale = 0.5f * m_Length/m_bbExtents.z;
+
+ D3DXMATRIX matMeshScale;
+ D3DXMatrixScaling(&matMeshScale, meshRenderScale, meshRenderScale, meshRenderScale);
+
+ D3DXMATRIX matMeshOrient;
+ D3DXMatrixRotationY(&matMeshOrient, D3DX_PI);
+
+ D3DXMATRIX matMeshOffset;
+ D3DXMatrixTranslation(&matMeshOffset, -m_bbCentre.x, 0.f, -m_bbCentre.z);
+
+ m_MeshToLocal = matMeshOffset * matMeshScale * matMeshOrient;
+
+ D3DXMatrixIdentity(&m_CameraToLocal);
+ m_CameraToLocal._42 = m_CameraHeightAboveWater;
+ m_CameraToLocal._43 = m_CameraLongitudinalOffset;
+
+ D3DXMatrixRotationX(&m_FunnelMouthToLocal,-3.14f*0.3f);
+ //D3DXMatrixIdentity(&m_FunnelMouthToLocal);
+ m_FunnelMouthToLocal._42 = m_FunnelHeightAboveWater;
+ m_FunnelMouthToLocal._43 = m_FunnelLongitudinalOffset;
+
+ m_Draft = (m_bbExtents.y-m_bbCentre.y) * meshRenderScale; // Assumes mesh was modelled with the MWL at y = 0
+ m_Beam = 2.f * m_bbExtents.x * meshRenderScale;
+ m_MeshHeight = 2.f * m_bbExtents.y * meshRenderScale;
+ m_BuoyantArea = m_Length * m_Beam;
+ m_Mass = m_BuoyantArea * m_Draft * kDensityOfWater; // At equilibrium, the displaced water is equal to the mass of the ship
+ m_Mass *= 0.25f*D3DX_PI; // We approximate the hull profile with an ellipse, it is important to
+ // match this in the mass calc so that the ship sits at the right height
+ // in the water at rest
+ m_Mass *= m_MassMult;
+ m_PitchInertia = m_Mass * (m_Draft * m_Draft + m_Length * m_Length)/12.f; // Use the inertia of the displaced water
+ m_RollInertia = m_Mass * (m_Draft * m_Draft + m_Beam * m_Beam)/12.f;
+
+ m_PitchInertia *= m_PitchInertiaMult;
+ m_RollInertia *= m_RollInertiaMult;
+
+ SAFE_RELEASE(m_pFX);
+ ID3DXBuffer* pEffectBuffer = NULL;
+ V_RETURN(LoadFile(TEXT(".\\Media\\ocean_vessel_d3d11.fxo"), &pEffectBuffer));
+ V_RETURN(D3DX11CreateEffectFromMemory(pEffectBuffer->GetBufferPointer(), pEffectBuffer->GetBufferSize(), 0, m_pd3dDevice, &m_pFX));
+ pEffectBuffer->Release();
+
+ m_pRenderToSceneTechnique = m_pFX->GetTechniqueByName("RenderVesselToSceneTech");
+ m_pRenderToShadowMapTechnique = m_pFX->GetTechniqueByName("RenderVesselToShadowMapTech");
+ m_pRenderToHullProfileTechnique = m_pFX->GetTechniqueByName("RenderVesselToHullProfileTech");
+ m_pRenderQuadToUITechnique = m_pFX->GetTechniqueByName("RenderQuadToUITech");
+ m_pRenderQuadToCrackFixTechnique = m_pFX->GetTechniqueByName("RenderQuadToCrackFixTech");
+ m_pWireframeOverrideTechnique = m_pFX->GetTechniqueByName("WireframeOverrideTech");
+ m_pMatWorldViewProjVariable = m_pFX->GetVariableByName("g_matWorldViewProj")->AsMatrix();
+ m_pMatWorldVariable = m_pFX->GetVariableByName("g_matWorld")->AsMatrix();
+ m_pMatWorldViewVariable = m_pFX->GetVariableByName("g_matWorldView")->AsMatrix();
+ m_pTexDiffuseVariable = m_pFX->GetVariableByName("g_texDiffuse")->AsShaderResource();
+ m_pTexRustMapVariable = m_pFX->GetVariableByName("g_texRustMap")->AsShaderResource();
+ m_pTexRustVariable = m_pFX->GetVariableByName("g_texRust")->AsShaderResource();
+ m_pTexBumpVariable = m_pFX->GetVariableByName("g_texBump")->AsShaderResource();
+ m_pDiffuseColorVariable = m_pFX->GetVariableByName("g_DiffuseColor")->AsVector();
+ m_pLightDirectionVariable = m_pFX->GetVariableByName("g_LightDirection")->AsVector();
+ m_pLightColorVariable = m_pFX->GetVariableByName("g_LightColor")->AsVector();
+ m_pAmbientColorVariable = m_pFX->GetVariableByName("g_AmbientColor")->AsVector();
+
+ m_pSpotlightNumVariable = m_pFX->GetVariableByName("g_LightsNum")->AsScalar();
+ m_pSpotlightPositionVariable = m_pFX->GetVariableByName("g_SpotlightPosition")->AsVector();
+ m_pSpotLightAxisAndCosAngleVariable = m_pFX->GetVariableByName("g_SpotLightAxisAndCosAngle")->AsVector();
+ m_pSpotlightColorVariable = m_pFX->GetVariableByName("g_SpotlightColor")->AsVector();
+ m_pSpotlightShadowMatrixVar = m_pFX->GetVariableByName("g_SpotlightMatrix")->AsMatrix();
+ m_pSpotlightShadowResourceVar = m_pFX->GetVariableByName("g_SpotlightResource")->AsShaderResource();
+
+ m_pLightningPositionVariable = m_pFX->GetVariableByName("g_LightningPosition")->AsVector();
+ m_pLightningColorVariable = m_pFX->GetVariableByName("g_LightningColor")->AsVector();
+
+ m_pFogExponentVariable = m_pFX->GetVariableByName("g_FogExponent")->AsScalar();
+
+ D3DX11_PASS_DESC PassDesc;
+ V_RETURN(m_pRenderToSceneTechnique->GetPassByIndex(0)->GetDesc(&PassDesc));
+
+ SAFE_RELEASE(m_pLayout);
+ V_RETURN(m_pMesh->CreateInputLayout(m_pd3dDevice, 0, 0, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &m_pLayout));
+
+ // Set up an all-white texture SRV to use when a mesh subset has no associated texture
+ {
+ SAFE_RELEASE(m_pWhiteTextureSRV);
+
+ enum { WhiteTextureWH = 4 };
+ D3D11_TEXTURE2D_DESC tex_desc;
+ tex_desc.Width = WhiteTextureWH;
+ tex_desc.Height = WhiteTextureWH;
+ tex_desc.ArraySize = 1;
+ tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ tex_desc.CPUAccessFlags = 0;
+ tex_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ tex_desc.MipLevels = 1;
+ tex_desc.MiscFlags = 0;
+ tex_desc.SampleDesc.Count = 1;
+ tex_desc.SampleDesc.Quality = 0;
+ tex_desc.Usage = D3D11_USAGE_IMMUTABLE;
+
+ DWORD tex_data[WhiteTextureWH * WhiteTextureWH];
+ for(int i = 0; i != sizeof(tex_data)/sizeof(tex_data[0]); ++i) {
+ tex_data[i] = 0xFFFFFFFF;
+ }
+
+ D3D11_SUBRESOURCE_DATA tex_srd;
+ tex_srd.pSysMem = tex_data;
+ tex_srd.SysMemPitch = WhiteTextureWH * sizeof(tex_data[0]);
+ tex_srd.SysMemSlicePitch = sizeof(tex_data);
+
+ ID3D11Texture2D* pWhiteTetxure = NULL;
+ V_RETURN(m_pd3dDevice->CreateTexture2D(&tex_desc,&tex_srd,&pWhiteTetxure));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pWhiteTetxure,NULL,&m_pWhiteTextureSRV));
+ SAFE_RELEASE(pWhiteTetxure);
+ }
+
+ {
+ SAFE_RELEASE(m_pHullProfileSRV[0]);
+ SAFE_RELEASE(m_pHullProfileSRV[1]);
+ SAFE_RELEASE(m_pHullProfileRTV[0]);
+ SAFE_RELEASE(m_pHullProfileRTV[1]);
+ SAFE_RELEASE(m_pHullProfileDSV);
+ ID3D11Texture2D* pTexture = NULL;
+
+ // Set up textures for rendering hull profile
+ D3D11_TEXTURE2D_DESC tex_desc;
+ tex_desc.Width = m_HullProfileTextureWH;
+ tex_desc.Height = m_HullProfileTextureWH;
+ tex_desc.ArraySize = 1;
+ tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+ tex_desc.CPUAccessFlags = 0;
+ tex_desc.Format = DXGI_FORMAT_R16G16_UNORM;
+ tex_desc.MipLevels = 1;
+ tex_desc.MiscFlags = 0;
+ tex_desc.SampleDesc.Count = 1;
+ tex_desc.SampleDesc.Quality = 0;
+ tex_desc.Usage = D3D11_USAGE_DEFAULT;
+
+ V_RETURN(m_pd3dDevice->CreateTexture2D(&tex_desc,NULL,&pTexture));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pTexture,NULL,&m_pHullProfileSRV[0]));
+ V_RETURN(m_pd3dDevice->CreateRenderTargetView(pTexture,NULL,&m_pHullProfileRTV[0]));
+ SAFE_RELEASE(pTexture);
+
+ tex_desc.MipLevels = 0;
+ tex_desc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
+ V_RETURN(m_pd3dDevice->CreateTexture2D(&tex_desc,NULL,&pTexture));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pTexture,NULL,&m_pHullProfileSRV[1]));
+ V_RETURN(m_pd3dDevice->CreateRenderTargetView(pTexture,NULL,&m_pHullProfileRTV[1]));
+ SAFE_RELEASE(pTexture);
+
+ D3D11_TEXTURE2D_DESC depth_tex_desc;
+ depth_tex_desc.Width = m_HullProfileTextureWH;
+ depth_tex_desc.Height = m_HullProfileTextureWH;
+ depth_tex_desc.ArraySize = 1;
+ depth_tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
+ depth_tex_desc.CPUAccessFlags = 0;
+ depth_tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
+ depth_tex_desc.MipLevels = 1;
+ depth_tex_desc.MiscFlags = 0;
+ depth_tex_desc.SampleDesc.Count = 1;
+ depth_tex_desc.SampleDesc.Quality = 0;
+ depth_tex_desc.Usage = D3D11_USAGE_DEFAULT;
+
+ V_RETURN(m_pd3dDevice->CreateTexture2D(&depth_tex_desc,NULL,&pTexture));
+ V_RETURN(m_pd3dDevice->CreateDepthStencilView(pTexture,NULL,&m_pHullProfileDSV));
+ SAFE_RELEASE(pTexture);
+ }
+
+#if ENABLE_SHADOWS
+ if (!m_Spotlights.empty())
+ {
+ size_t lightsNum = m_Spotlights.size();
+ m_SpotlightsShadows.resize(lightsNum);
+
+ for (size_t i=0; i<lightsNum; ++i)
+ {
+ SpotlightShadow& shadow = m_SpotlightsShadows[i];
+
+ CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R24G8_TYPELESS, (UINT)kSpotlightShadowResolution, (UINT)kSpotlightShadowResolution, 1, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL);
+ V_RETURN(m_pd3dDevice->CreateTexture2D(&desc, NULL, &shadow.m_pResource));
+
+ CD3D11_DEPTH_STENCIL_VIEW_DESC descDSV(D3D11_DSV_DIMENSION_TEXTURE2D, DXGI_FORMAT_D24_UNORM_S8_UINT);
+ V_RETURN(m_pd3dDevice->CreateDepthStencilView(shadow.m_pResource, &descDSV, &m_SpotlightsShadows[i].m_pDSV));
+
+ CD3D11_SHADER_RESOURCE_VIEW_DESC descSRV(D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R24_UNORM_X8_TYPELESS);
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(shadow.m_pResource, &descSRV, &m_SpotlightsShadows[i].m_pSRV));
+ }
+ }
+#endif
+
+ if(m_SmokeTextureFileName && allow_smoke) {
+
+ ID3D11Resource* pD3D11Resource = NULL;
+ V_RETURN(CreateTextureFromFileSRGB(m_pd3dDevice, m_SmokeTextureFileName, &pD3D11Resource));
+ ID3D11ShaderResourceView* pSmokeTextureSRV;
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pD3D11Resource, NULL, &pSmokeTextureSRV));
+ SAFE_RELEASE(pD3D11Resource);
+
+ m_pSmoke = new OceanSmoke();
+ V_RETURN(m_pSmoke->init( pSmokeTextureSRV,
+ m_NumSmokeParticles,
+ m_SmokeParticleEmitRate,
+ m_SmokeParticleBeginSize,
+ m_SmokeParticleEndSize,
+ m_SmokeParticleEmitMinVelocity,
+ m_SmokeParticleEmitMaxVelocity,
+ m_SmokeParticleEmitSpread,
+ m_SmokeWindDrag,
+ m_SmokeParticleMinBuoyancy,
+ m_SmokeParticleMaxBuoyancy,
+ m_SmokeParticleCoolingRate,
+ m_FunnelMouthSize,
+ m_SmokePSMBoundsFadeMargin,
+ m_SmokeShadowOpacity,
+ m_SmokeTint,
+ m_SmokeWindNoiseSpatialScale,
+ m_SmokeWindNoiseTimeScale
+ ));
+ SAFE_RELEASE(pSmokeTextureSRV);
+ }
+
+ m_pPSM = new OceanPSM();
+ V_RETURN(m_pPSM->init(m_PSMMinCorner,m_PSMMaxCorner,m_PSMRes));
+
+ if(NULL == m_pRustMapSRV)
+ {
+ ID3D11Resource* pD3D11Resource = NULL;
+ V_RETURN(D3DX11CreateTextureFromFile(m_pd3dDevice, TEXT(".\\media\\rustmap.dds"), NULL, NULL, &pD3D11Resource, NULL));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pD3D11Resource, NULL, &m_pRustMapSRV));
+ SAFE_RELEASE(pD3D11Resource);
+ }
+
+ if(NULL == m_pRustSRV)
+ {
+ ID3D11Resource* pD3D11Resource = NULL;
+ V_RETURN(D3DX11CreateTextureFromFile(m_pd3dDevice, TEXT(".\\media\\rust.dds"), NULL, NULL, &pD3D11Resource, NULL));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pD3D11Resource, NULL, &m_pRustSRV));
+ SAFE_RELEASE(pD3D11Resource);
+ }
+
+ if(NULL == m_pBumpSRV)
+ {
+ ID3D11Resource* pD3D11Resource = NULL;
+ V_RETURN(D3DX11CreateTextureFromFile(m_pd3dDevice, TEXT(".\\media\\foam_intensity_perlin2.dds"), NULL, NULL, &pD3D11Resource, NULL));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pD3D11Resource, NULL, &m_pBumpSRV));
+ SAFE_RELEASE(pD3D11Resource);
+ }
+
+ gfsdk_float2 UVToWorldScale;
+ UVToWorldScale.x = 2.f * sqrtf(m_Beam*m_Beam+m_MeshHeight*m_MeshHeight); // Use double-diagonal, to be conservative
+ UVToWorldScale.x += m_Length; // Then add another vessel length, to make sure we catch big bow sprays
+ UVToWorldScale.y = m_Length + 2.f * m_MeshHeight; // Add height, to be conservative
+
+ m_pSurfaceHeights = new OceanSurfaceHeights(m_NumSurfaceHeightSamples,UVToWorldScale);
+ V_RETURN(m_pSurfaceHeights->init());
+
+ m_pHullSensors = new OceanHullSensors();
+ V_RETURN(m_pHullSensors->init(m_pMesh, *getMeshToLocalXform()));
+ m_bFirstSensorUpdate = true;
+
+ return S_OK;
+}
+
+void OceanVessel::renderVessel(ID3D11DeviceContext* pDC, ID3DX11EffectTechnique* pTechnique, const OceanVesselSubset* pSubsetOverride, bool wireframe, bool depthOnly)
+{
+ if(NULL == m_pMesh)
+ return;
+
+ // Iterate over mesh subsets to draw
+ BoatMesh& mesh = *m_pMesh;
+ UINT Strides[1];
+ UINT Offsets[1];
+ ID3D11Buffer* pVB[1];
+ pVB[0] = mesh.GetVB11(0,0);
+ Strides[0] = (UINT)mesh.GetVertexStride(0,0);
+ Offsets[0] = 0;
+ pDC->IASetVertexBuffers( 0, 1, pVB, Strides, Offsets );
+ pDC->IASetInputLayout(m_pLayout);
+
+ m_pTexRustMapVariable->SetResource(m_pRustMapSRV);
+ m_pTexRustVariable->SetResource(m_pRustSRV);
+ m_pTexBumpVariable->SetResource(m_pBumpSRV);
+
+ if(pSubsetOverride) {
+ pDC->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_POINTLIST );
+ pDC->IASetIndexBuffer( pSubsetOverride->pIB, pSubsetOverride->ib_format, 0);
+ m_pTexDiffuseVariable->SetResource(m_pWhiteTextureSRV);
+ D3DXVECTOR4 diffuse = D3DXVECTOR4(100,100,100,100);
+ m_pDiffuseColorVariable->SetFloatVector((FLOAT*)&diffuse);
+ pTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ if(wireframe)
+ m_pWireframeOverrideTechnique->GetPassByIndex(0)->Apply(0,pDC);
+ pDC->DrawIndexed(pSubsetOverride->index_count, 0, 0);
+ } else {
+ pDC->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
+ pDC->IASetIndexBuffer( mesh.GetIB11(0), mesh.GetIBFormat11(0), 0 );
+ pTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ if(wireframe)
+ m_pWireframeOverrideTechnique->GetPassByIndex(0)->Apply(0,pDC);
+ for (UINT subset = 0; subset < mesh.GetNumSubsets(0); ++subset)
+ {
+ SDKMESH_SUBSET* pSubset = mesh.GetSubset( 0, subset );
+
+ if (depthOnly == false) // TODO: Currently don't support alpha-tested materials
+ {
+ SDKMESH_MATERIAL* pMat = mesh.GetMaterial(pSubset->MaterialID);
+
+ m_pTexDiffuseVariable->SetResource(pMat->pDiffuseRV11);// ? pMat->pDiffuseRV11 : m_pWhiteTextureSRV);
+
+ D3DXVECTOR4 diffuse = pMat->Diffuse;
+ diffuse.x = powf(diffuse.x,m_DiffuseGamma);//*1.9f;
+ diffuse.y = powf(diffuse.y,m_DiffuseGamma);//*1.9f;
+ diffuse.z = powf(diffuse.z,m_DiffuseGamma);//*1.9f;
+ // de-saturating the diffuse color a bit
+ D3DXVECTOR4 LuminanceWeights = D3DXVECTOR4(0.299f,0.587f,0.114f, 0.0f);
+ float Luminance = D3DXVec4Dot(&diffuse,&LuminanceWeights);
+ D3DXVECTOR4 LuminanceVec = D3DXVECTOR4(Luminance,Luminance,Luminance,1.0f);
+ D3DXVec4Lerp(&diffuse,&diffuse,&LuminanceVec,0.7f);
+
+ m_pDiffuseColorVariable->SetFloatVector((FLOAT*)&diffuse);
+
+ // HACK to render the hull with no backface culling but the rest with backface
+ if(pSubset->MaterialID != 0)
+ pTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ else
+ pTechnique->GetPassByIndex(1)->Apply(0, pDC);
+
+ if(wireframe)
+ m_pWireframeOverrideTechnique->GetPassByIndex(0)->Apply(0,pDC);
+ }
+
+ pDC->DrawIndexed( (UINT)pSubset->IndexCount, (UINT)pSubset->IndexStart, (UINT)pSubset->VertexStart );
+ }
+ }
+}
+
+void OceanVessel::renderVesselToScene( ID3D11DeviceContext* pDC,
+ const D3DXMATRIX& matView,
+ const D3DXMATRIX& matProj,
+ const OceanEnvironment& ocean_env,
+ const OceanVesselSubset* pSubsetOverride,
+ bool wireframe
+ )
+{
+ D3DXMATRIX matLocalToView = m_pDynamicState->m_LocalToWorld * matView;
+
+ // View-proj
+ D3DXMATRIX matW = m_MeshToLocal * m_pDynamicState->m_LocalToWorld;
+ D3DXMATRIX matWV = m_MeshToLocal * matLocalToView;
+ D3DXMATRIX matWVP = matWV * matProj;
+ m_pMatWorldViewProjVariable->SetMatrix((FLOAT*)&matWVP);
+ m_pMatWorldVariable->SetMatrix((FLOAT*)&matW);
+ m_pMatWorldViewVariable->SetMatrix((FLOAT*)&matWV);
+
+ // Global lighting
+ m_pLightDirectionVariable->SetFloatVector((FLOAT*)&ocean_env.main_light_direction);
+ m_pLightColorVariable->SetFloatVector((FLOAT*)&ocean_env.main_light_color);
+ m_pAmbientColorVariable->SetFloatVector((FLOAT*)&ocean_env.sky_color);
+
+ // Spot lights - transform to view space
+ D3DXMATRIX matSpotlightsToView = ocean_env.spotlights_to_world_matrix * matView;
+ D3DXMATRIX matViewToSpotlights;
+ D3DXMatrixInverse(&matViewToSpotlights,NULL,&matSpotlightsToView);
+ D3DXVECTOR4 spotlight_position[MaxNumSpotlights];
+ D3DXVECTOR4 spotlight_axis_and_cos_angle[MaxNumSpotlights];
+ D3DXVECTOR4 spotlight_color[MaxNumSpotlights];
+ int lightsNum = 0;
+
+ D3DXVec4TransformArray(spotlight_position,sizeof(spotlight_position[0]),ocean_env.spotlight_position,sizeof(ocean_env.spotlight_position[0]),&matSpotlightsToView,MaxNumSpotlights);
+ D3DXVec3TransformNormalArray((D3DXVECTOR3*)spotlight_axis_and_cos_angle,sizeof(spotlight_axis_and_cos_angle[0]),(D3DXVECTOR3*)ocean_env.spotlight_axis_and_cos_angle,sizeof(ocean_env.spotlight_axis_and_cos_angle[0]),&matSpotlightsToView,MaxNumSpotlights);
+
+ for(int i=0; i!=ocean_env.activeLightsNum; ++i) {
+
+ if (ocean_env.lightFilter != -1 && ocean_env.objectID[i] != ocean_env.lightFilter) continue;
+
+ spotlight_position[lightsNum] = spotlight_position[i];
+ spotlight_axis_and_cos_angle[lightsNum] = spotlight_axis_and_cos_angle[i];
+ spotlight_color[lightsNum] = ocean_env.spotlight_color[i];
+ spotlight_axis_and_cos_angle[lightsNum].w = ocean_env.spotlight_axis_and_cos_angle[i].w;
+
+#if ENABLE_SHADOWS
+ D3DXMATRIX spotlight_shadow_matrix = matViewToSpotlights * ocean_env.spotlight_shadow_matrix[i];
+ m_pSpotlightShadowMatrixVar->SetMatrixArray((float*)&spotlight_shadow_matrix, lightsNum, 1);
+ m_pSpotlightShadowResourceVar->SetResourceArray((ID3D11ShaderResourceView**)&ocean_env.spotlight_shadow_resource[i], lightsNum, 1);
+#endif
+
+ ++lightsNum;
+ }
+
+ m_pSpotlightNumVariable->SetInt(lightsNum);
+ m_pSpotlightPositionVariable->SetFloatVectorArray((FLOAT*)spotlight_position,0,lightsNum);
+ m_pSpotLightAxisAndCosAngleVariable->SetFloatVectorArray((FLOAT*)spotlight_axis_and_cos_angle,0,lightsNum);
+ m_pSpotlightColorVariable->SetFloatVectorArray((FLOAT*)spotlight_color,0,lightsNum);
+
+ // Lightnings
+ m_pLightningColorVariable->SetFloatVector((FLOAT*)&ocean_env.lightning_light_intensity);
+ m_pLightningPositionVariable->SetFloatVector((FLOAT*)&ocean_env.lightning_light_position);
+
+ // Fog
+ m_pFogExponentVariable->SetFloat(ocean_env.fog_exponent*ocean_env.cloud_factor);
+
+ renderVessel(pDC, m_pRenderToSceneTechnique, pSubsetOverride, wireframe, false);
+
+ // Release input refs
+ ID3D11ShaderResourceView* pNullSRVs[MaxNumSpotlights];
+ memset(pNullSRVs,0,sizeof(pNullSRVs));
+ m_pSpotlightShadowResourceVar->SetResourceArray(pNullSRVs,0,MaxNumSpotlights);
+ m_pRenderToSceneTechnique->GetPassByIndex(0)->Apply(0,pDC);
+}
+
+
+void OceanVessel::renderReflectedVesselToScene( ID3D11DeviceContext* pDC,
+ const CBaseCamera& camera,
+ const D3DXPLANE& world_reflection_plane,
+ const OceanEnvironment& ocean_env
+ )
+{
+ D3DXMATRIX matView = *camera.GetViewMatrix();
+ D3DXMATRIX matProj = *camera.GetProjMatrix();
+
+ D3DXMATRIX matReflection;
+ D3DXMatrixReflect(&matReflection, &world_reflection_plane);
+
+ matView = matReflection*matView;
+
+ renderVesselToScene(pDC, matView, matProj, ocean_env, NULL, false);
+}
+
+void OceanVessel::updateVesselShadows( ID3D11DeviceContext* pDC
+ )
+{
+#if ENABLE_SHADOWS
+ D3D11_VIEWPORT original_viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ UINT num_original_viewports = sizeof(original_viewports)/sizeof(original_viewports[0]);
+ pDC->RSGetViewports( &num_original_viewports, original_viewports);
+
+ CD3D11_VIEWPORT viewport(0.0f, 0.0f, (float)kSpotlightShadowResolution, (float)kSpotlightShadowResolution);
+ pDC->RSSetViewports(1, &viewport);
+
+ size_t lightsNum = m_Spotlights.size();
+ for (size_t i=0; i<lightsNum; ++i)
+ {
+ if (m_SpotlightsShadows[i].m_Dirty == false)
+ {
+ continue;
+ }
+
+ const Spotlight& sl = m_Spotlights[i];
+
+ D3DXMATRIX matView;
+ D3DXMATRIX matProj;
+
+ D3DXVECTOR3 lightPosWorldSpace;
+ D3DXVec3TransformCoord(&lightPosWorldSpace, (D3DXVECTOR3*)&sl.position, &m_pDynamicState->m_LocalToWorld);
+
+ D3DXVECTOR3 lightAxisWorldSpace;
+ D3DXVec3TransformNormal(&lightAxisWorldSpace, (D3DXVECTOR3*)&sl.axis, &m_pDynamicState->m_LocalToWorld);
+
+ D3DXVECTOR3 lookAt = (D3DXVECTOR3&)sl.position + (D3DXVECTOR3&)sl.axis;
+ D3DXVECTOR3 up(1.0f, 0.0, 1.0f);
+ D3DXMatrixLookAtLH(&matView, (D3DXVECTOR3*)&sl.position, &lookAt, &up);
+
+ D3DXMatrixPerspectiveFovLH(&matProj, m_Spotlights[i].beam_angle, 1.0f, kSpotlightClipNear, kSpotlightClipFar);
+
+ D3DXMATRIX matW = m_MeshToLocal;
+ D3DXMATRIX matWV = matW * matView;
+ D3DXMATRIX matWVP = matWV * matProj;
+ m_pMatWorldViewProjVariable->SetMatrix((FLOAT*)&matWVP);
+
+ m_SpotlightsShadows[i].m_ViewProjMatrix = matView * matProj;
+
+ pDC->ClearDepthStencilView(m_SpotlightsShadows[i].m_pDSV, D3D11_CLEAR_DEPTH, 1.0f, 0);
+ pDC->OMSetRenderTargets(0, NULL, m_SpotlightsShadows[i].m_pDSV);
+
+ renderVessel(pDC, m_pRenderToShadowMapTechnique, NULL, false, true);
+
+ m_SpotlightsShadows[i].m_Dirty = false;
+ }
+
+ pDC->RSSetViewports(num_original_viewports, original_viewports);
+
+ pDC->OMSetRenderTargets(0, NULL, NULL);
+#endif
+}
+
+void OceanVesselDynamicState::setPosition(D3DXVECTOR2 pos)
+{
+ m_Position = pos;
+ ResetDynamicState();
+}
+
+OceanVesselDynamicState::OceanVesselDynamicState()
+{
+ m_bFirstUpdate = true;
+}
+
+void OceanVesselDynamicState::setHeading(D3DXVECTOR2 heading, FLOAT speed)
+{
+ m_NominalHeading = heading;
+ m_Speed = speed;
+ D3DXVec2Normalize(&m_NominalHeading, &m_NominalHeading);
+ ResetDynamicState();
+}
+
+void OceanVessel::updateVesselMotion(ID3D11DeviceContext* pDC, GFSDK_WaveWorks_SimulationHandle hSim, FLOAT sea_level, FLOAT time_delta, FLOAT water_scale)
+{
+ m_pDynamicState->m_Position += time_delta * m_pDynamicState->m_Speed * m_pDynamicState->m_NominalHeading;
+
+ const FLOAT actual_heading_angle = atan2f(m_pDynamicState->m_NominalHeading.x, m_pDynamicState->m_NominalHeading.y) + m_pDynamicState->m_Yaw;
+ D3DXVECTOR2 actual_heading;
+ actual_heading.x = sinf(actual_heading_angle);
+ actual_heading.y = cosf(actual_heading_angle);
+ const D3DXVECTOR2 heading_perp = D3DXVECTOR2(actual_heading.y, -actual_heading.x);
+
+ // Use the displacement of our current position for establishing a footprint
+ gfsdk_float4 nominal_displacement;
+ GFSDK_WaveWorks_Simulation_GetDisplacements(hSim, (gfsdk_float2*)&m_pDynamicState->m_Position, &nominal_displacement, 1);
+ gfsdk_float2 UVToWorldRotation;
+ UVToWorldRotation.x = actual_heading.y;
+ UVToWorldRotation.y = actual_heading.x;
+ gfsdk_float2 worldCentroid;
+ worldCentroid.x = m_pDynamicState->m_Position.x + nominal_displacement.x;
+ worldCentroid.y = m_pDynamicState->m_Position.y + nominal_displacement.y;
+ m_pSurfaceHeights->updateHeights(pDC,hSim,UVToWorldRotation,worldCentroid);
+
+ // Force a sensor update on first update (for subsequent updates, we will re-use the trailing update next frame)
+ if(m_bFirstSensorUpdate) {
+ if(m_pDynamicState->m_bFirstUpdate) {
+
+ // m_pDynamicState->m_LocalToWorld has yet to be updated so lookup the displacement of the origin and use a reasonable estimate
+
+ gfsdk_float2 lookup_coord;
+ lookup_coord.x = m_pDynamicState->m_Position.x;
+ lookup_coord.y = m_pDynamicState->m_Position.y;
+
+ gfsdk_float4 nominal_displacement;
+ m_pSurfaceHeights->getDisplacements(&lookup_coord,&nominal_displacement,1);
+
+ D3DXMATRIX mat_roll;
+ D3DXMatrixRotationZ(&mat_roll, m_pDynamicState->m_Roll);
+
+ D3DXMATRIX mat_pitch;
+ D3DXMatrixRotationX(&mat_pitch, -m_pDynamicState->m_Pitch);
+
+ D3DXMATRIX mat_heading;
+ const FLOAT heading = atan2f(m_pDynamicState->m_NominalHeading.x, m_pDynamicState->m_NominalHeading.y);
+ D3DXMatrixRotationY(&mat_heading, heading + m_pDynamicState->m_Yaw);
+
+ m_pDynamicState->m_LocalToWorld = mat_roll * mat_pitch * mat_heading;
+
+ m_pDynamicState->m_LocalToWorld._41 = m_pDynamicState->m_Position.x + nominal_displacement.x;
+ m_pDynamicState->m_LocalToWorld._42 = sea_level + m_pDynamicState->m_Height;
+ m_pDynamicState->m_LocalToWorld._43 = m_pDynamicState->m_Position.y + nominal_displacement.y;
+
+ m_pHullSensors->update(m_pSurfaceHeights,m_pDynamicState->m_LocalToWorld);
+ m_pDynamicState->m_bFirstUpdate = false;
+
+ } else {
+
+ // m_pDynamicState->m_LocalToWorld is valid
+ m_pHullSensors->update(m_pSurfaceHeights,m_pDynamicState->m_LocalToWorld);
+ }
+ m_bFirstSensorUpdate = false;
+ }
+
+ // Caculate the means
+ D3DXVECTOR4 mean_displacement(0.f,0.f,0.f,0.f);
+ float mean_displaced_head = 0.f;
+ float mean_pitch_moment = 0.f;
+ float mean_roll_moment = 0.f;
+ const int num_samples = m_pHullSensors->getNumSensors();
+ float immersed_ratio = 0.f;
+ {
+ const D3DXVECTOR4* pDisplacements = m_pHullSensors->getDisplacements();
+ const D3DXVECTOR3* pWorldSensorPositions = m_pHullSensors->getWorldSensorPositions();
+ const D3DXVECTOR3* pWorldSensorNormals = m_pHullSensors->getWorldSensorNormals();
+ const D3DXVECTOR3* pSensorPositions = m_pHullSensors->getSensorPositions();
+ for(int sample_ix = 0; sample_ix != num_samples; ++sample_ix)
+ {
+ mean_displacement += pDisplacements[sample_ix];
+
+ // Only immersed areas of the hull contribute to physics
+ float water_depth_at_sample = pDisplacements[sample_ix].z - pWorldSensorPositions[sample_ix].z;
+ if(water_depth_at_sample > 0.f)
+ {
+ float upward_head = water_depth_at_sample * -pWorldSensorNormals[sample_ix].z; // Assume that non-upward pressure cancel out
+ mean_displaced_head += upward_head;
+ mean_pitch_moment += upward_head * pSensorPositions[sample_ix].z;
+ mean_roll_moment += upward_head * pSensorPositions[sample_ix].x;
+ immersed_ratio += 1.f;
+ }
+ }
+ }
+ mean_displacement *= water_scale/float(num_samples);
+ mean_displaced_head *= water_scale/float(num_samples);
+ mean_pitch_moment *= (water_scale*water_scale)/float(num_samples);
+ mean_roll_moment *= (water_scale*water_scale)/float(num_samples);
+ immersed_ratio /= float(num_samples);
+
+ // Directly sample displacement at bow and stern
+ D3DXVECTOR3 bowPos;
+ bowPos.x = 0.f;
+ bowPos.y = 0.f;
+ bowPos.z = 0.5f * m_Length;
+ D3DXVECTOR3 sternPos = -bowPos;
+ D3DXVec3TransformCoord(&bowPos,&bowPos,&m_pDynamicState->m_LocalToWorld);
+ D3DXVec3TransformCoord(&sternPos,&sternPos,&m_pDynamicState->m_LocalToWorld);
+
+ gfsdk_float2 lookup_coords[2];
+ lookup_coords[0].x = bowPos.x;
+ lookup_coords[0].y = bowPos.z;
+ lookup_coords[1].x = sternPos.x;
+ lookup_coords[1].y = sternPos.z;
+
+ gfsdk_float2 projected_stern_to_bow;
+ projected_stern_to_bow.x = bowPos.x - sternPos.x;
+ projected_stern_to_bow.y = bowPos.y - sternPos.y;
+ const float projected_length = sqrtf(projected_stern_to_bow.x*projected_stern_to_bow.x + projected_stern_to_bow.y*projected_stern_to_bow.y);
+
+ gfsdk_float4 bow_stern_disps[2];
+ m_pSurfaceHeights->getDisplacements(lookup_coords,bow_stern_disps,sizeof(bow_stern_disps)/sizeof(bow_stern_disps[0]));
+
+ D3DXVECTOR2 sea_yaw_vector = NvToDX(bow_stern_disps[0]) - NvToDX(bow_stern_disps[1]);
+ FLOAT sea_yaw_angle = D3DXVec2Dot(&heading_perp,&sea_yaw_vector)/projected_length;
+ FLOAT sea_yaw_rate = (sea_yaw_angle - m_pDynamicState->m_PrevSeaYaw)/time_delta;
+ m_pDynamicState->m_PrevSeaYaw = sea_yaw_angle;
+
+ if(m_pDynamicState->m_DynamicsCountdown) {
+ // Snap to surface on first few updates
+ m_pDynamicState->m_Height = m_InitialHeight;
+ m_pDynamicState->m_Pitch = m_InitialPitch;
+ m_pDynamicState->m_Roll = 0.f;
+ --m_pDynamicState->m_DynamicsCountdown;
+ } else {
+ // Run pseudo-dynamics
+ const int num_steps = int(ceilf(time_delta/kMaxSimulationTimeStep));
+ const FLOAT time_step = time_delta/float(num_steps);
+ for(int i = 0; i != num_steps; ++i)
+ {
+ // Height
+ const FLOAT buoyancy_accel = (m_BuoyantArea * mean_displaced_head * kDensityOfWater * kAccelerationDueToGravity)/m_Mass;
+ const FLOAT drag_accel = (m_HeightDrag * m_pDynamicState->m_HeightRate * immersed_ratio);
+ const FLOAT height_accel = (buoyancy_accel - kAccelerationDueToGravity - drag_accel);
+ m_pDynamicState->m_HeightRate += height_accel * time_step;
+ m_pDynamicState->m_Height += m_pDynamicState->m_HeightRate * time_step;
+
+ // Pitch
+ const FLOAT pitch_COM_accel = m_LongitudinalCOM * cosf(m_pDynamicState->m_Pitch) * m_Mass * kAccelerationDueToGravity/m_PitchInertia;
+ const FLOAT pitch_buoyancy_accel = (m_BuoyantArea * mean_pitch_moment * kDensityOfWater * kAccelerationDueToGravity)/m_PitchInertia;
+ const FLOAT pitch_drag_accel = (m_PitchDrag * m_pDynamicState->m_PitchRate * immersed_ratio);
+ const FLOAT pitch_accel = (pitch_buoyancy_accel - pitch_drag_accel - pitch_COM_accel);
+ m_pDynamicState->m_PitchRate += pitch_accel * time_step;
+ m_pDynamicState->m_Pitch += m_pDynamicState->m_PitchRate * time_step;
+
+ // Roll
+ const FLOAT roll_buoyancy_accel = (m_BuoyantArea * mean_roll_moment * kDensityOfWater * kAccelerationDueToGravity)/m_RollInertia;
+ const FLOAT roll_righting_accel = 2.f * sinf(m_pDynamicState->m_Roll) * m_MetacentricHeight * m_Mass * kAccelerationDueToGravity/m_RollInertia;
+ const FLOAT roll_drag_accel = (m_RollDrag * m_pDynamicState->m_RollRate * immersed_ratio);
+ const FLOAT roll_accel = (roll_buoyancy_accel - roll_drag_accel - roll_righting_accel);
+ m_pDynamicState->m_RollRate += roll_accel * time_step;
+ m_pDynamicState->m_Roll += m_pDynamicState->m_RollRate * time_step;
+
+ // Yaw
+ const FLOAT yaw_accel = immersed_ratio * (m_YawDrag * (sea_yaw_rate - m_pDynamicState->m_YawRate) + m_YawCoefficient * (sea_yaw_angle - m_pDynamicState->m_Yaw));
+ m_pDynamicState->m_YawRate += yaw_accel * time_step;
+ m_pDynamicState->m_Yaw += m_pDynamicState->m_YawRate * time_step;
+
+ // Clamp pitch to {-pi/2,pi/2}
+ if(m_pDynamicState->m_Pitch > 0.5f * D3DX_PI)
+ m_pDynamicState->m_Pitch = 0.5f * D3DX_PI;
+ if(m_pDynamicState->m_Pitch < -0.5f * D3DX_PI)
+ m_pDynamicState->m_Pitch = -0.5f * D3DX_PI;
+ }
+ }
+
+ D3DXMATRIX mat_roll;
+ D3DXMatrixRotationZ(&mat_roll, m_pDynamicState->m_Roll);
+
+ D3DXMATRIX mat_pitch;
+ D3DXMatrixRotationX(&mat_pitch, -m_pDynamicState->m_Pitch);
+
+ D3DXMATRIX mat_heading;
+ const FLOAT heading = atan2f(m_pDynamicState->m_NominalHeading.x, m_pDynamicState->m_NominalHeading.y);
+ D3DXMatrixRotationY(&mat_heading, heading + m_pDynamicState->m_Yaw);
+
+ m_pDynamicState->m_LocalToWorld = mat_roll * mat_pitch * mat_heading;
+
+ m_pDynamicState->m_LocalToWorld._41 = m_pDynamicState->m_Position.x + mean_displacement.x;
+ m_pDynamicState->m_LocalToWorld._42 = sea_level + m_pDynamicState->m_Height;
+ m_pDynamicState->m_LocalToWorld._43 = m_pDynamicState->m_Position.y + mean_displacement.y;
+
+ // We want damped movement for camera
+ D3DXMATRIX mat_local_to_world_damped;
+ D3DXMatrixRotationZ(&mat_roll, m_pDynamicState->m_Roll*0.5f);
+ D3DXMatrixRotationX(&mat_pitch, -m_pDynamicState->m_Pitch*0.5f);
+ D3DXMatrixRotationY(&mat_heading, heading + m_pDynamicState->m_Yaw*0.5f);
+ mat_local_to_world_damped = mat_roll * mat_pitch * mat_heading;
+ mat_local_to_world_damped._41 = m_pDynamicState->m_Position.x + mean_displacement.x;
+ mat_local_to_world_damped._42 = sea_level + m_pDynamicState->m_Height;
+ mat_local_to_world_damped._43 = m_pDynamicState->m_Position.y + mean_displacement.y;
+ m_pDynamicState->m_CameraToWorld = m_CameraToLocal*mat_local_to_world_damped;
+
+ // We do not want the wake to yaw around, hence
+ D3DXMatrixRotationY(&m_pDynamicState->m_WakeToWorld, heading + 3.141592f*1.5f);
+ m_pDynamicState->m_WakeToWorld._41 = m_pDynamicState->m_Position.x + mean_displacement.x;
+ m_pDynamicState->m_WakeToWorld._42 = sea_level + m_pDynamicState->m_Height;
+ m_pDynamicState->m_WakeToWorld._43 = m_pDynamicState->m_Position.y + mean_displacement.y;
+
+ // Ensure sensors are bang-up-to-date
+ m_pHullSensors->update(m_pSurfaceHeights,m_pDynamicState->m_LocalToWorld);
+}
+
+void OceanVesselDynamicState::ResetDynamicState()
+{
+ m_Pitch = 0.f;
+ m_PitchRate = 0.f;
+ m_Roll = 0.f;
+ m_RollRate = 0.f;
+ m_Yaw = 0.f;
+ m_YawRate = 0.f;
+ m_PrevSeaYaw = 0.f;
+ m_Height = 0.f;
+ m_HeightRate = 0.f;
+ m_DynamicsCountdown = 3;
+ m_bFirstUpdate = true;
+}
+
+void OceanVessel::renderVesselToHullProfile(ID3D11DeviceContext* pDC, OceanHullProfile& profile)
+{
+ OceanHullProfile result(m_pHullProfileSRV[1]);
+
+ // Calculate transforms etc. - we render from below, world-aligned
+
+ // Transform calc - 1/ transform the bounds based on current mesh->world
+ D3DXVECTOR3 xEdge(2.f*m_bbExtents.x,0.f,0.f);
+ D3DXVECTOR3 yEdge(0.f,2.f*m_bbExtents.y,0.f);
+ D3DXVECTOR3 zEdge(0.f,0.f,2.f*m_bbExtents.z);
+ D3DXVECTOR3 bbCorners[8];
+ bbCorners[0] = m_bbCentre - m_bbExtents;
+ bbCorners[1] = bbCorners[0] + xEdge;
+ bbCorners[2] = bbCorners[0] + yEdge;
+ bbCorners[3] = bbCorners[1] + yEdge;
+ bbCorners[4] = bbCorners[0] + zEdge;
+ bbCorners[5] = bbCorners[1] + zEdge;
+ bbCorners[6] = bbCorners[2] + zEdge;
+ bbCorners[7] = bbCorners[3] + zEdge;
+
+ D3DXMATRIX matW = m_MeshToLocal * m_pDynamicState->m_LocalToWorld;
+ D3DXVec3TransformCoordArray(bbCorners, sizeof(bbCorners[0]), bbCorners, sizeof(bbCorners[0]), &matW, sizeof(bbCorners)/sizeof(bbCorners[0]));
+
+ // Transform calc - 2/ calculate the world bounds
+ D3DXVECTOR3 minCorner = bbCorners[0];
+ D3DXVECTOR3 maxCorner = minCorner;
+ for(int i = 1; i != sizeof(bbCorners)/sizeof(bbCorners[0]); ++i) {
+ minCorner = D3DXVec3Min(minCorner,bbCorners[i]);
+ maxCorner = D3DXVec3Max(maxCorner,bbCorners[i]);
+ }
+
+ // Transform calc - 3/inflate the world bounds so that the x and y footprints are equal
+ FLOAT w = maxCorner.x - minCorner.x;
+ FLOAT l = maxCorner.z - minCorner.z;
+ if(w > l) {
+ minCorner.z -= 0.5f*(w-l);
+ maxCorner.z += 0.5f*(w-l);
+ l = w;
+ } else {
+ minCorner.x -= 0.5f*(l-w);
+ maxCorner.x += 0.5f*(l-w);
+ w = l;
+ }
+
+ // Transform calc - 4/ calculate hull profile transforms
+ result.m_ProfileToWorldHeightScale = maxCorner.y - minCorner.y;
+ result.m_ProfileToWorldHeightOffset = minCorner.y;
+ result.m_WorldToProfileCoordsScale = D3DXVECTOR2(1.f/(maxCorner.x-minCorner.x),1.f/(maxCorner.z-minCorner.z));
+ result.m_WorldToProfileCoordsOffset = D3DXVECTOR2(result.m_WorldToProfileCoordsScale.x * -minCorner.x, result.m_WorldToProfileCoordsScale.y * -minCorner.z);
+ result.m_TexelSizeInWorldSpace = w/float(m_HullProfileTextureWH);
+
+ // Transform calc - 5/ set up view-proj for rendering into the hull profile
+ D3DXMATRIX matVP;
+ memset(matVP,0,sizeof(matVP));
+ matVP._11 = 2.f/(maxCorner.x-minCorner.x); // x out from x
+ matVP._32 = 2.f/(minCorner.z-maxCorner.z); // y out from z
+ matVP._23 = 1.f/(maxCorner.y-minCorner.y); // z out from y
+ matVP._44 = 1.f;
+ matVP._41 = 1.f - matVP._11 * maxCorner.x;
+ matVP._42 = -1.f - matVP._32 * maxCorner.z;
+ matVP._43 = 1.f - matVP._23 * maxCorner.y;
+
+ // Set up matrices for rendering
+ D3DXMATRIX matWVP = matW* matVP;
+ m_pMatWorldViewProjVariable->SetMatrix((FLOAT*)&matWVP);
+ m_pMatWorldVariable->SetMatrix((FLOAT*)&matW);
+
+ // Save rt setup to restore shortly...
+ D3D11_VIEWPORT original_viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ UINT num_original_viewports = sizeof(original_viewports)/sizeof(original_viewports[0]);
+ pDC->RSGetViewports( &num_original_viewports, original_viewports);
+ ID3D11RenderTargetView* original_rtvs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
+ ID3D11DepthStencilView* original_dsv = NULL;
+ UINT num_original_rtvs = sizeof(original_rtvs)/sizeof(original_rtvs[0]);
+ pDC->OMGetRenderTargets( num_original_rtvs, original_rtvs, &original_dsv );
+
+ // Do the rendering
+ pDC->ClearDepthStencilView(m_pHullProfileDSV, D3D11_CLEAR_DEPTH, 1.f, 0);
+ const FLOAT rtvClearColor[4] = { 1.f, 0.f, 0.f, 0.f };
+ pDC->ClearRenderTargetView(m_pHullProfileRTV[0], rtvClearColor);
+ pDC->OMSetRenderTargets( 1, &m_pHullProfileRTV[0], m_pHullProfileDSV);
+
+ D3D11_VIEWPORT vp;
+ vp.TopLeftX = vp.TopLeftY = 0.f;
+ vp.Height = vp.Width = FLOAT(m_HullProfileTextureWH);
+ vp.MinDepth = 0.f;
+ vp.MaxDepth = 1.f;
+ pDC->RSSetViewports(1, &vp);
+
+ renderVessel(pDC, m_pRenderToHullProfileTechnique, NULL, false, false);
+
+ // Fix up cracks
+ pDC->OMSetRenderTargets( 1, &m_pHullProfileRTV[1], NULL);
+ m_pTexDiffuseVariable->SetResource(m_pHullProfileSRV[0]);
+ m_pRenderQuadToCrackFixTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ pDC->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ pDC->IASetInputLayout(NULL);
+ pDC->Draw(4,0);
+ m_pTexDiffuseVariable->SetResource(NULL);
+ m_pRenderQuadToCrackFixTechnique->GetPassByIndex(0)->Apply(0, pDC);
+
+ // Restore original state
+ pDC->OMSetRenderTargets(num_original_rtvs, original_rtvs, original_dsv);
+ pDC->RSSetViewports(num_original_viewports, original_viewports);
+ SAFE_RELEASE(original_dsv);
+ for(UINT i = 0; i != num_original_rtvs; ++i) {
+ SAFE_RELEASE(original_rtvs[i]);
+ }
+
+ // Generate mips
+ pDC->GenerateMips(m_pHullProfileSRV[1]);
+
+ // Set result
+ profile = result;
+}
+
+void OceanVessel::renderTextureToUI(ID3D11DeviceContext* pDC, ID3D11ShaderResourceView* pSRV)
+{
+ m_pTexDiffuseVariable->SetResource(pSRV);
+ m_pRenderQuadToUITechnique->GetPassByIndex(0)->Apply(0, pDC);
+
+ pDC->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ pDC->IASetInputLayout(NULL);
+ pDC->Draw(4,0);
+
+ m_pTexDiffuseVariable->SetResource(NULL);
+ m_pRenderQuadToUITechnique->GetPassByIndex(0)->Apply(0, pDC);
+}
+
+void OceanVessel::renderHullProfileInUI(ID3D11DeviceContext* pDC)
+{
+ renderTextureToUI(pDC, m_pHullProfileSRV[1]);
+}
+
+void OceanVessel::updateVesselLightsInEnv(OceanEnvironment& env, const D3DXMATRIX& matView, float lighting_mult, int objectID)
+{
+ const int num_lights_to_update = min(int(m_Spotlights.size()), MaxNumSpotlights - env.activeLightsNum);
+ for(int i = 0; i != num_lights_to_update; ++i) {
+ const Spotlight& sl = m_Spotlights[i];
+ env.spotlight_position[env.activeLightsNum] = D3DXVECTOR4(sl.position,1.f);
+
+ const float cosHalfBeamAngle = cosf(0.5f * sl.beam_angle);
+ env.spotlight_axis_and_cos_angle[env.activeLightsNum] = D3DXVECTOR4(sl.axis,cosHalfBeamAngle);
+
+ env.spotlight_color[env.activeLightsNum] = D3DXVECTOR4(D3DXVECTOR3(sl.color) * lighting_mult,1.f);
+#if ENABLE_SHADOWS
+ env.spotlight_shadow_matrix[env.activeLightsNum] = m_SpotlightsShadows[i].m_ViewProjMatrix;
+ env.spotlight_shadow_resource[env.activeLightsNum] = m_SpotlightsShadows[i].m_pSRV;
+#endif
+
+ env.objectID[env.activeLightsNum] = objectID;
+ ++env.activeLightsNum;
+ }
+
+ env.spotlights_to_world_matrix = m_pDynamicState->m_LocalToWorld;
+}
+
+namespace {
+
+ bool IsKwd(const char* str, const char* kwd) {
+ const int kwd_len = strlen(kwd);
+ return 0 == strncmp(kwd,str,kwd_len);
+ }
+
+ const char* GetValString(const char* str, const char* kwd) {
+ const int kwd_len = strlen(kwd);
+
+ if(strncmp(kwd,str,kwd_len))
+ return NULL;
+
+ const char* curr = str + kwd_len;
+
+ // Next char *must* be space
+ if(!isspace(*curr))
+ return NULL;
+
+ // Skip intervening wspc
+ while(*curr && isspace(*curr))
+ ++curr;
+
+ if(!*curr)
+ return NULL;
+
+ return curr;
+ }
+
+ bool ReadFloat(const char* str, const char* kwd, float& value) {
+
+ const char* val_string = GetValString(str,kwd);
+ if(NULL == val_string)
+ return false;
+
+ value = (float)atof(val_string);
+
+ return true;
+ }
+
+ bool ReadInt(const char* str, const char* kwd, int& value) {
+
+ const char* val_string = GetValString(str,kwd);
+ if(NULL == val_string)
+ return false;
+
+ value = atoi(val_string);
+
+ return true;
+ }
+
+ bool ReadString(const char* str, const char* kwd, LPTSTR& value) {
+
+ const char* val_string = GetValString(str,kwd);
+ if(NULL == val_string)
+ return false;
+
+ int l = MultiByteToWideChar(CP_ACP, 0, val_string, -1, NULL, 0);
+ delete [] value;
+ value = new TCHAR[l];
+ MultiByteToWideChar(CP_ACP, 0, val_string, -1, value, l);
+
+ return true;
+ }
+}
+
+OceanVessel::Spotlight* OceanVessel::processSpotlightConfigLine(const char* line, Spotlight* pSpot)
+{
+ const char* curr = line;
+
+ // Skip leading wspc
+ while(*curr && isspace(*curr))
+ ++curr;
+
+ // Skip empty lines
+ if(!*curr)
+ return pSpot;
+
+ if(ReadFloat(curr,"x",pSpot->position.x))
+ return pSpot;
+ if(ReadFloat(curr,"y",pSpot->position.y))
+ return pSpot;
+ if(ReadFloat(curr,"z",pSpot->position.z))
+ return pSpot;
+
+ if(ReadFloat(curr,"axis-x",pSpot->axis.x))
+ return pSpot;
+ if(ReadFloat(curr,"axis-y",pSpot->axis.y))
+ return pSpot;
+ if(ReadFloat(curr,"axis-z",pSpot->axis.z))
+ return pSpot;
+
+ if(ReadFloat(curr,"r",pSpot->color.x))
+ return pSpot;
+ if(ReadFloat(curr,"g",pSpot->color.y))
+ return pSpot;
+ if(ReadFloat(curr,"b",pSpot->color.z))
+ return pSpot;
+
+ if(ReadFloat(curr,"beam_angle",pSpot->beam_angle)) {
+ pSpot->beam_angle *= D3DX_PI/180.f; // Convert deg to rad
+ return pSpot;
+ }
+
+ if(IsKwd(curr,"EndSpotlight")) {
+ D3DXVec3Normalize((D3DXVECTOR3*)&pSpot->axis,(D3DXVECTOR3*)&pSpot->axis);
+ return NULL;
+ }
+
+ return pSpot;
+}
+
+OceanVessel::Spotlight* OceanVessel::processGlobalConfigLine(const char* line)
+{
+ const char* curr = line;
+
+ // Skip leading wspc
+ while(*curr && isspace(*curr))
+ ++curr;
+
+ // Skip empty lines
+ if(!*curr)
+ return NULL;
+
+ if(ReadFloat(curr,"Length",m_Length))
+ return NULL;
+
+ if(ReadFloat(curr,"CameraHeightAboveWater",m_CameraHeightAboveWater))
+ return NULL;
+
+ if(ReadFloat(curr,"CameraLongitudinalOffset",m_CameraLongitudinalOffset))
+ return NULL;
+
+ if(ReadFloat(curr,"HeightDrag",m_HeightDrag))
+ return NULL;
+
+ if(ReadFloat(curr,"PitchDrag",m_PitchDrag))
+ return NULL;
+
+ if(ReadFloat(curr,"YawDrag",m_YawDrag))
+ return NULL;
+
+ if(ReadFloat(curr,"YawCoefficient",m_YawCoefficient))
+ return NULL;
+
+ if(ReadFloat(curr,"RollDrag",m_RollDrag))
+ return NULL;
+
+ if(ReadFloat(curr,"MetacentricHeight",m_MetacentricHeight))
+ return NULL;
+
+ if(ReadFloat(curr,"MassMult",m_MassMult))
+ return NULL;
+
+ if(ReadFloat(curr,"PitchInertiaMult",m_PitchInertiaMult))
+ return NULL;
+
+ if(ReadFloat(curr,"RollInertiaMult",m_RollInertiaMult))
+ return NULL;
+
+ if(ReadFloat(curr,"InitialPitch",m_InitialPitch))
+ return NULL;
+
+ if(ReadFloat(curr,"InitialHeight",m_InitialHeight))
+ return NULL;
+
+ if(ReadFloat(curr,"LongitudinalCOM",m_LongitudinalCOM))
+ return NULL;
+
+ if(ReadFloat(curr,"DiffuseGamma",m_DiffuseGamma))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeEmitRate",m_SmokeParticleEmitRate))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeEmitMinVelocity",m_SmokeParticleEmitMinVelocity))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeEmitMaxVelocity",m_SmokeParticleEmitMaxVelocity))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeMinBuoyancy",m_SmokeParticleMinBuoyancy))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeMaxBuoyancy",m_SmokeParticleMaxBuoyancy))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeCoolingRate",m_SmokeParticleCoolingRate))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeEmitSpread",m_SmokeParticleEmitSpread))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeParticleBeginSize",m_SmokeParticleBeginSize))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeParticleEndSize",m_SmokeParticleEndSize))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeWindDrag",m_SmokeWindDrag))
+ return NULL;
+
+ if(ReadFloat(curr,"PSMMinCornerX",m_PSMMinCorner.x))
+ return NULL;
+
+ if(ReadFloat(curr,"PSMMinCornerY",m_PSMMinCorner.y))
+ return NULL;
+
+ if(ReadFloat(curr,"PSMMinCornerZ",m_PSMMinCorner.z))
+ return NULL;
+
+ if(ReadFloat(curr,"PSMMaxCornerX",m_PSMMaxCorner.x))
+ return NULL;
+
+ if(ReadFloat(curr,"PSMMaxCornerY",m_PSMMaxCorner.y))
+ return NULL;
+
+ if(ReadFloat(curr,"PSMMaxCornerZ",m_PSMMaxCorner.z))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokePSMBoundsFadeMargin",m_SmokePSMBoundsFadeMargin))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeWindNoiseLevel",m_SmokeWindNoiseLevel))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeWindNoiseSpatialScale",m_SmokeWindNoiseSpatialScale))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeWindNoiseTimeScale",m_SmokeWindNoiseTimeScale))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeShadowOpacity",m_SmokeShadowOpacity))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeTintR",m_SmokeTint.x))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeTintG",m_SmokeTint.y))
+ return NULL;
+
+ if(ReadFloat(curr,"SmokeTintB",m_SmokeTint.z))
+ return NULL;
+
+ if(ReadInt(curr,"PSMRes",m_PSMRes))
+ return NULL;
+
+ if(ReadFloat(curr,"FunnelLongitudinalOffset",m_FunnelLongitudinalOffset))
+ return NULL;
+
+ if(ReadFloat(curr,"FunnelHeightAboveWater",m_FunnelHeightAboveWater))
+ return NULL;
+
+ if(ReadFloat(curr,"FunnelXSize",m_FunnelMouthSize.x))
+ return NULL;
+
+ if(ReadFloat(curr,"FunnelYSize",m_FunnelMouthSize.y))
+ return NULL;
+
+ if(ReadInt(curr,"NumSmokeParticles",m_NumSmokeParticles))
+ return NULL;
+
+ if(ReadInt(curr,"NumSurfaceHeightSamples",m_NumSurfaceHeightSamples))
+ return NULL;
+
+ if(ReadInt(curr,"HullProfileTextureWH",m_HullProfileTextureWH))
+ return NULL;
+
+ if(ReadString(curr,"Mesh",m_MeshFileName))
+ return NULL;
+
+ if(ReadString(curr,"SmokeTexture",m_SmokeTextureFileName))
+ return NULL;
+
+ if(IsKwd(curr,"BeginSpotlight")) {
+ Spotlight new_spotlight;
+ memset(&new_spotlight,0,sizeof(new_spotlight));
+ m_Spotlights.push_back(new_spotlight);
+ return &m_Spotlights.back();
+ }
+
+ return NULL;
+}
+
+HRESULT OceanVessel::parseConfig(LPCTSTR cfg_string)
+{
+ int buffer_size = 256;
+ char* buffer = new char[buffer_size];
+ Spotlight* pCurrSpotlight = NULL;
+ const LPCTSTR cfg_end = cfg_string + _tcslen(cfg_string);
+ for(LPCTSTR cfg_cur = cfg_string; cfg_cur != cfg_end;) {
+ bool eol = false;
+ int line_length = 0;
+ while(!eol) {
+ int ch = *cfg_cur;
+ ++cfg_cur;
+ if(cfg_cur == cfg_end) {
+ eol = true;
+ } else {
+ if(line_length == buffer_size) {
+ // Need to realloc
+ buffer_size *= 2;
+ char* new_buff = new char[buffer_size];
+ memcpy(new_buff, buffer, line_length * sizeof(buffer[0]));
+ delete [] buffer;
+ buffer = new_buff;
+ }
+
+ if('\n' == ch) {
+ eol = true;
+ ch = '\0';
+ }
+
+ buffer[line_length] = (char)ch;
+ ++line_length;
+ }
+ }
+
+ if(NULL == pCurrSpotlight) {
+ pCurrSpotlight = processGlobalConfigLine(buffer);
+ } else {
+ pCurrSpotlight = processSpotlightConfigLine(buffer, pCurrSpotlight);
+ }
+ }
+
+ delete [] buffer;
+
+ // Mesh name is mandatory
+ if(NULL == m_MeshFileName)
+ return E_FAIL;
+
+ return S_OK;
+}
+
+void OceanVessel::updateSmokeSimulation(ID3D11DeviceContext* pDC, const CBaseCamera& camera, FLOAT time_delta, const D3DXVECTOR2& wind_dir, FLOAT wind_speed, FLOAT emit_rate_scale)
+{
+ if(m_pSmoke)
+ {
+ D3DXVECTOR3 vWindVector;
+ vWindVector.x = wind_dir.x * wind_speed;
+ vWindVector.y = 0.f;
+ vWindVector.z = wind_dir.y * wind_speed;
+ D3DXMATRIX matEmitter = m_FunnelMouthToLocal * m_pDynamicState->m_LocalToWorld;
+ m_pSmoke->updateSimulation(pDC, camera, time_delta, matEmitter, vWindVector, m_SmokeWindNoiseLevel * wind_speed, emit_rate_scale);
+ }
+}
+
+void OceanVessel::renderSmokeToScene( ID3D11DeviceContext* pDC,
+ const CBaseCamera& camera,
+ const OceanEnvironment& ocean_env
+ )
+{
+ if(m_pSmoke)
+ {
+ m_pSmoke->renderToScene(pDC, camera, m_pPSM, ocean_env);
+ }
+}
+
+void OceanVessel::renderSmokeToPSM( ID3D11DeviceContext* pDC,
+ const OceanEnvironment& ocean_env
+ )
+{
+ if(m_pSmoke)
+ {
+ m_pSmoke->renderToPSM(pDC, m_pPSM, ocean_env);
+ }
+}
+
+BoatMesh* OceanVessel::getMesh() const
+{
+ return m_pMesh;
+}
+
+void OceanVessel::beginRenderToPSM(ID3D11DeviceContext* pDC, const D3DXVECTOR2& wind_dir)
+{
+ const D3DXMATRIX matEmitter = m_FunnelMouthToLocal * m_pDynamicState->m_LocalToWorld;
+
+ // Get the emitter position from the emitter matrix and set up a wind-aligned local
+ // space with the emitter at the origin
+ D3DXVECTOR3 emitter_pos = D3DXVECTOR3(0,0,0);
+ D3DXVec3TransformCoord(&emitter_pos, &emitter_pos, &matEmitter);
+
+ // Local y is wind-aligned in the plane
+ D3DXVECTOR3 local_y = -D3DXVECTOR3(wind_dir.x,0,wind_dir.y);
+ local_y.y = 0.f;
+ D3DXVec3Normalize(&local_y, &local_y);
+
+ // Local z is world down (effective light dir - to put shadows on bottom of smoke plume)
+ D3DXVECTOR3 local_z = D3DXVECTOR3(0.f,-1.f,0.f);
+
+ // Local x is implied by y and z
+ D3DXVECTOR3 local_x;
+ D3DXVec3Cross(&local_x,&local_y,&local_z);
+
+ D3DXMATRIX matPSM;
+ D3DXMatrixTranslation(&matPSM,emitter_pos.x,emitter_pos.y,emitter_pos.z);
+
+ matPSM._11 = local_x.x;
+ matPSM._12 = local_x.y;
+ matPSM._13 = local_x.z;
+
+ matPSM._21 = local_y.x;
+ matPSM._22 = local_y.y;
+ matPSM._23 = local_y.z;
+
+ matPSM._31 = local_z.x;
+ matPSM._32 = local_z.y;
+ matPSM._33 = local_z.z;
+
+
+ m_pPSM->beginRenderToPSM(matPSM,pDC);
+}
+
+void OceanVessel::endRenderToPSM(ID3D11DeviceContext* pDC)
+{
+ m_pPSM->endRenderToPSM(pDC);
+}