render parity unit H2: verbatim 40250 water

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-28 14:03:12 +09:00
co-authored by Claude Opus 5.5
parent 6dffd1572a
commit 3e270dccc1
3 changed files with 57 additions and 33 deletions
+1
View File
@@ -565,3 +565,4 @@
{"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: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"} {"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"}
{"date": "2026-09-28T04:56:02+00:00", "unit": "GameLib/MapOutdoorRenderHTP.cpp", "action": "unit H1: platform rewrite replaced by the full 40250 source (native-terrain gate only); drops the invented texture-0 fallback splat, restores first-splat stage-1 ALPHAOP DISABLE, GetNumTextures() loop bound, shadow-pass FOGCOLOR white/restore, stage-0 ALPHAOP DISABLE + CLAMP, TEXTURE1 = m_matDynamicShadow, stage-1 SELECTARG1 restore, TEXTURE0 1/640 tiling", "evidence": "ctest (see commit); fake-server frame 900: white far band gone, terrain matches STP-path layout (mean abs diff vs STP ~20/255 from per-texture m_matTransform vs STP's fixed 1/640, as in 40250); HTP pixels NEEDS_LIVE"} {"date": "2026-09-28T04:56:02+00:00", "unit": "GameLib/MapOutdoorRenderHTP.cpp", "action": "unit H1: platform rewrite replaced by the full 40250 source (native-terrain gate only); drops the invented texture-0 fallback splat, restores first-splat stage-1 ALPHAOP DISABLE, GetNumTextures() loop bound, shadow-pass FOGCOLOR white/restore, stage-0 ALPHAOP DISABLE + CLAMP, TEXTURE1 = m_matDynamicShadow, stage-1 SELECTARG1 restore, TEXTURE0 1/640 tiling", "evidence": "ctest (see commit); fake-server frame 900: white far band gone, terrain matches STP-path layout (mean abs diff vs STP ~20/255 from per-texture m_matTransform vs STP's fixed 1/640, as in 40250); HTP pixels NEEDS_LIVE"}
{"date": "2026-09-28T04:59:25+00:00", "unit": "GameLib/MapOutdoorWater.cpp", "action": "unit H2: platform rewrite replaced by the full 40250 source (native-terrain gate only): far-fog second water pass restored, invented LIGHTING=FALSE save/restore and empty-texture guard removed", "evidence": "build ok; fake-server spawn frame 900 unchanged (mean abs diff ~0.4/255, no water in view); water visuals NEEDS_LIVE"}
@@ -17,16 +17,18 @@
] ]
}, },
"CMapOutdoor::RenderWater": { "CMapOutdoor::RenderWater": {
"status": "DIVERGENT", "status": "NEEDS_LIVE",
"impl": [ "impl": [
"extension/src/platform/GameLib/MapOutdoorWater.cpp:CMapOutdoor::RenderWater" "extension/src/platform/GameLib/MapOutdoorWater.cpp:CMapOutdoor::RenderWater"
], ],
"note": "No-op: water surfaces are not drawn through the recording device yet (the Godot terrain adapter owns terrain rendering, PORT-PLAN §3)." "note": "Verbatim 40250 plus an early return when IsNativeTerrainRenderEnabled() is false (Godot water adapter, PORT-PLAN §3). Restores the far-fog second pass (untextured, blend off, patches >= __GetFogDistance()) and drops the invented LIGHTING=FALSE save/restore and empty-texture guard. No water in the fake-server spawn view; visuals not verified."
}, },
"CMapOutdoor::DrawWater": { "CMapOutdoor::DrawWater": {
"status": "DIVERGENT", "status": "NEEDS_LIVE",
"impl": [], "impl": [
"note": "Not built: only called from RenderWater, which is a no-op." "extension/src/platform/GameLib/MapOutdoorWater.cpp:CMapOutdoor::DrawWater"
],
"note": "Verbatim 40250, reached from RenderWater on the native path; visuals not verified."
} }
} }
} }
@@ -1,5 +1,6 @@
// Platform implementation of 40250 GameLib/MapOutdoorWater.cpp. The water texture set is loaded as in // Platform copy of 40250 GameLib/MapOutdoorWater.cpp, as is apart from the includes and the
// 40250; the water surface itself is drawn by the Godot water adapter (PORT-PLAN §3). // native-terrain gate: the Godot water adapter draws the surface (PORT-PLAN §3) unless
// IsNativeTerrainRenderEnabled().
#include "GameLib/StdAfx.h" #include "GameLib/StdAfx.h"
#include "EterLib/StateManager.h" #include "EterLib/StateManager.h"
#include "EterLib/ResourceManager.h" #include "EterLib/ResourceManager.h"
@@ -28,15 +29,18 @@ void CMapOutdoor::UnloadWaterTexture()
void CMapOutdoor::RenderWater() void CMapOutdoor::RenderWater()
{ {
if (!IsNativeTerrainRenderEnabled())
return;
if (m_PatchVector.empty()) if (m_PatchVector.empty())
return; return;
if (!IsVisiblePart(PART_WATER)) if (!IsVisiblePart(PART_WATER))
return; return;
// PORT: see the file comment.
if (!IsNativeTerrainRenderEnabled())
return;
//////////////////////////////////////////////////////////////////////////
// RenderState
D3DXMATRIX matTexTransformWater; D3DXMATRIX matTexTransformWater;
STATEMANAGER.SaveRenderState(D3DRS_ZWRITEENABLE, FALSE); STATEMANAGER.SaveRenderState(D3DRS_ZWRITEENABLE, FALSE);
@@ -44,19 +48,14 @@ void CMapOutdoor::RenderWater()
STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_NONE); STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
STATEMANAGER.SaveRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); STATEMANAGER.SaveRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
STATEMANAGER.SaveRenderState(D3DRS_COLORVERTEX, TRUE); STATEMANAGER.SaveRenderState(D3DRS_COLORVERTEX, TRUE);
STATEMANAGER.SaveRenderState(D3DRS_LIGHTING, FALSE);
CGraphicImageInstance& rkWaterInst = m_WaterInstances[((ELTimer_GetMSec() / 70) % 30)]; STATEMANAGER.SetTexture(0, m_WaterInstances[((ELTimer_GetMSec() / 70) % 30)].GetTexturePointer()->GetD3DTexture());
if (!rkWaterInst.IsEmpty() && rkWaterInst.GetTexturePointer())
STATEMANAGER.SetTexture(0, rkWaterInst.GetTexturePointer()->GetD3DTexture());
else
STATEMANAGER.SetTexture(0, NULL);
D3DXMatrixScaling(&matTexTransformWater, m_fWaterTexCoordBase, -m_fWaterTexCoordBase, 0.0f); D3DXMatrixScaling(&matTexTransformWater, m_fWaterTexCoordBase, -m_fWaterTexCoordBase, 0.0f);
D3DXMatrixMultiply(&matTexTransformWater, &m_matViewInverse, &matTexTransformWater); D3DXMatrixMultiply(&matTexTransformWater, &m_matViewInverse, &matTexTransformWater);
STATEMANAGER.SaveTransform(D3DTS_TEXTURE0, &matTexTransformWater); STATEMANAGER.SaveTransform(D3DTS_TEXTURE0, &matTexTransformWater);
STATEMANAGER.SaveVertexShader(D3DFVF_XYZ | D3DFVF_DIFFUSE); STATEMANAGER.SaveVertexShader(D3DFVF_XYZ|D3DFVF_DIFFUSE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION); STATEMANAGER.SaveTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); STATEMANAGER.SaveTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
@@ -71,22 +70,28 @@ void CMapOutdoor::RenderWater()
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
STATEMANAGER.SetTexture(1, NULL);
STATEMANAGER.SetTexture(1,NULL);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
// RenderState
//////////////////////////////////////////////////////////////////////////
// 물 위 아래 애니시키기...
static float s_fWaterHeightCurrent = 0; static float s_fWaterHeightCurrent = 0;
static float s_fWaterHeightBegin = 0; static float s_fWaterHeightBegin = 0;
static float s_fWaterHeightEnd = 0; static float s_fWaterHeightEnd = 0;
static DWORD s_dwLastHeightChangeTime = CTimer::Instance().GetCurrentMillisecond(); static DWORD s_dwLastHeightChangeTime = CTimer::Instance().GetCurrentMillisecond();
static DWORD s_dwBlendtime = 300; static DWORD s_dwBlendtime = 300;
// 1.5초 마다 변경
if ((CTimer::Instance().GetCurrentMillisecond() - s_dwLastHeightChangeTime) > s_dwBlendtime) if ((CTimer::Instance().GetCurrentMillisecond() - s_dwLastHeightChangeTime) > s_dwBlendtime)
{ {
s_dwBlendtime = random_range(1000, 3000); s_dwBlendtime = random_range(1000, 3000);
if (s_fWaterHeightEnd == 0) if (s_fWaterHeightEnd == 0)
s_fWaterHeightEnd = -static_cast<float>(random_range(0, 15)); s_fWaterHeightEnd = -random_range(0, 15);
else else
s_fWaterHeightEnd = 0; s_fWaterHeightEnd = 0;
@@ -94,20 +99,37 @@ void CMapOutdoor::RenderWater()
s_dwLastHeightChangeTime = CTimer::Instance().GetCurrentMillisecond(); s_dwLastHeightChangeTime = CTimer::Instance().GetCurrentMillisecond();
} }
s_fWaterHeightCurrent = s_fWaterHeightBegin + (s_fWaterHeightEnd - s_fWaterHeightBegin) * (float)((CTimer::Instance().GetCurrentMillisecond() - s_dwLastHeightChangeTime) / (float)s_dwBlendtime); s_fWaterHeightCurrent = s_fWaterHeightBegin + (s_fWaterHeightEnd - s_fWaterHeightBegin) * (float) ((CTimer::Instance().GetCurrentMillisecond() - s_dwLastHeightChangeTime) / (float) s_dwBlendtime);
m_matWorldForCommonUse._43 = s_fWaterHeightCurrent; m_matWorldForCommonUse._43 = s_fWaterHeightCurrent;
m_matWorldForCommonUse._41 = 0.0f; m_matWorldForCommonUse._41 = 0.0f;
m_matWorldForCommonUse._42 = 0.0f; m_matWorldForCommonUse._42 = 0.0f;
STATEMANAGER.SetTransform(D3DTS_WORLD, &m_matWorldForCommonUse); STATEMANAGER.SetTransform(D3DTS_WORLD, &m_matWorldForCommonUse);
for (auto i = m_PatchVector.begin(); i != m_PatchVector.end(); ++i) float fFogDistance = __GetFogDistance();
std::vector<std::pair<float, long> >::iterator i;
for(i = m_PatchVector.begin();i != m_PatchVector.end(); ++i)
{ {
DrawWater(i->second); if (i->first<fFogDistance)
DrawWater(i->second);
} }
STATEMANAGER.SetTexture(0, NULL);
STATEMANAGER.SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
for(i = m_PatchVector.begin();i != m_PatchVector.end(); ++i)
{
if (i->first>=fFogDistance)
DrawWater(i->second);
}
// 렌더링 한 후에는 물 z 위치를 복구
m_matWorldForCommonUse._43 = 0.0f; m_matWorldForCommonUse._43 = 0.0f;
//////////////////////////////////////////////////////////////////////////
// RenderState
STATEMANAGER.RestoreVertexShader(); STATEMANAGER.RestoreVertexShader();
STATEMANAGER.RestoreTransform(D3DTS_TEXTURE0); STATEMANAGER.RestoreTransform(D3DTS_TEXTURE0);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_MINFILTER); STATEMANAGER.RestoreTextureStageState(0, D3DTSS_MINFILTER);
@@ -118,7 +140,6 @@ void CMapOutdoor::RenderWater()
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_TEXCOORDINDEX); STATEMANAGER.RestoreTextureStageState(0, D3DTSS_TEXCOORDINDEX);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS); STATEMANAGER.RestoreTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS);
STATEMANAGER.RestoreRenderState(D3DRS_LIGHTING);
STATEMANAGER.RestoreRenderState(D3DRS_DIFFUSEMATERIALSOURCE); STATEMANAGER.RestoreRenderState(D3DRS_DIFFUSEMATERIALSOURCE);
STATEMANAGER.RestoreRenderState(D3DRS_COLORVERTEX); STATEMANAGER.RestoreRenderState(D3DRS_COLORVERTEX);
STATEMANAGER.RestoreRenderState(D3DRS_ZWRITEENABLE); STATEMANAGER.RestoreRenderState(D3DRS_ZWRITEENABLE);
@@ -128,7 +149,7 @@ void CMapOutdoor::RenderWater()
void CMapOutdoor::DrawWater(long patchnum) void CMapOutdoor::DrawWater(long patchnum)
{ {
assert(NULL != m_pTerrainPatchProxyList); assert(NULL!=m_pTerrainPatchProxyList);
if (!m_pTerrainPatchProxyList) if (!m_pTerrainPatchProxyList)
return; return;
@@ -140,14 +161,14 @@ void CMapOutdoor::DrawWater(long patchnum)
if (!rkTerrainPatchProxy.isWaterExists()) if (!rkTerrainPatchProxy.isWaterExists())
return; return;
CGraphicVertexBuffer* pkVB = rkTerrainPatchProxy.GetWaterVertexBufferPointer(); CGraphicVertexBuffer* pkVB=rkTerrainPatchProxy.GetWaterVertexBufferPointer();
if (!pkVB) if (!pkVB)
return; return;
if (!pkVB->GetD3DVertexBuffer()) if (!pkVB->GetD3DVertexBuffer())
return; return;
UINT uPriCount = rkTerrainPatchProxy.GetWaterFaceCount(); UINT uPriCount=rkTerrainPatchProxy.GetWaterFaceCount();
if (!uPriCount) if (!uPriCount)
return; return;