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:
shenlei
2026-09-28 13:54:11 +09:00
co-authored by Claude Opus 5.5
parent 91ce13c3cf
commit 863f3771af
10 changed files with 864 additions and 66 deletions
@@ -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();