SpeedTreeLib: port 40250 wrapper/forest verbatim over a CSpeedTreeRT stand-in
Delete the platform proxy tree renderer and copy SpeedTreeWrapper, SpeedTreeForest, SpeedTreeForestDirectX8, SpeedTreeConfig.h and VertexShaders.h from 40250. The SDK SpeedTreeRT.h public API becomes the shim; the closed CSpeedTreeRT is reimplemented in platform/SpeedTreeLib/SpeedTreeRT.cpp (procedural geometry, static lighting, single LOD, DIVERGENT). Shims gain the D3D8 vertex shader declaration tokens, D3D_OK, CreateVertexShader/DeleteVertexShader, ID3DXBuffer/D3DXAssembleShader, MessageBox and __min/__max. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
86e602cb32
commit
d817bd7cab
@@ -561,3 +561,4 @@
|
||||
{"date": "2026-09-28T03:59:30+00:00", "unit": "EterLib/GrpLightManager.cpp", "action": "unit B: platform stub removed, 40250 GrpLightManager.cpp copied verbatim into port/ (port_copy.py); CPythonApplication::Create now calls m_LightManager.Initialize() (40250 :1263) so light IDs start at skip index 1; 40250 never calls FlushLight/RestoreLight, so no device-light change", "evidence": "ctest 35/35 (login_live excluded); fake-server frame 900 vs baseline mean abs diff 0.21/255"}
|
||||
{"date": "2026-09-28T04:02:30+00:00", "unit": "EterLib/LensFlare.cpp + ScreenFilter.cpp + Decal.cpp", "action": "unit C (part 1): platform stubs removed, 40250 sources copied verbatim (GL code is commented out in 40250 too); CMapOutdoor callers were already ported, so lens flare, screen filter and CDecal clipping (TerrainDecal) now run", "evidence": "ctest 35/35 (login_live excluded); fake-server frame 900 vs unit B mean abs diff 0.014/255; flare/filter visuals NEEDS_LIVE"}
|
||||
{"date": "2026-09-28T04:05:55+00:00", "unit": "EterLib/GrpShadowTexture.cpp + character shadow render target (RecordingDevice)", "action": "unit C part 2 / unit D: GrpShadowTexture stub replaced with verbatim 40250 copy (dead in 40250); CPU shadow-target rasterizer kept (flat TFACTOR pass, output-equivalent) and switched to the D3D top-left fill rule; Vulkan offscreen targets not needed since snow blur is hard-disabled in 40250", "evidence": "ctest 35/35 (login_live excluded); fake-server frame 900 vs previous mean abs diff 0.013/255 (frame noise); shadow parity NEEDS_LIVE"}
|
||||
{"date": "2026-09-28T04:31:20+00:00", "unit": "SpeedTreeLib/SpeedTreeWrapper.cpp + SpeedTreeForest.cpp + SpeedTreeForestDirectX8.cpp (+ CSpeedTreeRT stand-in)", "action": "unit E: platform proxy tree renderer deleted; 40250 wrapper/forest/DirectX8 copied verbatim (with SpeedTreeConfig.h, VertexShaders.h); SDK SpeedTreeRT.h public API as shim, closed CSpeedTreeRT reimplemented in platform/SpeedTreeLib/SpeedTreeRT.cpp (procedural geometry kept, DIVERGENT); D3D8 vertex-shader decl tokens, D3D_OK, CreateVertexShader/DeleteVertexShader, ID3DXBuffer/D3DXAssembleShader, MessageBox, __min/__max added to shims", "evidence": "ctest 35/35 (login_live excluded); fake-server frame 900 at spawn vs unit D mean abs diff ~3.2/255 (area-name fade + anim phase, no trees in view); spawn moved next to a tree (temporary) shows trunk/branches/leaf cards drawn by the wrapper; tree visuals NEEDS_LIVE"}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"reference": "SpeedTreeLib/SpeedTreeForest.cpp",
|
||||
"reference_sha256": "655f3a39fac7fd4e0c5a151a5c2ab21d94bee5035acf9045af23b78bf609d2aa",
|
||||
"priority": "P4",
|
||||
"contracts": [],
|
||||
"functions": {
|
||||
"CSpeedTreeForest::CSpeedTreeForest": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::CSpeedTreeForest"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::~CSpeedTreeForest": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::~CSpeedTreeForest"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::Clear": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::Clear"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::GetMainTree": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::GetMainTree"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::CreateInstance": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::CreateInstance"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::DeleteInstance": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::DeleteInstance"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::UpdateSystem": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::UpdateSystem"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::AdjustExtents": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::AdjustExtents"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::SetWindStrength": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::SetWindStrength"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::SetupWindMatrices": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::SetupWindMatrices"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::SetLight": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::SetLight"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForest::SetFog": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForest.cpp:CSpeedTreeForest::SetFog"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"reference": "SpeedTreeLib/SpeedTreeForestDirectX8.cpp",
|
||||
"reference_sha256": "7dd29079a158ed8af665e45ee1ed7b319732c5d33b5c8a8edcc458b5337c005a",
|
||||
"priority": "P4",
|
||||
"contracts": [],
|
||||
"functions": {
|
||||
"CSpeedTreeForestDirectX8::CSpeedTreeForestDirectX8": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForestDirectX8.cpp:CSpeedTreeForestDirectX8::CSpeedTreeForestDirectX8"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForestDirectX8::~CSpeedTreeForestDirectX8": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForestDirectX8.cpp:CSpeedTreeForestDirectX8::~CSpeedTreeForestDirectX8"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForestDirectX8::InitVertexShaders": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForestDirectX8.cpp:CSpeedTreeForestDirectX8::InitVertexShaders"
|
||||
],
|
||||
"note": "verbatim; WRAPPER_USE_NO_WIND / no GPU placement in SpeedTreeConfig.h, so the shader path returns the FVF as in 40250"
|
||||
},
|
||||
"CSpeedTreeForestDirectX8::SetRenderingDevice": {
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForestDirectX8.cpp:CSpeedTreeForestDirectX8::SetRenderingDevice"
|
||||
],
|
||||
"note": "verbatim; light 0 attributes reach the CSpeedTreeRT stand-in's static lighting; tone NEEDS_LIVE"
|
||||
},
|
||||
"CSpeedTreeForestDirectX8::UploadWindMatrix": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForestDirectX8.cpp:CSpeedTreeForestDirectX8::UploadWindMatrix"
|
||||
],
|
||||
"note": "verbatim; WRAPPER_USE_NO_WIND / no GPU placement in SpeedTreeConfig.h, so the shader path returns the FVF as in 40250"
|
||||
},
|
||||
"CSpeedTreeForestDirectX8::UpdateCompundMatrix": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForestDirectX8.cpp:CSpeedTreeForestDirectX8::UpdateCompundMatrix"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeForestDirectX8::Render": {
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeForestDirectX8.cpp:CSpeedTreeForestDirectX8::Render"
|
||||
],
|
||||
"note": "verbatim; render states as 40250 (branch CULL_CW, leaf/billboard passes); visual NEEDS_LIVE"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"reference": "SpeedTreeLib/SpeedTreeWrapper.cpp",
|
||||
"reference_sha256": "938924f5303879f1b322ad48f11c974319471fcdcca616fcb958d8cf43469fa5",
|
||||
"priority": "P4",
|
||||
"contracts": [],
|
||||
"functions": {
|
||||
"CSpeedTreeWrapper::CSpeedTreeWrapper": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::CSpeedTreeWrapper"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::SetVertexShaders": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::SetVertexShaders"
|
||||
],
|
||||
"note": "verbatim; WRAPPER_USE_NO_WIND / no GPU placement in SpeedTreeConfig.h, so the shader path returns the FVF as in 40250"
|
||||
},
|
||||
"CSpeedTreeWrapper::OnRenderPCBlocker": {
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::OnRenderPCBlocker"
|
||||
],
|
||||
"note": "verbatim; PC-blocker alpha visual NEEDS_LIVE"
|
||||
},
|
||||
"CSpeedTreeWrapper::OnRender": {
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::OnRender"
|
||||
],
|
||||
"note": "verbatim; visual NEEDS_LIVE"
|
||||
},
|
||||
"CSpeedTreeWrapper::~CSpeedTreeWrapper": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::~CSpeedTreeWrapper"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::LoadTree": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::LoadTree"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::SetupBuffers": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::SetupBuffers"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::SetupBranchBuffers": {
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::SetupBranchBuffers"
|
||||
],
|
||||
"note": "verbatim. DIVERGENT input: CSpeedTreeRT is the closed IDV lib; platform/SpeedTreeLib/SpeedTreeRT.cpp stands in for it and yields procedural branch strips (height 1000, species from file name), not the .spt-computed geometry; visual NEEDS_LIVE"
|
||||
},
|
||||
"CSpeedTreeWrapper::SetupFrondBuffers": {
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::SetupFrondBuffers"
|
||||
],
|
||||
"note": "verbatim; the CSpeedTreeRT stand-in reports no fronds (0 vertices), so palms/ferns lose their fronds -- DIVERGENT until the .spt engine is reproduced; NEEDS_LIVE"
|
||||
},
|
||||
"CSpeedTreeWrapper::SetupLeafBuffers": {
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::SetupLeafBuffers"
|
||||
],
|
||||
"note": "verbatim. DIVERGENT input: the stand-in's leaf clusters and composite-atlas rects are hand-picked (not the .spt leaf-map texcoords); NEEDS_LIVE"
|
||||
},
|
||||
"CSpeedTreeWrapper::Advance": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::Advance"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::MakeInstance": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::MakeInstance"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::GetInstances": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::GetInstances"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::DeleteInstance": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::DeleteInstance"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::SetupBranchForTreeType": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::SetupBranchForTreeType"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::RenderBranches": {
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::RenderBranches"
|
||||
],
|
||||
"note": "verbatim; static-lit colours (LIGHT_STATIC, LIGHTING FALSE), stage-1 self-shadow modulate, ALPHAREF 84; visual NEEDS_LIVE"
|
||||
},
|
||||
"CSpeedTreeWrapper::SetupFrondForTreeType": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::SetupFrondForTreeType"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::RenderFronds": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::RenderFronds"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::SetupLeafForTreeType": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::SetupLeafForTreeType"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::UploadLeafTables": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::UploadLeafTables"
|
||||
],
|
||||
"note": "verbatim; WRAPPER_USE_NO_WIND / no GPU placement in SpeedTreeConfig.h, so the shader path returns the FVF as in 40250"
|
||||
},
|
||||
"CSpeedTreeWrapper::RenderLeaves": {
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::RenderLeaves"
|
||||
],
|
||||
"note": "verbatim; camera-facing leaf cards come from the stand-in's m_pLeafMapCoords (rebuilt from SetCamera); visual NEEDS_LIVE"
|
||||
},
|
||||
"CSpeedTreeWrapper::EndLeafForTreeType": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::EndLeafForTreeType"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::RenderBillboards": {
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::RenderBillboards"
|
||||
],
|
||||
"note": "verbatim; the stand-in keeps billboards inactive (single LOD), so far trees never drop to billboards -- NEEDS_LIVE"
|
||||
},
|
||||
"CSpeedTreeWrapper::CleanUpMemory": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::CleanUpMemory"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::PositionTree": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::PositionTree"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::LoadTexture": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::LoadTexture"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::SetShaderConstants": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::SetShaderConstants"
|
||||
],
|
||||
"note": "verbatim; WRAPPER_USE_NO_WIND / no GPU placement in SpeedTreeConfig.h, so the shader path returns the FVF as in 40250"
|
||||
},
|
||||
"CSpeedTreeWrapper::SetPosition": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::SetPosition"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::GetBoundingSphere": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::GetBoundingSphere"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::CalculateBBox": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::CalculateBBox"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::GetCollisionObjectCount": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::GetCollisionObjectCount"
|
||||
],
|
||||
"note": "verbatim; the stand-in returns one trunk CO_CYLINDER (radius 35, height 750), not the .spt collision objects"
|
||||
},
|
||||
"CSpeedTreeWrapper::GetCollisionObject": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::GetCollisionObject"
|
||||
],
|
||||
"note": "verbatim; the stand-in returns one trunk CO_CYLINDER (radius 35, height 750), not the .spt collision objects"
|
||||
},
|
||||
"CSpeedTreeWrapper::GetPosition": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::GetPosition"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::GetTreeSize": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::GetTreeSize"
|
||||
]
|
||||
},
|
||||
"CSpeedTreeWrapper::OnUpdateCollisionData": {
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/port/SpeedTreeLib/SpeedTreeWrapper.cpp:CSpeedTreeWrapper::OnUpdateCollisionData"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,6 +463,14 @@ public:
|
||||
// PORT: fixed function only; CGraphicDevice's stream "shaders" are the FVFs they describe.
|
||||
HRESULT SetVertexShader(DWORD handle) override { m_fvf = handle; return S_OK; }
|
||||
HRESULT SetPixelShader(DWORD) override { return S_OK; }
|
||||
// PORT: no programmable vertex shaders; 40250 falls back to its FVF when creation fails.
|
||||
HRESULT CreateVertexShader(const DWORD*, const DWORD*, DWORD* pHandle, DWORD) override
|
||||
{
|
||||
if (pHandle)
|
||||
*pHandle = 0;
|
||||
return E_FAIL;
|
||||
}
|
||||
HRESULT DeleteVertexShader(DWORD) override { return S_OK; }
|
||||
HRESULT SetVertexShaderConstant(DWORD, const void*, DWORD) override { return S_OK; }
|
||||
HRESULT SetPixelShaderConstant(DWORD, const void*, DWORD) override { return S_OK; }
|
||||
HRESULT SetStreamSource(UINT stream, IDirect3DVertexBuffer8* buffer, UINT stride) override
|
||||
|
||||
@@ -1,241 +0,0 @@
|
||||
#include "SpeedTreeLib/StdAfx.h"
|
||||
#include "SpeedTreeLib/SpeedTreeForest.h"
|
||||
|
||||
#include "EterPack/EterPackManager.h"
|
||||
#include "GameLib/Property.h"
|
||||
#include "GameLib/PropertyManager.h"
|
||||
#include "../EterLib/RenderCommands3D.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
CSpeedTreeForest::CSpeedTreeForest()
|
||||
: m_fWindStrength(0.2f)
|
||||
, m_fAccumTime(0.0f)
|
||||
{
|
||||
std::memset(m_afLighting, 0, sizeof(m_afLighting));
|
||||
std::memset(m_afFog, 0, sizeof(m_afFog));
|
||||
m_afForestExtents[0] = m_afForestExtents[1] = m_afForestExtents[2] = FLT_MAX;
|
||||
m_afForestExtents[3] = m_afForestExtents[4] = m_afForestExtents[5] = -FLT_MAX;
|
||||
}
|
||||
|
||||
CSpeedTreeForest::~CSpeedTreeForest()
|
||||
{
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::ClearMainTree() -> void
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::GetMainTree(DWORD dwCRC, CSpeedTreeWrapper ** ppMainTree, const char * c_pszFileName) -> BOOL
|
||||
{
|
||||
if (!ppMainTree)
|
||||
return FALSE;
|
||||
*ppMainTree = NULL;
|
||||
|
||||
if (!IsNativeTerrainRenderEnabled())
|
||||
return FALSE;
|
||||
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.find(dwCRC);
|
||||
CSpeedTreeWrapper * pTree = NULL;
|
||||
|
||||
if (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
pTree = itor->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!c_pszFileName || !c_pszFileName[0])
|
||||
return FALSE;
|
||||
|
||||
CMappedFile file;
|
||||
LPCVOID c_pvData = NULL;
|
||||
if (!CEterPackManager::Instance().Get(file, c_pszFileName, &c_pvData))
|
||||
return FALSE;
|
||||
|
||||
float fSize = 1000.0f;
|
||||
float fVariance = 0.0f;
|
||||
CProperty * pProperty = NULL;
|
||||
if (CPropertyManager::InstancePtr() && CPropertyManager::Instance().Get(dwCRC, &pProperty) && pProperty)
|
||||
{
|
||||
const char * c_pszTreeSize = NULL;
|
||||
const char * c_pszTreeVariance = NULL;
|
||||
if (pProperty->GetString("TreeSize", &c_pszTreeSize) && c_pszTreeSize)
|
||||
fSize = static_cast<float>( std::atof(c_pszTreeSize));
|
||||
if (pProperty->GetString("TreeVariance", &c_pszTreeVariance) && c_pszTreeVariance)
|
||||
fVariance = static_cast<float>(std::atof(c_pszTreeVariance));
|
||||
}
|
||||
|
||||
pTree = new CSpeedTreeWrapper;
|
||||
if (!pTree->LoadTree(c_pszFileName, static_cast<const BYTE *>(c_pvData), file.Size(), 1, fSize, fVariance))
|
||||
{
|
||||
delete pTree;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_pMainTreeMap.insert(TTreeMap::value_type(dwCRC, pTree));
|
||||
file.Destroy();
|
||||
}
|
||||
|
||||
*ppMainTree = pTree;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::GetMainTree(DWORD dwCRC) -> CSpeedTreeWrapper *
|
||||
{
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.find(dwCRC);
|
||||
if (itor == m_pMainTreeMap.end())
|
||||
return NULL;
|
||||
return itor->second;
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::DeleteMainTree(DWORD dwCRC) -> void
|
||||
{
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.find(dwCRC);
|
||||
if (itor == m_pMainTreeMap.end())
|
||||
return;
|
||||
|
||||
CSpeedTreeWrapper * pMainTree = itor->second;
|
||||
UINT uiCount = 0;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
delete ppInstances[i];
|
||||
|
||||
delete pMainTree;
|
||||
m_pMainTreeMap.erase(itor);
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::CreateInstance(float x, float y, float z, DWORD dwTreeCRC, const char * c_pszTreeName) -> CSpeedTreeWrapper *
|
||||
{
|
||||
if (!IsNativeTerrainRenderEnabled())
|
||||
return NULL;
|
||||
|
||||
CSpeedTreeWrapper * pMainTree = NULL;
|
||||
if (!GetMainTree(dwTreeCRC, &pMainTree, c_pszTreeName) || !pMainTree)
|
||||
return NULL;
|
||||
|
||||
CSpeedTreeWrapper * pTreeInst = pMainTree->MakeInstance();
|
||||
if (!pTreeInst)
|
||||
return NULL;
|
||||
|
||||
pTreeInst->SetPosition(x, y, z);
|
||||
pTreeInst->RegisterBoundingSphere();
|
||||
AdjustExtents(x, y, z);
|
||||
return pTreeInst;
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::DeleteInstance(CSpeedTreeWrapper * pInstance) -> void
|
||||
{
|
||||
if (!pInstance)
|
||||
return;
|
||||
|
||||
CSpeedTreeWrapper * pParentTree = pInstance->InstanceOf();
|
||||
if (!pParentTree)
|
||||
return;
|
||||
|
||||
pParentTree->DeleteInstance(pInstance);
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::UpdateSystem(float fCurrentTime) -> void
|
||||
{
|
||||
static float fLastTime = fCurrentTime;
|
||||
float fElapsedTime = fCurrentTime - fLastTime;
|
||||
fLastTime = fCurrentTime;
|
||||
if (fElapsedTime > 0.0f && fElapsedTime < 10.0f)
|
||||
m_fAccumTime += fElapsedTime;
|
||||
SetupWindMatrices(m_fAccumTime);
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::Clear() -> void
|
||||
{
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.begin();
|
||||
UINT uiCount = 0;
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
if (!pMainTree)
|
||||
continue;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
delete ppInstances[i];
|
||||
delete pMainTree;
|
||||
}
|
||||
|
||||
m_pMainTreeMap.clear();
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::SetLight(const float * afDirection, const float * afAmbient, const float * afDiffuse) -> void
|
||||
{
|
||||
if (!afDirection || !afAmbient || !afDiffuse)
|
||||
return;
|
||||
|
||||
m_afLighting[0] = afDirection[0];
|
||||
m_afLighting[1] = afDirection[1];
|
||||
m_afLighting[2] = afDirection[2];
|
||||
m_afLighting[3] = 1.0f;
|
||||
|
||||
m_afLighting[4] = afAmbient[0];
|
||||
m_afLighting[5] = afAmbient[1];
|
||||
m_afLighting[6] = afAmbient[2];
|
||||
m_afLighting[7] = afAmbient[3];
|
||||
|
||||
m_afLighting[8] = afDiffuse[0];
|
||||
m_afLighting[9] = afDiffuse[1];
|
||||
m_afLighting[10] = afDiffuse[2];
|
||||
m_afLighting[11] = afDiffuse[3];
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::SetFog(float fFogNear, float fFogFar) -> void
|
||||
{
|
||||
const float denom = (fFogFar - fFogNear);
|
||||
const float c_fFogLinearScale = (std::fabs(denom) > 1e-4f) ? (1.0f / denom) : 0.0f;
|
||||
|
||||
m_afFog[0] = fFogNear;
|
||||
m_afFog[1] = fFogFar;
|
||||
m_afFog[2] = c_fFogLinearScale;
|
||||
m_afFog[3] = 0.0f;
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::SetWindStrength(float fStrength) -> void
|
||||
{
|
||||
if (m_fWindStrength == fStrength)
|
||||
return;
|
||||
|
||||
m_fWindStrength = fStrength;
|
||||
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.begin();
|
||||
UINT uiCount = 0;
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
if (!pMainTree)
|
||||
continue;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
{
|
||||
if (ppInstances[i] && ppInstances[i]->GetSpeedTree())
|
||||
ppInstances[i]->GetSpeedTree()->SetWindStrength(m_fWindStrength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::SetupWindMatrices(float /*fTimeInSecs*/) -> void
|
||||
{
|
||||
}
|
||||
|
||||
auto CSpeedTreeForest::AdjustExtents(float x, float y, float z) -> void
|
||||
{
|
||||
m_afForestExtents[0] = std::min(m_afForestExtents[0], x);
|
||||
m_afForestExtents[1] = std::min(m_afForestExtents[1], y);
|
||||
m_afForestExtents[2] = std::min(m_afForestExtents[2], z);
|
||||
|
||||
m_afForestExtents[3] = std::max(m_afForestExtents[3], x);
|
||||
m_afForestExtents[4] = std::max(m_afForestExtents[4], y);
|
||||
m_afForestExtents[5] = std::max(m_afForestExtents[5], z);
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
#include "SpeedTreeLib/StdAfx.h"
|
||||
#include "SpeedTreeLib/SpeedTreeForestDirectX8.h"
|
||||
|
||||
#include "EterBase/Timer.h"
|
||||
#include "EterLib/Camera.h"
|
||||
#include "EterLib/StateManager.h"
|
||||
#include "../EterLib/RenderCommands3D.h"
|
||||
|
||||
CSpeedTreeForestDirectX8::CSpeedTreeForestDirectX8()
|
||||
: m_pDx(NULL)
|
||||
, m_dwBranchVertexShader(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1)
|
||||
, m_dwLeafVertexShader(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1)
|
||||
{
|
||||
}
|
||||
|
||||
CSpeedTreeForestDirectX8::~CSpeedTreeForestDirectX8()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
auto CSpeedTreeForestDirectX8::UploadWindMatrix(unsigned int uiLocation, const float * pMatrix) const -> void
|
||||
{
|
||||
if (pMatrix)
|
||||
STATEMANAGER.SetVertexShaderConstant(uiLocation, pMatrix, 4);
|
||||
}
|
||||
|
||||
auto CSpeedTreeForestDirectX8::UpdateCompundMatrix(const D3DXVECTOR3 & /*c_rEyeVec*/, const D3DXMATRIX & c_rmatView, const D3DXMATRIX & c_rmatProj) -> void
|
||||
{
|
||||
D3DXMATRIX matBlendShader;
|
||||
D3DXMatrixMultiply(&matBlendShader, &c_rmatView, &c_rmatProj);
|
||||
D3DXMatrixTranspose(&matBlendShader, &matBlendShader);
|
||||
STATEMANAGER.SetVertexShaderConstant(0, &matBlendShader, 4);
|
||||
}
|
||||
|
||||
auto CSpeedTreeForestDirectX8::Render(unsigned long ulRenderBitVector) -> void
|
||||
{
|
||||
if (!IsNativeTerrainRenderEnabled())
|
||||
return;
|
||||
|
||||
UpdateSystem(CTimer::Instance().GetCurrentSecond());
|
||||
|
||||
if (m_pMainTreeMap.empty())
|
||||
return;
|
||||
|
||||
if (!(ulRenderBitVector & Forest_RenderToShadow) && !(ulRenderBitVector & Forest_RenderToMiniMap))
|
||||
{
|
||||
CCamera * pCamera = CCameraManager::Instance().GetCurrentCamera();
|
||||
if (pCamera)
|
||||
UpdateCompundMatrix(pCamera->GetEye(), ms_matView, ms_matProj);
|
||||
}
|
||||
|
||||
DWORD dwLightState = STATEMANAGER.GetRenderState(D3DRS_LIGHTING);
|
||||
DWORD dwColorVertexState = STATEMANAGER.GetRenderState(D3DRS_COLORVERTEX);
|
||||
DWORD dwFogVertexMode = STATEMANAGER.GetRenderState(D3DRS_FOGVERTEXMODE);
|
||||
|
||||
STATEMANAGER.SetRenderState(D3DRS_LIGHTING, TRUE);
|
||||
STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, TRUE);
|
||||
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.begin();
|
||||
UINT uiCount = 0;
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
if (!pMainTree)
|
||||
continue;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
{
|
||||
if (ppInstances[i])
|
||||
ppInstances[i]->Advance();
|
||||
}
|
||||
}
|
||||
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
|
||||
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||
|
||||
STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||
STATEMANAGER.SaveRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
|
||||
STATEMANAGER.SaveRenderState(D3DRS_ALPHAREF, 0x00000060);
|
||||
STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
|
||||
STATEMANAGER.SetVertexShader(m_dwBranchVertexShader);
|
||||
|
||||
// Render branches
|
||||
if (ulRenderBitVector & Forest_RenderBranches)
|
||||
{
|
||||
STATEMANAGER.SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||
itor = m_pMainTreeMap.begin();
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
if (!pMainTree)
|
||||
continue;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
pMainTree->SetupBranchForTreeType();
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
{
|
||||
if (ppInstances[i] && ppInstances[i]->isShow())
|
||||
ppInstances[i]->RenderBranches();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render leaves
|
||||
if (ulRenderBitVector & Forest_RenderLeaves)
|
||||
{
|
||||
STATEMANAGER.SetVertexShader(m_dwLeafVertexShader);
|
||||
STATEMANAGER.SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
|
||||
STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
|
||||
STATEMANAGER.SetRenderState(D3DRS_ALPHAREF, 0x00000060);
|
||||
STATEMANAGER.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
|
||||
itor = m_pMainTreeMap.begin();
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
if (!pMainTree)
|
||||
continue;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
pMainTree->SetupLeafForTreeType();
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
{
|
||||
if (ppInstances[i] && ppInstances[i]->isShow())
|
||||
ppInstances[i]->RenderLeaves();
|
||||
}
|
||||
pMainTree->EndLeafForTreeType();
|
||||
}
|
||||
}
|
||||
|
||||
STATEMANAGER.SetRenderState(D3DRS_LIGHTING, dwLightState);
|
||||
STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, dwColorVertexState);
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, dwFogVertexMode);
|
||||
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_ALPHAFUNC);
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_ALPHAREF);
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
|
||||
}
|
||||
|
||||
auto CSpeedTreeForestDirectX8::SetRenderingDevice(LPDIRECT3DDEVICE8 pDevice) -> bool
|
||||
{
|
||||
m_pDx = pDevice;
|
||||
return InitVertexShaders();
|
||||
}
|
||||
|
||||
auto CSpeedTreeForestDirectX8::InitVertexShaders() -> bool
|
||||
{
|
||||
m_dwBranchVertexShader = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
|
||||
m_dwLeafVertexShader = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
|
||||
CSpeedTreeWrapper::SetVertexShaders(m_dwBranchVertexShader, m_dwLeafVertexShader);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,858 @@
|
||||
// PORT: stand-in for the closed IDV SpeedTreeRT 1.6.0 library (40250 extern/library/SpeedTreeRT.lib,
|
||||
// Windows COFF). The class interface is the SDK header (port/common/shim/sdk/SpeedTreeRT.h) and the
|
||||
// 40250 SpeedTreeLib wrapper/forest call it unchanged; this file implements the members they call.
|
||||
//
|
||||
// What is the SDK's contract and kept here:
|
||||
// - GetGeometry fills SGeometry the way SpeedTreeWrapper reads it: one contiguous branch strip per
|
||||
// LOD, static-lit m_pColors (LIGHT_STATIC; light 0 from SetLightAttributes, the tree material),
|
||||
// m_pTexCoords1 self-shadow coordinates, camera-facing leaf clusters (m_pCenterCoords +
|
||||
// m_pLeafMapCoords rebuilt from SetCamera) with m_pLeafMapTexCoords, alpha test values of 84
|
||||
// (SetLeafTargetAlphaMask default 0x54 == c_nDefaultAlphaTestValue).
|
||||
// - SetLodLevel(1.0f), which the wrapper always applies, selects discrete LOD 0 with billboards
|
||||
// inactive; there is only that LOD.
|
||||
// - GetTextures returns bare file names: the wrapper prefixes the .spt directory.
|
||||
// - GetTreeSize reads the Size / SizeVariance header tokens (2001 / 2002) of the .spt.
|
||||
// What is not the SDK (DIVERGENT; the notes are on the wrapper in audit/port-map/SpeedTreeLib/):
|
||||
// - Branch and leaf geometry cannot be generated from the .spt parameters without the closed
|
||||
// engine; it is the previous procedural proxy (species hints from the file name, 1000-unit
|
||||
// height, crossed-branch trunk, hand-picked composite atlas rects), no fronds.
|
||||
// - Collision objects are one trunk cylinder; the .spt collision block is not parsed.
|
||||
// - Materials are the SDK defaults (white); the .spt material block is not parsed.
|
||||
#include "SpeedTreeLib/StdAfx.h"
|
||||
|
||||
#include <SpeedTreeRT.h>
|
||||
#include <spt.h>
|
||||
|
||||
#include "../EterLib/RenderCommands3D.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr float kPI = 3.14159265358979323846f;
|
||||
constexpr float kTAU = 2.0f * kPI;
|
||||
constexpr float kAlphaTestValue = 84.0f; // SetLeafTargetAlphaMask(0x54) default
|
||||
constexpr float kProxyHeight = 1000.0f;
|
||||
|
||||
struct Vec3
|
||||
{
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||
Vec3() = default;
|
||||
Vec3(float a, float b, float c) : x(a), y(b), z(c) {}
|
||||
Vec3 operator+(const Vec3 & o) const { return { x + o.x, y + o.y, z + o.z }; }
|
||||
Vec3 operator-(const Vec3 & o) const { return { x - o.x, y - o.y, z - o.z }; }
|
||||
Vec3 operator*(float s) const { return { x * s, y * s, z * s }; }
|
||||
};
|
||||
|
||||
float dot(const Vec3 & a, const Vec3 & b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
|
||||
Vec3 cross(const Vec3 & a, const Vec3 & b) { return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x }; }
|
||||
Vec3 normalize(const Vec3 & v)
|
||||
{
|
||||
const float l = std::sqrt(dot(v, v));
|
||||
return l > 1e-6f ? v * (1.0f / l) : Vec3(0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
std::string to_lower_str(std::string s)
|
||||
{
|
||||
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string basename_only(std::string path)
|
||||
{
|
||||
std::replace(path.begin(), path.end(), '\\', '/');
|
||||
const size_t slash = path.find_last_of('/');
|
||||
return slash == std::string::npos ? path : path.substr(slash + 1);
|
||||
}
|
||||
|
||||
bool has_any(const std::string & hint, std::initializer_list<const char *> keys)
|
||||
{
|
||||
const std::string h = to_lower_str(hint);
|
||||
for (const char * k : keys)
|
||||
if (h.find(k) != std::string::npos)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_conifer_species(const std::string & hint)
|
||||
{
|
||||
return has_any(hint, { "cedar", "cypress", "pine", "fir", "spruce", "conifer", "juniper", "christmastree" });
|
||||
}
|
||||
|
||||
bool is_palm_species(const std::string & hint)
|
||||
{
|
||||
return has_any(hint, { "palm", "banana", "aloe", "fern", "joshua" });
|
||||
}
|
||||
|
||||
uint32_t hash32(uint32_t s)
|
||||
{
|
||||
s ^= s >> 16;
|
||||
s *= 0x7feb352dU;
|
||||
s ^= s >> 15;
|
||||
s *= 0x846ca68bU;
|
||||
s ^= s >> 16;
|
||||
return s;
|
||||
}
|
||||
|
||||
float hash01(uint32_t s) { return float(hash32(s) & 0x00FFFFFFU) / float(0x01000000U); }
|
||||
|
||||
uint32_t species_seed(const std::string & s)
|
||||
{
|
||||
uint32_t h = 2166136261U;
|
||||
for (unsigned char c : s)
|
||||
{
|
||||
h ^= c;
|
||||
h *= 16777619U;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
// Composite-atlas leaf rects, D3D image space (v down).
|
||||
struct UVRect
|
||||
{
|
||||
float u0 = 0.0f, v0 = 0.0f, u1 = 1.0f, v1 = 1.0f;
|
||||
};
|
||||
|
||||
std::vector<UVRect> foliage_rects(const std::string & species, const std::string & composite)
|
||||
{
|
||||
if (composite.empty())
|
||||
return { { 0.0f, 0.0f, 1.0f, 1.0f } };
|
||||
const std::string s = to_lower_str(species);
|
||||
const std::string c = to_lower_str(composite);
|
||||
const bool fall = s.find("fall") != std::string::npos;
|
||||
const bool winter = s.find("winter") != std::string::npos;
|
||||
if (c.find("b1") != std::string::npos)
|
||||
{
|
||||
if (fall)
|
||||
return { { 0.00f, 0.05f, 0.25f, 0.25f }, { 0.25f, 0.25f, 0.50f, 0.50f } };
|
||||
return { { 0.25f, 0.02f, 0.50f, 0.23f }, { 0.25f, 0.18f, 0.50f, 0.36f }, { 0.00f, 0.27f, 0.27f, 0.49f } };
|
||||
}
|
||||
if (c.find("b2") != std::string::npos)
|
||||
{
|
||||
if (fall)
|
||||
return { { 0.00f, 0.00f, 0.25f, 0.25f }, { 0.25f, 0.25f, 0.50f, 0.50f } };
|
||||
return { { 0.50f, 0.38f, 0.75f, 0.63f }, { 0.50f, 0.63f, 0.75f, 0.88f }, { 0.00f, 0.38f, 0.25f, 0.62f } };
|
||||
}
|
||||
if (c.find("b3") != std::string::npos)
|
||||
{
|
||||
if (fall)
|
||||
return { { 0.25f, 0.25f, 0.50f, 0.50f } };
|
||||
return { { 0.00f, 0.25f, 0.25f, 0.50f }, { 0.00f, 0.50f, 0.25f, 0.75f }, { 0.25f, 0.50f, 0.50f, 0.75f } };
|
||||
}
|
||||
if (c.find("n1") != std::string::npos)
|
||||
{
|
||||
if (winter)
|
||||
return { { 0.00f, 0.36f, 0.50f, 0.58f }, { 0.25f, 0.55f, 0.52f, 0.75f } };
|
||||
return { { 0.00f, 0.72f, 0.28f, 0.96f }, { 0.25f, 0.74f, 0.53f, 0.97f } };
|
||||
}
|
||||
if (c.find("n2") != std::string::npos)
|
||||
return { { 0.00f, 0.48f, 0.27f, 0.75f }, { 0.26f, 0.73f, 0.58f, 1.00f }, { 0.75f, 0.48f, 1.00f, 0.80f } };
|
||||
return { { 0.0f, 0.0f, 1.0f, 1.0f } };
|
||||
}
|
||||
|
||||
// .spt header: 1000 <len> "__IdvSpt_02_", 1002, 2000 <len> <branch texture>, 2001 <float size>,
|
||||
// 2002 <float variance>.
|
||||
bool read_spt_size(const unsigned char * p, size_t n, float & size, float & variance)
|
||||
{
|
||||
size_t o = 0;
|
||||
auto i32 = [&](int32_t & v) {
|
||||
if (o + 4 > n)
|
||||
return false;
|
||||
std::memcpy(&v, p + o, 4);
|
||||
o += 4;
|
||||
return true;
|
||||
};
|
||||
int32_t t = 0, len = 0;
|
||||
if (!i32(t) || t != 1000 || !i32(len) || len < 0 || (o += size_t(len)) > n)
|
||||
return false;
|
||||
if (!i32(t) || t != 1002 || !i32(t) || t != 2000 || !i32(len) || len < 0 || (o += size_t(len)) > n)
|
||||
return false;
|
||||
int32_t bits = 0;
|
||||
if (!i32(t) || t != 2001 || !i32(bits))
|
||||
return false;
|
||||
std::memcpy(&size, &bits, 4);
|
||||
if (!i32(t) || t != 2002 || !i32(bits))
|
||||
return false;
|
||||
std::memcpy(&variance, &bits, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SStaticLight
|
||||
{
|
||||
float afAttributes[16] = {
|
||||
-0.707f, 0.0f, 0.707f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f
|
||||
};
|
||||
bool bOn = false;
|
||||
};
|
||||
|
||||
SStaticLight g_aLights[8];
|
||||
float g_afCameraPos[3] = { 0.0f, 0.0f, 0.0f };
|
||||
float g_afCameraDir[3] = { 0.0f, 1.0f, 0.0f };
|
||||
bool g_bTextureFlip = false;
|
||||
bool g_bDropToBillboard = false;
|
||||
std::string g_strError;
|
||||
|
||||
void SetError(const char * pError) { g_strError = pError ? pError : ""; }
|
||||
|
||||
const float c_afDefaultMaterial[13] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 5.0f };
|
||||
|
||||
// Static lighting (SLS_BASIC): material ambient x light ambient + material diffuse x light diffuse x N.L
|
||||
// for every light switched on, clamped per channel.
|
||||
unsigned long static_color(const Vec3 & n, const float * mat)
|
||||
{
|
||||
float rgb[3] = { 0.0f, 0.0f, 0.0f };
|
||||
bool any = false;
|
||||
for (const SStaticLight & light : g_aLights)
|
||||
{
|
||||
if (!light.bOn)
|
||||
continue;
|
||||
any = true;
|
||||
const float * a = light.afAttributes;
|
||||
const float ndotl = std::max(0.0f, dot(n, normalize(Vec3(a[0], a[1], a[2]))));
|
||||
for (int c = 0; c < 3; ++c)
|
||||
rgb[c] += mat[3 + c] * a[6 + c] + mat[c] * a[3 + c] * ndotl;
|
||||
}
|
||||
if (!any)
|
||||
rgb[0] = rgb[1] = rgb[2] = 1.0f;
|
||||
auto channel = [](float v) { return static_cast<unsigned long>(std::clamp(v, 0.0f, 1.0f) * 255.0f + 0.5f); };
|
||||
return 0xFF000000UL | (channel(rgb[0]) << 16) | (channel(rgb[1]) << 8) | channel(rgb[2]);
|
||||
}
|
||||
|
||||
// Geometry shared by a tree and its instances (the SDK shares it through m_pRefCount).
|
||||
struct STreeData
|
||||
{
|
||||
std::string strName;
|
||||
float fFileSize = -1.0f, fFileVariance = 0.0f;
|
||||
float fSize = -1.0f, fVariance = 0.0f;
|
||||
|
||||
std::string strBranchTexture, strCompositeTexture, strSelfShadowTexture;
|
||||
|
||||
// branches
|
||||
std::vector<float> vBranchCoords, vBranchNormals, vBranchTex0, vBranchTex1;
|
||||
std::vector<unsigned long> vBranchColors;
|
||||
std::vector<unsigned short> vBranchStrip;
|
||||
unsigned short usBranchStripLength = 0;
|
||||
const unsigned short * pBranchStrip = nullptr;
|
||||
|
||||
// leaves
|
||||
struct SCluster
|
||||
{
|
||||
Vec3 vCenter, vNormal;
|
||||
float fWidth = 0.0f, fHeight = 0.0f;
|
||||
UVRect rect;
|
||||
bool bFlip = false;
|
||||
};
|
||||
std::vector<SCluster> vClusters;
|
||||
std::vector<float> vLeafCenters, vLeafNormals, vLeafTexCoords, vLeafCoords;
|
||||
std::vector<unsigned long> vLeafColors;
|
||||
std::vector<unsigned char> vLeafMapIndices;
|
||||
std::vector<const float *> vLeafTexPtrs, vLeafCoordPtrs;
|
||||
|
||||
float afBoundingBox[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
float fTrunkRadius = 35.0f, fTrunkHeight = 600.0f;
|
||||
float afBranchMaterial[13], afFrondMaterial[13], afLeafMaterial[13];
|
||||
float fLeafLightingAdjustment = 0.75f;
|
||||
bool bComputed = false;
|
||||
|
||||
STreeData()
|
||||
{
|
||||
std::memcpy(afBranchMaterial, c_afDefaultMaterial, sizeof(afBranchMaterial));
|
||||
std::memcpy(afFrondMaterial, c_afDefaultMaterial, sizeof(afFrondMaterial));
|
||||
std::memcpy(afLeafMaterial, c_afDefaultMaterial, sizeof(afLeafMaterial));
|
||||
}
|
||||
|
||||
void Parse(const unsigned char * p, size_t n)
|
||||
{
|
||||
fmt::SptInfo info;
|
||||
fmt::sniff_spt(std::string(reinterpret_cast<const char *>(p), n), info);
|
||||
for (const std::string & ref : info.texture_refs)
|
||||
if (to_lower_str(ref).find("bark") != std::string::npos)
|
||||
{
|
||||
strBranchTexture = basename_only(ref);
|
||||
break;
|
||||
}
|
||||
if (strBranchTexture.empty() && !info.texture_refs.empty())
|
||||
strBranchTexture = basename_only(info.texture_refs.front());
|
||||
strCompositeTexture = basename_only(info.composite_texture);
|
||||
strSelfShadowTexture = basename_only(info.self_shadow_texture);
|
||||
read_spt_size(p, n, fFileSize, fFileVariance);
|
||||
fSize = fFileSize;
|
||||
fVariance = fFileVariance;
|
||||
}
|
||||
|
||||
void AppendStrip(const std::vector<unsigned short> & sub)
|
||||
{
|
||||
if (sub.empty())
|
||||
return;
|
||||
if (!vBranchStrip.empty())
|
||||
{
|
||||
// degenerate join; keep the next strip on an even triangle so its winding is unchanged
|
||||
vBranchStrip.push_back(vBranchStrip.back());
|
||||
vBranchStrip.push_back(sub.front());
|
||||
if (vBranchStrip.size() & 1)
|
||||
vBranchStrip.push_back(sub.front());
|
||||
}
|
||||
vBranchStrip.insert(vBranchStrip.end(), sub.begin(), sub.end());
|
||||
}
|
||||
|
||||
void AddTube(const Vec3 & from, const Vec3 & to, float r0, float r1, int seg, float bark_repeat)
|
||||
{
|
||||
Vec3 axis = to - from;
|
||||
if (dot(axis, axis) < 1e-6f)
|
||||
return;
|
||||
axis = normalize(axis);
|
||||
const Vec3 helper = std::fabs(axis.z) > 0.9f ? Vec3(1.0f, 0.0f, 0.0f) : Vec3(0.0f, 0.0f, 1.0f);
|
||||
const Vec3 u = normalize(cross(axis, helper));
|
||||
const Vec3 w = normalize(cross(axis, u));
|
||||
|
||||
std::vector<unsigned short> strip;
|
||||
for (int i = 0; i <= seg; ++i)
|
||||
{
|
||||
if (vBranchCoords.size() / 3 + 2 > 65530)
|
||||
break;
|
||||
const float a = float(i) / float(seg) * kTAU;
|
||||
const Vec3 n = u * std::cos(a) + w * std::sin(a);
|
||||
const float s = float(i) / float(seg);
|
||||
for (int end = 0; end < 2; ++end)
|
||||
{
|
||||
const Vec3 p = end ? to + n * r1 : from + n * r0;
|
||||
strip.push_back(static_cast<unsigned short>(vBranchCoords.size() / 3));
|
||||
vBranchCoords.insert(vBranchCoords.end(), { p.x, p.y, p.z });
|
||||
vBranchNormals.insert(vBranchNormals.end(), { n.x, n.y, n.z });
|
||||
vBranchTex0.insert(vBranchTex0.end(), { s, end ? 0.0f : bark_repeat });
|
||||
}
|
||||
}
|
||||
AppendStrip(strip);
|
||||
}
|
||||
|
||||
void BuildBranches(float H, bool conifer, bool palm)
|
||||
{
|
||||
const float trunk_top = H * (palm ? 0.82f : (conifer ? 0.90f : 0.76f));
|
||||
const float trunk_r = H * (palm ? 0.028f : 0.035f);
|
||||
const float H_m = H * 0.01f;
|
||||
AddTube(Vec3(0.0f, 0.0f, 0.0f), Vec3(0.0f, 0.0f, trunk_top), trunk_r * 1.35f, trunk_r * 0.42f, 9, H_m * 0.22f);
|
||||
if (palm)
|
||||
return;
|
||||
|
||||
const int count = conifer ? 9 : 8;
|
||||
const uint32_t seed = species_seed(strName);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
const float f = (i + 1.0f) / (count + 1.0f);
|
||||
const float z = H * (conifer ? (0.28f + f * 0.52f) : (0.32f + f * 0.34f));
|
||||
const float angle = kTAU * (f * 1.6180339f + hash01(seed + i * 17U));
|
||||
const float len = H * (conifer ? (0.24f * (1.0f - f * 0.55f)) : (0.18f + 0.08f * hash01(seed + i * 29U)));
|
||||
const Vec3 from(0.0f, 0.0f, z);
|
||||
const Vec3 to(std::cos(angle) * len, std::sin(angle) * len,
|
||||
z + H * (conifer ? 0.06f : (0.10f + 0.06f * hash01(seed + i * 31U))));
|
||||
AddTube(from, to, trunk_r * (0.55f - 0.20f * f), trunk_r * 0.12f, 6, H_m * 0.08f);
|
||||
if (!conifer && (i % 2 == 0))
|
||||
{
|
||||
const float side = angle + (hash01(seed + i * 37U) > 0.5f ? 0.65f : -0.65f);
|
||||
const Vec3 tip = to + Vec3(std::cos(side), std::sin(side), 0.65f) * (len * 0.42f);
|
||||
AddTube(to, tip, trunk_r * 0.16f, trunk_r * 0.05f, 5, H_m * 0.04f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BuildLeaves(float H, bool conifer, bool palm)
|
||||
{
|
||||
const std::vector<UVRect> rects = foliage_rects(strName, strCompositeTexture);
|
||||
const uint32_t seed = species_seed(strName);
|
||||
const int count = palm ? 16 : 24;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
const float a = kTAU * (float(i) * 0.6180339f + hash01(seed + i * 101U) * 0.15f);
|
||||
SCluster c;
|
||||
if (palm)
|
||||
{
|
||||
const float radial = H * (0.10f + 0.18f * hash01(seed + i * 103U));
|
||||
c.vCenter = Vec3(std::cos(a) * radial, std::sin(a) * radial, H * (0.78f + 0.12f * hash01(seed + i * 107U)));
|
||||
c.fWidth = H * 0.32f;
|
||||
c.fHeight = H * 0.18f;
|
||||
}
|
||||
else if (conifer)
|
||||
{
|
||||
const float zf = 0.30f + 0.62f * (float(i) + 0.5f) / float(count);
|
||||
const float radial = H * 0.23f * (1.0f - zf * 0.70f) * (0.35f + 0.65f * hash01(seed + i * 109U));
|
||||
c.vCenter = Vec3(std::cos(a) * radial, std::sin(a) * radial, H * zf);
|
||||
c.fWidth = H * (0.18f + 0.10f * (1.0f - zf));
|
||||
c.fHeight = H * 0.18f;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float zf = hash01(seed + i * 109U);
|
||||
const float zn = zf * 2.0f - 1.0f;
|
||||
const float radial = H * 0.34f * std::sqrt(std::max(0.05f, 1.0f - zn * zn)) *
|
||||
(0.25f + 0.75f * std::sqrt(hash01(seed + i * 113U)));
|
||||
c.vCenter = Vec3(std::cos(a) * radial, std::sin(a) * radial, H * (0.58f + zf * 0.34f));
|
||||
c.fWidth = H * (0.23f + 0.10f * hash01(seed + i * 127U));
|
||||
c.fHeight = H * (0.15f + 0.08f * hash01(seed + i * 131U));
|
||||
}
|
||||
// cluster normal: away from the crown centre, biased up
|
||||
const Vec3 out = normalize(c.vCenter - Vec3(0.0f, 0.0f, H * 0.6f));
|
||||
c.vNormal = normalize(Vec3(out.x, out.y, std::fabs(out.z) * 0.5f + 0.5f));
|
||||
c.rect = rects[size_t(i) % rects.size()];
|
||||
c.bFlip = (i & 1) != 0;
|
||||
vClusters.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
void Compute()
|
||||
{
|
||||
const bool enabled = IsNativeTerrainRenderEnabled();
|
||||
const float H = kProxyHeight;
|
||||
const float R = H * 0.35f;
|
||||
afBoundingBox[0] = -R;
|
||||
afBoundingBox[1] = -R;
|
||||
afBoundingBox[2] = 0.0f;
|
||||
afBoundingBox[3] = R;
|
||||
afBoundingBox[4] = R;
|
||||
afBoundingBox[5] = H;
|
||||
fTrunkRadius = H * 0.035f;
|
||||
fTrunkHeight = H * 0.75f;
|
||||
|
||||
// PORT: the Godot host draws its own trees unless the native terrain renderer is on; the tree
|
||||
// then has no geometry so the forest submits nothing.
|
||||
if (enabled)
|
||||
{
|
||||
const bool conifer = is_conifer_species(strName);
|
||||
const bool palm = is_palm_species(strName);
|
||||
BuildBranches(H, conifer, palm);
|
||||
BuildLeaves(H, conifer, palm);
|
||||
}
|
||||
|
||||
const size_t nBranchVerts = vBranchCoords.size() / 3;
|
||||
vBranchColors.resize(nBranchVerts);
|
||||
vBranchTex1.resize(nBranchVerts * 2);
|
||||
for (size_t i = 0; i < nBranchVerts; ++i)
|
||||
{
|
||||
const Vec3 n(vBranchNormals[i * 3], vBranchNormals[i * 3 + 1], vBranchNormals[i * 3 + 2]);
|
||||
vBranchColors[i] = static_color(n, afBranchMaterial);
|
||||
// self-shadow map projected straight down over the bounding box
|
||||
vBranchTex1[i * 2] = (vBranchCoords[i * 3] - afBoundingBox[0]) / (afBoundingBox[3] - afBoundingBox[0]);
|
||||
vBranchTex1[i * 2 + 1] = (vBranchCoords[i * 3 + 1] - afBoundingBox[1]) / (afBoundingBox[4] - afBoundingBox[1]);
|
||||
}
|
||||
if (g_bTextureFlip)
|
||||
for (size_t i = 0; i < nBranchVerts; ++i)
|
||||
{
|
||||
vBranchTex0[i * 2 + 1] = 1.0f - vBranchTex0[i * 2 + 1];
|
||||
vBranchTex1[i * 2 + 1] = 1.0f - vBranchTex1[i * 2 + 1];
|
||||
}
|
||||
usBranchStripLength = static_cast<unsigned short>(vBranchStrip.size());
|
||||
pBranchStrip = vBranchStrip.empty() ? nullptr : vBranchStrip.data();
|
||||
|
||||
const size_t nLeaves = vClusters.size();
|
||||
vLeafCenters.resize(nLeaves * 3);
|
||||
vLeafNormals.resize(nLeaves * 3);
|
||||
vLeafColors.resize(nLeaves);
|
||||
vLeafMapIndices.assign(nLeaves, 0);
|
||||
vLeafTexCoords.resize(nLeaves * 8);
|
||||
vLeafCoords.assign(nLeaves * 16, 0.0f);
|
||||
vLeafTexPtrs.resize(nLeaves);
|
||||
vLeafCoordPtrs.resize(nLeaves);
|
||||
for (size_t i = 0; i < nLeaves; ++i)
|
||||
{
|
||||
const SCluster & c = vClusters[i];
|
||||
std::memcpy(&vLeafCenters[i * 3], &c.vCenter, 12);
|
||||
std::memcpy(&vLeafNormals[i * 3], &c.vNormal, 12);
|
||||
vLeafColors[i] = static_color(c.vNormal, afLeafMaterial);
|
||||
// corners 0..3: (+r,+u) (-r,+u) (-r,-u) (+r,-u); drawn as 0,1,2 / 0,2,3
|
||||
const float uR = c.bFlip ? c.rect.u0 : c.rect.u1, uL = c.bFlip ? c.rect.u1 : c.rect.u0;
|
||||
float * t = &vLeafTexCoords[i * 8];
|
||||
const float vTop = g_bTextureFlip ? c.rect.v0 : 1.0f - c.rect.v0;
|
||||
const float vBottom = g_bTextureFlip ? c.rect.v1 : 1.0f - c.rect.v1;
|
||||
t[0] = uR; t[1] = vTop;
|
||||
t[2] = uL; t[3] = vTop;
|
||||
t[4] = uL; t[5] = vBottom;
|
||||
t[6] = uR; t[7] = vBottom;
|
||||
vLeafTexPtrs[i] = t;
|
||||
vLeafCoordPtrs[i] = &vLeafCoords[i * 16];
|
||||
}
|
||||
bComputed = true;
|
||||
}
|
||||
|
||||
// SDK leaf clusters face the camera given to SetCamera.
|
||||
void UpdateLeafCoords()
|
||||
{
|
||||
const Vec3 dir = normalize(Vec3(g_afCameraDir[0], g_afCameraDir[1], g_afCameraDir[2]));
|
||||
Vec3 right = cross(dir, Vec3(0.0f, 0.0f, 1.0f));
|
||||
right = dot(right, right) < 1e-6f ? Vec3(1.0f, 0.0f, 0.0f) : normalize(right);
|
||||
const Vec3 up = normalize(cross(right, dir));
|
||||
for (size_t i = 0; i < vClusters.size(); ++i)
|
||||
{
|
||||
const SCluster & c = vClusters[i];
|
||||
const Vec3 r = right * (c.fWidth * 0.5f), u = up * (c.fHeight * 0.5f);
|
||||
const Vec3 corners[4] = { r + u, u - r, Vec3() - r - u, r - u };
|
||||
float * p = &vLeafCoords[i * 16];
|
||||
for (int k = 0; k < 4; ++k)
|
||||
{
|
||||
p[k * 4 + 0] = corners[k].x;
|
||||
p[k * 4 + 1] = corners[k].y;
|
||||
p[k * 4 + 2] = corners[k].z;
|
||||
p[k * 4 + 3] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
struct CSpeedTreeRT::SImpl
|
||||
{
|
||||
std::shared_ptr<STreeData> pTree = std::make_shared<STreeData>();
|
||||
const CSpeedTreeRT * pInstanceOf = nullptr;
|
||||
float afPosition[3] = { 0.0f, 0.0f, 0.0f };
|
||||
float fLodLevel = 1.0f;
|
||||
float fLodNear = 100.0f, fLodFar = 1000.0f;
|
||||
float fWindStrength = 0.0f;
|
||||
unsigned int uiLocalStart = 0, uiLocalSpan = 0;
|
||||
unsigned int uiSeed = 1;
|
||||
bool bLeafRocking = false;
|
||||
unsigned int uiRockingGroups = 1;
|
||||
ELightingMethod eBranchLighting = LIGHT_STATIC, eLeafLighting = LIGHT_STATIC, eFrondLighting = LIGHT_STATIC;
|
||||
EWindMethod eBranchWind = WIND_NONE, eLeafWind = WIND_NONE, eFrondWind = WIND_NONE;
|
||||
float afLeafLodSizes[1] = { 1.0f };
|
||||
};
|
||||
|
||||
CSpeedTreeRT::SGeometry::SIndexed::SIndexed()
|
||||
: m_nDiscreteLodLevel(-1), m_usNumStrips(0), m_pStripLengths(nullptr), m_pStrips(nullptr), m_usVertexCount(0),
|
||||
m_pColors(nullptr), m_pNormals(nullptr), m_pBinormals(nullptr), m_pTangents(nullptr), m_pCoords(nullptr),
|
||||
m_pTexCoords0(nullptr), m_pTexCoords1(nullptr), m_pWindWeights(nullptr), m_pWindMatrixIndices(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CSpeedTreeRT::SGeometry::SIndexed::~SIndexed() {}
|
||||
|
||||
CSpeedTreeRT::SGeometry::SLeaf::SLeaf()
|
||||
: m_bIsActive(false), m_fAlphaTestValue(0.0f), m_nDiscreteLodLevel(-1), m_usLeafCount(0), m_pLeafMapIndices(nullptr),
|
||||
m_pLeafClusterIndices(nullptr), m_pCenterCoords(nullptr), m_pLeafMapTexCoords(nullptr), m_pLeafMapCoords(nullptr),
|
||||
m_pColors(nullptr), m_pNormals(nullptr), m_pBinormals(nullptr), m_pTangents(nullptr), m_pWindWeights(nullptr),
|
||||
m_pWindMatrixIndices(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CSpeedTreeRT::SGeometry::SLeaf::~SLeaf() {}
|
||||
|
||||
CSpeedTreeRT::SGeometry::SBillboard::SBillboard()
|
||||
: m_bIsActive(false), m_pTexCoords(nullptr), m_pCoords(nullptr), m_fAlphaTestValue(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
CSpeedTreeRT::SGeometry::SBillboard::~SBillboard() {}
|
||||
|
||||
CSpeedTreeRT::SGeometry::SGeometry() : m_fBranchAlphaTestValue(0.0f), m_fFrondAlphaTestValue(0.0f) {}
|
||||
CSpeedTreeRT::SGeometry::~SGeometry() {}
|
||||
|
||||
CSpeedTreeRT::STextures::STextures()
|
||||
: m_pBranchTextureFilename(nullptr), m_uiLeafTextureCount(0), m_pLeafTextureFilenames(nullptr),
|
||||
m_uiFrondTextureCount(0), m_pFrondTextureFilenames(nullptr), m_pCompositeFilename(nullptr),
|
||||
m_pSelfShadowFilename(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CSpeedTreeRT::STextures::~STextures() {}
|
||||
|
||||
CSpeedTreeRT::CSpeedTreeRT() : m_pImpl(new SImpl) {}
|
||||
CSpeedTreeRT::~CSpeedTreeRT() { delete m_pImpl; }
|
||||
|
||||
void * CSpeedTreeRT::operator new(size_t nSize) { return ::operator new(nSize); }
|
||||
void * CSpeedTreeRT::operator new[](size_t nSize) { return ::operator new[](nSize); }
|
||||
void CSpeedTreeRT::operator delete(void * pRawMemory) { ::operator delete(pRawMemory); }
|
||||
void CSpeedTreeRT::operator delete[](void * pRawMemory) { ::operator delete[](pRawMemory); }
|
||||
|
||||
bool CSpeedTreeRT::LoadTree(const char * pFilename)
|
||||
{
|
||||
SetError(pFilename ? "SpeedTreeRT: file loading is not supported, pass the pack block" : "SpeedTreeRT: no file name");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSpeedTreeRT::LoadTree(const unsigned char * pBlock, unsigned int nNumBytes)
|
||||
{
|
||||
if (!pBlock || nNumBytes < 16)
|
||||
{
|
||||
SetError("SpeedTreeRT: empty tree block");
|
||||
return false;
|
||||
}
|
||||
m_pImpl->pTree = std::make_shared<STreeData>();
|
||||
m_pImpl->pTree->Parse(pBlock, nNumBytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSpeedTreeRT::Compute(const float * /*pTransform*/, unsigned int nSeed, bool /*bCompositeStrips*/)
|
||||
{
|
||||
STreeData & tree = *m_pImpl->pTree;
|
||||
if (tree.bComputed)
|
||||
{
|
||||
SetError("SpeedTreeRT: tree already computed");
|
||||
return false;
|
||||
}
|
||||
m_pImpl->uiSeed = nSeed;
|
||||
tree.Compute();
|
||||
return true;
|
||||
}
|
||||
|
||||
CSpeedTreeRT * CSpeedTreeRT::MakeInstance(void)
|
||||
{
|
||||
CSpeedTreeRT * pInstance = new CSpeedTreeRT;
|
||||
*pInstance->m_pImpl = *m_pImpl;
|
||||
pInstance->m_pImpl->pInstanceOf = this;
|
||||
return pInstance;
|
||||
}
|
||||
|
||||
const CSpeedTreeRT * CSpeedTreeRT::InstanceOf(void) const { return m_pImpl->pInstanceOf; }
|
||||
|
||||
void CSpeedTreeRT::DeleteTransientData(void) {}
|
||||
|
||||
void CSpeedTreeRT::GetTreeSize(float & fSize, float & fVariance) const
|
||||
{
|
||||
fSize = m_pImpl->pTree->fSize;
|
||||
fVariance = m_pImpl->pTree->fVariance;
|
||||
}
|
||||
|
||||
void CSpeedTreeRT::SetTreeSize(float fNewSize, float fNewVariance)
|
||||
{
|
||||
m_pImpl->pTree->fSize = fNewSize;
|
||||
m_pImpl->pTree->fVariance = fNewVariance;
|
||||
}
|
||||
|
||||
unsigned int CSpeedTreeRT::GetSeed() const { return m_pImpl->uiSeed; }
|
||||
|
||||
const float * CSpeedTreeRT::GetTreePosition(void) const { return m_pImpl->afPosition; }
|
||||
|
||||
void CSpeedTreeRT::SetTreePosition(float x, float y, float z)
|
||||
{
|
||||
m_pImpl->afPosition[0] = x;
|
||||
m_pImpl->afPosition[1] = y;
|
||||
m_pImpl->afPosition[2] = z;
|
||||
}
|
||||
|
||||
CSpeedTreeRT::ELightingMethod CSpeedTreeRT::GetBranchLightingMethod(void) const { return m_pImpl->eBranchLighting; }
|
||||
void CSpeedTreeRT::SetBranchLightingMethod(ELightingMethod eMethod) { m_pImpl->eBranchLighting = eMethod; }
|
||||
CSpeedTreeRT::ELightingMethod CSpeedTreeRT::GetLeafLightingMethod(void) const { return m_pImpl->eLeafLighting; }
|
||||
void CSpeedTreeRT::SetLeafLightingMethod(ELightingMethod eMethod) { m_pImpl->eLeafLighting = eMethod; }
|
||||
CSpeedTreeRT::ELightingMethod CSpeedTreeRT::GetFrondLightingMethod(void) const { return m_pImpl->eFrondLighting; }
|
||||
void CSpeedTreeRT::SetFrondLightingMethod(ELightingMethod eMethod) { m_pImpl->eFrondLighting = eMethod; }
|
||||
|
||||
float CSpeedTreeRT::GetLeafLightingAdjustment() const { return m_pImpl->pTree->fLeafLightingAdjustment; }
|
||||
void CSpeedTreeRT::SetLeafLightingAdjustment(float fScalar) { m_pImpl->pTree->fLeafLightingAdjustment = fScalar; }
|
||||
|
||||
bool CSpeedTreeRT::GetLightState(unsigned int nLightIndex) { return nLightIndex < 8 && g_aLights[nLightIndex].bOn; }
|
||||
|
||||
void CSpeedTreeRT::SetLightState(unsigned int nLightIndex, bool bLightOn)
|
||||
{
|
||||
if (nLightIndex < 8)
|
||||
g_aLights[nLightIndex].bOn = bLightOn;
|
||||
}
|
||||
|
||||
const float * CSpeedTreeRT::GetLightAttributes(unsigned int nLightIndex)
|
||||
{
|
||||
return nLightIndex < 8 ? g_aLights[nLightIndex].afAttributes : nullptr;
|
||||
}
|
||||
|
||||
void CSpeedTreeRT::SetLightAttributes(unsigned int nLightIndex, const float * pLightAttributes)
|
||||
{
|
||||
if (nLightIndex < 8 && pLightAttributes)
|
||||
std::memcpy(g_aLights[nLightIndex].afAttributes, pLightAttributes, sizeof(g_aLights[nLightIndex].afAttributes));
|
||||
}
|
||||
|
||||
const float * CSpeedTreeRT::GetBranchMaterial(void) const { return m_pImpl->pTree->afBranchMaterial; }
|
||||
void CSpeedTreeRT::SetBranchMaterial(const float * pMaterial) { std::memcpy(m_pImpl->pTree->afBranchMaterial, pMaterial, 13 * sizeof(float)); }
|
||||
const float * CSpeedTreeRT::GetLeafMaterial(void) const { return m_pImpl->pTree->afLeafMaterial; }
|
||||
void CSpeedTreeRT::SetLeafMaterial(const float * pMaterial) { std::memcpy(m_pImpl->pTree->afLeafMaterial, pMaterial, 13 * sizeof(float)); }
|
||||
const float * CSpeedTreeRT::GetFrondMaterial(void) const { return m_pImpl->pTree->afFrondMaterial; }
|
||||
void CSpeedTreeRT::SetFrondMaterial(const float * pMaterial) { std::memcpy(m_pImpl->pTree->afFrondMaterial, pMaterial, 13 * sizeof(float)); }
|
||||
|
||||
void CSpeedTreeRT::GetCamera(float * pPosition, float * pDirection)
|
||||
{
|
||||
if (pPosition)
|
||||
std::memcpy(pPosition, g_afCameraPos, sizeof(g_afCameraPos));
|
||||
if (pDirection)
|
||||
std::memcpy(pDirection, g_afCameraDir, sizeof(g_afCameraDir));
|
||||
}
|
||||
|
||||
void CSpeedTreeRT::SetCamera(const float * pPosition, const float * pDirection)
|
||||
{
|
||||
if (pPosition)
|
||||
std::memcpy(g_afCameraPos, pPosition, sizeof(g_afCameraPos));
|
||||
if (pDirection)
|
||||
std::memcpy(g_afCameraDir, pDirection, sizeof(g_afCameraDir));
|
||||
}
|
||||
|
||||
// WRAPPER_USE_NO_WIND: the wind entry points only keep their state.
|
||||
void CSpeedTreeRT::SetTime(float /*fTime*/) {}
|
||||
void CSpeedTreeRT::ComputeWindEffects(bool /*bBranches*/, bool /*bLeaves*/, bool /*bFronds*/) {}
|
||||
void CSpeedTreeRT::ResetLeafWindState(void) {}
|
||||
bool CSpeedTreeRT::GetLeafRockingState(void) const { return m_pImpl->bLeafRocking; }
|
||||
void CSpeedTreeRT::SetLeafRockingState(bool bFlag) { m_pImpl->bLeafRocking = bFlag; }
|
||||
void CSpeedTreeRT::SetNumLeafRockingGroups(unsigned int nRockingGroups) { m_pImpl->uiRockingGroups = nRockingGroups; }
|
||||
CSpeedTreeRT::EWindMethod CSpeedTreeRT::GetLeafWindMethod(void) const { return m_pImpl->eLeafWind; }
|
||||
void CSpeedTreeRT::SetLeafWindMethod(EWindMethod eMethod) { m_pImpl->eLeafWind = eMethod; }
|
||||
CSpeedTreeRT::EWindMethod CSpeedTreeRT::GetBranchWindMethod(void) const { return m_pImpl->eBranchWind; }
|
||||
void CSpeedTreeRT::SetBranchWindMethod(EWindMethod eMethod) { m_pImpl->eBranchWind = eMethod; }
|
||||
CSpeedTreeRT::EWindMethod CSpeedTreeRT::GetFrondWindMethod(void) const { return m_pImpl->eFrondWind; }
|
||||
void CSpeedTreeRT::SetFrondWindMethod(EWindMethod eMethod) { m_pImpl->eFrondWind = eMethod; }
|
||||
float CSpeedTreeRT::GetWindStrength(void) const { return m_pImpl->fWindStrength; }
|
||||
|
||||
float CSpeedTreeRT::SetWindStrength(float fNewStrength, float /*fOldStrength*/, float /*fFrequencyTimeOffset*/)
|
||||
{
|
||||
const float fOld = m_pImpl->fWindStrength;
|
||||
m_pImpl->fWindStrength = fNewStrength;
|
||||
return fOld;
|
||||
}
|
||||
|
||||
void CSpeedTreeRT::SetNumWindMatrices(unsigned int /*nNumMatrices*/) {}
|
||||
void CSpeedTreeRT::SetWindMatrix(unsigned int /*nMatrixIndex*/, const float * /*pMatrix*/) {}
|
||||
|
||||
void CSpeedTreeRT::GetLocalMatrices(unsigned int & nStartingIndex, unsigned int & nMatrixSpan)
|
||||
{
|
||||
nStartingIndex = m_pImpl->uiLocalStart;
|
||||
nMatrixSpan = m_pImpl->uiLocalSpan;
|
||||
}
|
||||
|
||||
void CSpeedTreeRT::SetLocalMatrices(unsigned int nStartingMatrix, unsigned int nMatrixSpan)
|
||||
{
|
||||
m_pImpl->uiLocalStart = nStartingMatrix;
|
||||
m_pImpl->uiLocalSpan = nMatrixSpan;
|
||||
}
|
||||
|
||||
void CSpeedTreeRT::ComputeLodLevel(void)
|
||||
{
|
||||
const float dx = m_pImpl->afPosition[0] - g_afCameraPos[0];
|
||||
const float dy = m_pImpl->afPosition[1] - g_afCameraPos[1];
|
||||
const float dz = m_pImpl->afPosition[2] - g_afCameraPos[2];
|
||||
const float fDistance = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
const float fRange = std::max(1e-3f, m_pImpl->fLodFar - m_pImpl->fLodNear);
|
||||
m_pImpl->fLodLevel = 1.0f - std::clamp((fDistance - m_pImpl->fLodNear) / fRange, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
float CSpeedTreeRT::GetLodLevel(void) const { return m_pImpl->fLodLevel; }
|
||||
void CSpeedTreeRT::SetLodLevel(float fLodLevel) { m_pImpl->fLodLevel = std::clamp(fLodLevel, 0.0f, 1.0f); }
|
||||
void CSpeedTreeRT::SetDropToBillboard(bool bFlag) { g_bDropToBillboard = bFlag; }
|
||||
|
||||
void CSpeedTreeRT::GetLodLimits(float & fNear, float & fFar) const
|
||||
{
|
||||
fNear = m_pImpl->fLodNear;
|
||||
fFar = m_pImpl->fLodFar;
|
||||
}
|
||||
|
||||
void CSpeedTreeRT::SetLodLimits(float fNear, float fFar)
|
||||
{
|
||||
m_pImpl->fLodNear = fNear;
|
||||
m_pImpl->fLodFar = fFar;
|
||||
}
|
||||
|
||||
short CSpeedTreeRT::GetDiscreteBranchLodLevel(float /*fLodLevel*/) const { return 0; }
|
||||
unsigned short CSpeedTreeRT::GetDiscreteLeafLodLevel(float /*fLodLevel*/) const { return 0; }
|
||||
short CSpeedTreeRT::GetDiscreteFrondLodLevel(float /*fLodLevel*/) const { return 0; }
|
||||
unsigned short CSpeedTreeRT::GetNumBranchLodLevels(void) const { return 1; }
|
||||
unsigned short CSpeedTreeRT::GetNumLeafLodLevels(void) const { return 1; }
|
||||
unsigned short CSpeedTreeRT::GetNumFrondLodLevels(void) const { return 1; }
|
||||
|
||||
const float * CSpeedTreeRT::GetLeafBillboardTable(unsigned int & nEntryCount) const
|
||||
{
|
||||
nEntryCount = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const float * CSpeedTreeRT::GetLeafLodSizeAdjustments(void) { return m_pImpl->afLeafLodSizes; }
|
||||
|
||||
void CSpeedTreeRT::GetGeometry(SGeometry & sGeometry, unsigned long ulBitVector, short /*sOverrideBranchLodValue*/,
|
||||
short /*sOverrideFrondLodValue*/, short /*sOverrideLeafLodValue*/)
|
||||
{
|
||||
STreeData & tree = *m_pImpl->pTree;
|
||||
|
||||
if (ulBitVector & SpeedTree_BranchGeometry)
|
||||
{
|
||||
SGeometry::SIndexed & b = sGeometry.m_sBranches;
|
||||
b = SGeometry::SIndexed();
|
||||
b.m_nDiscreteLodLevel = 0;
|
||||
b.m_usVertexCount = static_cast<unsigned short>(tree.vBranchCoords.size() / 3);
|
||||
b.m_usNumStrips = tree.usBranchStripLength ? 1 : 0;
|
||||
b.m_pStripLengths = &tree.usBranchStripLength;
|
||||
b.m_pStrips = &tree.pBranchStrip;
|
||||
b.m_pColors = tree.vBranchColors.data();
|
||||
b.m_pNormals = tree.vBranchNormals.data();
|
||||
b.m_pCoords = tree.vBranchCoords.data();
|
||||
b.m_pTexCoords0 = tree.vBranchTex0.data();
|
||||
b.m_pTexCoords1 = tree.vBranchTex1.data();
|
||||
sGeometry.m_fBranchAlphaTestValue = kAlphaTestValue;
|
||||
}
|
||||
|
||||
if (ulBitVector & SpeedTree_FrondGeometry)
|
||||
{
|
||||
sGeometry.m_sFronds = SGeometry::SIndexed();
|
||||
sGeometry.m_sFronds.m_nDiscreteLodLevel = 0;
|
||||
sGeometry.m_fFrondAlphaTestValue = kAlphaTestValue;
|
||||
}
|
||||
|
||||
if (ulBitVector & SpeedTree_LeafGeometry)
|
||||
{
|
||||
tree.UpdateLeafCoords();
|
||||
SGeometry::SLeaf & l = sGeometry.m_sLeaves0;
|
||||
l = SGeometry::SLeaf();
|
||||
l.m_bIsActive = !tree.vClusters.empty();
|
||||
l.m_fAlphaTestValue = kAlphaTestValue;
|
||||
l.m_nDiscreteLodLevel = 0;
|
||||
l.m_usLeafCount = static_cast<unsigned short>(tree.vClusters.size());
|
||||
l.m_pLeafMapIndices = tree.vLeafMapIndices.data();
|
||||
l.m_pCenterCoords = tree.vLeafCenters.data();
|
||||
l.m_pLeafMapTexCoords = tree.vLeafTexPtrs.data();
|
||||
l.m_pLeafMapCoords = tree.vLeafCoordPtrs.data();
|
||||
l.m_pColors = tree.vLeafColors.data();
|
||||
l.m_pNormals = tree.vLeafNormals.data();
|
||||
sGeometry.m_sLeaves1 = SGeometry::SLeaf();
|
||||
}
|
||||
|
||||
if (ulBitVector & SpeedTree_BillboardGeometry)
|
||||
{
|
||||
sGeometry.m_sBillboard0 = SGeometry::SBillboard();
|
||||
sGeometry.m_sBillboard1 = SGeometry::SBillboard();
|
||||
sGeometry.m_sHorizontalBillboard = SGeometry::SBillboard();
|
||||
}
|
||||
}
|
||||
|
||||
void CSpeedTreeRT::GetTextures(STextures & sTextures) const
|
||||
{
|
||||
const STreeData & tree = *m_pImpl->pTree;
|
||||
sTextures = STextures();
|
||||
sTextures.m_pBranchTextureFilename = tree.strBranchTexture.c_str();
|
||||
sTextures.m_pCompositeFilename = tree.strCompositeTexture.empty() ? nullptr : tree.strCompositeTexture.c_str();
|
||||
sTextures.m_pSelfShadowFilename = tree.strSelfShadowTexture.empty() ? nullptr : tree.strSelfShadowTexture.c_str();
|
||||
}
|
||||
|
||||
bool CSpeedTreeRT::GetTextureFlip(void) { return g_bTextureFlip; }
|
||||
void CSpeedTreeRT::SetTextureFlip(bool bFlag) { g_bTextureFlip = bFlag; }
|
||||
|
||||
const char * CSpeedTreeRT::GetCurrentError(void) { return g_strError.c_str(); }
|
||||
void CSpeedTreeRT::ResetError(void) { g_strError.clear(); }
|
||||
|
||||
void CSpeedTreeRT::GetBoundingBox(float * pBounds) const
|
||||
{
|
||||
std::memcpy(pBounds, m_pImpl->pTree->afBoundingBox, 6 * sizeof(float));
|
||||
}
|
||||
|
||||
unsigned int CSpeedTreeRT::GetCollisionObjectCount(void) { return 1; }
|
||||
|
||||
void CSpeedTreeRT::GetCollisionObject(unsigned int /*nIndex*/, ECollisionObjectType & eType, float * pPosition, float * pDimensions)
|
||||
{
|
||||
const STreeData & tree = *m_pImpl->pTree;
|
||||
eType = CO_CYLINDER;
|
||||
if (pPosition)
|
||||
pPosition[0] = pPosition[1] = pPosition[2] = 0.0f;
|
||||
if (pDimensions)
|
||||
{
|
||||
pDimensions[0] = tree.fTrunkRadius;
|
||||
pDimensions[1] = tree.fTrunkHeight;
|
||||
pDimensions[2] = 0.0f;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,120 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// SpeedTreeRT runtime configuration #defines
|
||||
//
|
||||
// (c) 2003 IDV, Inc.
|
||||
//
|
||||
// *** INTERACTIVE DATA VISUALIZATION (IDV) PROPRIETARY INFORMATION ***
|
||||
//
|
||||
// This software is supplied under the terms of a license agreement or
|
||||
// nondisclosure agreement with Interactive Data Visualization and may
|
||||
// not be copied or disclosed except in accordance with the terms of
|
||||
// that agreement.
|
||||
//
|
||||
// Copyright (c) 2001-2003 IDV, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// IDV, Inc.
|
||||
// 1233 Washington St. Suite 610
|
||||
// Columbia, SC 29201
|
||||
// Voice: (803) 799-1699
|
||||
// Fax: (803) 931-0320
|
||||
// Web: http://www.idvinc.com
|
||||
|
||||
#pragma once
|
||||
|
||||
const int c_nNumWindMatrices = 4;
|
||||
const int c_nNumInstancesPerModel = 10;
|
||||
const float c_fForestSize = 200.0f;
|
||||
const float c_fSpacingTolerance = 30.0f;
|
||||
const int c_nMaxPlacementIterations = 500;
|
||||
const int c_nDefaultAlphaTestValue = 84;
|
||||
const float c_fNearLodFactor = 2.0f;
|
||||
const float c_fFarLodFactor = 9.0f;
|
||||
const float c_fBenchmarkPeriod = 1.0f;
|
||||
|
||||
// vertex shader constant locations
|
||||
const int c_nVertexShader_LeafLightingAdjustment = 70;
|
||||
const int c_nVertexShader_Light = 71;
|
||||
const int c_nVertexShader_Material = 74;
|
||||
const int c_nVertexShader_TreePos = 52;
|
||||
const int c_nVertexShader_CompoundMatrix = 0;
|
||||
const int c_nVertexShader_WindMatrices = 54;
|
||||
const int c_nVertexShader_LeafTables = 4;
|
||||
const int c_nVertexShader_Fog = 85;
|
||||
|
||||
// lighting
|
||||
const float c_afLightPosition[4] = { -0.707f, 0.0f, 0.707f, 0.0f };
|
||||
const float c_afLightAmbient[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||||
const float c_afLightDiffuse[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
const float c_afLightSpecular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
const float c_afLightGlobalAmbient[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
|
||||
// setup lighting (enable ONE of the two below)
|
||||
#define WRAPPER_USE_STATIC_LIGHTING
|
||||
//#define WRAPPER_USE_DYNAMIC_LIGHTING
|
||||
|
||||
#if defined WRAPPER_USE_STATIC_LIGHTING && defined WRAPPER_USE_DYNAMIC_LIGHTING
|
||||
#error Please define exactly one lighting mode
|
||||
#endif
|
||||
|
||||
// setup wind (enable ONE of the three below)
|
||||
//#define WRAPPER_USE_GPU_WIND
|
||||
//#define WRAPPER_USE_CPU_WIND
|
||||
#define WRAPPER_USE_NO_WIND
|
||||
|
||||
#if defined WRAPPER_USE_GPU_WIND && defined WRAPPER_USE_CPU_WIND
|
||||
#error Please define exactly one lighting mode
|
||||
#elif defined WRAPPER_USE_GPU_WIND && defined WRAPPER_USE_NO_WIND
|
||||
#error Please define exactly one lighting mode
|
||||
#elif defined WRAPPER_USE_CPU_WIND && defined WRAPPER_USE_NO_WIND
|
||||
#error Please define exactly one lighting mode
|
||||
#endif
|
||||
|
||||
// leaf placement algorithm (enable ONE of the two below)
|
||||
//#define WRAPPER_USE_GPU_LEAF_PLACEMENT
|
||||
#define WRAPPER_USE_CPU_LEAF_PLACEMENT
|
||||
|
||||
#if defined WRAPPER_USE_GPU_LEAF_PLACEMENT && defined WRAPPER_USE_CPU_LEAF_PLACEMENT
|
||||
#error Please define exactly one leaf placement algorithm
|
||||
#endif
|
||||
|
||||
// texture coordinates (enable this define for DirectX-based engines)
|
||||
#define WRAPPER_FLIP_T_TEXCOORD
|
||||
|
||||
// up vector
|
||||
//#define WRAPPER_UP_POS_Y
|
||||
#define WRAPPER_UP_POS_Z
|
||||
|
||||
#if defined WRAPPER_UP_POS_Y && defined WRAPPER_UP_POS_Z
|
||||
#error Please define exactly one up vector
|
||||
#endif
|
||||
|
||||
// loading from STF or clones/instances? (enable ONE of the two below)
|
||||
//#define WRAPPER_FOREST_FROM_STF
|
||||
#define WRAPPER_FOREST_FROM_INSTANCES
|
||||
|
||||
#if defined WRAPPER_FOREST_FROM_STF && defined WRAPPER_FOREST_FROM_INSTANCES
|
||||
#error Please define exactly one loading mechanism
|
||||
#endif
|
||||
|
||||
// billboard modes
|
||||
#define WRAPPER_BILLBOARD_MODE
|
||||
//#define WRAPPER_RENDER_HORIZONTAL_BILLBOARD
|
||||
|
||||
// render self-shadows
|
||||
#define WRAPPER_RENDER_SELF_SHADOWS
|
||||
|
||||
// use fog
|
||||
#define WRAPPER_USE_FOG
|
||||
|
||||
// derived constants
|
||||
#ifdef WRAPPER_USE_GPU_WIND
|
||||
#define BRANCHES_USE_SHADERS
|
||||
#define FRONDS_USE_SHADERS
|
||||
#define LEAVES_USE_SHADERS
|
||||
#endif
|
||||
|
||||
#ifdef WRAPPER_USE_GPU_LEAF_PLACEMENT
|
||||
#define LEAVES_USE_SHADERS
|
||||
#endif
|
||||
@@ -0,0 +1,316 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForest Class
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Include Files
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include <vector>
|
||||
#include "../EterBase/Filename.h"
|
||||
#include "../EterBase/MappedFile.h"
|
||||
#include "../EterPack/EterPackManager.h"
|
||||
|
||||
#include "SpeedTreeForest.h"
|
||||
#include "SpeedTreeConfig.h"
|
||||
#include <cfloat>
|
||||
|
||||
using namespace std;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForest constructor
|
||||
|
||||
CSpeedTreeForest::CSpeedTreeForest() : m_fWindStrength(0.0f)
|
||||
{
|
||||
CSpeedTreeRT::SetNumWindMatrices(c_nNumWindMatrices);
|
||||
|
||||
m_afForestExtents[0] = m_afForestExtents[1] = m_afForestExtents[2] = FLT_MAX;
|
||||
m_afForestExtents[3] = m_afForestExtents[4] = m_afForestExtents[5] = -FLT_MAX;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForest destructor
|
||||
|
||||
CSpeedTreeForest::~CSpeedTreeForest()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void CSpeedTreeForest::Clear()
|
||||
{
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.begin();
|
||||
UINT uiCount;
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
delete ppInstances[i];
|
||||
|
||||
delete pMainTree;
|
||||
}
|
||||
|
||||
m_pMainTreeMap.clear();
|
||||
}
|
||||
|
||||
CSpeedTreeWrapper * CSpeedTreeForest::GetMainTree(DWORD dwCRC)
|
||||
{
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.find(dwCRC);
|
||||
|
||||
if (itor == m_pMainTreeMap.end())
|
||||
return NULL;
|
||||
|
||||
return itor->second;
|
||||
}
|
||||
|
||||
BOOL CSpeedTreeForest::GetMainTree(DWORD dwCRC, CSpeedTreeWrapper ** ppMainTree, const char * c_pszFileName)
|
||||
{
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.find(dwCRC);
|
||||
|
||||
CSpeedTreeWrapper * pTree;
|
||||
|
||||
if (itor != m_pMainTreeMap.end())
|
||||
pTree = itor->second;
|
||||
else
|
||||
{
|
||||
CMappedFile file;
|
||||
LPCVOID c_pvData;
|
||||
|
||||
// NOTE : 파일이 없을때는 return FALSE 아닌가요? - [levites]
|
||||
if (!CEterPackManager::Instance().Get(file, c_pszFileName, &c_pvData))
|
||||
return FALSE;
|
||||
|
||||
pTree = new CSpeedTreeWrapper;
|
||||
|
||||
if (!pTree->LoadTree(c_pszFileName, (const BYTE *) c_pvData, file.Size()))
|
||||
{
|
||||
delete pTree;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_pMainTreeMap.insert(std::map<DWORD, CSpeedTreeWrapper *>::value_type(dwCRC, pTree));
|
||||
|
||||
file.Destroy();
|
||||
}
|
||||
|
||||
*ppMainTree = pTree;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CSpeedTreeWrapper* CSpeedTreeForest::CreateInstance(float x, float y, float z, DWORD dwTreeCRC, const char * c_szTreeName)
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree;
|
||||
if (!GetMainTree(dwTreeCRC, &pMainTree, c_szTreeName))
|
||||
return NULL;
|
||||
|
||||
CSpeedTreeWrapper* pTreeInst = pMainTree->MakeInstance();
|
||||
pTreeInst->SetPosition(x, y, z);
|
||||
pTreeInst->RegisterBoundingSphere();
|
||||
return pTreeInst;
|
||||
}
|
||||
|
||||
void CSpeedTreeForest::DeleteInstance(CSpeedTreeWrapper * pInstance)
|
||||
{
|
||||
if (!pInstance)
|
||||
return;
|
||||
|
||||
CSpeedTreeWrapper * pParentTree = pInstance->InstanceOf();
|
||||
|
||||
if (!pParentTree)
|
||||
return;
|
||||
|
||||
pParentTree->DeleteInstance(pInstance);
|
||||
}
|
||||
|
||||
void CSpeedTreeForest::UpdateSystem(float fCurrentTime)
|
||||
{
|
||||
// 업데이트 할 때 한번
|
||||
static float fLastTime = fCurrentTime;
|
||||
float fElapsedTime = fCurrentTime - fLastTime;
|
||||
CSpeedTreeRT::SetTime(fElapsedTime);
|
||||
|
||||
m_fAccumTime += fElapsedTime;
|
||||
SetupWindMatrices(m_fAccumTime);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForest::AdjustExtents
|
||||
void CSpeedTreeForest::AdjustExtents(float x, float y, float z)
|
||||
{
|
||||
// min
|
||||
m_afForestExtents[0] = __min(m_afForestExtents[0], x);
|
||||
m_afForestExtents[1] = __min(m_afForestExtents[1], y);
|
||||
m_afForestExtents[2] = __min(m_afForestExtents[2], z);
|
||||
|
||||
// max
|
||||
m_afForestExtents[3] = __max(m_afForestExtents[3], x);
|
||||
m_afForestExtents[4] = __max(m_afForestExtents[4], y);
|
||||
m_afForestExtents[5] = __max(m_afForestExtents[5], z);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForest::SetWindStrength
|
||||
void CSpeedTreeForest::SetWindStrength(float fStrength)
|
||||
{
|
||||
if (m_fWindStrength == fStrength)
|
||||
return;
|
||||
|
||||
m_fWindStrength = fStrength;
|
||||
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.begin();
|
||||
UINT uiCount;
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
ppInstances[i]->GetSpeedTree()->SetWindStrength(m_fWindStrength);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForest::SetupWindMatrices
|
||||
void CSpeedTreeForest::SetupWindMatrices(float fTimeInSecs)
|
||||
{
|
||||
// matrix computational data
|
||||
static float afMatrixTimes[c_nNumWindMatrices] = { 0.0f };
|
||||
static float afFrequencies[c_nNumWindMatrices][2] =
|
||||
{
|
||||
{ 0.15f, 0.17f },
|
||||
{ 0.25f, 0.15f },
|
||||
{ 0.19f, 0.05f },
|
||||
{ 0.15f, 0.22f }
|
||||
};
|
||||
|
||||
// compute time since last call
|
||||
static float fTimeOfLastCall = 0.0f;
|
||||
float fTimeSinceLastCall = fTimeInSecs - fTimeOfLastCall;
|
||||
fTimeOfLastCall = fTimeInSecs;
|
||||
|
||||
// wind strength
|
||||
static float fOldStrength = m_fWindStrength;
|
||||
|
||||
// increment matrix times
|
||||
for (int i = 0; i < c_nNumWindMatrices; ++i)
|
||||
afMatrixTimes[i] += fTimeSinceLastCall;
|
||||
|
||||
// compute maximum branch throw
|
||||
float fBaseAngle = m_fWindStrength * 35.0f;
|
||||
|
||||
// build rotation matrices
|
||||
for (int j = 0; j < c_nNumWindMatrices; ++j)
|
||||
{
|
||||
// adjust time to prevent "jumping"
|
||||
if (m_fWindStrength != 0.0f)
|
||||
afMatrixTimes[j] = (afMatrixTimes[j] * fOldStrength) / m_fWindStrength;
|
||||
|
||||
// compute percentages for each axis
|
||||
float fBaseFreq = m_fWindStrength * 20.0f;
|
||||
float fXPercent = sinf(fBaseFreq * afFrequencies[j % c_nNumWindMatrices][0] * afMatrixTimes[j]);
|
||||
float fYPercent = cosf(fBaseFreq * afFrequencies[j % c_nNumWindMatrices][1] * afMatrixTimes[j]);
|
||||
|
||||
// build compound rotation matrix (rotate on 'x' then on 'y')
|
||||
const float c_fDeg2Rad = 57.2957795f;
|
||||
float fSinX = sinf(fBaseAngle * fXPercent / c_fDeg2Rad);
|
||||
float fSinY = sinf(fBaseAngle * fYPercent / c_fDeg2Rad);
|
||||
float fCosX = cosf(fBaseAngle * fXPercent / c_fDeg2Rad);
|
||||
float fCosY = cosf(fBaseAngle * fYPercent / c_fDeg2Rad);
|
||||
|
||||
float afMatrix[16] = { 0.0f };
|
||||
afMatrix[0] = fCosY;
|
||||
afMatrix[2] = -fSinY;
|
||||
afMatrix[4] = fSinX * fSinY;
|
||||
afMatrix[5] = fCosX;
|
||||
afMatrix[6] = fSinX * fCosY;
|
||||
afMatrix[8] = fSinY * fCosX;
|
||||
afMatrix[9] = -fSinX;
|
||||
afMatrix[10] = fCosX * fCosY;
|
||||
afMatrix[15] = 1.0f;
|
||||
|
||||
#ifdef WRAPPER_USE_CPU_WIND
|
||||
CSpeedTreeRT::SetWindMatrix(j, afMatrix);
|
||||
#endif
|
||||
|
||||
#ifdef WRAPPER_USE_GPU_WIND
|
||||
// graphics API specific
|
||||
UploadWindMatrix(c_nVertexShader_WindMatrices + j * 4, afMatrix);
|
||||
#endif
|
||||
}
|
||||
|
||||
// track wind strength
|
||||
fOldStrength = m_fWindStrength;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForest::SetLodLimits
|
||||
/*
|
||||
void CSpeedTreeForest::SetLodLimits(void)
|
||||
{
|
||||
// find tallest tree
|
||||
float fTallest = -1.0f;
|
||||
|
||||
TTreeMap::iterator itor = m_pMainTreeMap.begin();
|
||||
UINT uiCount;
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
|
||||
float fHeight;
|
||||
fHeight = pMainTree->GetBoundingBox()[5] - pMainTree->GetBoundingBox()[0];
|
||||
fTallest = __max(fHeight, fTallest);
|
||||
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
{
|
||||
fHeight = ppInstances[i]->GetBoundingBox()[5] - ppInstances[i]->GetBoundingBox()[0];
|
||||
fTallest = __max(fHeight, fTallest);
|
||||
}
|
||||
}
|
||||
|
||||
itor = m_pMainTreeMap.begin();
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
|
||||
pMainTree->GetSpeedTree()->SetLodLimits(fTallest * c_fNearLodFactor, fTallest * c_fFarLodFactor);
|
||||
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
ppInstances[i]->GetSpeedTree()->SetLodLimits(fTallest * c_fNearLodFactor, fTallest * c_fFarLodFactor);
|
||||
}
|
||||
}
|
||||
*/
|
||||
void CSpeedTreeForest::SetLight(const float * afDirection, const float * afAmbient, const float * afDiffuse)
|
||||
{
|
||||
m_afLighting[0] = afDirection[0];
|
||||
m_afLighting[1] = afDirection[1];
|
||||
m_afLighting[2] = afDirection[2];
|
||||
m_afLighting[3] = 1.0f;
|
||||
|
||||
m_afLighting[4] = afAmbient[0];
|
||||
m_afLighting[5] = afAmbient[1];
|
||||
m_afLighting[6] = afAmbient[2];
|
||||
m_afLighting[7] = afAmbient[3];
|
||||
|
||||
m_afLighting[8] = afDiffuse[0];
|
||||
m_afLighting[9] = afDiffuse[1];
|
||||
m_afLighting[10] = afDiffuse[2];
|
||||
m_afLighting[11] = afDiffuse[3];
|
||||
}
|
||||
|
||||
void CSpeedTreeForest::SetFog(float fFogNear, float fFogFar)
|
||||
{
|
||||
const float c_fFogLinearScale = (1.0f / (fFogFar - fFogNear));
|
||||
|
||||
m_afFog[0] = fFogNear;
|
||||
m_afFog[1] = fFogFar;
|
||||
m_afFog[2] = c_fFogLinearScale;
|
||||
m_afFog[3] = 0.0f;
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForestDirectX8 Class
|
||||
//
|
||||
// (c) 2003 IDV, Inc.
|
||||
//
|
||||
// This class is provided to illustrate one way to incorporate
|
||||
// SpeedTreeRT into an OpenGL application. All of the SpeedTreeRT
|
||||
// calls that must be made on a per tree basis are done by this class.
|
||||
// Calls that apply to all trees (i.e. static SpeedTreeRT functions)
|
||||
// are made in the functions in main.cpp.
|
||||
//
|
||||
//
|
||||
// *** INTERACTIVE DATA VISUALIZATION (IDV) PROPRIETARY INFORMATION ***
|
||||
//
|
||||
// This software is supplied under the terms of a license agreement or
|
||||
// nondisclosure agreement with Interactive Data Visualization and may
|
||||
// not be copied or disclosed except in accordance with the terms of
|
||||
// that agreement.
|
||||
//
|
||||
// Copyright (c) 2001-2003 IDV, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// IDV, Inc.
|
||||
// 1233 Washington St. Suite 610
|
||||
// Columbia, SC 29201
|
||||
// Voice: (803) 799-1699
|
||||
// Fax: (803) 931-0320
|
||||
// Web: http://www.idvinc.com
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <d3d8.h>
|
||||
#include <d3d8types.h>
|
||||
#include <d3dx8.h>
|
||||
|
||||
#include "../EterBase/Timer.h"
|
||||
#include "../EterLib/StateManager.h"
|
||||
#include "../EterLib/Camera.h"
|
||||
|
||||
#include "SpeedTreeForestDirectX8.h"
|
||||
#include "SpeedTreeConfig.h"
|
||||
#include "VertexShaders.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForestDirectX8::CSpeedTreeForestDirectX8
|
||||
|
||||
CSpeedTreeForestDirectX8::CSpeedTreeForestDirectX8() : m_dwBranchVertexShader(0), m_dwLeafVertexShader(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForestDirectX8::~CSpeedTreeForestDirectX8
|
||||
|
||||
CSpeedTreeForestDirectX8::~CSpeedTreeForestDirectX8()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForestDirectX8::InitVertexShaders
|
||||
bool CSpeedTreeForestDirectX8::InitVertexShaders(void)
|
||||
{
|
||||
NANOBEGIN
|
||||
// load the vertex shaders
|
||||
if (!m_dwBranchVertexShader)
|
||||
m_dwBranchVertexShader = LoadBranchShader(m_pDx);
|
||||
|
||||
if (!m_dwLeafVertexShader)
|
||||
m_dwLeafVertexShader = LoadLeafShader(m_pDx);
|
||||
|
||||
if (m_dwBranchVertexShader && m_dwLeafVertexShader)
|
||||
{
|
||||
CSpeedTreeWrapper::SetVertexShaders(m_dwBranchVertexShader, m_dwLeafVertexShader);
|
||||
return true;
|
||||
}
|
||||
|
||||
NANOEND
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSpeedTreeForestDirectX8::SetRenderingDevice(LPDIRECT3DDEVICE8 lpDevice)
|
||||
{
|
||||
m_pDx = lpDevice;
|
||||
|
||||
if (!InitVertexShaders())
|
||||
return false;
|
||||
|
||||
const float c_afLightPosition[4] = { -0.707f, -0.300f, 0.707f, 0.0f };
|
||||
const float c_afLightAmbient[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||||
const float c_afLightDiffuse[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
const float c_afLightSpecular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
|
||||
float afLight1[] =
|
||||
{
|
||||
c_afLightPosition[0], c_afLightPosition[1], c_afLightPosition[2], // pos
|
||||
c_afLightDiffuse[0], c_afLightDiffuse[1], c_afLightDiffuse[2], // diffuse
|
||||
c_afLightAmbient[0], c_afLightAmbient[1], c_afLightAmbient[2], // ambient
|
||||
c_afLightSpecular[0], c_afLightSpecular[1], c_afLightSpecular[2], // specular
|
||||
c_afLightPosition[3], // directional flag
|
||||
1.0f, 0.0f, 0.0f // attenuation (constant, linear, quadratic)
|
||||
};
|
||||
|
||||
CSpeedTreeRT::SetNumWindMatrices(c_nNumWindMatrices);
|
||||
|
||||
CSpeedTreeRT::SetLightAttributes(0, afLight1);
|
||||
CSpeedTreeRT::SetLightState(0, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForestDirectX8::UploadWindMatrix
|
||||
|
||||
void CSpeedTreeForestDirectX8::UploadWindMatrix(UINT uiLocation, const float* pMatrix) const
|
||||
{
|
||||
STATEMANAGER.SetVertexShaderConstant(uiLocation, pMatrix, 4);
|
||||
}
|
||||
|
||||
void CSpeedTreeForestDirectX8::UpdateCompundMatrix(const D3DXVECTOR3 & c_rEyeVec, const D3DXMATRIX & c_rmatView, const D3DXMATRIX & c_rmatProj)
|
||||
{
|
||||
// setup composite matrix for shader
|
||||
D3DXMATRIX matBlend;
|
||||
D3DXMatrixIdentity(&matBlend);
|
||||
|
||||
D3DXMATRIX matBlendShader;
|
||||
D3DXMatrixMultiply(&matBlendShader, &c_rmatView, &c_rmatProj);
|
||||
|
||||
float afDirection[3];
|
||||
afDirection[0] = matBlendShader.m[0][2];
|
||||
afDirection[1] = matBlendShader.m[1][2];
|
||||
afDirection[2] = matBlendShader.m[2][2];
|
||||
CSpeedTreeRT::SetCamera(c_rEyeVec, afDirection);
|
||||
|
||||
D3DXMatrixTranspose(&matBlendShader, &matBlendShader);
|
||||
STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_CompoundMatrix, &matBlendShader, 4);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CSpeedTreeForestDirectX8::Render
|
||||
|
||||
void CSpeedTreeForestDirectX8::Render(unsigned long ulRenderBitVector)
|
||||
{
|
||||
UpdateSystem(CTimer::Instance().GetCurrentSecond());
|
||||
|
||||
if (m_pMainTreeMap.empty())
|
||||
return;
|
||||
|
||||
if (!(ulRenderBitVector & Forest_RenderToShadow) && !(ulRenderBitVector & Forest_RenderToMiniMap))
|
||||
UpdateCompundMatrix(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
|
||||
|
||||
DWORD dwLightState = STATEMANAGER.GetRenderState(D3DRS_LIGHTING);
|
||||
DWORD dwColorVertexState = STATEMANAGER.GetRenderState(D3DRS_COLORVERTEX);
|
||||
DWORD dwFogVertexMode = STATEMANAGER.GetRenderState(D3DRS_FOGVERTEXMODE);
|
||||
|
||||
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
|
||||
STATEMANAGER.SetRenderState(D3DRS_LIGHTING, TRUE);
|
||||
#else
|
||||
STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||
STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, TRUE);
|
||||
#endif
|
||||
|
||||
TTreeMap::iterator itor;
|
||||
UINT uiCount;
|
||||
|
||||
itor = m_pMainTreeMap.begin();
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
{
|
||||
ppInstances[i]->Advance();
|
||||
}
|
||||
}
|
||||
|
||||
STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_Light, m_afLighting, 3);
|
||||
STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_Fog, m_afFog, 1);
|
||||
|
||||
if (ulRenderBitVector & Forest_RenderToShadow)
|
||||
{
|
||||
//STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
|
||||
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);
|
||||
}
|
||||
|
||||
STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, TRUE);
|
||||
STATEMANAGER.SaveRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
|
||||
STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_CW);
|
||||
|
||||
// set up fog if it is enabled
|
||||
if (STATEMANAGER.GetRenderState(D3DRS_FOGENABLE))
|
||||
{
|
||||
#ifdef WRAPPER_USE_GPU_WIND
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_NONE); // GPU needs to work on all cards
|
||||
#endif
|
||||
}
|
||||
|
||||
// choose fixed function pipeline or custom shader for fronds and branches
|
||||
STATEMANAGER.SetVertexShader(m_dwBranchVertexShader);
|
||||
|
||||
// render branches
|
||||
if (ulRenderBitVector & Forest_RenderBranches)
|
||||
{
|
||||
itor = m_pMainTreeMap.begin();
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
|
||||
pMainTree->SetupBranchForTreeType();
|
||||
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
if (ppInstances[i]->isShow())
|
||||
ppInstances[i]->RenderBranches();
|
||||
}
|
||||
}
|
||||
|
||||
// set render states
|
||||
STATEMANAGER.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
|
||||
// render fronds
|
||||
if (ulRenderBitVector & Forest_RenderFronds)
|
||||
{
|
||||
itor = m_pMainTreeMap.begin();
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
|
||||
pMainTree->SetupFrondForTreeType();
|
||||
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
if (ppInstances[i]->isShow())
|
||||
ppInstances[i]->RenderFronds();
|
||||
}
|
||||
}
|
||||
|
||||
// render leaves
|
||||
if (ulRenderBitVector & Forest_RenderLeaves)
|
||||
{
|
||||
STATEMANAGER.SetVertexShader(m_dwLeafVertexShader);
|
||||
|
||||
if (STATEMANAGER.GetRenderState(D3DRS_FOGENABLE))
|
||||
{
|
||||
#if defined WRAPPER_USE_GPU_WIND || defined WRAPPER_USE_GPU_LEAF_PLACEMENT
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_NONE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ulRenderBitVector & Forest_RenderToShadow || ulRenderBitVector & Forest_RenderToMiniMap)
|
||||
{
|
||||
STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_NOTEQUAL);
|
||||
STATEMANAGER.SaveRenderState(D3DRS_ALPHAREF, 0x00000000);
|
||||
}
|
||||
|
||||
itor = m_pMainTreeMap.begin();
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
|
||||
pMainTree->SetupLeafForTreeType();
|
||||
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
if (ppInstances[i]->isShow())
|
||||
ppInstances[i]->RenderLeaves();
|
||||
}
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
(itor++)->second->EndLeafForTreeType();
|
||||
|
||||
if (ulRenderBitVector & Forest_RenderToShadow || ulRenderBitVector & Forest_RenderToMiniMap)
|
||||
{
|
||||
STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_ALPHAREF);
|
||||
}
|
||||
}
|
||||
|
||||
// render billboards
|
||||
#ifndef WRAPPER_NO_BILLBOARD_MODE
|
||||
if (ulRenderBitVector & Forest_RenderBillboards)
|
||||
{
|
||||
STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||
STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, FALSE);
|
||||
|
||||
itor = m_pMainTreeMap.begin();
|
||||
|
||||
while (itor != m_pMainTreeMap.end())
|
||||
{
|
||||
CSpeedTreeWrapper * pMainTree = (itor++)->second;
|
||||
CSpeedTreeWrapper ** ppInstances = pMainTree->GetInstances(uiCount);
|
||||
|
||||
pMainTree->SetupBranchForTreeType();
|
||||
|
||||
for (UINT i = 0; i < uiCount; ++i)
|
||||
if (ppInstances[i]->isShow())
|
||||
ppInstances[i]->RenderBillboards();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
STATEMANAGER.SetRenderState(D3DRS_LIGHTING, dwLightState);
|
||||
STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, dwColorVertexState);
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, dwFogVertexMode);
|
||||
|
||||
// 셀프섀도우로 쓰는 TextureStage 1의 COLOROP와 ALPHAOP를 꺼줘야 다음 렌더링 할 놈들이
|
||||
// 제대로 나온다. (안그러면 검게 나올 가능성이..)
|
||||
if (!(ulRenderBitVector & Forest_RenderToShadow))
|
||||
{
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||
}
|
||||
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_ALPHAFUNC);
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,332 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// SpeedTreeRT DirectX Example
|
||||
//
|
||||
// (c) 2003 IDV, Inc.
|
||||
//
|
||||
// This example demonstrates how to render trees using SpeedTreeRT
|
||||
// and DirectX. Techniques illustrated include ".spt" file parsing,
|
||||
// static lighting, dynamic lighting, LOD implementation, cloning,
|
||||
// instancing, and dynamic wind effects.
|
||||
//
|
||||
//
|
||||
// *** INTERACTIVE DATA VISUALIZATION (IDV) PROPRIETARY INFORMATION ***
|
||||
//
|
||||
// This software is supplied under the terms of a license agreement or
|
||||
// nondisclosure agreement with Interactive Data Visualization and may
|
||||
// not be copied or disclosed except in accordance with the terms of
|
||||
// that agreement.
|
||||
//
|
||||
// Copyright (c) 2001-2003 IDV, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// IDV, Inc.
|
||||
// 1233 Washington St. Suite 610
|
||||
// Columbia, SC 29201
|
||||
// Voice: (803) 799-1699
|
||||
// Fax: (803) 931-0320
|
||||
// Web: http://www.idvinc.com
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Includes
|
||||
|
||||
#pragma once
|
||||
#include "SpeedTreeConfig.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Branch & Frond Vertex Formats
|
||||
|
||||
static DWORD D3DFVF_SPEEDTREE_BRANCH_VERTEX =
|
||||
D3DFVF_XYZ | // always have the position
|
||||
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING // precomputed colors or geometric normals
|
||||
D3DFVF_NORMAL |
|
||||
#else
|
||||
D3DFVF_DIFFUSE |
|
||||
#endif
|
||||
#ifdef WRAPPER_RENDER_SELF_SHADOWS
|
||||
D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE2(1) // shadow texture coordinates
|
||||
#else
|
||||
D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0) // always have first texture layer coords
|
||||
#endif
|
||||
#ifdef WRAPPER_USE_GPU_WIND
|
||||
| D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE2(2) // GPU Only - wind weight and index passed in second texture layer
|
||||
#endif
|
||||
;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// FVF Branch Vertex Structure
|
||||
|
||||
struct SFVFBranchVertex
|
||||
{
|
||||
D3DXVECTOR3 m_vPosition; // Always Used
|
||||
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
|
||||
D3DXVECTOR3 m_vNormal; // Dynamic Lighting Only
|
||||
#else
|
||||
DWORD m_dwDiffuseColor; // Static Lighting Only
|
||||
#endif
|
||||
FLOAT m_fTexCoords[2]; // Always Used
|
||||
#ifdef WRAPPER_RENDER_SELF_SHADOWS
|
||||
FLOAT m_fShadowCoords[2]; // Texture coordinates for the shadows
|
||||
#endif
|
||||
#ifdef WRAPPER_USE_GPU_WIND
|
||||
FLOAT m_fWindIndex; // GPU Only
|
||||
FLOAT m_fWindWeight;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Branch/Frond Vertex Program
|
||||
|
||||
static const char g_achSimpleVertexProgram[] =
|
||||
{
|
||||
"vs.1.1\n" // identity shader version
|
||||
|
||||
"mov oT0.xy, v7\n" // always pass texcoord0 through
|
||||
|
||||
#ifdef WRAPPER_RENDER_SELF_SHADOWS
|
||||
"mov oT1.xy, v8\n" // pass shadow texcoords through if enabled
|
||||
#endif
|
||||
|
||||
// retrieve and convert wind matrix index
|
||||
"mov a0.x, v9.x\n"
|
||||
|
||||
// perform wind interpolation
|
||||
"m4x4 r1, v0, c[54+a0.x]\n" // compute full wind effect
|
||||
"sub r2, r1, v0\n" // compute difference between full wind and none
|
||||
"mov r3.x, v9.y\n" // mad can't access two v's at once, use r3.x as tmp
|
||||
"mad r1, r2, r3.x, v0\n" // perform interpolation
|
||||
|
||||
"add r2, c[52], r1\n" // translate to tree's position
|
||||
"m4x4 oPos, r2, c[0]\n" // project to screen
|
||||
|
||||
#ifdef WRAPPER_USE_FOG
|
||||
"dp4 r1, r2, c[2]\n" // find distance to vertex
|
||||
"sub r2.x, c[85].y, r1.z\n" // linear fogging
|
||||
"mul oFog, r2.x, c[85].z\n" // write to fog register
|
||||
#endif
|
||||
|
||||
#ifdef WRAPPER_USE_STATIC_LIGHTING
|
||||
"mov oD0, v5\n" // pass color through
|
||||
#else
|
||||
"mov r1, c[74]\n" // can only use one const register per instruction
|
||||
"mul r5, c[73], r1\n" // diffuse values
|
||||
|
||||
"mov r1, c[75]\n" // can only use one const register per instruction
|
||||
"mul r4, c[72], r1\n" // ambient values
|
||||
|
||||
"dp3 r2, v3, c[71]\n" // dot light direction with normal
|
||||
// "max r2.x, r2.x, c[70].x\n" // limit it
|
||||
"mad oD0, r2.x, r5, r4\n" // compute the final color
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// LoadBranchShader
|
||||
|
||||
static DWORD LoadBranchShader(LPDIRECT3DDEVICE8 pDx)
|
||||
{
|
||||
#ifndef WRAPPER_USE_GPU_WIND
|
||||
return D3DFVF_SPEEDTREE_BRANCH_VERTEX;
|
||||
#endif
|
||||
|
||||
// branch shader declaration
|
||||
DWORD pBranchShaderDecl[] =
|
||||
{
|
||||
D3DVSD_STREAM(0),
|
||||
D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
|
||||
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
|
||||
D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT3),
|
||||
#else
|
||||
D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR),
|
||||
#endif
|
||||
D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2),
|
||||
#ifdef WRAPPER_RENDER_SELF_SHADOWS
|
||||
D3DVSD_REG(D3DVSDE_TEXCOORD1, D3DVSDT_FLOAT2),
|
||||
#endif
|
||||
#ifdef WRAPPER_USE_GPU_WIND
|
||||
D3DVSD_REG(D3DVSDE_TEXCOORD2, D3DVSDT_FLOAT2),
|
||||
#endif
|
||||
D3DVSD_END( )
|
||||
};
|
||||
|
||||
// assemble shader
|
||||
DWORD dwShader;
|
||||
LPD3DXBUFFER pCode, pError;
|
||||
|
||||
if (D3DXAssembleShader(g_achSimpleVertexProgram, sizeof(g_achSimpleVertexProgram) - 1, 0, NULL, &pCode, &pError) == D3D_OK)
|
||||
{
|
||||
if (pDx->CreateVertexShader(pBranchShaderDecl, (DWORD*) pCode->GetBufferPointer( ), &dwShader, 0) != D3D_OK)
|
||||
{
|
||||
char szError[1024];
|
||||
sprintf(szError, "Failed to create branch vertex shader.");
|
||||
MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char szError[1024];
|
||||
sprintf(szError, "Failed to assemble branch vertex shader.\nThe error reported is [ %s ].\n", pError->GetBufferPointer( ));
|
||||
MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
|
||||
}
|
||||
|
||||
if (pCode)
|
||||
pCode->Release();
|
||||
|
||||
return dwShader;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Leaf Vertex Formats
|
||||
|
||||
static DWORD D3DFVF_SPEEDTREE_LEAF_VERTEX =
|
||||
D3DFVF_XYZ | // always have the position
|
||||
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING // precomputed colors or geometric normals
|
||||
D3DFVF_NORMAL |
|
||||
#else
|
||||
D3DFVF_DIFFUSE |
|
||||
#endif
|
||||
D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0) // always have first texture layer coords
|
||||
#if defined WRAPPER_USE_GPU_WIND || defined WRAPPER_USE_GPU_LEAF_PLACEMENT
|
||||
| D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE4(2) // GPU Only - wind weight and index passed in second texture layer
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// FVF Leaf Vertex Structure
|
||||
|
||||
struct SFVFLeafVertex
|
||||
{
|
||||
D3DXVECTOR3 m_vPosition; // Always Used
|
||||
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
|
||||
D3DXVECTOR3 m_vNormal; // Dynamic Lighting Only
|
||||
#else
|
||||
DWORD m_dwDiffuseColor; // Static Lighting Only
|
||||
#endif
|
||||
FLOAT m_fTexCoords[2]; // Always Used
|
||||
#if defined WRAPPER_USE_GPU_WIND || defined WRAPPER_USE_GPU_LEAF_PLACEMENT
|
||||
FLOAT m_fWindIndex; // Only used when GPU is involved
|
||||
FLOAT m_fWindWeight;
|
||||
FLOAT m_fLeafPlacementIndex;
|
||||
FLOAT m_fLeafScalarValue;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Leaf Vertex Program
|
||||
|
||||
static const char g_achLeafVertexProgram[] =
|
||||
{
|
||||
"vs.1.1\n" // identity shader version
|
||||
|
||||
"mov oT0.xy, v7\n" // always pass texcoord0 through
|
||||
|
||||
#ifdef WRAPPER_USE_GPU_WIND
|
||||
// retrieve and convert wind matrix index
|
||||
"mov a0.x, v9.x\n"
|
||||
|
||||
// perform wind interpolation
|
||||
"m4x4 r1, v0, c[54+a0.x]\n" // compute full wind effect
|
||||
"sub r2, r1, v0\n" // compute difference between full wind and none
|
||||
"mov r3.x, v9.y\n" // mad can't access two v's at once, use r3.x as tmp
|
||||
"mad r0, r2, r3.x, v0\n" // perform interpolation
|
||||
#else
|
||||
"mov r0, v0\n" // wind already handled, pass the vertex through
|
||||
#endif
|
||||
|
||||
#ifdef WRAPPER_USE_GPU_LEAF_PLACEMENT
|
||||
"mov a0.x, v9.z\n" // place the leaves
|
||||
"mul r1, c[a0.x], v9.w\n"
|
||||
"add r0, r1, r0\n"
|
||||
#endif
|
||||
|
||||
"add r0, c[52], r0\n" // translate to tree's position
|
||||
"m4x4 oPos, r0, c[0]\n" // project to screen
|
||||
|
||||
#ifdef WRAPPER_USE_FOG
|
||||
"dp4 r1, r0, c[2]\n" // find distance to vertex
|
||||
"sub r2.x, c[85].y, r1.z\n" //
|
||||
"mul oFog, r2.x, c[85].z\n"
|
||||
#endif
|
||||
|
||||
#ifdef WRAPPER_USE_STATIC_LIGHTING
|
||||
"mov oD0, v5\n" // pass color through
|
||||
#else
|
||||
"mov r1, c[74]\n" // can only use one const register per instruction
|
||||
"mul r5, c[73], r1\n" // diffuse values
|
||||
|
||||
"mov r1, c[75]\n" // can only use one const register per instruction
|
||||
"mul r4, c[72], r1\n" // ambient values
|
||||
|
||||
"dp3 r2.x, v3, c[71]\n" // dot light direction with normal
|
||||
"max r2.x, r2.x, c[70].x\n" // limit it
|
||||
"mad oD0, r2.x, r5, r4\n" // compute the final color
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// LoadLeafShader
|
||||
|
||||
static DWORD LoadLeafShader(LPDIRECT3DDEVICE8 pDx)
|
||||
{
|
||||
DWORD dwShader = D3DFVF_SPEEDTREE_LEAF_VERTEX;
|
||||
|
||||
#if defined WRAPPER_USE_GPU_LEAF_PLACEMENT || defined WRAPPER_USE_GPU_WIND
|
||||
|
||||
// leaf shader declaration
|
||||
DWORD pLeafShaderDecl[ ] =
|
||||
{
|
||||
D3DVSD_STREAM(0),
|
||||
D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
|
||||
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
|
||||
D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT3),
|
||||
#else
|
||||
D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR),
|
||||
#endif
|
||||
D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2),
|
||||
D3DVSD_REG(D3DVSDE_TEXCOORD2, D3DVSDT_FLOAT4),
|
||||
D3DVSD_END( )
|
||||
};
|
||||
|
||||
// assemble shader
|
||||
LPD3DXBUFFER pCode, pError;
|
||||
|
||||
if (D3DXAssembleShader(g_achLeafVertexProgram, sizeof(g_achLeafVertexProgram) - 1, 0, NULL, &pCode, &pError) == D3D_OK)
|
||||
{
|
||||
if (pDx->CreateVertexShader(pLeafShaderDecl, (DWORD*) pCode->GetBufferPointer( ), &dwShader, 0) != D3D_OK)
|
||||
{
|
||||
Tracef("Failed to create leaf vertex shader.");
|
||||
/*
|
||||
char szError[1024];
|
||||
sprintf(szError, "Failed to create leaf vertex shader.");
|
||||
MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Tracef("Failed to assemble leaf vertex shader. The error reported is [ %s ].\n", pError->GetBufferPointer( ));
|
||||
/*
|
||||
char szError[1024];
|
||||
sprintf(szError, "Failed to assemble leaf vertex shader. The error reported is [ %s ].\n", pError->GetBufferPointer( ));
|
||||
MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
|
||||
*/
|
||||
}
|
||||
|
||||
if (pCode)
|
||||
pCode->Release( );
|
||||
|
||||
#else
|
||||
|
||||
dwShader = D3DFVF_SPEEDTREE_LEAF_VERTEX;
|
||||
|
||||
#endif
|
||||
|
||||
return dwShader;
|
||||
}
|
||||
|
||||
@@ -503,6 +503,49 @@ typedef enum _D3DVERTEXBLENDFLAGS {
|
||||
#define D3DFVF_TEX8 0x800
|
||||
#define D3DFVF_LASTBETA_UBYTE4 0x1000
|
||||
#define D3DFVF_RESERVED2 0xE000
|
||||
// d3d8.h
|
||||
#define D3D_OK S_OK
|
||||
|
||||
// d3d8types.h vertex shader declaration tokens
|
||||
typedef enum _D3DVSD_TOKENTYPE
|
||||
{
|
||||
D3DVSD_TOKEN_NOP = 0,
|
||||
D3DVSD_TOKEN_STREAM = 1,
|
||||
D3DVSD_TOKEN_STREAMDATA = 2,
|
||||
D3DVSD_TOKEN_TESSELLATOR = 3,
|
||||
D3DVSD_TOKEN_CONSTMEM = 4,
|
||||
D3DVSD_TOKEN_EXT = 5,
|
||||
D3DVSD_TOKEN_END = 7,
|
||||
D3DVSD_FORCE_DWORD = 0x7fffffff,
|
||||
} D3DVSD_TOKENTYPE;
|
||||
#define D3DVSD_TOKENTYPESHIFT 29
|
||||
#define D3DVSD_TOKENTYPEMASK (7 << D3DVSD_TOKENTYPESHIFT)
|
||||
#define D3DVSD_DATATYPESHIFT 16
|
||||
#define D3DVSD_MAKETOKENTYPE(tokenType) ((tokenType << D3DVSD_TOKENTYPESHIFT) & D3DVSD_TOKENTYPEMASK)
|
||||
#define D3DVSD_STREAM(_StreamNumber) (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_STREAM) | (_StreamNumber))
|
||||
#define D3DVSD_REG(_VertexRegister, _Type) \
|
||||
(D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_STREAMDATA) | ((_Type) << D3DVSD_DATATYPESHIFT) | (_VertexRegister))
|
||||
#define D3DVSD_END() 0xFFFFFFFF
|
||||
#define D3DVSDT_FLOAT1 0x00
|
||||
#define D3DVSDT_FLOAT2 0x01
|
||||
#define D3DVSDT_FLOAT3 0x02
|
||||
#define D3DVSDT_FLOAT4 0x03
|
||||
#define D3DVSDT_D3DCOLOR 0x04
|
||||
#define D3DVSDT_UBYTE4 0x05
|
||||
#define D3DVSDT_SHORT2 0x06
|
||||
#define D3DVSDT_SHORT4 0x07
|
||||
#define D3DVSDE_POSITION 0
|
||||
#define D3DVSDE_BLENDWEIGHT 1
|
||||
#define D3DVSDE_BLENDINDICES 2
|
||||
#define D3DVSDE_NORMAL 3
|
||||
#define D3DVSDE_PSIZE 4
|
||||
#define D3DVSDE_DIFFUSE 5
|
||||
#define D3DVSDE_SPECULAR 6
|
||||
#define D3DVSDE_TEXCOORD0 7
|
||||
#define D3DVSDE_TEXCOORD1 8
|
||||
#define D3DVSDE_TEXCOORD2 9
|
||||
#define D3DVSDE_TEXCOORD3 10
|
||||
|
||||
#define D3DFVF_TEXTUREFORMAT2 0
|
||||
#define D3DFVF_TEXTUREFORMAT1 3
|
||||
#define D3DFVF_TEXTUREFORMAT3 1
|
||||
@@ -777,6 +820,8 @@ struct IDirect3DDevice8
|
||||
virtual HRESULT SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) = 0;
|
||||
virtual HRESULT SetTexture(DWORD Stage, IDirect3DBaseTexture8* pTexture) = 0;
|
||||
virtual HRESULT SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) = 0;
|
||||
virtual HRESULT CreateVertexShader(const DWORD* pDeclaration, const DWORD* pFunction, DWORD* pHandle, DWORD Usage) = 0;
|
||||
virtual HRESULT DeleteVertexShader(DWORD Handle) = 0;
|
||||
virtual HRESULT SetVertexShader(DWORD Handle) = 0;
|
||||
virtual HRESULT SetPixelShader(DWORD Handle) = 0;
|
||||
virtual HRESULT SetVertexShaderConstant(DWORD Register, const void* pConstantData, DWORD ConstantCount) = 0;
|
||||
|
||||
@@ -423,3 +423,9 @@ LPSTR CharPrevExA(WORD CodePage, LPCSTR lpStart, LPCSTR lpCurrentChar, DWORD dwF
|
||||
}
|
||||
|
||||
#endif // !_WIN32
|
||||
|
||||
int MessageBox(HWND, LPCSTR lpText, LPCSTR lpCaption, UINT)
|
||||
{
|
||||
std::fprintf(stderr, "[MessageBox] %s: %s\n", lpCaption ? lpCaption : "", lpText ? lpText : "");
|
||||
return IDOK;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,21 @@ BOOL FindNextFile(HANDLE handle, WIN32_FIND_DATA* data);
|
||||
BOOL FindClose(HANDLE handle);
|
||||
void Sleep(DWORD milliseconds);
|
||||
|
||||
// MSVC <stdlib.h> __min / __max
|
||||
#ifndef __min
|
||||
#define __min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef __max
|
||||
#define __max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
// user32 MessageBox (ANSI): no dialog on these hosts; writes caption and text to stderr, returns IDOK.
|
||||
#define MB_OK 0x00000000L
|
||||
#define MB_ICONHAND 0x00000010L
|
||||
#define MB_ICONSTOP MB_ICONHAND
|
||||
#define IDOK 1
|
||||
int MessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
|
||||
|
||||
// winmm `timeGetTime`: milliseconds since system start, wrapping at 2^32.
|
||||
DWORD timeGetTime();
|
||||
DWORD GetTickCount();
|
||||
|
||||
@@ -1,21 +1,463 @@
|
||||
#pragma once
|
||||
// Shim for IDV SpeedTreeRT <SpeedTreeRT.h> (40250 extern/include): the CSpeedTreeRT members that
|
||||
// SpeedTreeLib headers name. Tree geometry and wind go through platform/, which defines them.
|
||||
// Shim for IDV SpeedTreeRT 1.6.0 <SpeedTreeRT.h> (40250 extern/include): the public section below is
|
||||
// the SDK header verbatim. SpeedTreeRT.lib is closed Windows COFF, so the private section is replaced
|
||||
// by one opaque pointer and the members SpeedTreeLib calls are implemented in
|
||||
// platform/SpeedTreeLib/SpeedTreeRT.cpp. <cstddef> stands in for the size_t the SDK got from <windows.h>.
|
||||
#include <cstddef>
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Name: SpeedTreeRT.h
|
||||
//
|
||||
// *** INTERACTIVE DATA VISUALIZATION (IDV) PROPRIETARY INFORMATION ***
|
||||
//
|
||||
// Copyright (c) 2001-2003 IDV, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// IDV, Inc.
|
||||
// 1233 Washington St. Suite 610
|
||||
// Columbia, SC 29201
|
||||
// Voice: (803) 799-1699
|
||||
// Fax: (803) 931-0320
|
||||
// Web: http://www.idvinc.com
|
||||
//
|
||||
// This software is supplied under the terms of a license agreement or
|
||||
// nondisclosure agreement with Interactive Data Visualization and may not
|
||||
// be copied or disclosed except in accordance with the terms of that
|
||||
// agreement.
|
||||
//
|
||||
// Release version 1.6.0 (December 19, 2003)
|
||||
|
||||
class CSpeedTreeRT
|
||||
#pragma once
|
||||
|
||||
// define static or dynamic library build
|
||||
#ifdef SPEEDTREERT_DYNAMIC_LIB
|
||||
#ifdef IDV_SPEEDTREERT_EXPORTS
|
||||
#define BUILD_SPEED_TREE_RT_SET __declspec(dllexport)
|
||||
#else
|
||||
#define BUILD_SPEED_TREE_RT_SET __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define BUILD_SPEED_TREE_RT_SET
|
||||
#endif
|
||||
|
||||
// big or little endian system
|
||||
#ifdef __ppc__
|
||||
#define ST_BIG_ENDIAN
|
||||
#else
|
||||
#define ST_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
// Macintosh-specific
|
||||
#ifdef __ppc__
|
||||
#pragma export on
|
||||
#endif
|
||||
|
||||
// forward refernces
|
||||
class CIndexedGeometry;
|
||||
class CTreeEngine;
|
||||
class CLeafGeometry;
|
||||
class CLightingEngine;
|
||||
class CWindEngine;
|
||||
class CTreeFileAccess;
|
||||
class CSimpleBillboard;
|
||||
class CFrondEngine;
|
||||
struct STreeInstanceData;
|
||||
struct SInstanceList;
|
||||
struct SEmbeddedTexCoords;
|
||||
struct SCollisionObjects;
|
||||
class CProjectedShadow;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// class SpeedTreeRT
|
||||
//
|
||||
// In an effort to make the SpeedTreeRT.h header file dependency free
|
||||
// and easy to include into almost any project, a number of steps have
|
||||
// been taken:
|
||||
//
|
||||
// 1. No external header files need to be included by SpeedTreeRT.h
|
||||
// or by the application before including it.
|
||||
//
|
||||
// 2. Most of the implementation of the class is hidden by pointers
|
||||
// to the major sections of the library (the internal classes
|
||||
// can then just be forward-referenced)
|
||||
//
|
||||
// 3. Where possible, basic C++ datatypes are used to define the
|
||||
// member functions' parameters.
|
||||
//
|
||||
// Because almost all of the implementation details are hidden, none of
|
||||
// the functions for CSpeedTreeRT are inlined. However, inlined functions
|
||||
// were copiously used within the library.
|
||||
|
||||
class BUILD_SPEED_TREE_RT_SET CSpeedTreeRT
|
||||
{
|
||||
public:
|
||||
enum ECollisionObjectType
|
||||
{
|
||||
CO_SPHERE,
|
||||
CO_CYLINDER,
|
||||
CO_BOX
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Enumerations
|
||||
|
||||
struct SGeometry;
|
||||
struct STextures;
|
||||
enum EWindMethod
|
||||
{
|
||||
WIND_GPU, WIND_CPU, WIND_NONE
|
||||
};
|
||||
|
||||
float GetLeafLightingAdjustment() const;
|
||||
float SetWindStrength(float fNewStrength, float fOldStrength = -1.0f, float fFrequencyTimeOffset = -1.0f);
|
||||
void GetCollisionObject(unsigned int nIndex, ECollisionObjectType& eType, float* pPosition, float* pDimensions);
|
||||
enum ELodMethod
|
||||
{
|
||||
LOD_POP, LOD_SMOOTH, LOD_NONE = 3
|
||||
};
|
||||
|
||||
enum ELightingMethod
|
||||
{
|
||||
LIGHT_DYNAMIC, LIGHT_STATIC
|
||||
};
|
||||
|
||||
enum EStaticLightingStyle
|
||||
{
|
||||
SLS_BASIC, SLS_USE_LIGHT_SOURCES, SLS_SIMULATE_SHADOWS
|
||||
};
|
||||
|
||||
enum ECollisionObjectType
|
||||
{
|
||||
CO_SPHERE, CO_CYLINDER, CO_BOX
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// SGeometry bit vectors
|
||||
//
|
||||
// Passed into GetGeometry() in order to mask out unneeded geometric elements
|
||||
|
||||
#define SpeedTree_BranchGeometry (1 << 0)
|
||||
#define SpeedTree_FrondGeometry (1 << 1)
|
||||
#define SpeedTree_LeafGeometry (1 << 2)
|
||||
#define SpeedTree_BillboardGeometry (1 << 3)
|
||||
#define SpeedTree_SimpleBillboardOverride (1 << 4)
|
||||
#define SpeedTree_AllGeometry SpeedTree_BranchGeometry + SpeedTree_FrondGeometry + SpeedTree_LeafGeometry + SpeedTree_BillboardGeometry
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// struct SGeometry declaration
|
||||
|
||||
struct BUILD_SPEED_TREE_RT_SET SGeometry
|
||||
{
|
||||
SGeometry( );
|
||||
~SGeometry( );
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// struct SGeometry::SIndexed declaration
|
||||
|
||||
struct BUILD_SPEED_TREE_RT_SET SIndexed
|
||||
{
|
||||
SIndexed( );
|
||||
~SIndexed( );
|
||||
|
||||
// these values change depending on the active discrete LOD level
|
||||
int m_nDiscreteLodLevel; // range: [0, GetNumBranch/FrondLodLevels( ) - 1], -1 if inactive
|
||||
unsigned short m_usNumStrips; // total number of strips in current LOD
|
||||
const unsigned short* m_pStripLengths; // lengths of strips in current LOD (m_usNumStrips in length)
|
||||
const unsigned short** m_pStrips; // triangle strip indices (m_usNumStrips in length)
|
||||
|
||||
// these values are shared across all discete LOD levels
|
||||
unsigned short m_usVertexCount; // total vertex count in tables, referenced by all LOD levels
|
||||
const unsigned long* m_pColors; // RGBA values for each leaf - static lighting only (m_usVertexCount in length)
|
||||
const float* m_pNormals; // normals for each vertex (3 * m_usVertexCount in length)
|
||||
const float* m_pBinormals; // binormals (bump mapping) for each vertex (3 * m_usVertexCount in length)
|
||||
const float* m_pTangents; // tangents (bump mapping) for each vertex (3 * m_usVertexCount in length)
|
||||
const float* m_pCoords; // coordinates for each vertex (3 * m_usVertexCount in length)
|
||||
const float* m_pTexCoords0; // 1st layer (s,t) texcoords for each vertex (2 * m_usVertexCount in length)
|
||||
const float* m_pTexCoords1; // 2nd layer (s,t) texcoords for each vertex (2 * m_usVertexCount in length)
|
||||
const float* m_pWindWeights; // values from from 0.0 for rigid to 1.0 for flexible (m_usVertexCount in length)
|
||||
const unsigned char* m_pWindMatrixIndices; // table of wind matrix indices (m_usVertexCount in length)
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// struct SGeometry::SLeaf declaration
|
||||
|
||||
struct BUILD_SPEED_TREE_RT_SET SLeaf
|
||||
{
|
||||
SLeaf( );
|
||||
~SLeaf( );
|
||||
|
||||
// active LOD level data
|
||||
bool m_bIsActive; // flag indicating visibility
|
||||
float m_fAlphaTestValue; // 0.0 to 255.0 alpha testing value, used for fading
|
||||
int m_nDiscreteLodLevel; // range: [0, GetNumLeafLodLevels( ) - 1]
|
||||
unsigned short m_usLeafCount; // number of leaves stored in this structure
|
||||
|
||||
// tables for referencing the leaf cluster table
|
||||
const unsigned char* m_pLeafMapIndices; // references which leaf texture map used for each leaf (m_usLeafCount in length)
|
||||
const unsigned char* m_pLeafClusterIndices; // references which leaf cluster used for each leaf (m_usLeafCount in length)
|
||||
const float* m_pCenterCoords; // (x,y,z) values for the centers of leaf clusters (3 * m_usLeafCount in length)
|
||||
const float** m_pLeafMapTexCoords; // table of unique leaf cluster texcoords (m_usLeafCount in length) - each entry
|
||||
// points to 4 pairs of (s,t) texcoords stored in one contiguous array
|
||||
const float** m_pLeafMapCoords; // table of unique leaf cluster coordinates (m_usLeafCount in length) - each entry
|
||||
// points to 4 sets of (x,y,z,0) coordinates stored in one contiguous array
|
||||
// remaining vertex attributes
|
||||
const unsigned long* m_pColors; // RGBA values for each leaf (m_usLeafCount in length)
|
||||
const float* m_pNormals; // normals for each leaf (3 * m_usLeafCount in length)
|
||||
const float* m_pBinormals; // binormals (bump mapping) for each leaf (3 * m_usLeafCount in length)
|
||||
const float* m_pTangents; // tangents (bump mapping) for each leaf (3 * m_usLeafCount in length)
|
||||
const float* m_pWindWeights; // values from from 0.0 for rigid to 1.0 for flexible (m_usLeafCount in length)
|
||||
const unsigned char* m_pWindMatrixIndices; // table of wind matrix indices (m_usLeafCount in length)
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// struct SGeometry::SBillboard declaration
|
||||
|
||||
struct BUILD_SPEED_TREE_RT_SET SBillboard
|
||||
{
|
||||
SBillboard( );
|
||||
~SBillboard( );
|
||||
|
||||
bool m_bIsActive; // flag indicating visibility
|
||||
const float* m_pTexCoords; // 4 pairs of (s,t) texcoords stored in one contiguous array
|
||||
const float* m_pCoords; // 4 sets of (x,y,z) coordindates stored in one contiguous array
|
||||
float m_fAlphaTestValue; // 0.0 to 255.0 alpha testing value, used for fading
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// branch geometry
|
||||
|
||||
SIndexed m_sBranches; // holds the branch vertices and index buffers for all
|
||||
// of the discrete LOD levels
|
||||
float m_fBranchAlphaTestValue; // 0.0 to 255.0 alpha testing value, used for fading
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// frond geometry
|
||||
|
||||
SIndexed m_sFronds; // holds the frond vertices and index buffers for all
|
||||
// of the discrete LOD levels
|
||||
float m_fFrondAlphaTestValue; // 0.0 to 255.0 alpha testing value, used for fading
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// leaf geometry
|
||||
|
||||
SLeaf m_sLeaves0; // holds the primary leaf geometry, alpha fades into
|
||||
SLeaf m_sLeaves1; // m_sLeaves1 during LOD transitions
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// billboard geometry
|
||||
|
||||
SBillboard m_sBillboard0; // holds the main simple billboard geometry, alpha fades
|
||||
SBillboard m_sBillboard1; // into m_sBillboard1 in 360 degree mode
|
||||
SBillboard m_sHorizontalBillboard; // optional horizontal billboard used for aerial views
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// struct SGeometry::STextures declaration
|
||||
|
||||
struct BUILD_SPEED_TREE_RT_SET STextures
|
||||
{
|
||||
STextures( );
|
||||
~STextures( );
|
||||
|
||||
// branches
|
||||
const char* m_pBranchTextureFilename; // null-terminated string
|
||||
|
||||
// leaves
|
||||
unsigned int m_uiLeafTextureCount; // the number of char* elements in m_pLeafTextureFilenames
|
||||
const char** m_pLeafTextureFilenames; // array of null-terminated strings m_uiLeafTextureCount in size
|
||||
|
||||
// fronds
|
||||
unsigned int m_uiFrondTextureCount; // the number of char* elements in m_pFrondTextureFilenames
|
||||
const char** m_pFrondTextureFilenames; // array of null-terminated strings m_uiFrondTextureCount in size
|
||||
|
||||
// composite
|
||||
const char* m_pCompositeFilename; // null-terminated string
|
||||
|
||||
// self-shadow
|
||||
const char* m_pSelfShadowFilename; // null-terminated string
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Constructor/Destructor
|
||||
|
||||
CSpeedTreeRT( );
|
||||
~CSpeedTreeRT( );
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Memory allocation
|
||||
|
||||
static void* operator new(size_t nSize);
|
||||
static void* operator new[](size_t nSize);
|
||||
static void operator delete(void* pRawMemory);
|
||||
static void operator delete[](void* pRawMemory);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Specifying a tree model
|
||||
|
||||
bool Compute(const float* pTransform = 0, unsigned int nSeed = 1, bool bCompositeStrips = true);
|
||||
CSpeedTreeRT* Clone(float x = 0.0f, float y = 0.0f, float z = 0.0f, unsigned int nSeed = 0) const;
|
||||
const CSpeedTreeRT* InstanceOf(void) const;
|
||||
CSpeedTreeRT* MakeInstance(void);
|
||||
void DeleteTransientData(void);
|
||||
|
||||
bool LoadTree(const char* pFilename);
|
||||
bool LoadTree(const unsigned char* pBlock, unsigned int nNumBytes);
|
||||
unsigned char* SaveTree(unsigned int& nNumBytes, bool bSaveLeaves = false) const;
|
||||
|
||||
void GetTreeSize(float& fSize, float& fVariance) const;
|
||||
void SetTreeSize(float fNewSize, float fNewVariance = 0.0f);
|
||||
unsigned int GetSeed( ) const;
|
||||
|
||||
const float* GetTreePosition(void) const;
|
||||
void SetTreePosition(float x, float y, float z);
|
||||
|
||||
void SetLeafTargetAlphaMask(unsigned char ucMask = 0x54);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Lighting
|
||||
|
||||
// lighting style
|
||||
ELightingMethod GetBranchLightingMethod(void) const;
|
||||
void SetBranchLightingMethod(ELightingMethod eMethod);
|
||||
ELightingMethod GetLeafLightingMethod(void) const;
|
||||
void SetLeafLightingMethod(ELightingMethod eMethod);
|
||||
ELightingMethod GetFrondLightingMethod(void) const;
|
||||
void SetFrondLightingMethod(ELightingMethod eMethod);
|
||||
|
||||
EStaticLightingStyle GetStaticLightingStyle(void) const;
|
||||
void SetStaticLightingStyle(EStaticLightingStyle eStyle);
|
||||
float GetLeafLightingAdjustment( ) const;
|
||||
void SetLeafLightingAdjustment(float fScalar);
|
||||
|
||||
// global lighting state
|
||||
static bool GetLightState(unsigned int nLightIndex);
|
||||
static void SetLightState(unsigned int nLightIndex, bool bLightOn);
|
||||
static const float* GetLightAttributes(unsigned int nLightIndex);
|
||||
static void SetLightAttributes(unsigned int nLightIndex, const float* pLightAttributes);
|
||||
|
||||
// branch material
|
||||
const float* GetBranchMaterial(void) const;
|
||||
void SetBranchMaterial(const float* pMaterial);
|
||||
|
||||
// leaf material
|
||||
const float* GetLeafMaterial(void) const;
|
||||
void SetLeafMaterial(const float* pMaterial);
|
||||
|
||||
// frond material
|
||||
const float* GetFrondMaterial(void) const;
|
||||
void SetFrondMaterial(const float* pMaterial);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Camera
|
||||
|
||||
static void GetCamera(float* pPosition, float* pDirection);
|
||||
static void SetCamera(const float* pPosition, const float* pDirection);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Wind
|
||||
|
||||
static void SetTime(float fTime);
|
||||
void ComputeWindEffects(bool bBranches, bool bLeaves, bool bFronds = true);
|
||||
void ResetLeafWindState(void);
|
||||
|
||||
bool GetLeafRockingState(void) const;
|
||||
void SetLeafRockingState(bool bFlag);
|
||||
void SetNumLeafRockingGroups(unsigned int nRockingGroups);
|
||||
|
||||
EWindMethod GetLeafWindMethod(void) const;
|
||||
void SetLeafWindMethod(EWindMethod eMethod);
|
||||
EWindMethod GetBranchWindMethod(void) const;
|
||||
void SetBranchWindMethod(EWindMethod eMethod);
|
||||
EWindMethod GetFrondWindMethod(void) const;
|
||||
void SetFrondWindMethod(EWindMethod eMethod);
|
||||
|
||||
float GetWindStrength(void) const;
|
||||
float SetWindStrength(float fNewStrength, float fOldStrength = -1.0f, float fFrequencyTimeOffset = -1.0f);
|
||||
|
||||
static void SetNumWindMatrices(unsigned int nNumMatrices);
|
||||
static void SetWindMatrix(unsigned int nMatrixIndex, const float* pMatrix);
|
||||
void GetLocalMatrices(unsigned int& nStartingIndex, unsigned int& nMatrixSpan);
|
||||
void SetLocalMatrices(unsigned int nStartingMatrix, unsigned int nMatrixSpan);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// LOD
|
||||
|
||||
void ComputeLodLevel(void);
|
||||
float GetLodLevel(void) const;
|
||||
void SetLodLevel(float fLodLevel);
|
||||
static void SetDropToBillboard(bool bFlag);
|
||||
|
||||
void GetLodLimits(float& fNear, float& fFar) const;
|
||||
void SetLodLimits(float fNear, float fFar);
|
||||
|
||||
short GetDiscreteBranchLodLevel(float fLodLevel = -1.0f) const;
|
||||
unsigned short GetDiscreteLeafLodLevel(float fLodLevel = -1.0f) const;
|
||||
short GetDiscreteFrondLodLevel(float fLodLevel = -1.0f) const;
|
||||
|
||||
unsigned short GetNumBranchLodLevels(void) const;
|
||||
unsigned short GetNumLeafLodLevels(void) const;
|
||||
unsigned short GetNumFrondLodLevels(void) const;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Geometry
|
||||
|
||||
void DeleteBranchGeometry(void);
|
||||
void DeleteFrondGeometry(void);
|
||||
unsigned char* GetFrondGeometryMapIndexes(int nLodLevel) const;
|
||||
const float* GetLeafBillboardTable(unsigned int& nEntryCount) const;
|
||||
const float* GetLeafLodSizeAdjustments(void);
|
||||
void GetGeometry(SGeometry& sGeometry, unsigned long ulBitVector = SpeedTree_AllGeometry, short sOverrideBranchLodValue = -1, short sOverrideFrondLodValue = -1, short sOverrideLeafLodValue = -1);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Textures
|
||||
|
||||
void GetTextures(STextures& sTextures) const;
|
||||
void SetLeafTextureCoords(unsigned int nLeafMapIndex, const float* pTexCoords);
|
||||
void SetFrondTextureCoords(unsigned int nFrondMapIndex, const float* pTexCoords);
|
||||
static bool GetTextureFlip(void);
|
||||
static void SetTextureFlip(bool bFlag);
|
||||
void SetBranchTextureFilename(const char* pFilename);
|
||||
void SetLeafTextureFilename(unsigned int nLeafMapIndex, const char* pFilename);
|
||||
void SetFrondTextureFilename(unsigned int nFrondMapIndex, const char* pFilename);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Statistics & information
|
||||
|
||||
static void Authorize(const char* pKey);
|
||||
static bool IsAuthorized(void);
|
||||
static const char* GetCurrentError(void);
|
||||
static void ResetError(void);
|
||||
|
||||
void GetBoundingBox(float* pBounds) const;
|
||||
unsigned int GetLeafTriangleCount(float fLodLevel = -1.0f) const;
|
||||
unsigned int GetBranchTriangleCount(float fLodLevel = -1.0f) const;
|
||||
unsigned int GetFrondTriangleCount(float fLodLevel = -1.0f) const;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Collision objects
|
||||
|
||||
unsigned int GetCollisionObjectCount(void);
|
||||
void GetCollisionObject(unsigned int nIndex, ECollisionObjectType& eType, float* pPosition, float* pDimensions);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// User Data
|
||||
|
||||
const char* GetUserData(void) const;
|
||||
|
||||
private:
|
||||
// PORT: the SDK's private engine members (m_pEngine .. m_afHorizontalCoords) are opaque here.
|
||||
struct SImpl;
|
||||
SImpl* m_pImpl;
|
||||
CSpeedTreeRT(const CSpeedTreeRT&) = delete;
|
||||
CSpeedTreeRT& operator=(const CSpeedTreeRT&) = delete;
|
||||
};
|
||||
|
||||
|
||||
// Macintosh-specific
|
||||
#ifdef __ppc__
|
||||
#pragma export off
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,27 @@
|
||||
// opaque, owned by platform/.
|
||||
#include "d3d8.h"
|
||||
|
||||
// d3dx8core.h ID3DXBuffer / D3DXAssembleShader. There is no D3D8 shader assembler here:
|
||||
// D3DXAssembleShader fails with no code and no error buffer.
|
||||
struct ID3DXBuffer
|
||||
{
|
||||
virtual ~ID3DXBuffer() = default;
|
||||
virtual ULONG Release() = 0;
|
||||
virtual void* GetBufferPointer() = 0;
|
||||
virtual DWORD GetBufferSize() = 0;
|
||||
};
|
||||
typedef ID3DXBuffer* LPD3DXBUFFER;
|
||||
inline HRESULT D3DXAssembleShader(const void*, UINT, DWORD, LPD3DXBUFFER* ppConstants, LPD3DXBUFFER* ppCompiledShader, LPD3DXBUFFER* ppCompilationErrors)
|
||||
{
|
||||
if (ppConstants)
|
||||
*ppConstants = nullptr;
|
||||
if (ppCompiledShader)
|
||||
*ppCompiledShader = nullptr;
|
||||
if (ppCompilationErrors)
|
||||
*ppCompilationErrors = nullptr;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
struct ID3DXMesh;
|
||||
typedef ID3DXMesh* LPD3DXMESH;
|
||||
struct ID3DXMatrixStack;
|
||||
|
||||
Reference in New Issue
Block a user