//---------------------------------------------------------------------------- bool ConvexPolyhedron::ComputeSilhouette (vector<Vector3>& rkTerminator, const Vector3& rkEye, const Plane& rkPlane, const Vector3& rkU, const Vector3& rkV, vector<Vector2>& rkSilhouette) { Real fEDist = rkPlane.DistanceTo(rkEye); // assert: fEDist > 0 // closest planar point to E is K = E-dist*N Vector3 kClosest = rkEye - fEDist*rkPlane.Normal(); // project polyhedron points onto plane for (int i = 0; i < (int)rkTerminator.size(); i++) { Vector3& rkPoint = rkTerminator[i]; Real fVDist = rkPlane.DistanceTo(rkPoint); if ( fVDist >= fEDist ) { // cannot project vertex onto plane return false; } // compute projected point Q Real fRatio = fEDist/(fEDist-fVDist); Vector3 kProjected = rkEye + fRatio*(rkPoint - rkEye); // compute (x,y) so that Q = K+x*U+y*V+z*N Vector3 kDiff = kProjected - kClosest; rkSilhouette.push_back(Vector2(rkU.Dot(kDiff),rkV.Dot(kDiff))); } return true; }
bool Plane::PlanePlaneIntersection(const Plane &P1, const Plane &P2, Line3D &L) { float Denominator = P1.a * P2.b - P1.b * P2.a; if(Denominator == 0.0f) { // this case should be handled by switching axes... return false; } L.P0 = Vec3f((P2.d * P1.b - P1.d * P2.b) / Denominator, (P1.d * P2.a - P2.d * P1.a) / Denominator, 0.0f); L.D = Vec3f::Cross(P1.Normal(), P2.Normal()); if(L.D.Length() == 0.0f) { return false; } L.D = Vec3f::Normalize(L.D); return true; }
//---------------------------------------------------------------------------- bool Mgc::TestIntersection (const Plane& rkPlane, const Sphere& rkSphere, bool bUnitNormal) { Vector3 kNormal = rkPlane.Normal(); Real fConstant = rkPlane.Constant(); if ( !bUnitNormal ) { Real fLength = kNormal.Unitize(); fConstant /= fLength; } Real fPseudoDistance = kNormal.Dot(rkSphere.Center()) - fConstant; return Math::FAbs(fPseudoDistance) <= rkSphere.Radius(); }
//---------------------------------------------------------------------------- bool Mgc::Culled (const Plane& rkPlane, const Sphere& rkSphere, bool bUnitNormal) { Vector3 kNormal = rkPlane.Normal(); Real fConstant = rkPlane.Constant(); if ( !bUnitNormal ) { Real fLength = kNormal.Unitize(); fConstant /= fLength; } Real fTmp = kNormal.Dot(rkSphere.Center()) - fConstant; return fTmp <= -rkSphere.Radius(); }
//---------------------------------------------------------------------------- bool Mgc::Culled (const Plane& rkPlane, const Ellipsoid& rkEllipsoid, bool bUnitNormal) { Vector3 kNormal = rkPlane.Normal(); Real fConstant = rkPlane.Constant(); if ( !bUnitNormal ) { Real fLength = kNormal.Unitize(); fConstant /= fLength; } Real fDiscr = kNormal.Dot(rkEllipsoid.InverseA()*kNormal); Real fRoot = Math::Sqrt(Math::FAbs(fDiscr)); Real fSDist = kNormal.Dot(rkEllipsoid.Center()) - fConstant; return fSDist <= -fRoot; }
//---------------------------------------------------------------------------- bool Mgc::Culled (const Plane& rkPlane, const Lozenge& rkLozenge, bool bUnitNormal) { Vector3 kNormal = rkPlane.Normal(); Real fConstant = rkPlane.Constant(); if ( !bUnitNormal ) { Real fLength = kNormal.Unitize(); fConstant /= fLength; } Real fTmp00 = kNormal.Dot(rkLozenge.Origin()) - fConstant; if ( fTmp00 < 0.0f ) { Real fDotNE0 = kNormal.Dot(rkLozenge.Edge0()); Real fTmp10 = fTmp00 + fDotNE0; if ( fTmp10 < 0.0f ) { Real fDotNE1 = kNormal.Dot(rkLozenge.Edge1()); Real fTmp01 = fTmp00 + fDotNE1; if ( fTmp01 < 0.0f ) { Real fTmp11 = fTmp10 + fDotNE1; if ( fTmp11 < 0.0f ) { // all four lozenge corners on negative side of plane if ( fTmp00 <= fTmp10 ) { if ( fTmp00 <= fTmp01 ) return fTmp00 <= -rkLozenge.Radius(); else return fTmp01 <= -rkLozenge.Radius(); } else { if ( fTmp10 <= fTmp11 ) return fTmp10 <= -rkLozenge.Radius(); else return fTmp11 <= -rkLozenge.Radius(); } } } } } return false; }
//---------------------------------------------------------------------------- bool Mgc::TestIntersection (const Plane& rkPlane, const Lozenge& rkLozenge, bool bUnitNormal) { Vector3 kNormal = rkPlane.Normal(); Real fConstant = rkPlane.Constant(); if ( !bUnitNormal ) { Real fLength = kNormal.Unitize(); fConstant /= fLength; } Vector3 kC10 = rkLozenge.Origin() + rkLozenge.Edge0(); Vector3 kC01 = rkLozenge.Origin() + rkLozenge.Edge1(); Vector3 kC11 = kC10 + rkLozenge.Edge1(); Real fTmp00 = kNormal.Dot(rkLozenge.Origin()) - fConstant; Real fTmp10 = kNormal.Dot(kC10) - fConstant; if ( fTmp00*fTmp10 <= 0.0f ) { // two lozenge ends on opposite sides of the plane return true; } Real fTmp01 = kNormal.Dot(kC01) - fConstant; if ( fTmp00*fTmp01 <= 0.0f ) { // two lozenge ends on opposite sides of the plane return true; } Real fTmp11 = kNormal.Dot(kC11) - fConstant; if ( fTmp10*fTmp11 <= 0.0f ) { // two lozenge ends on opposite sides of the plane return true; } return Math::FAbs(fTmp00) <= rkLozenge.Radius() || Math::FAbs(fTmp10) <= rkLozenge.Radius() || Math::FAbs(fTmp01) <= rkLozenge.Radius() || Math::FAbs(fTmp11) <= rkLozenge.Radius(); }
//---------------------------------------------------------------------------- bool Mgc::FindIntersection (const Plane& rkPlane0, const Plane& rkPlane1, Line3& rkLine) { // If Cross(N0,N1) is zero, then either planes are parallel and separated // or the same plane. In both cases, 'false' is returned. Otherwise, // the intersection line is // // L(t) = t*Cross(N0,N1) + c0*N0 + c1*N1 // // for some coefficients c0 and c1 and for t any real number (the line // parameter). Taking dot products with the normals, // // d0 = Dot(N0,L) = c0*Dot(N0,N0) + c1*Dot(N0,N1) // d1 = Dot(N1,L) = c0*Dot(N0,N1) + c1*Dot(N1,N1) // // which are two equations in two unknowns. The solution is // // c0 = (Dot(N1,N1)*d0 - Dot(N0,N1)*d1)/det // c1 = (Dot(N0,N0)*d1 - Dot(N0,N1)*d0)/det // // where det = Dot(N0,N0)*Dot(N1,N1)-Dot(N0,N1)^2. Real fN00 = rkPlane0.Normal().SquaredLength(); Real fN01 = rkPlane0.Normal().Dot(rkPlane1.Normal()); Real fN11 = rkPlane1.Normal().SquaredLength(); Real fDet = fN00*fN11 - fN01*fN01; if ( Math::FAbs(fDet) < gs_fEpsilon ) return false; Real fInvDet = 1.0f/fDet; Real fC0 = (fN11*rkPlane0.Constant() - fN01*rkPlane1.Constant())*fInvDet; Real fC1 = (fN00*rkPlane1.Constant() - fN01*rkPlane0.Constant())*fInvDet; rkLine.Direction() = rkPlane0.Normal().Cross(rkPlane1.Normal()); rkLine.Origin() = fC0*rkPlane0.Normal() + fC1*rkPlane1.Normal(); return true; }
//---------------------------------------------------------------------------- void Mgc::PerspProjEllipsoid (const GeneralEllipsoid& rkEllipsoid, const Vector3& rkEye, const Plane& rkPlane, GeneralEllipse& rkEllipse) { // compute matrix M Vector3 kAE = rkEllipsoid.m_kA*rkEye; Real fEAE = rkEye.Dot(kAE); Real fBE = rkEllipsoid.m_kB.Dot(rkEye); Real fTmp = 4.0f*(fEAE + fBE + rkEllipsoid.m_fC); Vector3 kTmp = rkEllipsoid.m_kB + 2.0f*kAE; Matrix3 kMat; kMat[0][0] = kTmp.x*kTmp.x - fTmp*rkEllipsoid.m_kA[0][0]; kMat[0][1] = kTmp.x*kTmp.y - fTmp*rkEllipsoid.m_kA[0][1]; kMat[0][2] = kTmp.x*kTmp.z - fTmp*rkEllipsoid.m_kA[0][2]; kMat[1][1] = kTmp.y*kTmp.y - fTmp*rkEllipsoid.m_kA[1][1]; kMat[1][2] = kTmp.y*kTmp.z - fTmp*rkEllipsoid.m_kA[1][2]; kMat[2][2] = kTmp.z*kTmp.z - fTmp*rkEllipsoid.m_kA[2][2]; kMat[1][0] = kMat[0][1]; kMat[2][0] = kMat[0][2]; kMat[2][1] = kMat[1][2]; // Normalize N and construct U and V so that {U,V,N} forms a // right-handed, orthonormal basis. Vector3 kU, kV, kN = rkPlane.Normal(); Vector3::GenerateOrthonormalBasis(kU,kV,kN,false); // compute coefficients for projected ellipse Vector3 kMU = kMat*kU, kMV = kMat*kV, kMN = kMat*kN; Real fDmNE = rkPlane.Constant() - kN.Dot(rkEye); rkEllipse.m_kA[0][0] = kU.Dot(kMU); rkEllipse.m_kA[0][1] = kU.Dot(kMV); rkEllipse.m_kA[1][1] = kV.Dot(kMV); rkEllipse.m_kA[1][0] = rkEllipse.m_kA[0][1]; rkEllipse.m_kB.x = 2.0f*fDmNE*(kU.Dot(kMN)); rkEllipse.m_kB.y = 2.0f*fDmNE*(kV.Dot(kMN)); rkEllipse.m_fC = fDmNE*fDmNE*(kN.Dot(kMN)); }
APlot Camera::GetPlot(int x, int y, const Plane & plane) const { real tx = real(fScreenWidth)/2; real ty = real(fScreenHeight)/2; real f = real( min(tx,ty))*fZoom; real sx = (x-tx)/f; real sy = (y-ty)/f; Vector3 origin(0,0,-fFocal); origin = origin+fTranslation; origin = (!fRotation)*origin; Vector3 pointed(sx, sy, 0); pointed = pointed+fTranslation; pointed = (!fRotation)*pointed; Vector3 director = pointed-origin; Vector3 normal = plane.Normal(); real denom = director*normal; if (abs(denom) < zero) return APlot(); real t = (plane.GetDist() - real(origin*normal))/denom; Vector3 result = origin + director*t; return result; }
void GLWall::SetupLights() { float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2}; Plane p; lightdata.Clear(); p.Init(vtx,4); if (!p.ValidNormal()) { return; } for(int i=0;i<2;i++) { FLightNode *node; if (!seg->bPolySeg) { // Iterate through all dynamic lights which touch this wall and render them if (seg->sidedef) { node = seg->sidedef->lighthead[i]; } else node = NULL; } else if (sub) { // To avoid constant rechecking for polyobjects use the subsector's lightlist instead node = sub->lighthead[i]; } else node = NULL; while (node) { if (!(node->lightsource->flags2&MF2_DORMANT)) { iter_dlight++; Vector fn, pos; float x = FIXED2FLOAT(node->lightsource->x); float y = FIXED2FLOAT(node->lightsource->y); float z = FIXED2FLOAT(node->lightsource->z); float dist = fabsf(p.DistToPoint(x, z, y)); float radius = (node->lightsource->GetRadius() * gl_lights_size); float scale = 1.0f / ((2.f * radius) - dist); if (radius > 0.f && dist < radius) { Vector nearPt, up, right; pos.Set(x,z,y); fn=p.Normal(); fn.GetRightUp(right, up); Vector tmpVec = fn * dist; nearPt = pos + tmpVec; Vector t1; int outcnt[4]={0,0,0,0}; texcoord tcs[4]; // do a quick check whether the light touches this polygon for(int i=0;i<4;i++) { t1.Set(&vtx[i*3]); Vector nearToVert = t1 - nearPt; tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f; tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f; if (tcs[i].u<0) outcnt[0]++; if (tcs[i].u>1) outcnt[1]++; if (tcs[i].v<0) outcnt[2]++; if (tcs[i].v>1) outcnt[3]++; } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { gl_GetLight(p, node->lightsource, Colormap.colormap, true, false, lightdata); } } } node = node->nextLight; } } int numlights[3]; lightdata.Combine(numlights, gl.MaxLights()); if (numlights[2] > 0) { draw_dlight+=numlights[2]/2; gl_RenderState.EnableLight(true); gl_RenderState.SetLights(numlights, &lightdata.arrays[0][0]); } }
void BaseMesh::ClosedPlaneSplit(const Plane &P, BaseMesh &M1, BaseMesh &M2) { UINT VC = VertexCount(), IC = IndexCount(); MeshVertex *V = Vertices(); DWORD *I = Indices(); Vector<Vec3f> NewVertices[2]; Vector<TriMeshFace> NewFaces[2]; Vector<Vec2f> BoundaryVertices; Vector<UINT> BoundaryIndices[2]; Vec3f OrthogonalBasis1, OrthogonalBasis2; Vec3f::CompleteOrthonormalBasis(P.Normal(), OrthogonalBasis1, OrthogonalBasis2); PerfectSplitVMapper *VMap = new PerfectSplitVMapper[VC]; for(UINT VertexIndex = 0; VertexIndex < VC; VertexIndex++) { Vec3f Pos = V[VertexIndex].Pos; float Value = Plane::DotCoord(P, Pos); if(Value < 0.0f) { VMap[VertexIndex].Side = 0; VMap[VertexIndex].NVMap = NewVertices[0].Length(); NewVertices[0].PushEnd(Pos); } else { VMap[VertexIndex].Side = 1; VMap[VertexIndex].NVMap = NewVertices[1].Length(); NewVertices[1].PushEnd(Pos); } } for(UINT IndexIndex = 0; IndexIndex < IC; IndexIndex += 3) { int TSide[3]; TSide[0] = VMap[I[IndexIndex + 0]].Side; TSide[1] = VMap[I[IndexIndex + 1]].Side; TSide[2] = VMap[I[IndexIndex + 2]].Side; DWORD LocalTriangleM1[6], LocalTriangleM2[6]; LocalTriangleM2[0] = LocalTriangleM1[0] = VMap[I[IndexIndex + 0]].NVMap; LocalTriangleM2[1] = LocalTriangleM1[1] = VMap[I[IndexIndex + 1]].NVMap; LocalTriangleM2[2] = LocalTriangleM1[2] = VMap[I[IndexIndex + 2]].NVMap; UINT TriangleType = TSide[0] * 4 + TSide[1] * 2 + TSide[2] * 1; for(UINT EdgeIndex = 0; EdgeIndex < 3; EdgeIndex++) { if(PerfectEdges[TriangleType][EdgeIndex]) { Vec3f Vtx1 = V[I[IndexIndex + PerfectEdgeList[EdgeIndex][0]]].Pos; Vec3f Vtx2 = V[I[IndexIndex + PerfectEdgeList[EdgeIndex][1]]].Pos; Vec3f VtxIntersect = P.IntersectLine(Vtx1, Vtx2); if(!Vec3f::WithinRect(VtxIntersect, Rectangle3f::ConstructFromTwoPoints(Vtx1, Vtx2))) { VtxIntersect = (Vtx1 + Vtx2) * 0.5f; } BoundaryVertices.PushEnd(Vec2f(Vec3f::Dot(VtxIntersect, OrthogonalBasis1), Vec3f::Dot(VtxIntersect, OrthogonalBasis2))); LocalTriangleM1[3 + EdgeIndex] = NewVertices[0].Length(); BoundaryIndices[0].PushEnd(NewVertices[0].Length()); NewVertices[0].PushEnd(VtxIntersect); LocalTriangleM2[3 + EdgeIndex] = NewVertices[1].Length(); BoundaryIndices[1].PushEnd(NewVertices[1].Length()); NewVertices[1].PushEnd(VtxIntersect); } } for(UINT LocalTriangleIndex = 0; LocalTriangleIndex < 6; LocalTriangleIndex += 3) { if(M1Indices[TriangleType][LocalTriangleIndex] != -1) { TriMeshFace Tri; Tri.I[0] = LocalTriangleM1[M1Indices[TriangleType][LocalTriangleIndex + 0]]; Tri.I[1] = LocalTriangleM1[M1Indices[TriangleType][LocalTriangleIndex + 1]]; Tri.I[2] = LocalTriangleM1[M1Indices[TriangleType][LocalTriangleIndex + 2]]; NewFaces[0].PushEnd(Tri); } if(M2Indices[TriangleType][LocalTriangleIndex] != -1) { TriMeshFace Tri; Tri.I[0] = LocalTriangleM2[M2Indices[TriangleType][LocalTriangleIndex + 0]]; Tri.I[1] = LocalTriangleM2[M2Indices[TriangleType][LocalTriangleIndex + 1]]; Tri.I[2] = LocalTriangleM2[M2Indices[TriangleType][LocalTriangleIndex + 2]]; NewFaces[1].PushEnd(Tri); } } } #ifdef DELAUNAY_TRIANGULATOR if(BoundaryVertices.Length() > 0) { Vector<DWORD> BoundaryTriangulation; DelaunayTriangulator::Triangulate(BoundaryVertices, BoundaryTriangulation); for(UINT TriangleIndex = 0; TriangleIndex < BoundaryTriangulation.Length() / 3; TriangleIndex++) { for(UINT MeshIndex = 0; MeshIndex < 2; MeshIndex++) { TriMeshFace Tri; Vec3f V[3]; for(UINT LocalVertexIndex = 0; LocalVertexIndex < 3; LocalVertexIndex++) { Tri.I[LocalVertexIndex] = BoundaryIndices[MeshIndex][UINT(BoundaryTriangulation[TriangleIndex * 3 + LocalVertexIndex])]; V[LocalVertexIndex] = NewVertices[MeshIndex][UINT(Tri.I[LocalVertexIndex])]; } //Utility::Swap(Tri.I[0], Tri.I[1]); //if(Math::TriangleArea(V[0], V[1], V[2]) > 1e-5f) { NewFaces[MeshIndex].PushEnd(Tri); } } } } #endif delete[] VMap; M1.SetGD(GetGD()); M2.SetGD(GetGD()); M1.Allocate(NewVertices[0].Length(), NewFaces[0].Length()); M2.Allocate(NewVertices[1].Length(), NewFaces[1].Length()); for(UINT VertexIndex = 0; VertexIndex < NewVertices[0].Length(); VertexIndex++) { M1.Vertices()[VertexIndex].Pos = NewVertices[0][VertexIndex]; } for(UINT VertexIndex = 0; VertexIndex < NewVertices[1].Length(); VertexIndex++) { M2.Vertices()[VertexIndex].Pos = NewVertices[1][VertexIndex]; } if(NewFaces[0].Length() > 0) { memcpy(M1.Indices(), NewFaces[0].CArray(), M1.IndexCount() * sizeof(DWORD)); } if(NewFaces[1].Length() > 0) { memcpy(M2.Indices(), NewFaces[1].CArray(), M2.IndexCount() * sizeof(DWORD)); } }
void BaseMesh::CreatePlane(const Plane &P, float Length, UINT Slices, const Vec3f &Center) { CreatePlane(Length, Slices, Slices); ApplyMatrix(Matrix4::Face(Vec3f(0.0f, 0.0f, 1.0f), P.Normal()) * Matrix4::Translation(Center)); }
//---------------------------------------------------------------------------- bool Mgc::TestIntersection (const Plane& rkPlane0, const Plane& rkPlane1) { Vector3 kCross = rkPlane0.Normal().Cross(rkPlane1.Normal()); Real fSqrLength = kCross.SquaredLength(); return fSqrLength > gs_fEpsilon; }
void GLWall::SetupLights() { if (RenderStyle == STYLE_Add && !glset.lightadditivesurfaces) return; // no lights on additively blended surfaces. // check for wall types which cannot have dynamic lights on them (portal types never get here so they don't need to be checked.) switch (type) { case RENDERWALL_FOGBOUNDARY: case RENDERWALL_MIRRORSURFACE: case RENDERWALL_COLOR: return; } float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2}; Plane p; lightdata.Clear(); p.Set(&glseg); /* if (!p.ValidNormal()) { return; } */ FLightNode *node; if (seg->sidedef == NULL) { node = NULL; } else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) { node = seg->sidedef->lighthead; } else if (sub) { // Polobject segs cannot be checked per sidedef so use the subsector instead. node = sub->lighthead; } else node = NULL; // Iterate through all dynamic lights which touch this wall and render them while (node) { if (!(node->lightsource->flags2&MF2_DORMANT)) { iter_dlight++; DVector3 posrel = node->lightsource->PosRelative(seg->frontsector); float x = posrel.X; float y = posrel.Y; float z = posrel.Z; float dist = fabsf(p.DistToPoint(x, z, y)); float radius = node->lightsource->GetRadius(); float scale = 1.0f / ((2.f * radius) - dist); FVector3 fn, pos; if (radius > 0.f && dist < radius) { FVector3 nearPt, up, right; pos = { x, z, y }; fn = p.Normal(); fn.GetRightUp(right, up); FVector3 tmpVec = fn * dist; nearPt = pos + tmpVec; FVector3 t1; int outcnt[4]={0,0,0,0}; texcoord tcs[4]; // do a quick check whether the light touches this polygon for(int i=0;i<4;i++) { t1 = FVector3(&vtx[i*3]); FVector3 nearToVert = t1 - nearPt; tcs[i].u = ((nearToVert | right) * scale) + 0.5f; tcs[i].v = ((nearToVert | up) * scale) + 0.5f; if (tcs[i].u<0) outcnt[0]++; if (tcs[i].u>1) outcnt[1]++; if (tcs[i].v<0) outcnt[2]++; if (tcs[i].v>1) outcnt[3]++; } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { gl_GetLight(seg->frontsector->PortalGroup, p, node->lightsource, true, lightdata); } } } node = node->nextLight; } dynlightindex = GLRenderer->mLights->UploadLights(lightdata); }
void BaseMesh::CreatePlane(const Plane &p, float length, UINT slices) { CreatePlane(p, length, slices, p.Normal()*-p.d); }
void GLWall::SetupLights() { // check for wall types which cannot have dynamic lights on them (portal types never get here so they don't need to be checked.) switch (type) { case RENDERWALL_FOGBOUNDARY: case RENDERWALL_MIRRORSURFACE: case RENDERWALL_COLOR: case RENDERWALL_COLORLAYER: return; } float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2}; Plane p; lightdata.Clear(); p.Init(vtx,4); if (!p.ValidNormal()) { return; } FLightNode *node; if (seg->sidedef == NULL) { node = NULL; } else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) { node = seg->sidedef->lighthead; } else if (sub) { // Polobject segs cannot be checked per sidedef so use the subsector instead. node = sub->lighthead; } else node = NULL; // Iterate through all dynamic lights which touch this wall and render them while (node) { if (!(node->lightsource->flags2&MF2_DORMANT)) { iter_dlight++; Vector fn, pos; float x = FIXED2FLOAT(node->lightsource->X()); float y = FIXED2FLOAT(node->lightsource->Y()); float z = FIXED2FLOAT(node->lightsource->Z()); float dist = fabsf(p.DistToPoint(x, z, y)); float radius = (node->lightsource->GetRadius() * gl_lights_size); float scale = 1.0f / ((2.f * radius) - dist); if (radius > 0.f && dist < radius) { Vector nearPt, up, right; pos.Set(x,z,y); fn=p.Normal(); fn.GetRightUp(right, up); Vector tmpVec = fn * dist; nearPt = pos + tmpVec; Vector t1; int outcnt[4]={0,0,0,0}; texcoord tcs[4]; // do a quick check whether the light touches this polygon for(int i=0;i<4;i++) { t1.Set(&vtx[i*3]); Vector nearToVert = t1 - nearPt; tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f; tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f; if (tcs[i].u<0) outcnt[0]++; if (tcs[i].u>1) outcnt[1]++; if (tcs[i].v<0) outcnt[2]++; if (tcs[i].v>1) outcnt[3]++; } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { gl_GetLight(p, node->lightsource, true, false, lightdata); } } } node = node->nextLight; } dynlightindex = GLRenderer->mLights->UploadLights(lightdata); }