static void RB_CreateProjectedProjectionMatrix( const idRenderLightLocal* light, float* m ) { auto parms = light->parms; if (parms.start.LengthSqr() < 0.0001f) parms.start = parms.target.Normalized() * 8.0f; if (parms.end.LengthSqr() < 0.0001f) parms.end = parms.target; idPlane planes[4]; R_SetLightProject( planes, idVec3( 0, 0, 0 ), parms.target, parms.right, parms.up, parms.start, parms.end ); idPlane frustrum[6]; R_SetLightFrustum( planes, frustrum ); idVec3 start[4]; idVec3 dir[4]; frustrum[0].PlaneIntersection( frustrum[1], start[0], dir[0] ); //ok frustrum[1].PlaneIntersection( frustrum[2], start[1], dir[1] ); frustrum[2].PlaneIntersection( frustrum[3], start[2], dir[2] ); frustrum[3].PlaneIntersection( frustrum[0], start[3], dir[3] ); float scale[8]; frustrum[4].RayIntersection( start[0], dir[0], scale[0] ); frustrum[4].RayIntersection( start[1], dir[1], scale[1] ); frustrum[4].RayIntersection( start[2], dir[2], scale[2] ); frustrum[4].RayIntersection( start[3], dir[3], scale[3] ); frustrum[5].RayIntersection( start[0], dir[0], scale[4] ); frustrum[5].RayIntersection( start[1], dir[1], scale[5] ); frustrum[5].RayIntersection( start[2], dir[2], scale[6] ); frustrum[5].RayIntersection( start[3], dir[3], scale[7] ); float n = parms.start.Length(); float f = parms.end.Length(); idVec3 nearPoint[4]; nearPoint[0] = dir[0] * scale[0]; nearPoint[1] = dir[1] * scale[1]; nearPoint[2] = dir[2] * scale[2]; nearPoint[3] = dir[3] * scale[3]; float l = -((dir[0] * scale[0]) - parms.start).y; float r = -l; float b = -((dir[0] * scale[0]) - parms.start).x; float t = -b; memset( m, 0, sizeof(m[0]) * 16 ); m[0] = (2.0f * n) / (r - l); m[5] = (2.0f * n) / (t - b); m[8] = (r + l) / (r - l); m[9] = (t + b) / (t - b); m[10] = -((f + n) / (f - n)); m[11] = -1.0f; m[14] = -(2 * f * n) / (f - n); }
EIntersection IntersectLineCone(const idVec3 rkLine[LSG_COUNT], idVec3 rkCone[ELC_COUNT], idVec3 Intersect[2], bool Stump) { EIntersection rc = INTERSECT_COUNT; int i, n, l, x; float t, angle; idPlane lightProject[4]; idPlane frustum[6]; int Start[6]; int End[6]; bool bStart, bEnd; bool bCalcIntersection; idStr txt; idStr format("Frustum[%u]"); idVec3 EndPoint(rkLine[LSG_ORIGIN]+rkLine[LSG_DIRECTION]); DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING(" rkLine[LSG_ORIGIN] = [%s]\r", rkLine[LSG_ORIGIN].ToString()); DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING(" rkLine[LSG_DIRECTION] = [%s]\r", rkLine[LSG_DIRECTION].ToString()); DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING(" EndPoint = [%s]\r", EndPoint.ToString()); R_SetLightProject(lightProject, rkCone[ELC_ORIGIN], rkCone[ELA_TARGET], rkCone[ELA_RIGHT], rkCone[ELA_UP], rkCone[ELA_START], rkCone[ELA_END]); R_SetLightFrustum(lightProject, frustum); /* DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[0]", lightProject[0]); DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[1]", lightProject[1]); DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[2]", lightProject[2]); DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[3]", lightProject[3]); */ n = format.Length(); // Calculate the angle between the target and the lightvector. angle = rkCone[ELA_TARGET].Length() * rkLine[LSG_DIRECTION].Length(); DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Denominator: %f\r", angle); if ( angle >= idMath::FLT_EPSILON ) { angle = idMath::ACos((rkCone[ELA_TARGET] * rkLine[LSG_DIRECTION])/angle); // if(t > (idMath::PI/2)) // angle = idMath::PI - angle; DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Angle: %f\r", angle); } else { DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Impossible line!\r"); } bCalcIntersection = false; l = 0; for ( i = 0 ; i < 6 ; i++ ) { sprintf(txt, format, i); DM_LOGPLANE(LC_MATH, LT_DEBUG, txt, frustum[i]); Start[i] = frustum[i].Side(rkLine[LSG_ORIGIN], idMath::FLT_EPSILON); End[i] = frustum[i].Side(EndPoint, idMath::FLT_EPSILON); DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u]: Start %u End: %u\r", i, Start[i], End[i]); // If the points are all on the outside there will be no intersections if ( ( Start[i] == PLANESIDE_BACK ) || ( End[i] == PLANESIDE_BACK ) ) { bCalcIntersection = true; } } DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("CalcIntersection: %u\r", bCalcIntersection); if (bCalcIntersection == true) { DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "TargetOrigin", rkLine[LSG_ORIGIN]); DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "TargetDirection", rkLine[LSG_DIRECTION]); DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "Endpoint", EndPoint); for(i = 0; i < 6; i++) { if (frustum[i].LineIntersection(rkLine[LSG_ORIGIN], rkLine[LSG_DIRECTION], &t) == true) { DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u] intersects\r", i); Intersect[l] = rkLine[LSG_ORIGIN] + t*rkLine[LSG_DIRECTION]; l++; if (l > 1) { break; } } } } if (l < 2) { rc = INTERSECT_OUTSIDE; } else { rc = INTERSECT_FULL; bStart = bEnd = true; for (i = 0; i < 6; i++) { x = frustum[i].Side(Intersect[0], idMath::FLT_EPSILON); DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u/0] intersection test returns %u\r", i, x); if (x != PLANESIDE_BACK) { bStart = false; } x = frustum[i].Side(Intersect[1], idMath::FLT_EPSILON); DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u/1] intersection test returns %u\r", i, x); if (x != PLANESIDE_BACK) { bEnd = false; } } if (bStart == false && bEnd == false) { rc = INTERSECT_OUTSIDE; } } DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Intersection count = %u\r", l); DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "akPoint[0]", Intersect[0]); DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "akPoint[1]", Intersect[1]); return rc; }
// grayman #3584 - rewritten for light cones EIntersection IntersectLineLightCone(const idVec3 rkLine[LSG_COUNT], idVec3 rkCone[ELC_COUNT], idVec3 Intersect[2], bool inside[2]) { EIntersection rc = INTERSECT_COUNT; int i, n, intersectionCount, x; float t; idPlane lightProject[4]; idPlane frustum[6]; int sides[6][2] = { {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0} }; int sidesBack = 0; idStr txt; idStr format("Frustum[%u]"); idVec3 EndPoint(rkLine[LSG_ORIGIN]+rkLine[LSG_DIRECTION]); DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING(" rkLine[LSG_ORIGIN] = [%s]\r", rkLine[LSG_ORIGIN].ToString()); DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING(" rkLine[LSG_DIRECTION] = [%s]\r", rkLine[LSG_DIRECTION].ToString()); DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING(" EndPoint = [%s]\r", EndPoint.ToString()); R_SetLightProject(lightProject, rkCone[ELC_ORIGIN], rkCone[ELA_TARGET], rkCone[ELA_RIGHT], rkCone[ELA_UP], rkCone[ELA_START], rkCone[ELA_END]); R_SetLightFrustum(lightProject, frustum); /* DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[0]", lightProject[0]); DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[1]", lightProject[1]); DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[2]", lightProject[2]); DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[3]", lightProject[3]); */ n = format.Length(); // grayman #3584 - determine whether the start and end points of the line segment // lie on the back (inside) or front (outside) of each of the 6 planes of the light cone intersectionCount = 0; for ( i = 0 ; i < 6 ; i++ ) { sprintf(txt, format, i); DM_LOGPLANE(LC_MATH, LT_DEBUG, txt, frustum[i]); sides[i][0] = frustum[i].Side(rkLine[LSG_ORIGIN], idMath::FLT_EPSILON); sides[i][1] = frustum[i].Side(EndPoint, idMath::FLT_EPSILON); DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%d]: sides[%d][0]: %d sides[%d][1]: %d\r", i, i,sides[i][0], i,sides[i][1]); if ( ( sides[i][0] == PLANESIDE_FRONT ) && ( sides[i][1] == PLANESIDE_FRONT ) ) { // both ends of the line are outside the frustum, no need to calculate an intersection inside[0] = false; inside[1] = false; return INTERSECT_OUTSIDE; } if ( sides[i][0] == PLANESIDE_BACK ) { sidesBack++; } if ( sides[i][1] == PLANESIDE_BACK ) { sidesBack++; } } if ( sidesBack == 12 ) { // both ends of the line are inside the frustum, no need to calculate an intersection rc = INTERSECT_NONE; Intersect[0] = rkLine[LSG_ORIGIN]; Intersect[1] = EndPoint; inside[0] = true; inside[1] = true; } else // calculate an intersection { // We've determined that at least one of the endpoints is possibly inside // the frustum (light volume). for ( i = 0 ; i < 6 ; i++ ) { if ( sides[i][0] != sides[i][1] ) { // the line crosses the plane, so calculate an intersection if ( frustum[i].RayIntersection(rkLine[LSG_ORIGIN], rkLine[LSG_DIRECTION], t) ) // grayman #3584 //if (frustum[i].LineIntersection(rkLine[LSG_ORIGIN], rkLine[LSG_DIRECTION], &t) == true) // grayman #3584 - this call gives wrong answers { idVec3 candidate = rkLine[LSG_ORIGIN] + t*rkLine[LSG_DIRECTION]; // This intersection is valid iff it lies on the backside of all planes. // So check that, except for the plane you just intersected, because // you know that will return INTERSECT_ON, which is okay. bool inside = true; for ( int j = 0 ; j < 6 ; j++ ) { if ( j == i ) { continue; // skip the plane you just intersected } x = frustum[j].Side(candidate, idMath::FLT_EPSILON); if (x == PLANESIDE_FRONT) { inside = false; break; // no need to continue, since the point is outside } } if ( inside ) { // This is a valid intersection point. Intersect[intersectionCount] = candidate; DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u] intersects\r", i); if (++intersectionCount > 1) { break; } } } } } if ( intersectionCount == 0 ) { // both ends of the line are outside the frustum, no need to calculate an intersection rc = INTERSECT_OUTSIDE; inside[0] = false; inside[1] = false; } else if ( intersectionCount == 1 ) { // One end of the line segment is inside the cone, and the other outside. rc = INTERSECT_PARTIAL; // Need to determine which end of the line is inside. It will be // the second of the two points returned. The first point will be // the intersection, and it has already been filled in (Intersect[0]). // Check the results of the side checks. If sides[0..6][0] are all // PLANESIDE_BACK, then the line origin is inside. // Otherwise, the line end is inside Intersect[1] = rkLine[LSG_ORIGIN]; // assume it's the line origin inside[0] = true; inside[1] = false; for ( i = 0 ; i < 6 ; i++ ) { if (sides[i][0] == PLANESIDE_FRONT ) { Intersect[1] = EndPoint; // nope, it must be the line end inside[0] = false; inside[1] = true; break; } } } else // intersectionCount == 2 { rc = INTERSECT_FULL; inside[0] = false; inside[1] = false; /* // old code bool bStart = true; bool bEnd = true; for ( i = 0 ; i < 6 ; i++ ) { x = frustum[i].Side(Intersect[0], idMath::FLT_EPSILON); DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u/0] intersection test returns %u\r", i, x); if (x != PLANESIDE_BACK) { bStart = false; } x = frustum[i].Side(Intersect[1], idMath::FLT_EPSILON); DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u/1] intersection test returns %u\r", i, x); if (x != PLANESIDE_BACK) { bEnd = false; } } if (bStart == false && bEnd == false) { rc = INTERSECT_OUTSIDE; }*/ } } DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Intersection count = %u\r", intersectionCount); DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "Intersect[0]", Intersect[0]); DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "Intersect[1]", Intersect[1]); return rc; }