diff --git a/audit/history.jsonl b/audit/history.jsonl index 2911e4bf..4bbf1682 100644 --- a/audit/history.jsonl +++ b/audit/history.jsonl @@ -611,3 +611,6 @@ {"date": "2026-09-30", "unit": "EterLib/Thread.cpp", "action": "all PORTED verbatim over new Win32Crt _beginthreadex shim", "evidence": "port.file_loader_thread"} {"date": "2026-09-30", "unit": "EterLib/FileLoaderThread.cpp", "action": "all PORTED verbatim over new Win32Crt semaphore/thread/WaitForSingleObject/CloseHandle shims", "evidence": "port.file_loader_thread"} {"date": "2026-09-30", "unit": "EterLib/GrpVertexBufferDynamic.cpp", "action": "all PORTED verbatim (no 40250 instantiation)", "evidence": "build"} +{"date": "2026-09-30", "unit": "EterLib/GrpMath.cpp", "action": "all PORTED verbatim", "evidence": "port.grp_math"} +{"date": "2026-09-30", "unit": "EterLib/GrpColor.cpp", "action": "all PORTED verbatim", "evidence": "port.grp_math"} +{"date": "2026-09-30", "unit": "EterLib/GrpColorInstance.cpp", "action": "all PORTED verbatim", "evidence": "port.grp_math"} diff --git a/audit/port-map/EterLib/GrpColor.cpp.json b/audit/port-map/EterLib/GrpColor.cpp.json new file mode 100644 index 00000000..c9eb2e1d --- /dev/null +++ b/audit/port-map/EterLib/GrpColor.cpp.json @@ -0,0 +1,68 @@ +{ + "reference": "EterLib/GrpColor.cpp", + "reference_sha256": "592a3c1fe8f495cdedb3d5a68e084495b5f9ce1a649296b64fd024c2ee6c47bd", + "priority": "P4", + "contracts": [], + "functions": { + "CGraphicColor::CGraphicColor": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColor.cpp:CGraphicColor::CGraphicColor" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller outside GrpColorInstance)." + }, + "CGraphicColor::~CGraphicColor": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColor.cpp:CGraphicColor::~CGraphicColor" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller outside GrpColorInstance)." + }, + "CGraphicColor::Clear": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColor.cpp:CGraphicColor::Clear" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller outside GrpColorInstance)." + }, + "CGraphicColor::Set": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColor.cpp:CGraphicColor::Set" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller outside GrpColorInstance)." + }, + "CGraphicColor::Blend": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColor.cpp:CGraphicColor::Blend" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller outside GrpColorInstance)." + }, + "CGraphicColor::GetPackValue": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColor.cpp:CGraphicColor::GetPackValue" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller outside GrpColorInstance)." + } + } +} diff --git a/audit/port-map/EterLib/GrpColorInstance.cpp.json b/audit/port-map/EterLib/GrpColorInstance.cpp.json new file mode 100644 index 00000000..ae3fd510 --- /dev/null +++ b/audit/port-map/EterLib/GrpColorInstance.cpp.json @@ -0,0 +1,88 @@ +{ + "reference": "EterLib/GrpColorInstance.cpp", + "reference_sha256": "b9582ea06d7178d487e20e541d68b25ebd46ef56e5d6795fb12d81f2a4f7ff56", + "priority": "P4", + "contracts": [], + "functions": { + "CGraphicColorInstance::CGraphicColorInstance": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColorInstance.cpp:CGraphicColorInstance::CGraphicColorInstance" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller)." + }, + "CGraphicColorInstance::~CGraphicColorInstance": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColorInstance.cpp:CGraphicColorInstance::~CGraphicColorInstance" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller)." + }, + "CGraphicColorInstance::Clear": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColorInstance.cpp:CGraphicColorInstance::Clear" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller)." + }, + "CGraphicColorInstance::SetColorReference": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColorInstance.cpp:CGraphicColorInstance::SetColorReference" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller)." + }, + "CGraphicColorInstance::BlendColorReference": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColorInstance.cpp:CGraphicColorInstance::BlendColorReference" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller)." + }, + "CGraphicColorInstance::Update": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColorInstance.cpp:CGraphicColorInstance::Update" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller)." + }, + "CGraphicColorInstance::GetCurrentTime": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColorInstance.cpp:CGraphicColorInstance::GetCurrentTime" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller)." + }, + "CGraphicColorInstance::GetCurrentColorReference": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpColorInstance.cpp:CGraphicColorInstance::GetCurrentColorReference" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (no 40250 caller)." + } + } +} diff --git a/audit/port-map/EterLib/GrpMath.cpp.json b/audit/port-map/EterLib/GrpMath.cpp.json new file mode 100644 index 00000000..a4eb09d5 --- /dev/null +++ b/audit/port-map/EterLib/GrpMath.cpp.json @@ -0,0 +1,68 @@ +{ + "reference": "EterLib/GrpMath.cpp", + "reference_sha256": "bc15adf13da6227f7c768e1ddb82d2fcd25c16a863a433704bc66ea0fc654f07", + "priority": "P4", + "contracts": [], + "functions": { + "CrossProduct2D": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpMath.cpp:CrossProduct2D" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (IsInTriangle2D: AttributeInstance collision; the rotation helpers have no 40250 caller)." + }, + "IsInTriangle2D": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpMath.cpp:IsInTriangle2D" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (IsInTriangle2D: AttributeInstance collision; the rotation helpers have no 40250 caller)." + }, + "D3DXVec3Rotation": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpMath.cpp:D3DXVec3Rotation" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (IsInTriangle2D: AttributeInstance collision; the rotation helpers have no 40250 caller)." + }, + "GetRotationFromMatrix": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpMath.cpp:GetRotationFromMatrix" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (IsInTriangle2D: AttributeInstance collision; the rotation helpers have no 40250 caller)." + }, + "GetPivotAndRotationFromMatrix": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpMath.cpp:GetPivotAndRotationFromMatrix" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (IsInTriangle2D: AttributeInstance collision; the rotation helpers have no 40250 caller)." + }, + "ExtractMovement": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpMath.cpp:ExtractMovement" + ], + "test": [ + "tests/port/port_grp_math_test.cpp" + ], + "note": "Verbatim 40250 (IsInTriangle2D: AttributeInstance collision; the rotation helpers have no 40250 caller)." + } + } +} diff --git a/src/platform/EterLib/GrpColor.cpp b/src/platform/EterLib/GrpColor.cpp index cfd91b39..0f14592e 100644 --- a/src/platform/EterLib/GrpColor.cpp +++ b/src/platform/EterLib/GrpColor.cpp @@ -1,62 +1,78 @@ -// Platform skeleton for EterLib/GrpColor.h (40250 EterLib/GrpColor.cpp), generated by platform_stub.py. -// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation. +// 40250 EterLib/GrpColor.cpp, verbatim. #include "EterLib/StdAfx.h" #include "EterLib/GrpColor.h" -#include "../PlatformStub.h" - -CGraphicColor::CGraphicColor(const CGraphicColor &) -{ - MT_PLATFORM_STUB(); -} - -CGraphicColor::CGraphicColor(float, float, float, float) -{ - MT_PLATFORM_STUB(); -} - -CGraphicColor::CGraphicColor(DWORD) -{ - MT_PLATFORM_STUB(); -} - CGraphicColor::CGraphicColor() { - MT_PLATFORM_STUB(); + Clear(); +} + +CGraphicColor::CGraphicColor(const CGraphicColor& c_rSrcColor) +{ + Set(c_rSrcColor); +} + +CGraphicColor::CGraphicColor(float r, float g, float b, float a) +{ + Set(r, g, b, a); +} + +CGraphicColor::CGraphicColor(DWORD color) +{ + Set(color); } CGraphicColor::~CGraphicColor() { - MT_PLATFORM_STUB(); } -auto CGraphicColor::Clear() -> void +void CGraphicColor::Clear() { - MT_PLATFORM_STUB(); + Set(1.0f, 1.0f, 1.0f, 1.0f); } -auto CGraphicColor::Set(float, float, float, float) -> void +void CGraphicColor::Set(float r, float g, float b, float a) { - MT_PLATFORM_STUB(); + m_r=r; + m_g=g; + m_b=b; + m_a=a; } -auto CGraphicColor::Set(const CGraphicColor &) -> void +void CGraphicColor::Set(const CGraphicColor& c_rSrcColor) { - MT_PLATFORM_STUB(); + m_r=c_rSrcColor.m_r; + m_g=c_rSrcColor.m_g; + m_b=c_rSrcColor.m_b; + m_a=c_rSrcColor.m_a; } -auto CGraphicColor::Set(DWORD) -> void +void CGraphicColor::Blend(float p, const CGraphicColor& c_rSrcColor, const CGraphicColor& c_rDstColor) { - MT_PLATFORM_STUB(); + float q=1.0f-p; + m_r=c_rSrcColor.m_r*q+c_rDstColor.m_r*p; + m_g=c_rSrcColor.m_g*q+c_rDstColor.m_g*p; + m_b=c_rSrcColor.m_b*q+c_rDstColor.m_b*p; + m_a=c_rSrcColor.m_a*q+c_rDstColor.m_a*p; } -auto CGraphicColor::Blend(float, const CGraphicColor &, const CGraphicColor &) -> void +void CGraphicColor::Set(DWORD pack) { - MT_PLATFORM_STUB(); + m_b = (pack & 0xff) / 255.0f; pack >>= 8; + m_g = (pack & 0xff) / 255.0f; pack >>= 8; + m_r = (pack & 0xff) / 255.0f; pack >>= 8; + m_a = (pack) / 255.0f; } -auto CGraphicColor::GetPackValue() const -> DWORD +DWORD CGraphicColor::GetPackValue() const { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + DWORD packValue=0; + + packValue = int(255.0f * m_a);packValue <<= 8; + packValue |= int(255.0f * m_r);packValue <<= 8; + packValue |= int(255.0f * m_g);packValue <<= 8; + packValue |= int(255.0f * m_b); + + return packValue; } + diff --git a/src/platform/EterLib/GrpColorInstance.cpp b/src/platform/EterLib/GrpColorInstance.cpp index 79e26ad1..76ec727a 100644 --- a/src/platform/EterLib/GrpColorInstance.cpp +++ b/src/platform/EterLib/GrpColorInstance.cpp @@ -1,48 +1,66 @@ -// Platform skeleton for EterLib/GrpColorInstance.h (40250 EterLib/GrpColorInstance.cpp), generated by platform_stub.py. -// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation. +// 40250 EterLib/GrpColorInstance.cpp, verbatim. #include "EterLib/StdAfx.h" #include "EterLib/GrpColorInstance.h" - -#include "../PlatformStub.h" +#include "EterBase/Timer.h" CGraphicColorInstance::CGraphicColorInstance() { - MT_PLATFORM_STUB(); + m_baseTime=0; + m_blendTime=0; } CGraphicColorInstance::~CGraphicColorInstance() { - MT_PLATFORM_STUB(); } -auto CGraphicColorInstance::Clear() -> void +void CGraphicColorInstance::Clear() { - MT_PLATFORM_STUB(); + m_srcColor.Clear(); + m_dstColor.Clear(); + m_curColor.Clear(); + + m_baseTime=0; + m_blendTime=0; } -auto CGraphicColorInstance::SetColorReference(const CGraphicColor &) -> void +void CGraphicColorInstance::SetColorReference(const CGraphicColor & c_rSrcColor) { - MT_PLATFORM_STUB(); + m_srcColor = c_rSrcColor; + m_dstColor = c_rSrcColor; + m_curColor = c_rSrcColor; } -auto CGraphicColorInstance::BlendColorReference(DWORD, const CGraphicColor &) -> void +void CGraphicColorInstance::BlendColorReference(DWORD blendTime, const CGraphicColor& c_rDstColor) { - MT_PLATFORM_STUB(); + m_baseTime = GetCurrentTime(); + m_blendTime = blendTime; + + m_srcColor = m_curColor; + m_dstColor = c_rDstColor; } -auto CGraphicColorInstance::Update() -> void +void CGraphicColorInstance::Update() { - MT_PLATFORM_STUB(); + DWORD curTime = GetCurrentTime(); + DWORD elapsedTime = curTime - m_baseTime; + + if (elapsedTime < m_blendTime) + { + m_curColor.Blend(elapsedTime/float(m_blendTime), m_srcColor, m_dstColor); + } + else + { + m_curColor=m_dstColor; + } } -auto CGraphicColorInstance::GetCurrentColorReference() const -> const CGraphicColor & +DWORD CGraphicColorInstance::GetCurrentTime() { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + return CTimer::Instance().GetCurrentMillisecond(); } -auto CGraphicColorInstance::GetCurrentTime() -> DWORD +const CGraphicColor& CGraphicColorInstance::GetCurrentColorReference() const { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + return m_curColor; } + diff --git a/src/platform/EterLib/GrpMath.cpp b/src/platform/EterLib/GrpMath.cpp index 0aea0f41..9ce0aedb 100644 --- a/src/platform/EterLib/GrpMath.cpp +++ b/src/platform/EterLib/GrpMath.cpp @@ -1,45 +1,137 @@ -// Platform skeleton for EterLib/GrpMath.h (40250 EterLib/GrpMath.cpp), generated by platform_stub.py. -// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation. +// 40250 EterLib/GrpMath.cpp, verbatim. #include "EterLib/StdAfx.h" #include "EterLib/GrpMath.h" -#include "../PlatformStub.h" - -auto CrossProduct2D(float, float, float, float) -> float +float CrossProduct2D(float x1, float y1, float x2, float y2) { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + return x1*y2-y1*x2; } -auto IsInTriangle2D(float, float, float, float, float, float, float, float) -> bool +bool IsInTriangle2D(float ax, float ay, float bx, float by, float cx, float cy, float tx, float ty) { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + float c1 = CrossProduct2D(bx-ax, by-ay, tx-ax, ty-ay); + float c2 = CrossProduct2D(cx-bx, cy-by, tx-bx, ty-by); + float c3 = CrossProduct2D(ax-cx, ay-cy, tx-cx, ty-cy); + + if (c1 * c2 > 0.0f && c1 * c3 > 0.0f) + return true; + + if (c1 * c2 * c3 == 0.0f) + { + if (tx < ax) + if (tx < bx) + if (tx < cx) + return false; + + if (tx > ax) + if (tx > bx) + if (tx > cx) + return false; + + if (ty < ay) + if (ty < by) + if (ty < cy) + return false; + + if (ty > ay) + if (ty > by) + if (ty > cy) + return false; + + return true; + } + + return false; } -auto D3DXVec3Rotation(D3DXVECTOR3 *, const D3DXVECTOR3 *, const D3DXQUATERNION *) -> D3DXVECTOR3 * +D3DXVECTOR3* D3DXVec3Rotation(D3DXVECTOR3* pvtOut, const D3DXVECTOR3* c_pvtSrc, const D3DXQUATERNION* c_pqtRot) { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + D3DXQUATERNION qtSrc(c_pvtSrc->x, c_pvtSrc->y, c_pvtSrc->z, 0); + D3DXQUATERNION qtRet; + D3DXQuaternionConjugate(&qtRet, c_pqtRot); + D3DXQuaternionMultiply(&qtRet, &qtSrc, &qtRet); + D3DXQuaternionMultiply(&qtRet, c_pqtRot, &qtRet); + + pvtOut->x=qtRet.x; + pvtOut->y=qtRet.y; + pvtOut->z=qtRet.z; + + return pvtOut; } -auto D3DXVec3Translation(D3DXVECTOR3 *, const D3DXVECTOR3 *, const D3DXVECTOR3 *) -> D3DXVECTOR3 * + + +void GetRotationFromMatrix(D3DXVECTOR3 * pRotation, const D3DXMATRIX * c_pMatrix) { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + float sx = c_pMatrix->_32; + float cx = sqrtf(1.0f - sx * sx); + + if (cx < 0.00001f) + { + if (sx > 0) + pRotation->x = D3DX_PI / 2; + else + pRotation->x = -D3DX_PI / 2; + + pRotation->y = atan2f(c_pMatrix->_31, c_pMatrix->_11); + pRotation->z = 0.0f; + } + else + { + pRotation->x = atan2f(sx, cx); + pRotation->y = atan2f(-c_pMatrix->_31, c_pMatrix->_33); + pRotation->z = atan2f(-c_pMatrix->_12, c_pMatrix->_22); + } } -auto GetRotationFromMatrix(D3DXVECTOR3 *, const D3DXMATRIX *) -> void +void GetPivotAndRotationFromMatrix(D3DXMATRIX * pMatrix, D3DXVECTOR3 * pPivot, D3DXVECTOR3 * pRotation) { - MT_PLATFORM_STUB(); + float sx = pMatrix->_32; + float cx = sqrtf(1.0f - sx * sx); + float x, y, z; + + if (cx < 0.00001f) + { + if (sx > 0) + x = D3DX_PI / 2; + else + x = -D3DX_PI / 2; + + y = atan2f(pMatrix->_31, pMatrix->_11); + z = 0.0f; + } + else + { + x = atan2f(sx, cx); + y = atan2f(-pMatrix->_31, pMatrix->_33); + z = atan2f(-pMatrix->_12, pMatrix->_22); + } + + pRotation->x = x; + pRotation->y = y; + pRotation->z = z; + + pPivot->x = pMatrix->_41; + pPivot->y = pMatrix->_42; + pPivot->z = pMatrix->_43; } -auto GetPivotAndRotationFromMatrix(D3DXMATRIX *, D3DXVECTOR3 *, D3DXVECTOR3 *) -> void +// NOTE : must be optimized! +void ExtractMovement(D3DXMATRIX * pTargetMatrix, D3DXMATRIX * pSourceMatrix) { - MT_PLATFORM_STUB(); -} + D3DXVECTOR3 v3Pivot; + D3DXVECTOR3 v3Rotation; + GetPivotAndRotationFromMatrix(pSourceMatrix, &v3Pivot, &v3Rotation); -auto ExtractMovement(D3DXMATRIX *, D3DXMATRIX *) -> void -{ - MT_PLATFORM_STUB(); + D3DXMATRIX matRotationX; + D3DXMatrixRotationX(&matRotationX, v3Rotation.x); + D3DXMATRIX matRotationY; + D3DXMatrixRotationY(&matRotationY, v3Rotation.y); + D3DXMATRIX matRotationZ; + D3DXMatrixRotationZ(&matRotationZ, v3Rotation.z); + + D3DXMATRIX matTranslation; + D3DXMatrixTranslation(&matTranslation, v3Pivot.x, v3Pivot.y, v3Pivot.z); + + *pTargetMatrix = matRotationX * matRotationY * matRotationZ * matTranslation; } diff --git a/src/port/CMakeLists.txt b/src/port/CMakeLists.txt index 4337a038..adfc2836 100644 --- a/src/port/CMakeLists.txt +++ b/src/port/CMakeLists.txt @@ -216,6 +216,9 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME) add_executable(port_file_loader_thread_test ${PROJECT_SOURCE_DIR}/tests/port/port_file_loader_thread_test.cpp) target_link_libraries(port_file_loader_thread_test PRIVATE port_platform) add_test(NAME port.file_loader_thread COMMAND $) + add_executable(port_grp_math_test ${PROJECT_SOURCE_DIR}/tests/port/port_grp_math_test.cpp) + target_link_libraries(port_grp_math_test PRIVATE port_platform) + add_test(NAME port.grp_math COMMAND $) # EterBase/Debug.cpp: syserr.txt / log.txt (redirects its own stderr). add_executable(port_debug_log_test ${PROJECT_SOURCE_DIR}/tests/port/port_debug_log_test.cpp) diff --git a/tests/port/port_grp_math_test.cpp b/tests/port/port_grp_math_test.cpp new file mode 100644 index 00000000..87fc0860 --- /dev/null +++ b/tests/port/port_grp_math_test.cpp @@ -0,0 +1,131 @@ +// EterLib GrpMath / GrpColor / GrpColorInstance (40250 bodies, verbatim). +#include "EterLib/StdAfx.h" +#include "EterLib/GrpMath.h" +#include "EterLib/GrpColor.h" +#include "EterLib/GrpColorInstance.h" +#include "EterBase/Timer.h" + +#include +#include + +namespace +{ +int failures = 0; + +void check(bool ok, const char * name) +{ + if (!ok) + { + std::printf("FAIL %s\n", name); + ++failures; + } +} + +bool near(float a, float b, float eps = 1e-4f) +{ + return std::fabs(a - b) <= eps; +} +} + +int main() +{ + // CrossProduct2D / IsInTriangle2D (terrain + collision picking): interior, outside, and on an edge, + // where the zero cross product falls back to the bounding-box test. + check(CrossProduct2D(1, 0, 0, 1) == 1.0f && CrossProduct2D(0, 1, 1, 0) == -1.0f, "CrossProduct2D"); + check(IsInTriangle2D(0, 0, 4, 0, 0, 4, 1, 1), "IsInTriangle2D inside"); + check(IsInTriangle2D(0, 0, 0, 4, 4, 0, 1, 1), "IsInTriangle2D inside, other winding"); + check(!IsInTriangle2D(0, 0, 4, 0, 0, 4, 3, 3), "IsInTriangle2D outside"); + check(IsInTriangle2D(0, 0, 4, 0, 0, 4, 2, 0), "IsInTriangle2D on edge"); + check(!IsInTriangle2D(0, 0, 4, 0, 0, 4, 5, 0), "IsInTriangle2D on edge line, past the vertex"); + + // D3DXVec3Rotation: D3DXQuaternionMultiply(a, b) is b * a, so the two calls give conj(q) * v * q, the + // inverse rotation of the one D3DXMatrixRotationQuaternion(q) applies. + { + D3DXQUATERNION q; + D3DXVECTOR3 axis(0.3f, -0.5f, 0.8f); + D3DXVec3Normalize(&axis, &axis); + D3DXQuaternionRotationAxis(&q, &axis, 1.2f); + D3DXVECTOR3 v(1, 2, 3), out; + check(D3DXVec3Rotation(&out, &v, &q) == &out, "D3DXVec3Rotation returns out"); + D3DXQUATERNION inverse; + D3DXQuaternionConjugate(&inverse, &q); + D3DXMATRIX m; + D3DXMatrixRotationQuaternion(&m, &inverse); + D3DXVECTOR3 expect; + D3DXVec3TransformNormal(&expect, &v, &m); + check(near(out.x, expect.x) && near(out.y, expect.y) && near(out.z, expect.z), "D3DXVec3Rotation = inverse rotation"); + } + + // GetRotationFromMatrix / GetPivotAndRotationFromMatrix read sin(x) from _32: on Z*X*Y they return the + // negated angles. ExtractMovement rebuilds X*Y*Z*T from those angles, not the source rotation (40250 has + // no caller of these helpers; the bodies are kept verbatim). + { + const float rx = 0.3f, ry = -0.7f, rz = 1.1f; + D3DXMATRIX mx, my, mz, mt; + D3DXMatrixRotationX(&mx, rx); + D3DXMatrixRotationY(&my, ry); + D3DXMatrixRotationZ(&mz, rz); + D3DXMatrixTranslation(&mt, 10, 20, 30); + D3DXMATRIX rot3 = mz * mx * my; + D3DXMATRIX m = rot3 * mt; + + D3DXVECTOR3 rot; + GetRotationFromMatrix(&rot, &m); + check(near(rot.x, -rx) && near(rot.y, -ry) && near(rot.z, -rz), "GetRotationFromMatrix"); + D3DXVECTOR3 pivot; + GetPivotAndRotationFromMatrix(&m, &pivot, &rot); + check(near(rot.x, -rx) && near(rot.y, -ry) && near(rot.z, -rz) && pivot == D3DXVECTOR3(10, 20, 30), "GetPivotAndRotationFromMatrix"); + + D3DXMATRIX extracted; + ExtractMovement(&extracted, &m); + D3DXMATRIX ix, iy, iz; + D3DXMatrixRotationX(&ix, -rx); + D3DXMatrixRotationY(&iy, -ry); + D3DXMatrixRotationZ(&iz, -rz); + D3DXMATRIX expect = ix * iy * iz * mt; + bool same = true; + for (int i = 0; i < 16; ++i) + same = same && near(((const float *) extracted)[i], ((const float *) expect)[i]); + check(same, "ExtractMovement = X*Y*Z*T of the negated angles"); + + D3DXMATRIX gimbal; + D3DXMatrixRotationX(&gimbal, D3DX_PI / 2); + GetRotationFromMatrix(&rot, &gimbal); + check(near(rot.x, -D3DX_PI / 2) && rot.z == 0.0f, "GetRotationFromMatrix gimbal lock"); + } + + // CGraphicColor: ARGB pack round trip (truncating), Blend. + { + CGraphicColor c(0x80FF4000); + check(c.GetPackValue() == 0x80FF4000, "CGraphicColor pack round trip"); + CGraphicColor d; + check(d.GetPackValue() == 0xFFFFFFFF, "CGraphicColor default is opaque white"); + CGraphicColor half; + half.Blend(0.5f, CGraphicColor(0.0f, 0.0f, 0.0f, 0.0f), CGraphicColor(1.0f, 1.0f, 1.0f, 1.0f)); + check(half.GetPackValue() == 0x7F7F7F7F, "CGraphicColor Blend truncates"); + CGraphicColor copy(c); + check(copy.GetPackValue() == c.GetPackValue(), "CGraphicColor copy"); + } + + // CGraphicColorInstance: SetColorReference sets all three; a finished blend lands on the target; + // a fresh long blend starts from the current colour. + { + CTimer timer; + CGraphicColorInstance inst; + inst.SetColorReference(CGraphicColor(0xFF000000)); + inst.Update(); + check(inst.GetCurrentColorReference().GetPackValue() == 0xFF000000, "SetColorReference"); + inst.BlendColorReference(0, CGraphicColor(0xFFFFFFFF)); + inst.Update(); + check(inst.GetCurrentColorReference().GetPackValue() == 0xFFFFFFFF, "BlendColorReference zero time"); + inst.BlendColorReference(1000000, CGraphicColor(0xFF000000)); + inst.Update(); + check(inst.GetCurrentColorReference().GetPackValue() == 0xFFFFFFFF, "long blend starts at current colour"); + inst.Clear(); + check(inst.GetCurrentColorReference().GetPackValue() == 0xFFFFFFFF, "CGraphicColorInstance Clear"); + } + + if (!failures) + std::printf("ok\n"); + return failures ? 1 : 0; +}