render parity unit I: 40250 PythonGraphic SetGamma, cooldown fan, up/down buttons
SetGamma, RenderCoolTimeBox, RenderUp/DownButton and GetAvailableMemory are transliterated from 40250 in place of stubs. The cooldown fan is emitted as untextured polygon UI commands (native_render + python_ui_surface.gd draw Bar+quad as a polygon); D3D8 shim gains SetGammaRamp/D3DGAMMARAMP. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d3fd5f8613
commit
0e8a1574cb
@@ -566,3 +566,4 @@
|
|||||||
{"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"}
|
{"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"}
|
||||||
|
{"date": "2026-09-28T05:08:46+00:00", "unit": "EterPythonLib/PythonGraphic.cpp", "action": "unit I: SetGamma, RenderCoolTimeBox, RenderUp/DownButton, GetAvailableMemory ported from 40250 (stubs removed); cooldown fan drawn as polygon UI commands; SetViewport/RestoreViewport documented as ADAPTED (device viewport + UI clip)", "evidence": "port.app_loop drawing_primitives checks fan geometry at fTime 0.25/0.3/1.0 and viewport clip push/pop; cooldown visuals NEEDS_LIVE"}
|
||||||
|
|||||||
@@ -11,13 +11,22 @@
|
|||||||
"status": "TODO"
|
"status": "TODO"
|
||||||
},
|
},
|
||||||
"CPythonGraphic::GetOrthoDepth": {
|
"CPythonGraphic::GetOrthoDepth": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::GetOrthoDepth"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"CPythonGraphic::SetInterfaceRenderState": {
|
"CPythonGraphic::SetInterfaceRenderState": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::SetInterfaceRenderState"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"CPythonGraphic::SetGameRenderState": {
|
"CPythonGraphic::SetGameRenderState": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::SetGameRenderState"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"CPythonGraphic::SetCursorPosition": {
|
"CPythonGraphic::SetCursorPosition": {
|
||||||
"status": "ADAPTED",
|
"status": "ADAPTED",
|
||||||
@@ -31,13 +40,27 @@
|
|||||||
"status": "TODO"
|
"status": "TODO"
|
||||||
},
|
},
|
||||||
"CPythonGraphic::SetViewport": {
|
"CPythonGraphic::SetViewport": {
|
||||||
"status": "TODO"
|
"status": "ADAPTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::SetViewport"
|
||||||
|
],
|
||||||
|
"test": "extension/tests/port_app_loop_test.cpp",
|
||||||
|
"note": "40250 device viewport set/backup kept (guarded for the device-less boot). The UI is drawn from UIRenderCommands, not the device, so the same rectangle is also pushed as the UI clip (UIRenderSetClip)."
|
||||||
},
|
},
|
||||||
"CPythonGraphic::RestoreViewport": {
|
"CPythonGraphic::RestoreViewport": {
|
||||||
"status": "TODO"
|
"status": "ADAPTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::RestoreViewport"
|
||||||
|
],
|
||||||
|
"test": "extension/tests/port_app_loop_test.cpp",
|
||||||
|
"note": "Restores the backup viewport as 40250 does and pops the UI clip pushed by SetViewport."
|
||||||
},
|
},
|
||||||
"CPythonGraphic::SetGamma": {
|
"CPythonGraphic::SetGamma": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::SetGamma"
|
||||||
|
],
|
||||||
|
"note": "Verbatim 40250. The recording device reports no D3DCAPS2_FULLSCREENGAMMA (windowed output, where D3D8 ignores the ramp as well), so it returns at the caps check; IDirect3DDevice8::SetGammaRamp added to the D3D8 shim."
|
||||||
},
|
},
|
||||||
"GenScreenShotTag": {
|
"GenScreenShotTag": {
|
||||||
"status": "TODO"
|
"status": "TODO"
|
||||||
@@ -49,10 +72,16 @@
|
|||||||
"status": "TODO"
|
"status": "TODO"
|
||||||
},
|
},
|
||||||
"CPythonGraphic::PushState": {
|
"CPythonGraphic::PushState": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::PushState"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"CPythonGraphic::PopState": {
|
"CPythonGraphic::PopState": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::PopState"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"CPythonGraphic::RenderImage": {
|
"CPythonGraphic::RenderImage": {
|
||||||
"status": "TODO"
|
"status": "TODO"
|
||||||
@@ -61,25 +90,48 @@
|
|||||||
"status": "TODO"
|
"status": "TODO"
|
||||||
},
|
},
|
||||||
"CPythonGraphic::RenderCoolTimeBox": {
|
"CPythonGraphic::RenderCoolTimeBox": {
|
||||||
"status": "TODO"
|
"status": "ADAPTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::RenderCoolTimeBox"
|
||||||
|
],
|
||||||
|
"test": "extension/tests/port_app_loop_test.cpp",
|
||||||
|
"note": "Fan vertex build verbatim. 40250's D3DPT_TRIANGLEFAN (untextured, SELECTARG1 DIFFUSE colour/alpha, 0x80000000) is emitted as one untextured quad UIRenderCommand per fan triangle (centre, j, j+1, j+1); native_render and python_ui_surface.gd draw Bar+quad as a polygon. On-screen look NEEDS_LIVE against a skill cooldown."
|
||||||
},
|
},
|
||||||
"CPythonGraphic::GenerateColor": {
|
"CPythonGraphic::GenerateColor": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::GenerateColor"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"CPythonGraphic::RenderDownButton": {
|
"CPythonGraphic::RenderDownButton": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::RenderDownButton"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"CPythonGraphic::RenderUpButton": {
|
"CPythonGraphic::RenderUpButton": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::RenderUpButton"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"CPythonGraphic::GetAvailableMemory": {
|
"CPythonGraphic::GetAvailableMemory": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::GetAvailableMemory"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"CPythonGraphic::CPythonGraphic": {
|
"CPythonGraphic::CPythonGraphic": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::CPythonGraphic"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"CPythonGraphic::~CPythonGraphic": {
|
"CPythonGraphic::~CPythonGraphic": {
|
||||||
"status": "TODO"
|
"status": "PORTED",
|
||||||
|
"impl": [
|
||||||
|
"extension/src/platform/EterPythonLib/PythonGraphic.cpp:CPythonGraphic::~CPythonGraphic"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,6 +316,9 @@ public:
|
|||||||
}
|
}
|
||||||
// PORT: CPU memory has no texture budget; report the 64MB of a mid-range 2004 card.
|
// PORT: CPU memory has no texture budget; report the 64MB of a mid-range 2004 card.
|
||||||
UINT GetAvailableTextureMem() override { return 64u << 20; }
|
UINT GetAvailableTextureMem() override { return 64u << 20; }
|
||||||
|
// The caps leave out D3DCAPS2_FULLSCREENGAMMA (the frame goes to a window, where D3D8 ignores the
|
||||||
|
// ramp too), so 40250 CPythonGraphic::SetGamma returns before it gets here.
|
||||||
|
void SetGammaRamp(DWORD, const D3DGAMMARAMP*) override {}
|
||||||
HRESULT BeginScene() override { return S_OK; }
|
HRESULT BeginScene() override { return S_OK; }
|
||||||
HRESULT EndScene() override { return S_OK; }
|
HRESULT EndScene() override { return S_OK; }
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,14 @@
|
|||||||
// 2V0-f;platform_stub.py 不认 EterPythonLib(port_map 把它划成 python 层),所以这里按手写平台桩的
|
// 2V0-f;platform_stub.py 不认 EterPythonLib(port_map 把它划成 python 层),所以这里按手写平台桩的
|
||||||
// 惯例来:先只放被引用到的符号,链接器会告诉我们下一个是谁。
|
// 惯例来:先只放被引用到的符号,链接器会告诉我们下一个是谁。
|
||||||
//
|
//
|
||||||
// RenderCoolTimeBox:CSlotWindow::OnRender 画技能冷却扇形用的,没有渲染设备时什么都不做。
|
// RenderCoolTimeBox:40250 的扇形顶点原样搬来,画法改成 UIRenderCommands(见函数注释)。
|
||||||
#include "EterPythonLib/StdAfx.h"
|
#include "EterPythonLib/StdAfx.h"
|
||||||
#include "EterPythonLib/PythonGraphic.h"
|
#include "EterPythonLib/PythonGraphic.h"
|
||||||
#include "EterLib/StateManager.h"
|
#include "EterLib/StateManager.h"
|
||||||
|
|
||||||
#include "../PlatformStub.h"
|
#include "../PlatformStub.h"
|
||||||
#include "../EterLib/UIRenderCommands.h"
|
#include "../EterLib/UIRenderCommands.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
// 40250 PythonGraphic.cpp:611
|
// 40250 PythonGraphic.cpp:611
|
||||||
CPythonGraphic::CPythonGraphic()
|
CPythonGraphic::CPythonGraphic()
|
||||||
@@ -135,20 +136,167 @@ void CPythonGraphic::SetOmniLight()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
long CPythonGraphic::GenerateColor(float r, float g, float b, float a) { return GetColor(r, g, b, a); }
|
long CPythonGraphic::GenerateColor(float r, float g, float b, float a) { return GetColor(r, g, b, a); }
|
||||||
void CPythonGraphic::RenderUpButton(float, float, float, float) { MT_PLATFORM_STUB(); }
|
// 40250 PythonGraphic.cpp:580
|
||||||
void CPythonGraphic::RenderDownButton(float, float, float, float) { MT_PLATFORM_STUB(); }
|
void CPythonGraphic::RenderDownButton(float sx, float sy, float ex, float ey)
|
||||||
|
{
|
||||||
|
RenderBox2d(sx, sy, ex, ey);
|
||||||
|
|
||||||
|
SetDiffuseColor(m_darkColor);
|
||||||
|
RenderLine2d(sx, sy, ex, sy);
|
||||||
|
RenderLine2d(sx, sy, sx, ey);
|
||||||
|
|
||||||
|
SetDiffuseColor(m_lightColor);
|
||||||
|
RenderLine2d(sx, ey, ex, ey);
|
||||||
|
RenderLine2d(ex, sy, ex, ey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 40250 PythonGraphic.cpp:593
|
||||||
|
void CPythonGraphic::RenderUpButton(float sx, float sy, float ex, float ey)
|
||||||
|
{
|
||||||
|
RenderBox2d(sx, sy, ex, ey);
|
||||||
|
|
||||||
|
SetDiffuseColor(m_lightColor);
|
||||||
|
RenderLine2d(sx, sy, ex, sy);
|
||||||
|
RenderLine2d(sx, sy, sx, ey);
|
||||||
|
|
||||||
|
SetDiffuseColor(m_darkColor);
|
||||||
|
RenderLine2d(sx, ey, ex, ey);
|
||||||
|
RenderLine2d(ex, sy, ex, ey);
|
||||||
|
}
|
||||||
bool CPythonGraphic::SaveScreenShot(const char*) { MT_PLATFORM_STUB(); return false; }
|
bool CPythonGraphic::SaveScreenShot(const char*) { MT_PLATFORM_STUB(); return false; }
|
||||||
// 40250 PythonGraphic.cpp:52.
|
// 40250 PythonGraphic.cpp:52.
|
||||||
void CPythonGraphic::SetCursorPosition(int x, int y)
|
void CPythonGraphic::SetCursorPosition(int x, int y)
|
||||||
{
|
{
|
||||||
CScreen::SetCursorPosition(x, y, ms_iWidth, ms_iHeight);
|
CScreen::SetCursorPosition(x, y, ms_iWidth, ms_iHeight);
|
||||||
}
|
}
|
||||||
DWORD CPythonGraphic::GetAvailableMemory() { MT_PLATFORM_STUB(); return 0; }
|
// 40250 PythonGraphic.cpp:606
|
||||||
void CPythonGraphic::SetGamma(float) { MT_PLATFORM_STUB(); }
|
DWORD CPythonGraphic::GetAvailableMemory()
|
||||||
|
{
|
||||||
|
return ms_lpd3dDevice->GetAvailableTextureMem();
|
||||||
|
}
|
||||||
|
// 40250 PythonGraphic.cpp:124. The recording device reports no D3DCAPS2_FULLSCREENGAMMA (the frame
|
||||||
|
// goes to a window), so this returns at the caps check like 40250 does on such a device.
|
||||||
|
void CPythonGraphic::SetGamma(float fGammaFactor)
|
||||||
|
{
|
||||||
|
D3DCAPS8 d3dCaps;
|
||||||
|
D3DGAMMARAMP NewRamp;
|
||||||
|
int ui, val;
|
||||||
|
|
||||||
|
ms_lpd3dDevice->GetDeviceCaps(&d3dCaps);
|
||||||
|
|
||||||
|
if (D3DCAPS2_FULLSCREENGAMMA != (d3dCaps.Caps2 & D3DCAPS2_FULLSCREENGAMMA))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
val = (int) (i * fGammaFactor * 255.0f);
|
||||||
|
ui = 0;
|
||||||
|
|
||||||
|
if (val > 32767)
|
||||||
|
{
|
||||||
|
val = val - 32767;
|
||||||
|
ui = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val > 32767)
|
||||||
|
val = 32767;
|
||||||
|
|
||||||
|
NewRamp.red[i] = (WORD) (val | (32768 * ui));
|
||||||
|
NewRamp.green[i] = (WORD) (val | (32768 * ui));
|
||||||
|
NewRamp.blue[i] = (WORD) (val | (32768 * ui));
|
||||||
|
}
|
||||||
|
|
||||||
|
ms_lpd3dDevice->SetGammaRamp(D3DSGR_NO_CALIBRATION, &NewRamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 40250 PythonGraphic.cpp:491. The fan's vertices are built verbatim.
|
||||||
|
// PORT: 40250 draws them as a D3DPT_TRIANGLEFAN with untextured SELECTARG1(DIFFUSE) colour and alpha;
|
||||||
|
// the UI here is drawn from UIRenderCommands, so each fan triangle goes out as one untextured quad
|
||||||
|
// command (vertices centre, j, j+1, j+1) in the same half-transparent black.
|
||||||
void CPythonGraphic::RenderCoolTimeBox(float fxCenter, float fyCenter, float fRadius, float fTime)
|
void CPythonGraphic::RenderCoolTimeBox(float fxCenter, float fyCenter, float fRadius, float fTime)
|
||||||
{
|
{
|
||||||
MT_PLATFORM_STUB();
|
if (fTime >= 1.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fTime = max(0.0f, fTime);
|
||||||
|
|
||||||
|
static D3DXCOLOR color = D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.5f);
|
||||||
|
static D3DXVECTOR2 s_v2BoxPos[8] =
|
||||||
|
{
|
||||||
|
D3DXVECTOR2( -1.0f, -1.0f ),
|
||||||
|
D3DXVECTOR2( -1.0f, 0.0f ),
|
||||||
|
D3DXVECTOR2( -1.0f, +1.0f ),
|
||||||
|
D3DXVECTOR2( 0.0f, +1.0f ),
|
||||||
|
D3DXVECTOR2( +1.0f, +1.0f ),
|
||||||
|
D3DXVECTOR2( +1.0f, 0.0f ),
|
||||||
|
D3DXVECTOR2( +1.0f, -1.0f ),
|
||||||
|
D3DXVECTOR2( 0.0f, -1.0f ),
|
||||||
|
};
|
||||||
|
|
||||||
|
int iTriCount = int(8 - 8.0f * fTime);
|
||||||
|
float fLastPercentage = (8 - 8.0f * fTime) - iTriCount;
|
||||||
|
|
||||||
|
std::vector<TPDTVertex> vertices;
|
||||||
|
TPDTVertex vertex;
|
||||||
|
vertex.position.x = fxCenter;
|
||||||
|
vertex.position.y = fyCenter;
|
||||||
|
vertex.position.z = 0.0f;
|
||||||
|
vertex.diffuse = color;
|
||||||
|
vertex.texCoord.x = 0.0f;
|
||||||
|
vertex.texCoord.x = 0.0f;
|
||||||
|
vertices.push_back(vertex);
|
||||||
|
vertex.position.x = fxCenter;
|
||||||
|
vertex.position.y = fyCenter - fRadius;
|
||||||
|
vertex.position.z = 0.0f;
|
||||||
|
vertex.diffuse = color;
|
||||||
|
vertex.texCoord.x = 0.0f;
|
||||||
|
vertex.texCoord.x = 0.0f;
|
||||||
|
vertices.push_back(vertex);
|
||||||
|
|
||||||
|
for (int j = 0; j < iTriCount; ++j)
|
||||||
|
{
|
||||||
|
vertex.position.x = fxCenter + s_v2BoxPos[j].x * fRadius;
|
||||||
|
vertex.position.y = fyCenter + s_v2BoxPos[j].y * fRadius;
|
||||||
|
vertices.push_back(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fLastPercentage > 0.0f)
|
||||||
|
{
|
||||||
|
D3DXVECTOR2 * pv2Pos;
|
||||||
|
D3DXVECTOR2 * pv2LastPos;
|
||||||
|
|
||||||
|
assert((iTriCount-1+8)%8 >= 0 && (iTriCount-1+8)%8 < 8);
|
||||||
|
assert((iTriCount+8)%8 >= 0 && (iTriCount+8)%8 < 8);
|
||||||
|
pv2LastPos = &s_v2BoxPos[(iTriCount-1+8)%8];
|
||||||
|
pv2Pos = &s_v2BoxPos[(iTriCount+8)%8];
|
||||||
|
|
||||||
|
vertex.position.x = fxCenter + ((pv2Pos->x-pv2LastPos->x) * fLastPercentage + pv2LastPos->x) * fRadius;
|
||||||
|
vertex.position.y = fyCenter + ((pv2Pos->y-pv2LastPos->y) * fLastPercentage + pv2LastPos->y) * fRadius;
|
||||||
|
vertices.push_back(vertex);
|
||||||
|
++iTriCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertices.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// PORT: the D3DPT_TRIANGLEFAN of iTriCount triangles, see the function comment.
|
||||||
|
const std::uint32_t argb = UIRenderColor(color);
|
||||||
|
for (int j = 0; j < iTriCount && j + 2 < int(vertices.size()); ++j)
|
||||||
|
{
|
||||||
|
const TPDTVertex* fan[4] = { &vertices[0], &vertices[j + 1], &vertices[j + 2], &vertices[j + 2] };
|
||||||
|
UIRenderCommand command{UIRenderCommand::Bar, 0, 0, 0, 0, argb};
|
||||||
|
for (int k = 0; k < 4; ++k)
|
||||||
|
{
|
||||||
|
command.qx[k] = fan[k]->position.x;
|
||||||
|
command.qy[k] = fan[k]->position.y;
|
||||||
|
}
|
||||||
|
command.x1 = std::min({command.qx[0], command.qx[1], command.qx[2]});
|
||||||
|
command.y1 = std::min({command.qy[0], command.qy[1], command.qy[2]});
|
||||||
|
command.x2 = std::max({command.qx[0], command.qx[1], command.qx[2]});
|
||||||
|
command.y2 = std::max({command.qy[0], command.qy[1], command.qy[2]});
|
||||||
|
command.quad = true;
|
||||||
|
UIRenderAdd(std::move(command));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 40250 PythonGraphic.cpp:17
|
// 40250 PythonGraphic.cpp:17
|
||||||
|
|||||||
@@ -687,6 +687,16 @@ typedef struct _D3DCAPS8
|
|||||||
} D3DCAPS8;
|
} D3DCAPS8;
|
||||||
|
|
||||||
#define D3DDEVCAPS_HWTRANSFORMANDLIGHT 0x00010000L
|
#define D3DDEVCAPS_HWTRANSFORMANDLIGHT 0x00010000L
|
||||||
|
#define D3DCAPS2_FULLSCREENGAMMA 0x00020000L
|
||||||
|
|
||||||
|
typedef struct _D3DGAMMARAMP
|
||||||
|
{
|
||||||
|
WORD red[256];
|
||||||
|
WORD green[256];
|
||||||
|
WORD blue[256];
|
||||||
|
} D3DGAMMARAMP;
|
||||||
|
#define D3DSGR_NO_CALIBRATION 0x00000000L
|
||||||
|
#define D3DSGR_CALIBRATE 0x00000001L
|
||||||
#define D3DPTFILTERCAPS_MINFANISOTROPIC 0x00000400L
|
#define D3DPTFILTERCAPS_MINFANISOTROPIC 0x00000400L
|
||||||
#define D3DPTFILTERCAPS_MAGFANISOTROPIC 0x04000000L
|
#define D3DPTFILTERCAPS_MAGFANISOTROPIC 0x04000000L
|
||||||
#define D3DPTADDRESSCAPS_WRAP 0x00000001L
|
#define D3DPTADDRESSCAPS_WRAP 0x00000001L
|
||||||
@@ -802,6 +812,7 @@ struct IDirect3DDevice8
|
|||||||
virtual HRESULT GetViewport(D3DVIEWPORT8* pViewport) = 0;
|
virtual HRESULT GetViewport(D3DVIEWPORT8* pViewport) = 0;
|
||||||
virtual HRESULT SetViewport(const D3DVIEWPORT8* pViewport) = 0;
|
virtual HRESULT SetViewport(const D3DVIEWPORT8* pViewport) = 0;
|
||||||
virtual UINT GetAvailableTextureMem() = 0;
|
virtual UINT GetAvailableTextureMem() = 0;
|
||||||
|
virtual void SetGammaRamp(DWORD Flags, const D3DGAMMARAMP* pRamp) = 0;
|
||||||
virtual HRESULT BeginScene() = 0;
|
virtual HRESULT BeginScene() = 0;
|
||||||
virtual HRESULT EndScene() = 0;
|
virtual HRESULT EndScene() = 0;
|
||||||
virtual HRESULT SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX* pMatrix) = 0;
|
virtual HRESULT SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX* pMatrix) = 0;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "../src/platform/UserInterface/UserInterface.h"
|
#include "../src/platform/UserInterface/UserInterface.h"
|
||||||
#include "../src/platform/EterLib/UIRenderCommands.h"
|
#include "../src/platform/EterLib/UIRenderCommands.h"
|
||||||
#include "EterLib/GrpScreen.h"
|
#include "EterLib/GrpScreen.h"
|
||||||
|
#include "EterPythonLib/PythonGraphic.h"
|
||||||
#include <dinput.h> // DIK_ESCAPE
|
#include <dinput.h> // DIK_ESCAPE
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@@ -126,6 +127,46 @@ static void drawing_primitives()
|
|||||||
CHECK(commands[4].kind == UIRenderCommand::GradientBar && commands[4].argb == 0xFF102030u &&
|
CHECK(commands[4].kind == UIRenderCommand::GradientBar && commands[4].argb == 0xFF102030u &&
|
||||||
commands[4].end_argb == 0xFF405060u);
|
commands[4].end_argb == 0xFF405060u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 40250 CPythonGraphic::RenderCoolTimeBox: fTime 0.25 leaves 6 whole fan triangles from the top
|
||||||
|
// centre anticlockwise round to (+1, 0); fTime 0.3 has 5 whole ones and a sixth 60% of the way
|
||||||
|
// from (+1, +1) to (+1, 0).
|
||||||
|
UIRenderBeginFrame();
|
||||||
|
{
|
||||||
|
CPythonGraphic graphic;
|
||||||
|
graphic.RenderCoolTimeBox(100, 100, 10, 0.25f);
|
||||||
|
CHECK(commands.size() == 6);
|
||||||
|
if (commands.size() == 6)
|
||||||
|
{
|
||||||
|
CHECK(commands[0].kind == UIRenderCommand::Bar && commands[0].quad && commands[0].argb == 0x80000000u);
|
||||||
|
CHECK(near(commands[0].qx[0], 100) && near(commands[0].qy[0], 100));
|
||||||
|
CHECK(near(commands[0].qx[1], 100) && near(commands[0].qy[1], 90));
|
||||||
|
CHECK(near(commands[0].qx[2], 90) && near(commands[0].qy[2], 90));
|
||||||
|
CHECK(near(commands[5].qx[2], 110) && near(commands[5].qy[2], 100));
|
||||||
|
}
|
||||||
|
UIRenderBeginFrame();
|
||||||
|
graphic.RenderCoolTimeBox(100, 100, 10, 0.3f);
|
||||||
|
CHECK(commands.size() == 6);
|
||||||
|
if (commands.size() == 6)
|
||||||
|
CHECK(near(commands[5].qx[1], 110) && near(commands[5].qy[1], 110) &&
|
||||||
|
near(commands[5].qx[2], 110) && near(commands[5].qy[2], 104));
|
||||||
|
UIRenderBeginFrame();
|
||||||
|
graphic.RenderCoolTimeBox(100, 100, 10, 1.0f);
|
||||||
|
CHECK(commands.empty());
|
||||||
|
|
||||||
|
// CPythonGraphic::SetViewport also clips the UI commands to the viewport until RestoreViewport.
|
||||||
|
graphic.SetViewport(10, 20, 30, 40);
|
||||||
|
screen.RenderBar2d(0, 0, 5, 5);
|
||||||
|
graphic.RestoreViewport();
|
||||||
|
screen.RenderBar2d(0, 0, 5, 5);
|
||||||
|
CHECK(commands.size() == 2);
|
||||||
|
if (commands.size() == 2)
|
||||||
|
{
|
||||||
|
CHECK(near(commands[0].clip_x1, 10) && near(commands[0].clip_y1, 20) &&
|
||||||
|
near(commands[0].clip_x2, 40) && near(commands[0].clip_y2, 60));
|
||||||
|
CHECK(near(commands[1].clip_x1, 0) && near(commands[1].clip_x2, 800) && near(commands[1].clip_y2, 600));
|
||||||
|
}
|
||||||
|
}
|
||||||
UIRenderSetSize(0, 0);
|
UIRenderSetSize(0, 0);
|
||||||
UIRenderBeginFrame();
|
UIRenderBeginFrame();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1838,6 +1838,16 @@ private:
|
|||||||
u[1] = eu; v[1] = sv;
|
u[1] = eu; v[1] = sv;
|
||||||
u[2] = su; v[2] = ev;
|
u[2] = su; v[2] = ev;
|
||||||
u[3] = eu; v[3] = ev;
|
u[3] = eu; v[3] = ev;
|
||||||
|
} else if (cmd.kind == UIRenderCommand::Bar && cmd.quad) {
|
||||||
|
// An untextured polygon piece (CPythonGraphic::RenderCoolTimeBox's fan triangles).
|
||||||
|
if (has_clip && (x2 <= cmd.clip_x1 || x1 >= cmd.clip_x2 || y2 <= cmd.clip_y1 || y1 >= cmd.clip_y2))
|
||||||
|
continue;
|
||||||
|
for (int k = 0; k < 4; ++k) {
|
||||||
|
qx[k] = cmd.qx[k];
|
||||||
|
qy[k] = cmd.qy[k];
|
||||||
|
u[k] = 0.0f;
|
||||||
|
v[k] = 0.0f;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (has_clip) {
|
if (has_clip) {
|
||||||
x1 = std::max(x1, cmd.clip_x1);
|
x1 = std::max(x1, cmd.clip_x1);
|
||||||
|
|||||||
@@ -374,6 +374,17 @@ func _draw() -> void:
|
|||||||
RenderingServer.canvas_item_add_polygon(target_segments[seg_idx], poly_pts,
|
RenderingServer.canvas_item_add_polygon(target_segments[seg_idx], poly_pts,
|
||||||
_get_color_array(argb), poly_uv, tex_rid)
|
_get_color_array(argb), poly_uv, tex_rid)
|
||||||
|
|
||||||
|
elif kind == &"bar" and command.has(&"quad"):
|
||||||
|
# An untextured polygon piece (CPythonGraphic::RenderCoolTimeBox's fan triangles).
|
||||||
|
if x2 > cx1 and x1 < cx2 and y2 > cy1 and y1 < cy2:
|
||||||
|
if not fg_plain:
|
||||||
|
fg_used = _segment(fg_used, RID())
|
||||||
|
fg_plain = true
|
||||||
|
var seg_idx := fg_used - 1
|
||||||
|
var quad: PackedVector2Array = command[&"quad"]
|
||||||
|
RenderingServer.canvas_item_add_polygon(target_segments[seg_idx],
|
||||||
|
PackedVector2Array([quad[0], quad[1], quad[2]]), _get_color_array(argb))
|
||||||
|
|
||||||
elif kind == &"bar":
|
elif kind == &"bar":
|
||||||
var bx1 := maxf(x1, cx1)
|
var bx1 := maxf(x1, cx1)
|
||||||
var by1 := maxf(y1, cy1)
|
var by1 := maxf(y1, cy1)
|
||||||
|
|||||||
Reference in New Issue
Block a user