// 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; }