render parity unit G: 40250 tiling selection + verbatim STP terrain
- PythonApplication::Create mirrors 40250 :1196-1251 (SOFTWARE_TILING cfg, auto tiling IsFastTNL ? HTP : STP, MinLOD on !IsFastTNL) - RecordingDevice caps: VertexShaderVersion 1.1 + CLIPTLVERTS (fast T&L -> HTP) - MapOutdoorRenderSTP.cpp replaced by the full 40250 source (native gate only) - native_render XYZRHW: fix inverted screen->NDC Y, negative rhw clip, no texture transform on TL vertices, specular-alpha vertex fog (capture v9) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
91ce13c3cf
commit
863f3771af
@@ -563,3 +563,4 @@
|
||||
{"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"}
|
||||
{"date": "2026-09-28T04:34:02+00:00", "unit": "EterLib/GrpMarkInstance.cpp", "action": "unit F: platform_stub skeleton deleted (every member was MT_PLATFORM_STUB), 40250 source copied verbatim; guild marks (PythonTextTail, PythonWindow CMarkBox) now load and draw", "evidence": "ctest 35/35 (login_live excluded); mark rendering NEEDS_LIVE"}
|
||||
{"date": "2026-09-28T04:53:55+00:00", "unit": "GameLib/MapOutdoorRenderSTP.cpp + UserInterface/PythonApplication.cpp Create (tiling) + RecordingDevice caps", "action": "unit G: STP file replaced by the full 40250 source (native-terrain gate only); Create gains the 40250 SOFTWARE_TILING/auto-tiling block and MinLOD for !IsFastTNL; RecordingDevice GetDeviceCaps reports VertexShaderVersion 1.1 + D3DPMISCCAPS_CLIPTLVERTS (40250 on a fast T&L card = HTP); native_render XYZRHW fixes: screen→NDC Y was inverted (drawn upside down and back-face culled), negative rhw forced w=1 (spikes), texture transform no longer applied to TL vertices, specular-alpha vertex fog plumbed (Render3DDraw.vertex_fog, capture v9)", "evidence": "ctest 35/35 (login_live excluded); default HTP frame 900 vs previous baseline mean abs diff ~0.6/255; STP forced (temporary edit, reverted) renders the spawn plaza/grass matching HTP layout, STP pixels NEEDS_LIVE"}
|
||||
|
||||
@@ -5,81 +5,97 @@
|
||||
"contracts": [],
|
||||
"functions": {
|
||||
"CMapOutdoor::__RenderTerrain_RenderSoftwareTransformPatch": {
|
||||
"status": "DIVERGENT",
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__RenderTerrain_RenderSoftwareTransformPatch"
|
||||
],
|
||||
"note": "No-op: the Godot terrain adapter draws the height-field (PORT-PLAN §3)."
|
||||
"note": "Verbatim 40250 body plus an early return when IsNativeTerrainRenderEnabled() is false (Godot terrain adapter path, PORT-PLAN §3), same gate as HTP. Reached only with SOFTWARE_TILING 1 or a non-fast-T&L device. Fake-server STP frame matches HTP layout; pixel parity vs a 40250 STP frame not verified."
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_RenderPatchSplat": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_RenderPatchSplat"
|
||||
],
|
||||
"note": "Drawn via XYZRHW through RecordingDevice/native_render (fixed 2026-09-28: pretransformed Y mapping, negative-rhw clip, specular-alpha vertex fog); fake-server frame with SOFTWARE_TILING forced matches the HTP layout; pixel parity vs a 40250 STP frame not verified."
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_RenderPatchNone": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "NEEDS_LIVE",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_RenderPatchNone"
|
||||
],
|
||||
"note": "Drawn via XYZRHW through RecordingDevice/native_render (fixed 2026-09-28: pretransformed Y mapping, negative-rhw clip, specular-alpha vertex fog); fake-server frame with SOFTWARE_TILING forced matches the HTP layout; pixel parity vs a 40250 STP frame not verified."
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_ApplyStaticShadowRenderState": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_ApplyStaticShadowRenderState"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_ApplyDynamicShadowRenderState": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_ApplyDynamicShadowRenderState"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_ApplyFogShadowRenderState": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_ApplyFogShadowRenderState"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_RestoreStaticShadowRenderState": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_RestoreStaticShadowRenderState"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_RestoreDynamicShadowRenderState": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_RestoreDynamicShadowRenderState"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_RestoreFogShadowRenderState": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_RestoreFogShadowRenderState"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_ApplyRenderState": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_ApplyRenderState"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_RestoreRenderState": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_RestoreRenderState"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_BuildPipeline": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_BuildPipeline"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_SetTransform": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_SetTransform"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_SetSplatStream": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_SetSplatStream"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_SetShadowStream": {
|
||||
"status": "DIVERGENT",
|
||||
"impl": [],
|
||||
"note": "Not built: only called from __RenderTerrain_RenderSoftwareTransformPatch, which is a no-op (Godot draws the terrain, PORT-PLAN §3)."
|
||||
"status": "PORTED",
|
||||
"impl": [
|
||||
"extension/src/platform/GameLib/MapOutdoorRenderSTP.cpp:CMapOutdoor::__SoftwareTransformPatch_SetShadowStream"
|
||||
]
|
||||
},
|
||||
"CMapOutdoor::__SoftwareTransformPatch_Initialize": {
|
||||
"status": "PORTED",
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
"impl": [
|
||||
"extension/src/platform/UserInterface/PythonApplication.cpp:CPythonApplication::Create"
|
||||
],
|
||||
"note": "40250 CPythonApplication lifecycle and state adapted for platform host and singletons; m_LightManager.Initialize() (40250 :1263) now called; Destroy() still empty (m_LightManager.Destroy at 40250 :1418 not yet mirrored)",
|
||||
"note": "40250 CPythonApplication lifecycle and state adapted for platform host and singletons; m_LightManager.Initialize() (40250 :1263) now called; Destroy() still empty (m_LightManager.Destroy at 40250 :1418 not yet mirrored); 40250 :1196-1251 tiling selection mirrored (SOFTWARE_TILING cfg → GRAPHICS_CAPS_SOFTWARE_TILING before device create, auto tiling IsFastTNL ? HTP : STP via ReserveSoftwareTilingEnable, !IsFastTNL → CGrannyLODController::SetMinLODMode(true)); RecordingDevice caps report VS 1.1 + CLIPTLVERTS so auto picks HTP",
|
||||
"test": "extension/tests/port_login_flow_test.cpp"
|
||||
},
|
||||
"CPythonApplication::SetGlobalCenterPosition": {
|
||||
|
||||
@@ -20,7 +20,7 @@ int g_native_terrain_override = -1;
|
||||
struct VertexLayout {
|
||||
unsigned stride = 0;
|
||||
bool rhw = false;
|
||||
int normal = -1, diffuse = -1, uv0 = -1, uv1 = -1;
|
||||
int normal = -1, diffuse = -1, specular = -1, uv0 = -1, uv1 = -1;
|
||||
};
|
||||
|
||||
// The element offsets of a fixed-function FVF (D3DXGetFVFVertexSize's order).
|
||||
@@ -41,7 +41,7 @@ VertexLayout fvf_layout(DWORD fvf)
|
||||
if (fvf & D3DFVF_NORMAL) { layout.normal = offset; offset += 12; }
|
||||
if (fvf & D3DFVF_PSIZE) offset += 4;
|
||||
if (fvf & D3DFVF_DIFFUSE) { layout.diffuse = offset; offset += 4; }
|
||||
if (fvf & D3DFVF_SPECULAR) offset += 4;
|
||||
if (fvf & D3DFVF_SPECULAR) { layout.specular = offset; offset += 4; }
|
||||
const unsigned texCount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
|
||||
for (unsigned i = 0; i < texCount; ++i)
|
||||
{
|
||||
@@ -281,11 +281,15 @@ public:
|
||||
return refs;
|
||||
}
|
||||
|
||||
// PORT: a D3D8 HAL on a T&L card (D3DDEVCAPS_HWTRANSFORMANDLIGHT), 8 lights, 4 texture stages.
|
||||
// PORT: a D3D8 HAL on a T&L card (D3DDEVCAPS_HWTRANSFORMANDLIGHT), 8 lights, 4 texture stages,
|
||||
// vertex shader 1.1 and T&L vertex clipping, as the D3D8 runtime reports for current GPUs; with
|
||||
// these CGraphicBase::IsFastTNL() is true, so auto tiling picks the hardware-transform terrain.
|
||||
HRESULT GetDeviceCaps(D3DCAPS8* caps) override
|
||||
{
|
||||
std::memset(caps, 0, sizeof(*caps));
|
||||
caps->DevCaps = D3DDEVCAPS_HWTRANSFORMANDLIGHT;
|
||||
caps->VertexShaderVersion = D3DVS_VERSION(1, 1);
|
||||
caps->PrimitiveMiscCaps = D3DPMISCCAPS_CLIPTLVERTS;
|
||||
caps->MaxActiveLights = 8;
|
||||
caps->MaxTextureBlendStages = 4;
|
||||
caps->MaxSimultaneousTextures = 4;
|
||||
@@ -785,6 +789,7 @@ private:
|
||||
// Elements past the stream's stride live in another stream (CreatePTStreamVertexShader).
|
||||
if (layout.normal + 12 > int(stride)) layout.normal = -1;
|
||||
if (layout.diffuse + 4 > int(stride)) layout.diffuse = -1;
|
||||
if (layout.specular + 4 > int(stride)) layout.specular = -1;
|
||||
if (layout.uv0 + 8 > int(stride)) layout.uv0 = -1;
|
||||
if (layout.uv1 + 8 > int(stride)) layout.uv1 = -1;
|
||||
|
||||
@@ -873,6 +878,7 @@ private:
|
||||
const Render3DDraw& prior = cached->second.geometry;
|
||||
draw.positions = prior.positions;
|
||||
draw.rhw = prior.rhw;
|
||||
draw.vertex_fog = prior.vertex_fog;
|
||||
draw.normals = prior.normals;
|
||||
draw.uv0 = prior.uv0;
|
||||
draw.uv1 = prior.uv1;
|
||||
@@ -885,6 +891,8 @@ private:
|
||||
{
|
||||
draw.positions.resize(count * 3);
|
||||
if (layout.rhw) draw.rhw.resize(count);
|
||||
const bool tl_fog = layout.rhw && layout.specular >= 0;
|
||||
if (tl_fog) draw.vertex_fog.resize(count);
|
||||
if (layout.normal >= 0) draw.normals.resize(count * 3);
|
||||
if (layout.uv0 >= 0) draw.uv0.resize(count * 2);
|
||||
if (layout.uv1 >= 0) draw.uv1.resize(count * 2);
|
||||
@@ -894,6 +902,7 @@ private:
|
||||
const uint8_t* v = vertices + (lo + i) * stride;
|
||||
std::memcpy(&draw.positions[i * 3], v, 12);
|
||||
if (layout.rhw) std::memcpy(&draw.rhw[i], v + 12, 4);
|
||||
if (tl_fog) draw.vertex_fog[i] = float(v[layout.specular + 3]) / 255.0f; // specular alpha
|
||||
if (layout.normal >= 0) std::memcpy(&draw.normals[i * 3], v + layout.normal, 12);
|
||||
if (layout.uv0 >= 0) std::memcpy(&draw.uv0[i * 2], v + layout.uv0, 8);
|
||||
if (layout.uv1 >= 0) std::memcpy(&draw.uv1[i * 2], v + layout.uv1, 8);
|
||||
|
||||
@@ -37,6 +37,8 @@ struct Render3DDraw {
|
||||
bool pretransformed = false;
|
||||
std::vector<float> positions; // x, y, z
|
||||
std::vector<float> rhw;
|
||||
// D3D8 vertex fog of an XYZRHW draw: the D3DFVF_SPECULAR alpha (0..1); empty otherwise.
|
||||
std::vector<float> vertex_fog;
|
||||
std::vector<float> normals; // x, y, z
|
||||
std::vector<float> uv0; // u, v
|
||||
std::vector<float> uv1; // u, v
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
// Platform implementation of 40250 GameLib/MapOutdoorRenderSTP.cpp (software-transform terrain patches).
|
||||
// The vertex-buffer lifecycle is the 40250 code as is; the patch drawing is left to the Godot terrain
|
||||
// (see MapOutdoorRenderHTP.cpp).
|
||||
// Platform copy of 40250 GameLib/MapOutdoorRenderSTP.cpp (software-transform terrain patches), as is
|
||||
// apart from the includes and the native-terrain gate: the Godot Metin2World adapter draws the terrain
|
||||
// unless IsNativeTerrainRenderEnabled() (see MapOutdoorRenderHTP.cpp). 40250 takes this path when
|
||||
// SOFTWARE_TILING is 1 in metin2.cfg, or with auto tiling on a device without fast T&L.
|
||||
#include "GameLib/StdAfx.h"
|
||||
#include "EterLib/StateManager.h"
|
||||
#include "GameLib/MapOutdoor.h"
|
||||
#include "GameLib/TerrainPatch.h"
|
||||
#include "GameLib/TerrainQuadtree.h"
|
||||
|
||||
#include "EterLib/Camera.h"
|
||||
#include "EterLib/StateManager.h"
|
||||
#include "../EterLib/RenderCommands3D.h"
|
||||
|
||||
struct SoftwareTransformPatch_SSplatVertex
|
||||
{
|
||||
@@ -15,9 +20,724 @@ struct SoftwareTransformPatch_SSplatVertex
|
||||
D3DXVECTOR2 kTex2;
|
||||
};
|
||||
|
||||
// PORT: Godot draws the terrain (PORT-PLAN §3).
|
||||
|
||||
|
||||
void CMapOutdoor::__RenderTerrain_RenderSoftwareTransformPatch()
|
||||
{
|
||||
// PORT: see the file comment.
|
||||
if (!IsNativeTerrainRenderEnabled())
|
||||
return;
|
||||
|
||||
SoftwareTransformPatch_SRenderState kTPRS;
|
||||
|
||||
DWORD dwFogEnable = STATEMANAGER.GetRenderState(D3DRS_FOGENABLE);
|
||||
|
||||
__SoftwareTransformPatch_ApplyRenderState();
|
||||
|
||||
__SoftwareTransformPatch_BuildPipeline(kTPRS);
|
||||
|
||||
std::pair<float, long> fog_far(kTPRS.m_fFogFarDistance+800.0f, 0);
|
||||
std::pair<float, long> fog_near(kTPRS.m_fFogNearDistance-3200.0f, 0);
|
||||
|
||||
std::vector<std::pair<float ,long> >::iterator far_it = std::upper_bound(m_PatchVector.begin(),m_PatchVector.end(),fog_far);
|
||||
std::vector<std::pair<float ,long> >::iterator near_it = std::upper_bound(m_PatchVector.begin(),m_PatchVector.end(),fog_near);
|
||||
|
||||
WORD wPrimitiveCount;
|
||||
D3DPRIMITIVETYPE ePrimitiveType;
|
||||
|
||||
BYTE byCUrrentLODLevel = 0;
|
||||
|
||||
float fLODLevel1Distance = __GetNoFogDistance();
|
||||
float fLODLevel2Distance = __GetFogDistance();
|
||||
|
||||
SelectIndexBuffer(0, &wPrimitiveCount, &ePrimitiveType);
|
||||
|
||||
STATEMANAGER.SetVertexShader(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_SPECULAR|D3DFVF_TEX2);
|
||||
|
||||
std::vector<std::pair<float, long> >::iterator it = m_PatchVector.begin();
|
||||
|
||||
for( ; it != near_it; ++it)
|
||||
{
|
||||
if (byCUrrentLODLevel == 0 && fLODLevel1Distance <= it->first)
|
||||
{
|
||||
byCUrrentLODLevel = 1;
|
||||
SelectIndexBuffer(1, &wPrimitiveCount, &ePrimitiveType);
|
||||
}
|
||||
else if (byCUrrentLODLevel == 1 && fLODLevel2Distance <= it->first)
|
||||
{
|
||||
byCUrrentLODLevel = 2;
|
||||
SelectIndexBuffer(2, &wPrimitiveCount, &ePrimitiveType);
|
||||
}
|
||||
|
||||
__SoftwareTransformPatch_RenderPatchSplat(kTPRS, it->second, wPrimitiveCount, ePrimitiveType, false);
|
||||
if (m_iRenderedSplatNum >= m_iSplatLimit)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (m_iRenderedSplatNum < m_iSplatLimit)
|
||||
{
|
||||
for(it = near_it; it != far_it; ++it)
|
||||
{
|
||||
if (byCUrrentLODLevel == 0 && fLODLevel1Distance <= it->first)
|
||||
{
|
||||
byCUrrentLODLevel = 1;
|
||||
SelectIndexBuffer(1, &wPrimitiveCount, &ePrimitiveType);
|
||||
}
|
||||
else if (byCUrrentLODLevel == 1 && fLODLevel2Distance <= it->first)
|
||||
{
|
||||
byCUrrentLODLevel = 2;
|
||||
SelectIndexBuffer(2, &wPrimitiveCount, &ePrimitiveType);
|
||||
}
|
||||
|
||||
__SoftwareTransformPatch_RenderPatchSplat(kTPRS, it->second, wPrimitiveCount, ePrimitiveType, true);
|
||||
|
||||
if (m_iRenderedSplatNum >= m_iSplatLimit)
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATEMANAGER.SetTexture(0, NULL);
|
||||
STATEMANAGER.SetTexture(1, NULL);
|
||||
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||
|
||||
STATEMANAGER.SetVertexShader(D3DFVF_XYZRHW);
|
||||
|
||||
if (IsFastTNL())
|
||||
{
|
||||
if (byCUrrentLODLevel != 2)
|
||||
{
|
||||
byCUrrentLODLevel = 2;
|
||||
SelectIndexBuffer(2, &wPrimitiveCount, &ePrimitiveType);
|
||||
}
|
||||
|
||||
if (m_iRenderedSplatNum < m_iSplatLimit)
|
||||
{
|
||||
for(it = far_it; it != m_PatchVector.end(); ++it)
|
||||
{
|
||||
__SoftwareTransformPatch_RenderPatchNone(kTPRS, it->second, wPrimitiveCount, ePrimitiveType);
|
||||
|
||||
if (m_iRenderedSplatNum >= m_iSplatLimit)
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Render State & TextureStageState
|
||||
__SoftwareTransformPatch_RestoreRenderState(dwFogEnable);
|
||||
}
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_RenderPatchSplat(SoftwareTransformPatch_SRenderState& rkTPRS, long patchnum, WORD wPrimitiveCount, D3DPRIMITIVETYPE ePrimitiveType, bool isFogEnable)
|
||||
{
|
||||
assert(NULL!=m_pTerrainPatchProxyList && "CMapOutdoor::__SoftwareTransformPatch_RenderPatchSplat");
|
||||
|
||||
CTerrainPatchProxy * pTerrainPatchProxy = &m_pTerrainPatchProxyList[patchnum];
|
||||
|
||||
if (!pTerrainPatchProxy->isUsed())
|
||||
return;
|
||||
|
||||
bool isDynamicShadow = pTerrainPatchProxy->IsIn(rkTPRS.m_v3Player, 3000.0f);
|
||||
|
||||
if (!m_bDrawChrShadow)
|
||||
isDynamicShadow = false;
|
||||
|
||||
long sPatchNum = pTerrainPatchProxy->GetPatchNum();
|
||||
|
||||
if (sPatchNum < 0)
|
||||
return;
|
||||
|
||||
BYTE ucTerrainNum = pTerrainPatchProxy->GetTerrainNum();
|
||||
|
||||
if (0xFF == ucTerrainNum)
|
||||
return;
|
||||
|
||||
CTerrain * pTerrain;
|
||||
if (!GetTerrainPointer(ucTerrainNum, &pTerrain))
|
||||
return;
|
||||
|
||||
WORD wCoordX, wCoordY;
|
||||
pTerrain->GetCoordinate(&wCoordX, &wCoordY);
|
||||
|
||||
TTerrainSplatPatch & rTerrainSplatPatch = pTerrain->GetTerrainSplatPatch();
|
||||
|
||||
SoftwareTransformPatch_STLVertex akTransVertex[CTerrainPatch::TERRAIN_VERTEX_COUNT];
|
||||
if (!__SoftwareTransformPatch_SetTransform(rkTPRS, akTransVertex, *pTerrainPatchProxy, wCoordX, wCoordY, isFogEnable, isDynamicShadow))
|
||||
return;
|
||||
|
||||
if (!__SoftwareTransformPatch_SetSplatStream(akTransVertex))
|
||||
return;
|
||||
|
||||
if (isFogEnable)
|
||||
{
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_BLENDDIFFUSEALPHA);
|
||||
}
|
||||
else
|
||||
{
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
||||
}
|
||||
|
||||
int iPrevRenderedSplatNum=m_iRenderedSplatNum;
|
||||
|
||||
bool isFirst=true;
|
||||
for (DWORD j = 1; j < pTerrain->GetNumTextures(); ++j)
|
||||
{
|
||||
TTerainSplat & rSplat = rTerrainSplatPatch.Splats[j];
|
||||
|
||||
if (!rSplat.Active)
|
||||
continue;
|
||||
|
||||
if (rTerrainSplatPatch.PatchTileCount[sPatchNum][j] == 0)
|
||||
continue;
|
||||
|
||||
const TTerrainTexture & rTexture = m_TextureSet.GetTexture(j);
|
||||
|
||||
if (isFirst)
|
||||
{
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
|
||||
STATEMANAGER.SetTexture(0, rTexture.pd3dTexture);
|
||||
STATEMANAGER.SetTexture(1, rSplat.pd3dTexture);
|
||||
STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
isFirst=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
STATEMANAGER.SetTexture(0, rTexture.pd3dTexture);
|
||||
STATEMANAGER.SetTexture(1, rSplat.pd3dTexture);
|
||||
STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
|
||||
}
|
||||
|
||||
std::vector<int>::iterator aIterator = std::find(m_RenderedTextureNumVector.begin(), m_RenderedTextureNumVector.end(), (int)j);
|
||||
if (aIterator == m_RenderedTextureNumVector.end())
|
||||
m_RenderedTextureNumVector.push_back(j);
|
||||
++m_iRenderedSplatNum;
|
||||
if (m_iRenderedSplatNum >= m_iSplatLimit)
|
||||
break;
|
||||
}
|
||||
|
||||
// 그림자
|
||||
if (m_bDrawShadow)
|
||||
{
|
||||
__SoftwareTransformPatch_SetShadowStream(akTransVertex);
|
||||
__SoftwareTransformPatch_ApplyStaticShadowRenderState();
|
||||
|
||||
if (isDynamicShadow)
|
||||
__SoftwareTransformPatch_ApplyDynamicShadowRenderState();
|
||||
else
|
||||
__SoftwareTransformPatch_ApplyFogShadowRenderState();
|
||||
|
||||
if (isFogEnable)
|
||||
{
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, TRUE);
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGCOLOR, 0xFFFFFFFF);
|
||||
STATEMANAGER.SetTexture(0, pTerrain->GetShadowTexture());
|
||||
STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGCOLOR, rkTPRS.m_dwFogColor);
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
STATEMANAGER.SetTexture(0, pTerrain->GetShadowTexture());
|
||||
STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
|
||||
}
|
||||
|
||||
if (isDynamicShadow)
|
||||
__SoftwareTransformPatch_RestoreDynamicShadowRenderState();
|
||||
else
|
||||
__SoftwareTransformPatch_RestoreFogShadowRenderState();
|
||||
|
||||
ms_faceCount += wPrimitiveCount;
|
||||
++m_iRenderedSplatNum;
|
||||
|
||||
|
||||
|
||||
__SoftwareTransformPatch_RestoreStaticShadowRenderState();
|
||||
}
|
||||
|
||||
++m_iRenderedPatchNum;
|
||||
|
||||
int iCurRenderedSplatNum=m_iRenderedSplatNum-iPrevRenderedSplatNum;
|
||||
|
||||
m_iRenderedSplatNumSqSum+=iCurRenderedSplatNum*iCurRenderedSplatNum;
|
||||
}
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_RenderPatchNone(SoftwareTransformPatch_SRenderState& rkTPRS, long patchnum, WORD wPrimitiveCount, D3DPRIMITIVETYPE ePrimitiveType)
|
||||
{
|
||||
assert(NULL!=m_pTerrainPatchProxyList && "CMapOutdoor::__SoftwareTransformPatch_RenderPatchNone");
|
||||
|
||||
CTerrainPatchProxy * pTerrainPatchProxy = &m_pTerrainPatchProxyList[patchnum];
|
||||
|
||||
if (!pTerrainPatchProxy->isUsed())
|
||||
return;
|
||||
|
||||
long sPatchNum = pTerrainPatchProxy->GetPatchNum();
|
||||
if (sPatchNum < 0)
|
||||
return;
|
||||
|
||||
BYTE ucTerrainNum = pTerrainPatchProxy->GetTerrainNum();
|
||||
if (0xFF == ucTerrainNum)
|
||||
return;
|
||||
|
||||
CTerrain * pTerrain;
|
||||
if (!GetTerrainPointer(ucTerrainNum, &pTerrain))
|
||||
return;
|
||||
|
||||
WORD wCoordX, wCoordY;
|
||||
pTerrain->GetCoordinate(&wCoordX, &wCoordY);
|
||||
|
||||
SoftwareTransformPatch_SSourceVertex* akSrcVertex=pTerrainPatchProxy->SoftwareTransformPatch_GetTerrainVertexDataPtr();
|
||||
if (!akSrcVertex)
|
||||
return;
|
||||
|
||||
float fScreenHalfWidth=rkTPRS.m_fScreenHalfWidth;
|
||||
float fScreenHalfHeight=rkTPRS.m_fScreenHalfHeight;
|
||||
|
||||
D3DXMATRIX m4Frustum=rkTPRS.m_m4Frustum;
|
||||
|
||||
SoftwareTransformPatch_STVertex akTransVertex[CTerrainPatch::TERRAIN_VERTEX_COUNT];
|
||||
|
||||
D3DXVECTOR4* akPosition=(D3DXVECTOR4*)akTransVertex;
|
||||
D3DXVECTOR4* pkPosition;
|
||||
for (UINT uIndex=0; uIndex!=CTerrainPatch::TERRAIN_VERTEX_COUNT; ++uIndex)
|
||||
{
|
||||
pkPosition=akPosition+uIndex;
|
||||
D3DXVec3Transform(pkPosition, &akSrcVertex[uIndex].kPosition, &m4Frustum);
|
||||
pkPosition->w=1.0f/pkPosition->w;
|
||||
pkPosition->z*=pkPosition->w;
|
||||
pkPosition->y=(pkPosition->y*pkPosition->w-1.0f)*fScreenHalfHeight;
|
||||
pkPosition->x=(pkPosition->x*pkPosition->w+1.0f)*fScreenHalfWidth;
|
||||
}
|
||||
|
||||
|
||||
IDirect3DVertexBuffer8* pkVB=m_kSTPD.m_pkVBNone[m_kSTPD.m_dwNonePos++];
|
||||
m_kSTPD.m_dwNonePos%=SoftwareTransformPatch_SData::NONE_VB_NUM;
|
||||
if (!pkVB)
|
||||
return;
|
||||
|
||||
DWORD dwVBSize=sizeof(SoftwareTransformPatch_STVertex)*CTerrainPatch::TERRAIN_VERTEX_COUNT;
|
||||
SoftwareTransformPatch_STVertex* akDstVertex;
|
||||
if (FAILED(
|
||||
pkVB->Lock(0, dwVBSize, (BYTE**)&akDstVertex, D3DLOCK_DISCARD)
|
||||
)) return;
|
||||
|
||||
memcpy(akDstVertex, akTransVertex, dwVBSize);
|
||||
|
||||
pkVB->Unlock();
|
||||
|
||||
STATEMANAGER.SetStreamSource(0, pkVB, sizeof(SoftwareTransformPatch_STVertex));
|
||||
STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
|
||||
ms_faceCount += wPrimitiveCount;
|
||||
}
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_ApplyStaticShadowRenderState()
|
||||
{
|
||||
STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
|
||||
STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);
|
||||
|
||||
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_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
|
||||
|
||||
}
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_ApplyDynamicShadowRenderState()
|
||||
{
|
||||
STATEMANAGER.SetTexture(1, m_lpCharacterShadowMapTexture);
|
||||
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_ALPHAARG1, D3DTA_CURRENT);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
|
||||
}
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_ApplyFogShadowRenderState()
|
||||
{
|
||||
STATEMANAGER.SetTexture(1, NULL);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
}
|
||||
void CMapOutdoor::__SoftwareTransformPatch_RestoreStaticShadowRenderState()
|
||||
{
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);
|
||||
|
||||
STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_RestoreDynamicShadowRenderState()
|
||||
{
|
||||
STATEMANAGER.SetTexture(1, NULL);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_RestoreFogShadowRenderState()
|
||||
{
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, FALSE);
|
||||
|
||||
STATEMANAGER.SetTexture(1, NULL);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
}
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_ApplyRenderState()
|
||||
{
|
||||
DWORD dwFogColor=0xffffffff;
|
||||
if (mc_pEnvironmentData)
|
||||
dwFogColor=mc_pEnvironmentData->FogColor;
|
||||
|
||||
BOOL isSoftwareVertexClipping=FALSE;
|
||||
if (!IsTLVertexClipping())
|
||||
isSoftwareVertexClipping=TRUE;
|
||||
|
||||
STATEMANAGER.SaveRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, isSoftwareVertexClipping);
|
||||
|
||||
STATEMANAGER.SaveRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||
STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, TRUE);
|
||||
STATEMANAGER.SaveRenderState(D3DRS_ALPHAREF, 0x00000000);
|
||||
STATEMANAGER.SaveRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
|
||||
|
||||
STATEMANAGER.SaveRenderState(D3DRS_TEXTUREFACTOR, dwFogColor);
|
||||
STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, FALSE);
|
||||
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);
|
||||
STATEMANAGER.SetBestFiltering(0);
|
||||
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
|
||||
STATEMANAGER.SetBestFiltering(1);
|
||||
|
||||
CSpeedTreeWrapper::ms_bSelfShadowOn = true;
|
||||
|
||||
// Render State & TextureStageState
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
m_iRenderedSplatNumSqSum = 0;
|
||||
m_iRenderedPatchNum = 0;
|
||||
m_iRenderedSplatNum = 0;
|
||||
m_RenderedTextureNumVector.clear();
|
||||
|
||||
m_matWorldForCommonUse._41 = 0.0f;
|
||||
m_matWorldForCommonUse._42 = 0.0f;
|
||||
STATEMANAGER.SetTransform(D3DTS_WORLD, &m_matWorldForCommonUse);
|
||||
}
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_RestoreRenderState(DWORD dwFogEnable)
|
||||
{
|
||||
STATEMANAGER.SetRenderState(D3DRS_LIGHTING, TRUE);
|
||||
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
|
||||
STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, dwFogEnable);
|
||||
|
||||
std::sort(m_RenderedTextureNumVector.begin(),m_RenderedTextureNumVector.end());
|
||||
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_TEXTUREFACTOR);
|
||||
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_ALPHABLENDENABLE);
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_ALPHAREF);
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_ALPHAFUNC);
|
||||
|
||||
STATEMANAGER.RestoreRenderState(D3DRS_SOFTWAREVERTEXPROCESSING);
|
||||
|
||||
// Render State & TextureStageState
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_BuildPipeline(SoftwareTransformPatch_SRenderState& rkTPRS)
|
||||
{
|
||||
memset(&rkTPRS, 0, sizeof(rkTPRS));
|
||||
|
||||
if (mc_pEnvironmentData)
|
||||
{
|
||||
rkTPRS.m_dwFogColor = mc_pEnvironmentData->FogColor;
|
||||
rkTPRS.m_fFogNearDistance = mc_pEnvironmentData->GetFogNearDistance();
|
||||
rkTPRS.m_fFogFarDistance = mc_pEnvironmentData->GetFogFarDistance();
|
||||
}
|
||||
else
|
||||
{
|
||||
rkTPRS.m_dwFogColor = 0xffffffff;
|
||||
rkTPRS.m_fFogNearDistance = 5000.0f;
|
||||
rkTPRS.m_fFogFarDistance = 10000.0f;
|
||||
}
|
||||
|
||||
UINT uScreenWidth;
|
||||
UINT uScreenHeight;
|
||||
CScreen::GetBackBufferSize(&uScreenWidth, &uScreenHeight);
|
||||
|
||||
rkTPRS.m_fScreenHalfWidth = +float(uScreenWidth) / 2.0f;
|
||||
rkTPRS.m_fScreenHalfHeight = -float(uScreenHeight) / 2.0f;
|
||||
|
||||
STATEMANAGER.GetLight(0, &rkTPRS.m_kLight);
|
||||
STATEMANAGER.GetMaterial(&rkTPRS.m_kMtrl);
|
||||
|
||||
D3DXMATRIX m4View;STATEMANAGER.GetTransform(D3DTS_VIEW, &m4View);
|
||||
D3DXMATRIX m4Proj;STATEMANAGER.GetTransform(D3DTS_PROJECTION, &m4Proj);
|
||||
|
||||
D3DXMatrixMultiply(&rkTPRS.m_m4Frustum, &m4View, &m4Proj);
|
||||
|
||||
rkTPRS.m_v3Player.x = +m_v3Player.x;
|
||||
rkTPRS.m_v3Player.y = -m_v3Player.y;
|
||||
rkTPRS.m_v3Player.z = +m_v3Player.z;
|
||||
|
||||
rkTPRS.m_m4Proj = m4Proj;
|
||||
rkTPRS.m_m4DynamicShadow = m_matLightView * m_matDynamicShadowScale;
|
||||
|
||||
D3DXVECTOR3 kFogNearVector;
|
||||
const auto farvv = D3DXVECTOR3(0.0f, 0.0f, -rkTPRS.m_fFogNearDistance);
|
||||
D3DXVec3TransformCoord(&kFogNearVector, &farvv, &rkTPRS.m_m4Proj);
|
||||
|
||||
D3DXVECTOR3 kFogFarVector;
|
||||
const auto nearvv = D3DXVECTOR3(0.0f, 0.0f, -rkTPRS.m_fFogFarDistance);
|
||||
D3DXVec3TransformCoord(&kFogFarVector, &nearvv, &rkTPRS.m_m4Proj);
|
||||
|
||||
float fFogNear = kFogNearVector.z;
|
||||
float fFogFar = kFogFarVector.z;
|
||||
float fFogLenInv = 1.0f / (fFogFar-fFogNear);
|
||||
|
||||
rkTPRS.m_fFogNearTransZ = fFogNear;
|
||||
rkTPRS.m_fFogFarTransZ = fFogFar;
|
||||
rkTPRS.m_fFogLenInv = fFogLenInv;
|
||||
|
||||
}
|
||||
|
||||
bool CMapOutdoor::__SoftwareTransformPatch_SetTransform(SoftwareTransformPatch_SRenderState& rkTPRS, SoftwareTransformPatch_STLVertex* akTransVertex, CTerrainPatchProxy& rkTerrainPatchProxy, UINT uTerrainX, UINT uTerrainY, bool isFogEnable, bool isDynamicShadow)
|
||||
{
|
||||
SoftwareTransformPatch_SSourceVertex* akSrcVertex=rkTerrainPatchProxy.SoftwareTransformPatch_GetTerrainVertexDataPtr();
|
||||
if (!akSrcVertex)
|
||||
return false;
|
||||
|
||||
rkTerrainPatchProxy.SoftwareTransformPatch_UpdateTerrainLighting(
|
||||
m_kSTPD.m_dwLightVersion,
|
||||
rkTPRS.m_kLight, rkTPRS.m_kMtrl);
|
||||
|
||||
D3DXVECTOR3* pkSrcPosition;
|
||||
|
||||
float fTilePatternX=+1/640.0f;
|
||||
float fTilePatternY=-1/640.0f;
|
||||
|
||||
float fTerrainBaseX=-(float) (uTerrainX * CTerrainImpl::TERRAIN_XSIZE)+m_fTerrainTexCoordBase * 12.30769f;
|
||||
float fTerrainBaseY=+(float) (uTerrainY * CTerrainImpl::TERRAIN_YSIZE)+m_fTerrainTexCoordBase * 12.30769f;
|
||||
|
||||
float fScreenHalfWidth=rkTPRS.m_fScreenHalfWidth;
|
||||
float fScreenHalfHeight=rkTPRS.m_fScreenHalfHeight;
|
||||
|
||||
float fAlphaPatternX=m_matSplatAlpha._11;
|
||||
float fAlphaPatternY=m_matSplatAlpha._22;
|
||||
float fAlphaBiasX=m_matSplatAlpha._41;
|
||||
float fAlphaBiasY=m_matSplatAlpha._42;
|
||||
float fShadowPatternX=+m_fTerrainTexCoordBase * ((float) CTerrainImpl::PATCH_XSIZE / static_cast<float>(CTerrainImpl::XSIZE));
|
||||
float fShadowPatternY=-m_fTerrainTexCoordBase * ((float) CTerrainImpl::PATCH_YSIZE / static_cast<float>(CTerrainImpl::YSIZE));
|
||||
|
||||
D3DXMATRIX m4Frustum=rkTPRS.m_m4Frustum;
|
||||
|
||||
if (isFogEnable)
|
||||
{
|
||||
float fFogCur;
|
||||
float fFogFar=rkTPRS.m_fFogFarTransZ;
|
||||
float fFogLenInv=rkTPRS.m_fFogLenInv;
|
||||
|
||||
float fLocalX;
|
||||
float fLocalY;
|
||||
|
||||
SoftwareTransformPatch_STLVertex kWorkVertex;
|
||||
for (UINT uIndex=0; uIndex!=CTerrainPatch::TERRAIN_VERTEX_COUNT; ++uIndex)
|
||||
{
|
||||
pkSrcPosition=&akSrcVertex[uIndex].kPosition;
|
||||
D3DXVec3Transform(&kWorkVertex.kPosition, pkSrcPosition, &m4Frustum);
|
||||
fLocalX=pkSrcPosition->x+fTerrainBaseX;
|
||||
fLocalY=pkSrcPosition->y+fTerrainBaseY;
|
||||
kWorkVertex.kPosition.w=1.0f/kWorkVertex.kPosition.w;
|
||||
kWorkVertex.kPosition.x*=kWorkVertex.kPosition.w;
|
||||
kWorkVertex.kPosition.y*=kWorkVertex.kPosition.w;
|
||||
kWorkVertex.kPosition.z*=kWorkVertex.kPosition.w;
|
||||
kWorkVertex.kPosition.x=(kWorkVertex.kPosition.x+1.0f)*fScreenHalfWidth;
|
||||
kWorkVertex.kPosition.y=(kWorkVertex.kPosition.y-1.0f)*fScreenHalfHeight;
|
||||
kWorkVertex.dwDiffuse=akSrcVertex[uIndex].dwDiffuse;
|
||||
kWorkVertex.kTexTile.x=pkSrcPosition->x*fTilePatternX;
|
||||
kWorkVertex.kTexTile.y=pkSrcPosition->y*fTilePatternY;
|
||||
kWorkVertex.kTexAlpha.x=fLocalX*fAlphaPatternX+fAlphaBiasX;
|
||||
kWorkVertex.kTexAlpha.y=fLocalY*fAlphaPatternY+fAlphaBiasY;
|
||||
kWorkVertex.kTexStaticShadow.x=fLocalX*fShadowPatternX;
|
||||
kWorkVertex.kTexStaticShadow.y=fLocalY*fShadowPatternY;
|
||||
kWorkVertex.kTexDynamicShadow.x=0.0f;
|
||||
kWorkVertex.kTexDynamicShadow.y=0.0f;
|
||||
|
||||
fFogCur=(fFogFar-kWorkVertex.kPosition.z)*fFogLenInv;
|
||||
if (fFogCur<0.0f)
|
||||
kWorkVertex.dwFog=kWorkVertex.dwDiffuse=0x0000000|(kWorkVertex.dwDiffuse&0xffffff);
|
||||
else if (fFogCur>1.0f)
|
||||
kWorkVertex.dwFog=kWorkVertex.dwDiffuse=0xFF000000|(kWorkVertex.dwDiffuse&0xffffff);
|
||||
else
|
||||
kWorkVertex.dwFog=kWorkVertex.dwDiffuse=BYTE(255.0f*fFogCur)<<24|(kWorkVertex.dwDiffuse&0xffffff);
|
||||
|
||||
*(akTransVertex+uIndex)=kWorkVertex;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float fLocalX;
|
||||
float fLocalY;
|
||||
|
||||
SoftwareTransformPatch_STLVertex kWorkVertex;
|
||||
for (UINT uIndex=0; uIndex!=CTerrainPatch::TERRAIN_VERTEX_COUNT; ++uIndex)
|
||||
{
|
||||
pkSrcPosition=&akSrcVertex[uIndex].kPosition;
|
||||
D3DXVec3Transform(&kWorkVertex.kPosition, pkSrcPosition, &m4Frustum);
|
||||
fLocalX=pkSrcPosition->x+fTerrainBaseX;
|
||||
fLocalY=pkSrcPosition->y+fTerrainBaseY;
|
||||
kWorkVertex.kPosition.w=1.0f/kWorkVertex.kPosition.w;
|
||||
kWorkVertex.kPosition.x*=kWorkVertex.kPosition.w;
|
||||
kWorkVertex.kPosition.y*=kWorkVertex.kPosition.w;
|
||||
kWorkVertex.kPosition.z*=kWorkVertex.kPosition.w;
|
||||
kWorkVertex.kPosition.x=(kWorkVertex.kPosition.x+1.0f)*fScreenHalfWidth;
|
||||
kWorkVertex.kPosition.y=(kWorkVertex.kPosition.y-1.0f)*fScreenHalfHeight;
|
||||
kWorkVertex.dwDiffuse=akSrcVertex[uIndex].dwDiffuse;
|
||||
kWorkVertex.dwFog=0xffffffff;
|
||||
kWorkVertex.kTexTile.x=pkSrcPosition->x*fTilePatternX;
|
||||
kWorkVertex.kTexTile.y=pkSrcPosition->y*fTilePatternY;
|
||||
kWorkVertex.kTexAlpha.x=fLocalX*fAlphaPatternX+fAlphaBiasX;
|
||||
kWorkVertex.kTexAlpha.y=fLocalY*fAlphaPatternY+fAlphaBiasY;
|
||||
kWorkVertex.kTexStaticShadow.x=fLocalX*fShadowPatternX;
|
||||
kWorkVertex.kTexStaticShadow.y=fLocalY*fShadowPatternY;
|
||||
kWorkVertex.kTexDynamicShadow.x=0.0f;
|
||||
kWorkVertex.kTexDynamicShadow.y=0.0f;
|
||||
|
||||
*(akTransVertex+uIndex)=kWorkVertex;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDynamicShadow)
|
||||
{
|
||||
D3DXMATRIX m4DynamicShadow=rkTPRS.m_m4DynamicShadow;
|
||||
|
||||
D3DXVECTOR3 v3Shadow;
|
||||
for (UINT uIndex=0; uIndex!=CTerrainPatch::TERRAIN_VERTEX_COUNT; ++uIndex)
|
||||
{
|
||||
D3DXVec3TransformCoord(&v3Shadow, &akSrcVertex[uIndex].kPosition, &m4DynamicShadow);
|
||||
akTransVertex[uIndex].kTexDynamicShadow.x=v3Shadow.x;
|
||||
akTransVertex[uIndex].kTexDynamicShadow.y=v3Shadow.y;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMapOutdoor::__SoftwareTransformPatch_SetSplatStream(SoftwareTransformPatch_STLVertex* akSrcVertex)
|
||||
{
|
||||
IDirect3DVertexBuffer8* pkVB=m_kSTPD.m_pkVBSplat[m_kSTPD.m_dwSplatPos++];
|
||||
m_kSTPD.m_dwSplatPos%=SoftwareTransformPatch_SData::SPLAT_VB_NUM;
|
||||
if (!pkVB)
|
||||
return false;
|
||||
|
||||
DWORD dwVBSize=sizeof(SoftwareTransformPatch_SSplatVertex)*CTerrainPatch::TERRAIN_VERTEX_COUNT;
|
||||
SoftwareTransformPatch_SSplatVertex* akDstVertex;
|
||||
if (FAILED(
|
||||
pkVB->Lock(0, dwVBSize, (BYTE**)&akDstVertex, 0)//D3DLOCK_DISCARD)
|
||||
)) return false;
|
||||
|
||||
for (UINT uIndex=0; uIndex!=CTerrainPatch::TERRAIN_VERTEX_COUNT; ++uIndex)
|
||||
*(akDstVertex+uIndex)=*((SoftwareTransformPatch_SSplatVertex*)(akSrcVertex+uIndex));
|
||||
|
||||
pkVB->Unlock();
|
||||
|
||||
STATEMANAGER.SetStreamSource(0, pkVB, sizeof(SoftwareTransformPatch_SSplatVertex));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMapOutdoor::__SoftwareTransformPatch_SetShadowStream(SoftwareTransformPatch_STLVertex* akSrcVertex)
|
||||
{
|
||||
IDirect3DVertexBuffer8* pkVB=m_kSTPD.m_pkVBSplat[m_kSTPD.m_dwSplatPos++];
|
||||
m_kSTPD.m_dwSplatPos%=SoftwareTransformPatch_SData::SPLAT_VB_NUM;
|
||||
if (!pkVB)
|
||||
return false;
|
||||
|
||||
DWORD dwVBSize=sizeof(SoftwareTransformPatch_SSplatVertex)*CTerrainPatch::TERRAIN_VERTEX_COUNT;
|
||||
SoftwareTransformPatch_SSplatVertex* akDstVertex;
|
||||
if (FAILED(
|
||||
pkVB->Lock(0, dwVBSize, (BYTE**)&akDstVertex, 0)//D3DLOCK_DISCARD)
|
||||
)) return false;
|
||||
|
||||
SoftwareTransformPatch_STLVertex* pkSrcVertex;
|
||||
SoftwareTransformPatch_SSplatVertex* pkDstVertex;
|
||||
for (UINT uIndex=0; uIndex!=CTerrainPatch::TERRAIN_VERTEX_COUNT; ++uIndex)
|
||||
{
|
||||
pkSrcVertex=akSrcVertex+uIndex;
|
||||
pkDstVertex=akDstVertex+uIndex;
|
||||
pkDstVertex->kPosition=pkSrcVertex->kPosition;
|
||||
pkDstVertex->dwDiffuse=pkSrcVertex->dwDiffuse;
|
||||
pkDstVertex->dwSpecular=pkSrcVertex->dwFog;
|
||||
pkDstVertex->kTex1=pkSrcVertex->kTexStaticShadow;
|
||||
pkDstVertex->kTex2=pkSrcVertex->kTexDynamicShadow;
|
||||
}
|
||||
pkVB->Unlock();
|
||||
|
||||
|
||||
ms_lpd3dDevice->SetStreamSource(0, pkVB, sizeof(SoftwareTransformPatch_SSplatVertex));
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMapOutdoor::__SoftwareTransformPatch_Initialize()
|
||||
@@ -91,3 +811,5 @@ void CMapOutdoor::__SoftwareTransformPatch_Destroy()
|
||||
}
|
||||
__SoftwareTransformPatch_Initialize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include "../EterLib/UIRenderCommands.h"
|
||||
#include "../EterLib/RenderCommands3D.h"
|
||||
#include "EterLib/GrpDevice.h"
|
||||
#include "EterGrnLib/LODController.h"
|
||||
#include "UserInterface/PythonBackground.h"
|
||||
#include "UserInterface/PythonSystem.h"
|
||||
#include "../ScriptLib/PythonBoot.h"
|
||||
#include "ServerClock.h"
|
||||
|
||||
@@ -85,6 +88,12 @@ bool CPythonApplication::Create(PyObject*, const char*, int, int, int)
|
||||
return false;
|
||||
}
|
||||
|
||||
// 40250 PythonApplication.cpp:1196-1199.
|
||||
extern bool GRAPHICS_CAPS_SOFTWARE_TILING;
|
||||
|
||||
if (!CPythonSystem::Instance().IsAutoTiling())
|
||||
GRAPHICS_CAPS_SOFTWARE_TILING = CPythonSystem::Instance().IsSoftwareTiling();
|
||||
|
||||
// In 40250 m_grpDevice is a member created here (PythonApplication.cpp:909).
|
||||
static CGraphicDevice s_grpDevice;
|
||||
int iRet = s_grpDevice.Create(NULL, width, height, true, 32, 0);
|
||||
@@ -117,6 +126,23 @@ bool CPythonApplication::Create(PyObject*, const char*, int, int, int)
|
||||
return false;
|
||||
}
|
||||
|
||||
// 40250 PythonApplication.cpp:1206-1220.
|
||||
if (CPythonSystem::Instance().IsAutoTiling())
|
||||
{
|
||||
if (s_grpDevice.IsFastTNL())
|
||||
{
|
||||
CPythonBackground::Instance().ReserveSoftwareTilingEnable(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPythonBackground::Instance().ReserveSoftwareTilingEnable(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CPythonBackground::Instance().ReserveSoftwareTilingEnable(CPythonSystem::Instance().IsSoftwareTiling());
|
||||
}
|
||||
|
||||
// In 40250 m_netDevice is a member created here (PythonApplication.cpp:1242).
|
||||
static CNetworkDevice s_netDevice;
|
||||
if (!s_netDevice.Create())
|
||||
@@ -126,6 +152,10 @@ bool CPythonApplication::Create(PyObject*, const char*, int, int, int)
|
||||
return false;
|
||||
}
|
||||
|
||||
// 40250 PythonApplication.cpp:1250-1251.
|
||||
if (!s_grpDevice.IsFastTNL())
|
||||
CGrannyLODController::SetMinLODMode(true);
|
||||
|
||||
// 40250 m_pyItem.Create() (PythonApplication.cpp:1253): registers dropitem.mse with CEffectManager.
|
||||
CPythonItem::Instance().Create();
|
||||
|
||||
|
||||
@@ -23,11 +23,12 @@
|
||||
// - Version 8: eight lights, back-buffer clear entries, viewport MinZ/MaxZ, border color,
|
||||
// TEXCOORDINDEX / TEXTURETRANSFORMFLAGS / D3DTS_TEXTUREn per stage, emissive
|
||||
// material source, NORMALIZENORMALS and LOCALVIEWER; UVs are raw vertex sets.
|
||||
// - Version 9: adds XYZRHW vertex fog (specular alpha).
|
||||
// Capture is opt-in and never runs in the normal game path.
|
||||
namespace native_draw_capture {
|
||||
|
||||
struct Capture {
|
||||
std::uint32_t version = 8;
|
||||
std::uint32_t version = 9;
|
||||
std::vector<Render3DDraw> draws;
|
||||
std::unordered_map<std::string, std::vector<std::uint8_t>> textures;
|
||||
std::uint32_t ui_width = 960;
|
||||
@@ -113,7 +114,7 @@ inline void write(
|
||||
std::ofstream file(path, std::ios::binary | std::ios::trunc);
|
||||
if (!file) throw std::runtime_error("cannot create native draw capture: " + path);
|
||||
const std::uint32_t magic = 0x4d544452; // MTDR
|
||||
const std::uint32_t version = 8;
|
||||
const std::uint32_t version = 9;
|
||||
const auto count = static_cast<std::uint32_t>(draws.size());
|
||||
write_scalar(file, magic); write_scalar(file, version); write_scalar(file, count);
|
||||
for (const auto& draw : draws) {
|
||||
@@ -188,6 +189,7 @@ inline void write(
|
||||
write_scalar(file, draw.emissive_material_source);
|
||||
write_scalar(file, draw.normalize_normals);
|
||||
write_scalar(file, draw.local_viewer);
|
||||
write_vector(file, draw.vertex_fog);
|
||||
write_vector(file, draw.bone_indices);
|
||||
write_vector(file, draw.bone_weights);
|
||||
write_vector(file, draw.bone_matrices);
|
||||
@@ -237,7 +239,7 @@ inline Capture read_capture(const std::string& path) {
|
||||
if (!file) throw std::runtime_error("cannot open native draw capture: " + path);
|
||||
std::uint32_t magic = 0, version = 0, count = 0;
|
||||
read_scalar(file, magic); read_scalar(file, version); read_scalar(file, count);
|
||||
if (magic != 0x4d544452 || (version < 1 || version > 8) || count > 10'000)
|
||||
if (magic != 0x4d544452 || (version < 1 || version > 9) || count > 10'000)
|
||||
throw std::runtime_error("unsupported native draw capture format");
|
||||
Capture capture;
|
||||
capture.version = version;
|
||||
@@ -328,6 +330,7 @@ inline Capture read_capture(const std::string& path) {
|
||||
read_scalar(file, draw.emissive_material_source);
|
||||
read_scalar(file, draw.normalize_normals);
|
||||
read_scalar(file, draw.local_viewer);
|
||||
if (version >= 9) read_vector(file, draw.vertex_fog);
|
||||
} else if (draw.light0) {
|
||||
auto& light = draw.lights[0];
|
||||
light.type = 3;
|
||||
|
||||
+11
-6
@@ -59,6 +59,7 @@ struct Vertex {
|
||||
float weights[4];
|
||||
float mask_uv[2];
|
||||
float rhw = 1.0f;
|
||||
float vertex_fog = 1.0f;
|
||||
};
|
||||
|
||||
struct PushConstants {
|
||||
@@ -166,7 +167,7 @@ FixedFunctionState make_fixed_function_state(const Render3DDraw& draw) {
|
||||
state.fog_params = {draw.fog_start, draw.fog_end, draw.fog_density,
|
||||
draw.fog_range_enable ? 1.0f : 0.0f};
|
||||
const std::uint32_t fog_mode = draw.fog_enable
|
||||
? (draw.fog_table_mode ? draw.fog_table_mode : draw.fog_vertex_mode) : 0;
|
||||
? (draw.fog_table_mode ? draw.fog_table_mode : (draw.pretransformed ? 4u : draw.fog_vertex_mode)) : 0;
|
||||
state.flags = {1u, !draw.texture0.empty() ? 1u : 0u, !draw.texture1.empty() ? 1u : 0u, fog_mode};
|
||||
state.lighting_flags = {draw.lighting, draw.color_vertex, draw.diffuse.empty() ? 0u : 1u,
|
||||
draw.normalize_normals};
|
||||
@@ -221,6 +222,7 @@ std::uint64_t geometry_hash(const Render3DDraw& draw) {
|
||||
hash = hash_bytes(hash, &flags, sizeof(flags));
|
||||
hash = hash_bytes(hash, draw.positions.data(), draw.positions.size() * sizeof(float));
|
||||
hash = hash_bytes(hash, draw.rhw.data(), draw.rhw.size() * sizeof(float));
|
||||
hash = hash_bytes(hash, draw.vertex_fog.data(), draw.vertex_fog.size() * sizeof(float));
|
||||
hash = hash_bytes(hash, draw.normals.data(), draw.normals.size() * sizeof(float));
|
||||
hash = hash_bytes(hash, draw.uv0.data(), draw.uv0.size() * sizeof(float));
|
||||
hash = hash_bytes(hash, draw.uv1.data(), draw.uv1.size() * sizeof(float));
|
||||
@@ -1422,10 +1424,11 @@ public:
|
||||
if (draw.pretransformed) {
|
||||
const float screen_width = float(logical_width());
|
||||
const float screen_height = float(logical_height());
|
||||
// Screen pixels (y down) to D3D NDC (y up); the shader's Y flip then maps to Vulkan.
|
||||
constants.mvp = {2.0f / screen_width, 0, 0, 0,
|
||||
0, 2.0f / screen_height, 0, 0,
|
||||
0, -2.0f / screen_height, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
-1, -1, 0, 1};
|
||||
-1, 1, 0, 1};
|
||||
}
|
||||
PreparedDraw prepared_draw{};
|
||||
prepared_draw.geometry = &geometry;
|
||||
@@ -2354,7 +2357,7 @@ private:
|
||||
stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; stages[1].module = fragment_module_; stages[1].pName = "main";
|
||||
|
||||
VkVertexInputBindingDescription binding{0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX};
|
||||
VkVertexInputAttributeDescription attributes[8] = {
|
||||
VkVertexInputAttributeDescription attributes[9] = {
|
||||
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, position)},
|
||||
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal)},
|
||||
{2, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv)},
|
||||
@@ -2362,10 +2365,11 @@ private:
|
||||
{4, 0, VK_FORMAT_R8G8B8A8_UINT, offsetof(Vertex, joints)},
|
||||
{5, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, weights)},
|
||||
{6, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, mask_uv)},
|
||||
{7, 0, VK_FORMAT_R32_SFLOAT, offsetof(Vertex, rhw)}};
|
||||
{7, 0, VK_FORMAT_R32_SFLOAT, offsetof(Vertex, rhw)},
|
||||
{8, 0, VK_FORMAT_R32_SFLOAT, offsetof(Vertex, vertex_fog)}};
|
||||
VkPipelineVertexInputStateCreateInfo input{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO};
|
||||
input.vertexBindingDescriptionCount = 1; input.pVertexBindingDescriptions = &binding;
|
||||
input.vertexAttributeDescriptionCount = 8; input.pVertexAttributeDescriptions = attributes;
|
||||
input.vertexAttributeDescriptionCount = 9; input.pVertexAttributeDescriptions = attributes;
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo assembly{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
|
||||
assembly.topology = lines ? VK_PRIMITIVE_TOPOLOGY_LINE_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
@@ -2867,6 +2871,7 @@ private:
|
||||
vertices[i].position[1] = draw.positions[3*i+1];
|
||||
vertices[i].position[2] = draw.positions[3*i+2];
|
||||
vertices[i].rhw = i < draw.rhw.size() ? draw.rhw[i] : 1.0f;
|
||||
vertices[i].vertex_fog = i < draw.vertex_fog.size() ? draw.vertex_fog[i] : 1.0f;
|
||||
if (3*i + 2 < draw.normals.size()) {
|
||||
vertices[i].normal[0] = draw.normals[3*i];
|
||||
vertices[i].normal[1] = draw.normals[3*i+1];
|
||||
|
||||
@@ -7,6 +7,7 @@ layout(location = 4) in uvec4 in_joints;
|
||||
layout(location = 5) in vec4 in_weights;
|
||||
layout(location = 6) in vec2 in_mask_uv;
|
||||
layout(location = 7) in float in_rhw;
|
||||
layout(location = 8) in float in_vertex_fog;
|
||||
|
||||
layout(location = 0) out vec4 out_color;
|
||||
layout(location = 1) out vec2 out_uv;
|
||||
@@ -73,7 +74,9 @@ vec2 stage_texcoord(int stage, bool pretransformed, vec3 eye, vec3 n) {
|
||||
? (length(eye) > 0.0 ? -normalize(eye) : vec3(0.0)) : vec3(0.0, 0.0, -1.0);
|
||||
coord = vec4(2.0 * dot(e, n) * n - e, 1.0);
|
||||
}
|
||||
uint transform_flags = fixed_state.stage_alpha[stage].w;
|
||||
// Pretransformed (XYZRHW) vertices bypass D3D8 T&L, texture transforms included
|
||||
// (RecordingDevice's CPU texcoord path does the same).
|
||||
uint transform_flags = pretransformed ? 0u : fixed_state.stage_alpha[stage].w;
|
||||
uint elements = transform_flags & 0xFFu;
|
||||
vec4 r = coord;
|
||||
if (elements != 0u)
|
||||
@@ -109,7 +112,9 @@ void main() {
|
||||
// D3D row-vector matrices are uploaded row-major. GLSL reads the bytes as their transpose.
|
||||
gl_Position = draw.mvp * vec4(pos, 1.0);
|
||||
if (pretransformed) {
|
||||
float clip_w = in_rhw > 0.0 ? 1.0 / in_rhw : 1.0;
|
||||
// Vertices behind the eye carry a negative rhw (STP terrain): rebuilding clip space
|
||||
// with w = 1/rhw < 0 lets the clipper drop them instead of drawing w = 1 spikes.
|
||||
float clip_w = in_rhw != 0.0 ? 1.0 / in_rhw : 1.0;
|
||||
gl_Position.xyz *= clip_w;
|
||||
gl_Position.w = clip_w;
|
||||
}
|
||||
@@ -172,8 +177,13 @@ void main() {
|
||||
out_mask_uv = stage_texcoord(1, pretransformed, eye, n);
|
||||
|
||||
out_fog = 1.0;
|
||||
if (fixed_state.flags.w != 0u && !pretransformed) {
|
||||
float distance_to_eye = fixed_state.fog_params.w > 0.5 ? length(eye) : abs(eye.z);
|
||||
if (fixed_state.flags.w == 4u) {
|
||||
// XYZRHW with FOGTABLEMODE NONE: D3D8 takes the vertex fog from the specular alpha.
|
||||
out_fog = in_vertex_fog;
|
||||
} else if (fixed_state.flags.w != 0u) {
|
||||
// Table fog on XYZRHW vertices runs on eye depth w = 1/rhw.
|
||||
float distance_to_eye = pretransformed ? gl_Position.w
|
||||
: (fixed_state.fog_params.w > 0.5 ? length(eye) : abs(eye.z));
|
||||
if (fixed_state.flags.w == 3u) {
|
||||
float span = fixed_state.fog_params.y - fixed_state.fog_params.x;
|
||||
if (span > 0.0001)
|
||||
|
||||
Reference in New Issue
Block a user