bool Storm3D_SpotlightShared::setScissorRect(Storm3D_Camera &camera, const VC2I &screenSize, Storm3D_Scene *scene) { D3DXMATRIX light; D3DXVECTOR3 lightPosition(position.x, position.y, position.z); D3DXVECTOR3 up(0, 1.f, 0); D3DXVECTOR3 lookAt = lightPosition; lookAt += D3DXVECTOR3(direction.x, direction.y, direction.z); D3DXMatrixLookAtLH(&light, &lightPosition, &lookAt, &up); // Create frustum vertices D3DXVECTOR3 v[5]; v[0] = D3DXVECTOR3(0, 0, 0); v[1] = D3DXVECTOR3(0, 0, 1.f); v[2] = D3DXVECTOR3(0, 0, 1.f); v[3] = D3DXVECTOR3(0, 0, 1.f); v[4] = D3DXVECTOR3(0, 0, 1.f); float det = D3DXMatrixDeterminant(&light); D3DXMatrixInverse(&light, &det, &light); float angle = D3DXToRadian(fov) * .5f; for(int i = 0; i <= 4; ++i) { if(i > 0) { float z = v[i].z; if(i == 1 || i == 2) { v[i].x = z * sinf(angle); v[i].z = z * cosf(angle); } else { v[i].x = z * sinf(-angle); v[i].z = z * cosf(-angle); } if(i == 1 || i == 3) v[i].y = z * sinf(angle); else v[i].y = z * sinf(-angle); float scale = range / cosf(angle); v[i] *= scale; } D3DXVec3TransformCoord(&v[i], &v[i], &light); } // Create area const Frustum &frustum = camera.getFrustum(); int minX = screenSize.x; int minY = screenSize.y; int maxX = 0; int maxY = 0; for(int i = 0; i < 6; ++i) { VC3 v1; VC3 v2; VC3 v3; if(i == 0) { v1 = toVC3(v[0]); v2 = toVC3(v[1]); v3 = toVC3(v[2]); } else if(i == 1) { v1 = toVC3(v[0]); v2 = toVC3(v[2]); v3 = toVC3(v[4]); } else if(i == 2) { v1 = toVC3(v[0]); v2 = toVC3(v[3]); v3 = toVC3(v[4]); } else if(i == 3) { v1 = toVC3(v[0]); v2 = toVC3(v[1]); v3 = toVC3(v[3]); } else if(i == 4) { v1 = toVC3(v[1]); v2 = toVC3(v[2]); v3 = toVC3(v[3]); } else if(i == 5) { v1 = toVC3(v[4]); v2 = toVC3(v[2]); v3 = toVC3(v[3]); } const ClipPolygon &clipPolygon = clipTriangleToFrustum(v1, v2, v3, frustum); for(int j = 0; j < clipPolygon.vertexAmount; ++j) { VC3 result; float rhw = 0.f; float real_z = 0.f; camera.GetTransformedToScreen(clipPolygon.vertices[j], result, rhw, real_z); int x = int(result.x * screenSize.x); int y = int(result.y * screenSize.y); //if(x < -1 || x > screenSize.x) // continue; //if(y < -1 || x > screenSize.y) // continue; x = max(x, 0); y = max(y, 0); x = min(x, screenSize.x - 1); y = min(y, screenSize.y - 1); maxX = max(x, maxX); maxY = max(y, maxY); minX = min(x, minX); minY = min(y, minY); /* // Visualize clipped polygons if(scene) { VC3 p1 = clipPolygon.vertices[j]; VC3 p2 = clipPolygon.vertices[(j + 1) % clipPolygon.vertexAmount]; for(int k = 0; k < 5; ++k) { const VC3 &planeNormal = frustum.planeNormals[k]; PLANE plane; if(k == 0) plane.MakeFromNormalAndPosition(planeNormal, frustum.position + planeNormal); else plane.MakeFromNormalAndPosition(planeNormal, frustum.position); float d1 = plane.GetPointRange(p1); float d2 = plane.GetPointRange(p2); if(d1 < .25f) p1 += planeNormal * (.25f - d1); if(d2 < .25f) p2 += planeNormal * (.25f - d2); } scene->AddLine(p1, p2, COL(1.f, 1.f, 1.f)); } */ } } RECT rc; bool visible = false; if(maxX > minX && maxY > minY) { visible = true; rc.left = minX; rc.top = minY; rc.right = maxX; rc.bottom = maxY; } else { visible = false; rc.left = 0; rc.top = 0; rc.right = 1; rc.bottom = 1; } /* // Visualize scissor area if(scene && visible) { static DWORD foo = GetTickCount(); int dif = (GetTickCount() - foo) % 2000; if(dif < 1000) scene->Render2D_Picture(0, VC2(float(minX), float(minY)), VC2(float(maxX - minX), float(maxY - minY)), 0.5f, 0.f, 0, 0, 0, 0, false); } */ device.SetScissorRect(&rc); device.SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); return visible; }
bool Storm3D_SpotlightShared::setScissorRect(Storm3D_Camera &camera, const VC2I &screenSize) { D3DXMATRIX light; D3DXVECTOR3 lightPosition(position.x, position.y, position.z); D3DXVECTOR3 up(0, 1.f, 0); D3DXVECTOR3 lookAt = lightPosition; lookAt += D3DXVECTOR3(direction.x, direction.y, direction.z); D3DXMatrixLookAtLH(&light, &lightPosition, &lookAt, &up); D3DXVECTOR3 v[5]; v[0] = D3DXVECTOR3(0, 0, 0); v[1] = D3DXVECTOR3(0, 0, 1.f); v[2] = D3DXVECTOR3(0, 0, 1.f); v[3] = D3DXVECTOR3(0, 0, 1.f); v[4] = D3DXVECTOR3(0, 0, 1.f); int minX = screenSize.x; int minY = screenSize.y; int maxX = 0; int maxY = 0; float det = D3DXMatrixDeterminant(&light); D3DXMatrixInverse(&light, &det, &light); float angle = D3DXToRadian(fov) * .5f; for(int i = 0; i <= 4; ++i) { if(i > 0) { float z = v[i].z; if(i == 1 || i == 2) { v[i].x = z * sinf(angle); v[i].z = z * cosf(angle); } else { v[i].x = z * sinf(-angle); v[i].z = z * cosf(-angle); } if(i == 1 || i == 3) v[i].y = z * sinf(angle); else v[i].y = z * sinf(-angle); float scale = range / cosf(angle); v[i] *= scale; } D3DXVec3TransformCoord(&v[i], &v[i], &light); } const Frustum &frustum = camera.getFrustum(); calculateLineToScissor(toVC3(v[0]), toVC3(v[1]), frustum, camera, screenSize, minX, minY, maxX, maxY); calculateLineToScissor(toVC3(v[0]), toVC3(v[2]), frustum, camera, screenSize, minX, minY, maxX, maxY); calculateLineToScissor(toVC3(v[0]), toVC3(v[3]), frustum, camera, screenSize, minX, minY, maxX, maxY); calculateLineToScissor(toVC3(v[0]), toVC3(v[4]), frustum, camera, screenSize, minX, minY, maxX, maxY); calculateLineToScissor(toVC3(v[1]), toVC3(v[2]), frustum, camera, screenSize, minX, minY, maxX, maxY); calculateLineToScissor(toVC3(v[2]), toVC3(v[3]), frustum, camera, screenSize, minX, minY, maxX, maxY); calculateLineToScissor(toVC3(v[3]), toVC3(v[4]), frustum, camera, screenSize, minX, minY, maxX, maxY); calculateLineToScissor(toVC3(v[4]), toVC3(v[1]), frustum, camera, screenSize, minX, minY, maxX, maxY); /* VC3 cameraPos = camera.GetPosition(); VC3 cameraPosResult; float cameraRhw = 0, cameraRealZ = 0; bool cameraVisible = camera.GetTransformedToScreen(cameraPos, cameraPosResult, cameraRhw, cameraRealZ); for(i = 0; i <= 4; ++i) { VC3 source(v[i].x, v[i].y, v[i].z); VC3 result; float rhw = 0, realZ = 0; bool inFront = camera.GetTransformedToScreen(source, result, rhw, realZ); // HAX HAX! result.x = std::max(0.f, result.x); result.y = std::max(0.f, result.y); result.x = std::min(1.f, result.x); result.y = std::min(1.f, result.y); //if(fabsf(rhw) < 0.0001f) // continue; bool flip = false; if(realZ < cameraRealZ) flip = true; if(flip) { result.x = 1.f - result.x; result.y = 1.f - result.y; //minX = 0; //minY = 0; //maxX = screenSize.x; //maxY = screenSize.y; } int x = int(result.x * screenSize.x); int y = int(result.y * screenSize.y); maxX = std::max(x, maxX); maxY = std::max(y, maxY); minX = std::min(x, minX); minY = std::min(y, minY); } */ if(maxX > screenSize.x) maxX = screenSize.x; if(maxY > screenSize.y) maxY = screenSize.y; if(minX < 0) minX = 0; if(minY < 0) minY = 0; RECT rc; rc.left = minX; rc.top = minY; rc.right = maxX; rc.bottom = maxY; if(rc.left < rc.right && rc.top < rc.bottom) { device.SetScissorRect(&rc); device.SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); } else { RECT rc; rc.left = 0; rc.top = 0; rc.right = 1; rc.bottom = 1; device.SetScissorRect(&rc); device.SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); return false; } return true; }