// NeL - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include "std3d.h"
#include "nel/3d/ray_mesh.h"
#include "nel/misc/vector_2f.h"
#include "nel/misc/fast_mem.h"
#include "nel/3d/matrix_3x4.h"
using namespace NLMISC;
using namespace std;
namespace NL3D
{
// ***************************************************************************
// The number of byte to process per block
const uint NL_BlockByteL1= 4096;
// Number of vertices per block to process For vertices mul
uint CRayMesh::NumCacheVertex= NL_BlockByteL1 / sizeof(CVector);
// ***************************************************************************
template
static bool getRayIntersectionT(std::vector &vertices, const std::vector &tris,
float &dist2D, float &distZ, bool computeDist2D)
{
uint numTris= (uint)tris.size()/3;
if(!numTris)
return false;
// test all tris
const TIndex *pTri= &tris[0];
float minSkinDistZ= FLT_MAX;
for(uint i=0;i=0;
// Line p1-p2.
a= -p12.y;
b= p12.x;
c= (p1.x*a + p1.y*b);
allInf= allInf && c<=0;
allSup= allSup && c>=0;
// Line p2-p0.
a= -p20.y;
b= p20.x;
c= (p2.x*a + p2.y*b);
allInf= allInf && c<=0;
allSup= allSup && c>=0;
// all on same side (don't bother front or backfaces)?
if(allInf || allSup)
{
// => ray intersect. compute the intersection now.
// This code is called for a very small subset of faces, hence don't bother optim.
CPlane plane;
plane.make(p0,p1,p2);
// intersect with the ray. Since vertices are in ray basis, the Ray is (Null, K).
CVector hit= plane.intersect(CVector::Null, CVector::K);
// then dist of Null to the tri is just Z.
float distToTri= hit.z;
// avoid problems if the plane is // to the ray. take maximum proj dist with the 3 points
float minVertDist= min(p0.z, p1.z);
minVertDist= min(minVertDist, p2.z);
// distToTri cannot be less than minVertDist
distToTri= max(minVertDist, distToTri);
// NB: it is possible than distToTri<0 (face behind or clipped by camera). clamp then to 0
distToTri= max(distToTri, 0.f);
minSkinDistZ= min(minSkinDistZ, distToTri);
}
}
// don't intersect?
if(minSkinDistZ==FLT_MAX)
{
// get the nearest distance to the ray (do the compute only if no IT found at all => optim)
const TIndex *pTri= &tris[0];
float minSkinSqrDist2D= FLT_MAX;
// only if user want this feature
if(computeDist2D)
{
for(uint i=0;i value between 0 and p01sqdist (if in segment)
fSeg= -p0.x*p01.x -p0.y*p01.y;
if(fSeg>0 && fSeg0 && fSeg0 && fSeg &vertices, const std::vector &tris,
float &dist2D, float &distZ, bool computeDist2D)
{
return getRayIntersectionT(vertices, tris, dist2D, distZ, computeDist2D);
}
// ***************************************************************************
bool CRayMesh::getRayIntersection(std::vector &vertices, const std::vector &tris,
float &dist2D, float &distZ, bool computeDist2D)
{
return getRayIntersectionT(vertices, tris, dist2D, distZ, computeDist2D);
}
// ***************************************************************************
bool CRayMesh::fastIntersect(const NLMISC::CMatrix &worldMatrix, const NLMISC::CVector &p0, const NLMISC::CVector &dir, float &dist2D, float &distZ, bool computeDist2D) const
{
if(empty())
return false;
// *** Compute toRaySpace matrix
// The skinning must be done in final RaySpace.
CMatrix toRaySpace;
// compute the ray matrix
CVector dirn= dir;
if(dirn.isNull())
dirn= CVector::K;
dirn.normalize();
toRaySpace.setArbitraryRotK(dirn);
toRaySpace.setPos(p0);
// The skinning must be done in ray space: (RayMat-1)*worldMatrix;
toRaySpace.invert();
toRaySpace*= worldMatrix;
CMatrix3x4 fastMat;
fastMat.set(toRaySpace);
// *** Make all points in ray space
uint numVerts= (uint)Vertices.size();
const CVector *src= &Vertices[0];
// enlarge temp buffer
static std::vector meshInRaySpace;
if(Vertices.size()>meshInRaySpace.size())
meshInRaySpace.resize(Vertices.size());
CVector *dst= &meshInRaySpace[0];
// Then do the skin
for(;numVerts>0;)
{
// number of vertices to process for this block.
uint nBlockInf= min(NumCacheVertex, numVerts);
// next block.
numVerts-= nBlockInf;
// cache the data in L1 cache.
CFastMem::precache(src, nBlockInf * sizeof(CVector));
// for all InfluencedVertices only.
for(;nBlockInf>0;nBlockInf--, src++, dst++)
{
fastMat.mulSetPoint( *src, *dst );
}
}
// *** and get ray intersection
return getRayIntersection(meshInRaySpace, Triangles, dist2D, distZ, computeDist2D);
}
} // NL3D