From: Nozomi Kodama Subject: d3dx9_36 [patch 2/3]: Implement D3DXSHEvalConeLight Message-Id: <1352876920.43242.YahooMailNeo@web132303.mail.ird.yahoo.com> Date: Wed, 14 Nov 2012 07:08:40 +0000 (GMT)
From 695df6effbd1de457d345f54a543461d7eb3bf7c Mon Sep 17 00:00:00 2001 From: Nozomi Kodama Date: Tue, 13 Nov 2012 20:57:09 -1000 Subject: Implement D3DXSHEvalConeLight --- dlls/d3dx9_36/d3dx9_36.spec | 2 +- dlls/d3dx9_36/math.c | 68 ++++++++++++++++++ dlls/d3dx9_36/tests/math.c | 165 +++++++++++++++++++++++++++++++++++++++++++ include/d3dx9math.h | 1 + 4 files changed, 235 insertions(+), 1 deletion(-) diff --git a/dlls/d3dx9_36/d3dx9_36.spec b/dlls/d3dx9_36/d3dx9_36.spec index a79b27a..8510c33 100644 --- a/dlls/d3dx9_36/d3dx9_36.spec +++ b/dlls/d3dx9_36/d3dx9_36.spec @@ -274,7 +274,7 @@ @ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) @ stdcall D3DXSHAdd(ptr long ptr ptr) @ stdcall D3DXSHDot(long ptr ptr) -@ stub D3DXSHEvalConeLight(long ptr long long long long ptr ptr ptr) +@ stdcall D3DXSHEvalConeLight(long ptr float float float float ptr ptr ptr) @ stdcall D3DXSHEvalDirection(ptr long ptr) @ stdcall D3DXSHEvalDirectionalLight(long ptr float float float ptr ptr ptr) @ stdcall D3DXSHEvalHemisphereLight(long ptr int128 int128 ptr ptr ptr) diff --git a/dlls/d3dx9_36/math.c b/dlls/d3dx9_36/math.c index 6ce5df8..33aca41 100644 --- a/dlls/d3dx9_36/math.c +++ b/dlls/d3dx9_36/math.c @@ -2230,6 +2230,74 @@ FLOAT WINAPI D3DXSHDot(UINT order, CONST FLOAT *a, CONST FLOAT *b) return s; } +static void weightedcapintegrale(FLOAT *out, FLOAT order, FLOAT angle) +{ + FLOAT coeff[4]; + + coeff[0] = cosf(angle); + coeff[1] = sinf(angle) * sinf(angle); + + out[0] = 2.0f * D3DX_PI * (1.0f - coeff[0]); + out[1] = D3DX_PI * coeff[1]; + if (order <= 2) + return; + + out[2] = D3DX_PI * coeff[0] * coeff[1]; + if (order == 3) + return; + + coeff[2] = coeff[0] * coeff[0]; + coeff[3] = coeff[2] * coeff[2]; + + out[3] = D3DX_PI * (-1.25f * coeff[3] + 1.5f * coeff[2] - 0.25f); + if (order == 4) + return; + + out[4] = -0.25f * D3DX_PI * coeff[0] * (7.0f * coeff[3] - 10.0f * coeff[2] + 3.0f); + if (order == 5) + return; + + out[5] = D3DX_PI * (-2.625f * coeff[3] * coeff[2] + 4.375f * coeff[3] - 1.875f * coeff[2] + 0.125f); +} + +HRESULT WINAPI D3DXSHEvalConeLight(UINT order, CONST D3DXVECTOR3 *dir, FLOAT radius, + FLOAT Rintensity, FLOAT Gintensity, FLOAT Bintensity, FLOAT *rout, FLOAT *gout, FLOAT *bout) +{ + FLOAT cap[6], clamped_angle, norm, scale, temp; + UINT i, index, j; + + TRACE("order %u, dir %p, radius %f, red %f, green %f, blue %f, rout %p, gout %p, bout %p\n", + order, dir, radius, Rintensity, Gintensity, Bintensity, rout, gout, bout); + + if (radius <= 0.0f) + return D3DXSHEvalDirectionalLight(order, dir, Rintensity, Gintensity, Bintensity, rout, gout, bout); + + clamped_angle = (radius > D3DX_PI / 2.0f) ? (D3DX_PI / 2.0f) : radius; + norm = sinf(clamped_angle) * sinf(clamped_angle); + + weightedcapintegrale(cap, order, radius); + D3DXSHEvalDirection(rout, order, dir); + + for (i = 0; i < order; i++) + { + scale = cap[i] / norm; + + for (j = 0; j < 2 * i + 1; j++) + { + index = i * i + j; + temp = rout[index] * scale; + + rout[index] = temp * Rintensity; + if (gout) + gout[index] = temp * Gintensity; + if (bout) + bout[index] = temp * Bintensity; + } + } + + return D3D_OK; +} + FLOAT* WINAPI D3DXSHEvalDirection(FLOAT *out, UINT order, CONST D3DXVECTOR3 *dir) { diff --git a/dlls/d3dx9_36/tests/math.c b/dlls/d3dx9_36/tests/math.c index e577e6f..9d9139c 100644 --- a/dlls/d3dx9_36/tests/math.c +++ b/dlls/d3dx9_36/tests/math.c @@ -2481,6 +2481,170 @@ static void test_D3DXSHDot(void) return; } +static void test_D3DXSHEvalConeLight(void) +{ + D3DXVECTOR3 dir; + FLOAT *blue_out, bout[49], expected, gout[49], *green_out, *red_out, rout[49]; + const FLOAT table[] = { + /* Red colour */ + 1.604815f, -3.131381f, 7.202175f, -2.870432f, 6.759296f, -16.959688f, + 32.303082f, -15.546381f, -0.588878f, -5.902123f, 40.084042f, -77.423569f, + 137.556320f, -70.971603f, -3.492171f, 7.683092f, -2.129311f, -35.971344f, + 183.086548f, -312.414948f, 535.091064f, -286.380371f, -15.950727f, 46.825714f, + -12.127637f, 11.289261f, -12.417809f, -155.039566f, 681.182556f, -1079.733643f, + 1807.650513f, -989.755798f, -59.345467f, 201.822815f, -70.726486f, 7.206529f, + + 3.101155f, -3.128710f, 7.196033f, -2.867984f, -0.224708f, 0.563814f, + -1.073895f, 0.516829f, 0.019577f, 2.059788f, -13.988971f, 27.020128f, + -48.005917f, 24.768450f, 1.218736f, -2.681329f, -0.088639f, -1.497410f, + 7.621501f, -13.005165f, 22.274696f, -11.921401f, -0.663995f, 1.949254f, + -0.504848f, 4.168484f, -4.585193f, -57.247314f, 251.522095f, -398.684387f, + 667.462891f, -365.460693f, -21.912912f, 74.521721f, -26.115280f, 2.660963f, + /* Green colour */ + 2.454422f, -4.789170f, 11.015091f, -4.390072f, 10.337747f, -25.938347f, + 49.404713f, -23.776817f, -0.900637f, -9.026776f, 61.305000f, -118.412514f, + 210.380249f, -108.544792f, -5.340967f, 11.750610f, -3.256593f, -55.014996f, + 280.014709f, -477.811066f, 818.374512f, -437.993469f, -24.395227f, 71.615799f, + -18.548151f, 17.265928f, -18.991943f, -237.119324f, 1041.808594f, -1651.357300f, + 2764.642090f, -1513.744141f, -90.763657f, 308.670197f, -108.169922f, 11.021750f, + + 4.742942f, -4.785086f, 11.005697f, -4.386329f, -0.343672f, 0.862303f, + -1.642427f, 0.790444f, 0.029941f, 3.150264f, -21.394896f, 41.324898f, + -73.420807f, 37.881153f, 1.863950f, -4.100857f, -0.135565f, -2.290156f, + 11.656413f, -19.890251f, 34.067181f, -18.232729f, -1.015521f, 2.981212f, + -0.772120f, 6.375328f, -7.012648f, -87.554710f, 384.680817f, -609.752563f, + 1020.825500f, -558.939819f, -33.513863f, 113.974388f, -39.941013f, 4.069707f, + /* Blue colour */ + 3.304030f, -6.446959f, 14.828006f, -5.909713f, 13.916198f, -34.917004f, + 66.506340f, -32.007256f, -1.212396f, -12.151429f, 82.525963f, -159.401459f, + 283.204193f, -146.117996f, -7.189764f, 15.818130f, -4.383876f, -74.058655f, + 376.942871f, -643.207214f, 1101.658081f, -589.606628f, -32.839729f, 96.405884f, + -24.968664f, 23.242596f, -25.566080f, -319.199097f, 1402.434692f, -2222.980957f, + 3721.633545f, -2037.732544f, -122.181847f, 415.517578f, -145.613358f, 14.836972f, + + 6.384730f, -6.441462f, 14.815362f, -5.904673f, -0.462635f, 1.160793f, + -2.210959f, 1.064060f, 0.040305f, 4.240739f, -28.800821f, 55.629673f, + -98.835709f, 50.993862f, 2.509163f, -5.520384f, -0.182491f, -3.082903f, + 15.691326f, -26.775339f, 45.859665f, -24.544060f, -1.367048f, 4.013170f, + -1.039392f, 8.582172f, -9.440103f, -117.862114f, 517.839600f, -820.820740f, + 1374.188232f, -752.419067f, -45.114819f, 153.427063f, -53.766754f, 5.478452f, }; + struct + { + FLOAT *red_in, *green_in, *blue_in; + const FLOAT *red_out, *green_out, *blue_out; + FLOAT radius, roffset, goffset, boffset; + } test[] = + { { rout, gout, bout, table, &table[72], &table[144], 0.5f, 1.01f, 1.02f, 1.03f, }, + { rout, gout, bout, &table[36], &table[108], &table[180], 1.6f, 1.01f, 1.02f, 1.03f, }, + { rout, rout, rout, &table[144], &table[144], &table[144], 0.5f, 1.03f, 1.03f, 1.03f, }, + { rout, rout, bout, &table[72], &table[72], &table[144], 0.5, 1.02f, 1.02f, 1.03f, }, + { rout, gout, gout, table, &table[144], &table[144], 0.5f, 1.01f, 1.03f, 1.03f, }, + { rout, gout, rout, &table[144], &table[72], &table[144], 0.5f, 1.03f, 1.02f, 1.03f, }, + /* D3DXSHEvalConeLight accepts NULL green or blue colour. */ + { rout, NULL, bout, table, NULL, &table[144], 0.5f, 1.01f, 0.0f, 1.03f, }, + { rout, gout, NULL, table, &table[72], NULL, 0.5f, 1.01f, 1.02f, 0.0f, }, + { rout, NULL, NULL, table, NULL, NULL, 0.5f, 1.01f, 0.0f, 0.0f, }, }; + HRESULT hr; + unsigned int j, l, order; + + dir.x = 1.1f; dir.y= 1.2f; dir.z = 2.76f; + + for (l = 0; l < sizeof(test) / sizeof(test[0]); l++) + { + for (order = D3DXSH_MINORDER; order <= D3DXSH_MAXORDER; order++) + { + red_out = test[l].red_in; + green_out = test[l].green_in; + blue_out = test[l].blue_in; + + for (j = 0; j < 49; j++) + { + red_out[j] = 1.01f + j; + if (green_out) + green_out[j] = 1.02f + j; + if (blue_out) + blue_out[j] = 1.03f + j; + } + + hr = D3DXSHEvalConeLight(order, &dir, test[l].radius, 1.7f, 2.6f, 3.5f, red_out, green_out, blue_out); + ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr); + + for (j = 0; j < 49; j++) + { + if (j >= order * order) + expected = j + test[l].roffset; + else + expected = test[l].red_out[j]; + ok(relative_error(expected, red_out[j]) < admitted_error, + "Red: case %u, order %u: expected[%u] = %f, received %f\n", l, order, j, expected, red_out[j]); + + if (green_out) + { + if (j >= order * order) + expected = j + test[l].goffset; + else + expected = test[l].green_out[j]; + ok(relative_error(expected, green_out[j]) < admitted_error, + "Green: case %u, order %u: expected[%u] = %f, received %f\n", l, order, j, expected, green_out[j]); + } + + if (blue_out) + { + if (j >= order * order) + expected = j + test[l].boffset; + else + expected = test[l].blue_out[j]; + ok(relative_error(expected, blue_out[j]) < admitted_error, + "Blue: case %u, order %u: expected[%u] = %f, received %f\n", l, order, j, expected, blue_out[j]); + } + } + } + } + + /* Cone light with radius <= 0.0f behaves as a directional light */ + for (order = D3DXSH_MINORDER; order <= D3DXSH_MAXORDER; order++) + { + FLOAT blue[49], green[49], red[49]; + + for (j = 0; j < 49; j++) + { + rout[j] = 1.01f + j; + gout[j] = 1.02f + j; + bout[j] = 1.03f + j; + red[j] = 1.01f + j; + green[j] = 1.02f + j; + blue[j] = 1.03f + j; + } + + hr = D3DXSHEvalConeLight(order, &dir, -0.1f, 1.7f, 2.6f, 3.5f, rout, gout, bout); + ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr); + D3DXSHEvalDirectionalLight(order, &dir, 1.7f, 2.6f, 3.5f, red, green, blue); + + for (j = 0; j < 49; j++) + { + expected = red[j]; + ok(relative_error(expected, rout[j]) < admitted_error, + "Red: case %u, order %u: expected[%u] = %f, received %f\n", l, order, j, expected, rout[j]); + + expected = green[j]; + ok(relative_error(expected, gout[j]) < admitted_error, + "Green: case %u, order %u: expected[%u] = %f, received %f\n", l, order, j, expected, gout[j]); + + expected = blue[j]; + ok(relative_error(expected, bout[j]) < admitted_error, + "Blue: case %u, order %u: expected[%u] = %f, received %f\n", l, order, j, expected, bout[j]); + } + } + + /* D3DXSHEvalConeLight accepts order < D3DXSH_MINORDER or order > D3DXSH_MAXORDER. But tests in native windows show that the colour outputs are not set */ + hr = D3DXSHEvalConeLight(7, &dir, 0.5f, 1.0f, 2.0f, 3.0f, rout, gout, bout); + ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr); + hr = D3DXSHEvalConeLight(0, &dir, 0.5f, 1.0f, 2.0f, 3.0f, rout, gout, bout); + ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr); + hr = D3DXSHEvalConeLight(1, &dir, 0.5f, 1.0f, 2.0f, 3.0f, rout, gout, bout); + ok(hr == D3D_OK, "Expected %#x, got %#x\n", D3D_OK, hr); +} + static void test_D3DXSHEvalDirection(void) { unsigned int i, order; @@ -3089,6 +3253,7 @@ START_TEST(math) test_D3DXFloat_Array(); test_D3DXSHAdd(); test_D3DXSHDot(); + test_D3DXSHEvalConeLight(); test_D3DXSHEvalDirection(); test_D3DXSHEvalDirectionalLight(); test_D3DXSHEvalHemisphereLight(); diff --git a/include/d3dx9math.h b/include/d3dx9math.h index dca7ea5..0167dfe 100644 --- a/include/d3dx9math.h +++ b/include/d3dx9math.h @@ -379,6 +379,7 @@ FLOAT *WINAPI D3DXFloat16To32Array(FLOAT *pout, CONST D3DXFLOAT16 *pin, UINT n); FLOAT* WINAPI D3DXSHAdd(FLOAT *out, UINT order, CONST FLOAT *a, CONST FLOAT *b); FLOAT WINAPI D3DXSHDot(UINT order, CONST FLOAT *a, CONST FLOAT *b); +HRESULT WINAPI D3DXSHEvalConeLight(UINT order, CONST D3DXVECTOR3 *dir, FLOAT radius, FLOAT Rintensity, FLOAT Gintensity, FLOAT Bintensity, FLOAT *rout, FLOAT *gout, FLOAT *bout); FLOAT* WINAPI D3DXSHEvalDirection(FLOAT *out, UINT order, CONST D3DXVECTOR3 *dir); HRESULT WINAPI D3DXSHEvalDirectionalLight(UINT order, CONST D3DXVECTOR3 *dir, FLOAT Rintensity, FLOAT Gintensity, FLOAT Bintensity, FLOAT *rout, FLOAT *gout, FLOAT *bout); HRESULT WINAPI D3DXSHEvalHemisphereLight(UINT order, CONST D3DXVECTOR3 *dir, D3DXCOLOR top, D3DXCOLOR bottom, FLOAT *rout, FLOAT *gout, FLOAT *bout); -- 1.7.10.4