Files
2025-09-18 17:55:52 -04:00

1206 lines
28 KiB
C++

#include "stdafx.h"
#include "V8World/Mesh.h"
#include "util/Math.h"
namespace RBX {
namespace POLY {
/*
WEDGE
Back: Looking along -z
^ y
3 0
4 1 > x
Front: Looking along z
^ y
0 3
2 5 > -x
Right: Looking along -x
^ y
0
1 2 > -z
Left: Looking along x
^ y
3
5 4 > z
Bottom: Looking along -y
^ -z
2 5
1 4 > -x
Top: Looking along -y
^ -z
5 2
3 0 > x
*/
/*
BLOCK
vertID x,y,z
0 1,1,1
1 1,1,-1
2 1,-1,1
3 1,-1,-1
4 -1,1,1
5 -1,1,-1
6 -1,-1,1
7 -1,-1,-1
0 +x
1 +y
2 +z
3 -x
4 -y
5 -z
Right: Looking at x
^ y
0 1
2 3 > -z
Top: Looking at y
^ -z
5 1
4 0 > x
Back: Looking at z
^ y
4 0
6 2 > x
Left: Looking at -x
^ y
5 4
7 6 > z
Bottom: Looking at -y
^ -z
3 7
2 6 > -x
Front: Looking at -z
^ y
1 5
3 7 > -x
*/
void Mesh::makeBlock(const Vector3& size)
{
float x = 0.5f * size.x;
float y = 0.5f * size.y;
float z = 0.5f * size.z;
clear();
// important - don't reallocate while we are building
vertices.reserve(8);
faces.reserve(6);
edges.reserve(12);
addVertex(x, y, z);
addVertex(x, y, -z);
addVertex(x, -y, z);
addVertex(x, -y, -z);
addVertex(-x, y, z);
addVertex(-x, y, -z);
addVertex(-x, -y, z);
addVertex(-x, -y, -z);
// counter clockwise
addFace(1, 0, 2, 3); // right
addFace(1, 5, 4, 0); // top
addFace(0, 4, 6, 2); // back
addFace(4, 5, 7, 6); // left
addFace(7, 3, 2, 6); // bottom
addFace(5, 1, 3, 7); // front
}
void Mesh::makeCell(const Vector3& size, const Vector3& offset)
{
float x = 0.5f * size.x;
float y = 0.5f * size.y;
float z = 0.5f * size.z;
float sumx = x + offset.x;
float diffx = offset.x - x;
float sumy = y + offset.y;
float diffy = offset.y - y;
float sumz = z + offset.z;
float diffz = offset.z - z;
clear();
// important - don't reallocate while we are building
vertices.reserve(8);
faces.reserve(6);
edges.reserve(12);
addVertex(sumx, sumy, sumz);
addVertex(sumx, sumy, diffz);
addVertex(sumx, diffy, sumz);
addVertex(sumx, diffy, diffz);
addVertex(diffx, sumy, sumz);
addVertex(diffx, sumy, diffz);
addVertex(diffx, diffy, sumz);
addVertex(diffx, diffy, diffz);
// counter clockwise
addFace(1, 0, 2, 3); // right
addFace(1, 5, 4, 0); // top
addFace(0, 4, 6, 2); // back
addFace(4, 5, 7, 6); // left
addFace(7, 3, 2, 6); // bottom
addFace(5, 1, 3, 7); // front
}
void Mesh::makeVerticalWedgeCell(const Vector3& size, const Vector3& offset, const int& orient)
{
float x = 0.5f * size.x;
float y = 0.5f * size.y;
float z = 0.5f * size.z;
float sumx = x + offset.x;
float diffx = offset.x - x;
float sumy = y + offset.y;
float diffy = offset.y - y;
float sumz = z + offset.z;
float diffz = offset.z - z;
clear();
// important - don't reallocate while we are building
vertices.reserve(6);
faces.reserve(5);
edges.reserve(9);
// add wedge base verts
addVertex(sumx, diffy, sumz);
addVertex(sumx, diffy, diffz);
addVertex(diffx, diffy, diffz);
addVertex(diffx, diffy, sumz);
addFace(0, 3, 2, 1);
switch( orient )
{
case 0: // UpperLeft
default:
addVertex(sumx, sumy, diffz);
addVertex(diffx, sumy, diffz);
addFace(0, 4, 5, 3);
addFace(1, 2, 5, 4);
addFace(1, 4, 0);
addFace(2, 3, 5);
break;
case 1: // UpperRight
addVertex(diffx, sumy, diffz);
addVertex(diffx, sumy, sumz);
addFace(4, 2, 3, 5);
addFace(0, 1, 4, 5);
addFace(0, 5, 3);
addFace(2, 4, 1);
break;
case 2: // LowerRight
addVertex(diffx, sumy, sumz);
addVertex(sumx, sumy, sumz);
addFace(0, 5, 4, 3);
addFace(1, 2, 4, 5);
addFace(3, 4, 2);
addFace(0, 1, 5);
break;
case 3: // LowerLeft
addVertex(sumx, sumy, sumz);
addVertex(sumx, sumy, diffz);
addFace(0, 1, 5, 4);
addFace(3, 4, 5, 2);
addFace(0, 4, 3);
addFace(1, 2, 5);
break;
}
}
void Mesh::makeHorizontalWedgeCell(const Vector3& size, const Vector3& offset, const int& orient)
{
float x = 0.5f * size.x;
float y = 0.5f * size.y;
float z = 0.5f * size.z;
float sumx = x + offset.x;
float diffx = offset.x - x;
float sumy = y + offset.y;
float diffy = offset.y - y;
float sumz = z + offset.z;
float diffz = offset.z - z;
clear();
// important - don't reallocate while we are building
vertices.reserve(6);
faces.reserve(5);
edges.reserve(9);
switch( orient )
{
case 0: // UpperLeft
default:
addVertex(sumx, diffy, sumz);
addVertex(sumx, diffy, diffz);
addVertex(diffx, diffy, diffz);
addVertex(sumx, sumy, sumz);
addVertex(sumx, sumy, diffz);
addVertex(diffx, sumy, diffz);
break;
case 1: // UpperRight
addVertex(sumx, diffy, diffz);
addVertex(diffx, diffy, diffz);
addVertex(diffx, diffy, sumz);
addVertex(sumx, sumy, diffz);
addVertex(diffx, sumy, diffz);
addVertex(diffx, sumy, sumz);
break;
case 2: // LowerRight
addVertex(diffx, diffy, diffz);
addVertex(diffx, diffy, sumz);
addVertex(sumx, diffy, sumz);
addVertex(diffx, sumy, diffz);
addVertex(diffx, sumy, sumz);
addVertex(sumx, sumy, sumz);
break;
case 3: // LowerLeft
addVertex(diffx, diffy, sumz);
addVertex(sumx, diffy, sumz);
addVertex(sumx, diffy, diffz);
addVertex(diffx, sumy, sumz);
addVertex(sumx, sumy, sumz);
addVertex(sumx, sumy, diffz);
break;
}
addFace(3,4,5);
addFace(2,1,0);
addFace(0,3,5,2);
addFace(0,1,4,3);
addFace(1,2,5,4);
}
void Mesh::makeCornerWedgeCell(const Vector3& size, const Vector3& offset, const int& orient)
{
float x = 0.5f * size.x;
float y = 0.5f * size.y;
float z = 0.5f * size.z;
float sumx = x + offset.x;
float diffx = offset.x - x;
float sumy = y + offset.y;
float diffy = offset.y - y;
float sumz = z + offset.z;
float diffz = offset.z - z;
clear();
// important - don't reallocate while we are building
vertices.reserve(4);
faces.reserve(4);
edges.reserve(6);
switch( orient )
{
case 0: // UpperLeft
default:
addVertex(sumx, diffy, sumz);
addVertex(sumx, diffy, diffz);
addVertex(diffx, diffy, diffz);
addVertex(sumx, sumy, diffz);
break;
case 1: // UpperRight
addVertex(sumx, diffy, diffz);
addVertex(diffx, diffy, diffz);
addVertex(diffx, diffy, sumz);
addVertex(diffx, sumy, diffz);
break;
case 2: // LowerRight
addVertex(diffx, diffy, diffz);
addVertex(diffx, diffy, sumz);
addVertex(sumx, diffy, sumz);
addVertex(diffx, sumy, sumz);
break;
case 3: // LowerLeft
addVertex(diffx, diffy, sumz);
addVertex(sumx, diffy, sumz);
addVertex(sumx, diffy, diffz);
addVertex(sumx, sumy, sumz);
break;
}
addFace(2,1,0);
addFace(0,1,3);
addFace(1,2,3);
addFace(0,3,2);
}
void Mesh::makeInverseCornerWedgeCell(const Vector3& size, const Vector3& offset, const int& orient)
{
float x = 0.5f * size.x;
float y = 0.5f * size.y;
float z = 0.5f * size.z;
float sumx = x + offset.x;
float diffx = offset.x - x;
float sumy = y + offset.y;
float diffy = offset.y - y;
float sumz = z + offset.z;
float diffz = offset.z - z;
clear();
// important - don't reallocate while we are building
vertices.reserve(7);
faces.reserve(7);
edges.reserve(12);
switch( orient )
{
case 0: // UpperLeft
default:
addVertex(sumx, diffy, sumz);
addVertex(sumx, diffy, diffz);
addVertex(diffx, diffy, diffz);
addVertex(diffx, diffy, sumz);
addVertex(sumx, sumy, sumz);
addVertex(sumx, sumy, diffz);
addVertex(diffx, sumy, diffz);
break;
case 1: // UpperRight
addVertex(sumx, diffy, diffz);
addVertex(diffx, diffy, diffz);
addVertex(diffx, diffy, sumz);
addVertex(sumx, diffy, sumz);
addVertex(sumx, sumy, diffz);
addVertex(diffx, sumy, diffz);
addVertex(diffx, sumy, sumz);
break;
case 2: // LowerRight
addVertex(diffx, diffy, diffz);
addVertex(diffx, diffy, sumz);
addVertex(sumx, diffy, sumz);
addVertex(sumx, diffy, diffz);
addVertex(diffx, sumy, diffz);
addVertex(diffx, sumy, sumz);
addVertex(sumx, sumy, sumz);
break;
case 3: // LowerLeft
addVertex(diffx, diffy, sumz);
addVertex(sumx, diffy, sumz);
addVertex(sumx, diffy, diffz);
addVertex(diffx, diffy, diffz);
addVertex(diffx, sumy, sumz);
addVertex(sumx, sumy, sumz);
addVertex(sumx, sumy, diffz);
break;
}
addFace(3,4,6);
addFace(3,6,2);
addFace(0,4,3);
addFace(0,1,5,4);
addFace(1,2,6,5);
addFace(0,3,2,1);
addFace(4,5,6);
}
void Mesh::makeWedge(const Vector3& size)
{
float x = 0.5f * size.x;
float y = 0.5f * size.y;
float z = 0.5f * size.z;
clear();
// important - don't reallocate while we are building
vertices.reserve(6);
faces.reserve(5);
edges.reserve(9);
addVertex(x, y, z);
addVertex(x, -y, z);
addVertex(x, -y, -z);
addVertex(-x, y, z);
addVertex(-x, -y, z);
addVertex(-x, -y, -z);
addFace(0, 3, 4, 1); // back
addFace(3, 0, 2, 5); // front / top
addFace(0, 1, 2); // right
addFace(3, 5, 4); // left
addFace(5, 2, 1, 4); // bottom
}
void Mesh::makePrism(const Vector3_2Ints& params, Vector3& cofm)
{
int sides = params.int1;
Vector3 size = params.vectPart;
RBXASSERT(sides < 21);
// no assert for this case since it happens safely during initialization
if( sides < 3 )
sides = 6;
clear();
// Set cofm to zero and recompute for this prism
cofm = Vector3::zero();
// Arrays of indices collected during construction of side walls to be used for end cap face creation.
int *baseVertIndices = new int[sides];
int *topVertIndices = new int[sides];
vertices.reserve(2*sides);
faces.reserve(sides + 2);
edges.reserve(3*sides);
// Start creation of prism - this sets the maximum width, which is the x-width in properties
float alpha = (float)(180.0/sides);
Vector2 startPoint = Math::polygonStartingPoint(sides, size.x);
// Apply 2D startPoint from Math to 3D starting point for the polyhedron
G3D::Vector3 Sa(startPoint.x, 0.0, startPoint.y);
G3D::Vector3 Sb(0, 0, 0);
G3D::Vector3 axis(0, 1, 0);
// start at bottom corner vertex for first side wall
addVertex(startPoint.x, (float)(-0.5*size.y), startPoint.y);
baseVertIndices[0] = 0;
addVertex(startPoint.x, (float)(0.5*size.y), startPoint.y);
topVertIndices[0] = 1;
cofm += Sa;
// Walk perimeter of prism until last closing section is reached
for( int i = 0; i < sides - 1; ++i )
{
G3D::Vector3 baseNorm = G3D::normalize(axis.cross(Sa));
G3D::Vector3 SbRevNorm = G3D::normalize(-Sa);
float effRad = Sa.magnitude();
double sideLen = 2.0 * effRad * sin(0.0174533 * alpha);
// update Sa to next facet
Sb = Sa + sideLen * sin(0.0174533 * alpha) * SbRevNorm + sideLen * cos(0.0174533 * alpha) * baseNorm;
cofm += Sb;
Sa = Sb;
addVertex(Sb.x, (float)(-0.5*size.y), Sb.z);
baseVertIndices[i+1] = 2*(i+1);
addVertex(Sb.x, (float)(0.5*size.y), Sb.z);
topVertIndices[i+1] = 2*(i+1) + 1;
addFace(2*i, 2*i+2, 2*i+3, 2*i+1);
}
// Finish off last side face
addFace(2*(sides-1), 0, 1, 2*(sides-1)+1);
cofm.x = cofm.y = cofm.z = 0.0f;
// Now the base and top
addFace(sides, topVertIndices, false);
addFace(sides, baseVertIndices, true);
delete [] topVertIndices;
delete [] baseVertIndices;
}
void Mesh::makePyramid(const Vector3_2Ints& params, Vector3& cofm )
{
int sides = params.int1;
Vector3 size = params.vectPart;
RBXASSERT(sides < 21);
// no assert for this case since it happens safely during initialization
if( sides < 3 )
sides = 6;
clear();
// Set cofm to zero and recompute for this prism
cofm = Vector3::zero();
// Arrays of indices collected during construction of side walls to be used for end cap face creation.
int *baseVertIndices = new int[sides];
vertices.reserve(sides + 1);
faces.reserve(sides + 1);
edges.reserve(2*sides);
// Start creation of prism
float alpha = (float)(180.0/sides);
Vector2 startPoint = Math::polygonStartingPoint(sides, size.x);
float xStart = startPoint.x;
float zStart = startPoint.y;
G3D::Vector3 Sa(xStart, 0.0, zStart);
G3D::Vector3 Sb(0, 0, 0);
G3D::Vector3 axis(0, 1, 0);
// One vertex at apex
// Vertex 0
addVertex(0.0f, (float)(0.5*size.y), 0.0f);
// start at bottom corner vertex for first side wall
// Vertex 1
addVertex(xStart, (float)(-0.5*size.y), zStart);
baseVertIndices[0] = 1;
// start accumulating cofm info.
cofm += Sa;
// Walk perimeter until last closing section is reached
for( int i = 0; i < sides - 1; ++i )
{
G3D::Vector3 baseNorm = G3D::normalize(axis.cross(Sa));
G3D::Vector3 SbRevNorm = G3D::normalize(-Sa);
float effRad = Sa.magnitude();
double sideLen = 2.0 * effRad * sin(0.0174533 * alpha);
// update Sa to next facet
Sb = Sa + sideLen * sin(0.0174533 * alpha) * SbRevNorm + sideLen * cos(0.0174533 * alpha) * baseNorm;
cofm += Sb;
Sa = Sb;
addVertex(Sb.x, (float)(-0.5*size.y), Sb.z);
baseVertIndices[i+1] = i+2;
addFace(i+1, i+2, 0);
}
// Finish off last side face
addFace(sides, 1, 0);
cofm.x = cofm.z = 0.0f;
cofm.y = (float)(-size.y/6.0);
// Now the base
addFace(sides, baseVertIndices, true);
delete [] baseVertIndices;
}
void Mesh::makeParallelRamp( const Vector3& size, Vector3& cofm )
{
float x = 0.5f * size.x;
float y = 0.5f * size.y;
float z = 0.5f * size.z;
//float connectionThickness = RBX::PartInstance::brickHeight();
// Move away from 1.2 form factor
float connectionThickness = 1.0f;
clear();
// important - don't reallocate while we are building
vertices.reserve(8);
faces.reserve(6);
edges.reserve(12);
addVertex(x, -y + connectionThickness, z);
addVertex(x, -y + connectionThickness, -z);
addVertex(x, -y, z);
addVertex(x, -y, -z);
addVertex(-x, y, z);
addVertex(-x, y, -z);
addVertex(-x, y - connectionThickness, z);
addVertex(-x, y - connectionThickness, -z);
addFace(1, 0, 2, 3); // Legacy norm: x
addFace(1, 5, 4, 0); // Legacy norm: y
addFace(0, 4, 6, 2); // Legacy norm: z
addFace(4, 5, 7, 6); // Legacy norm: -x
addFace(7, 3, 2, 6); // Legacy norm: -y
addFace(5, 1, 3, 7); // Legacy norm: -z
}
void Mesh::makeRightAngleRamp( const Vector3& size, Vector3& cofm )
{
float x = 0.5f * size.x;
float y = 0.5f * size.y;
float z = 0.5f * size.z;
//float connectionThickness = RBX::PartInstance::brickHeight();
// Move away from 1.2 form factor
float connectionThickness = 1.0f;
clear();
// important - don't reallocate while we are building
vertices.reserve(8);
faces.reserve(6);
edges.reserve(12);
addVertex(x, -y, z);
addVertex(x, -y, -z);
addVertex(x - connectionThickness, -y, z);
addVertex(x - connectionThickness, -y, -z);
addVertex(-x, y, z);
addVertex(-x, y, -z);
addVertex(-x, y - connectionThickness, z);
addVertex(-x, y - connectionThickness, -z);
addFace(1, 0, 2, 3); // Legacy norm: x
addFace(1, 5, 4, 0); // Legacy norm: y
addFace(0, 4, 6, 2); // Legacy norm: z
addFace(4, 5, 7, 6); // Legacy norm: -x
addFace(7, 3, 2, 6); // Legacy norm: -y
addFace(5, 1, 3, 7); // Legacy norm: -z
}
void Mesh::makeCornerWedge( const Vector3& size, Vector3& cofm )
{
float x = 0.5f * size.x;
float y = 0.5f * size.y;
float z = 0.5f * size.z;
clear();
// important - don't reallocate while we are building
vertices.reserve(5);
faces.reserve(5);
edges.reserve(8);
addVertex(x, -y, z);
addVertex(x, -y, -z);
addVertex(-x, -y, -z);
addVertex(-x, -y, z);
addVertex(x, y, -z);
addFace(0, 1, 4); // Legacy norm: x
addFace(0, 4, 3); // Legacy norm: z
addFace(2, 3, 4); // Legacy norm: -x
addFace(1, 0, 3, 2); // Legacy norm: -y
addFace(1, 2, 4); // Legacy norm: -z
// calculate center-of-mass here: for a corner-wedge should lie 1/4 of the way up from the base (height is -y/2)
// and in the center of the rectangular cross-section there
cofm = Vector3(x/4.0f, -y/2.0f, -z/4.0f);
}
void Mesh::clear()
{
vertices.clear();
edges.clear();
faces.clear();
}
void Mesh::addVertex(float x, float y, float z)
{
size_t id = vertices.size();
vertices.push_back(Vertex(id, Vector3(x, y, z)));
}
void Mesh::addFace(size_t i, size_t j, size_t k)
{
Edge* e0 = findOrMakeEdge(i, j);
Edge* e1 = findOrMakeEdge(j, k);
Edge* e2 = findOrMakeEdge(k, i);
size_t id = faces.size();
faces.push_back(Face(id, e0, e1, e2));
Face* face = &faces[id];
e0->addFace(face);
e1->addFace(face);
e2->addFace(face);
face->initPlane();
}
void Mesh::addFace(size_t i, size_t j, size_t k, size_t l)
{
Edge* e0 = findOrMakeEdge(i, j);
Edge* e1 = findOrMakeEdge(j, k);
Edge* e2 = findOrMakeEdge(k, l);
Edge* e3 = findOrMakeEdge(l, i);
size_t id = faces.size();
faces.push_back(Face(id, e0, e1, e2, e3));
Face* face = &faces[id];
e0->addFace(face);
e1->addFace(face);
e2->addFace(face);
e3->addFace(face);
face->initPlane();
}
void Mesh::addFace( int numVerts, int vertIndexList[], bool reverseOrder = false )
{
size_t id = faces.size();
Edge* anEdge = NULL;
std::vector<Edge*> faceEdges;
// find or make the edges and add them to a faceEdge container
if( !reverseOrder )
{
for( int i = 0; i < numVerts-1; i++ )
{
anEdge = findOrMakeEdge(vertIndexList[i], vertIndexList[i+1]);
if( anEdge )
faceEdges.push_back(anEdge);
}
anEdge = findOrMakeEdge(vertIndexList[numVerts-1], vertIndexList[0]);
if( anEdge )
faceEdges.push_back(anEdge);
}
else
{
for( int i = 0; i < numVerts-1; i++ )
{
anEdge = findOrMakeEdge(vertIndexList[numVerts-1-i], vertIndexList[numVerts-2-i]);
if( anEdge )
faceEdges.push_back(anEdge);
}
anEdge = findOrMakeEdge(vertIndexList[0], vertIndexList[numVerts-1]);
if( anEdge )
faceEdges.push_back(anEdge);
}
// Create a face based on this edge list and add it to the face container
faces.push_back(Face(id, faceEdges));
Face* face = &faces[id];
// Set each edge's face
if( !reverseOrder )
{
for( int i = 0; i < numVerts; i++ )
{
anEdge = faceEdges[i];
faceEdges.at(i)->addFace(face);
}
}
else
{
for( int i = 0; i < numVerts; i++ )
{
anEdge = faceEdges[numVerts-1-i];
faceEdges.at(numVerts-1-i)->addFace(face);
}
}
face->initPlane();
}
Edge* Mesh::findOrMakeEdge(size_t v0, size_t v1)
{
Vertex* vert0 = &vertices[v0];
Vertex* vert1 = &vertices[v1];
if (Edge* found = vert0->findEdge(vert1)) {
RBXASSERT(found->getVertex(NULL, 0) == vert1); // should be backwards - this is second face
RBXASSERT(found->getVertex(NULL, 1) == vert0);
RBXASSERT(found->getForward());
RBXASSERT(!found->getBackward());
return found;
}
else {
return addEdge(vert0, vert1);
}
}
Edge* Mesh::addEdge(Vertex* vert0, Vertex* vert1)
{
size_t id = edges.size();
Edge edge(id, vert0, vert1);
edges.push_back(edge);
Edge* answer = &edges[id];
vert0->addEdge(answer);
vert1->addEdge(answer);
return answer;
}
bool Mesh::pointInMesh(const Vector3& point) const
{
for (size_t i = 0; i < numFaces(); ++i) {
if (!getFace(i)->plane().pointOnOrBehind(point)) {
return false;
}
}
return true;
}
const Face* Mesh::findFaceIntersection(const Vector3& inside, const Vector3& outside) const
{
RBXASSERT(pointInMesh(inside));
RBXASSERT(!pointInMesh(outside));
RbxRay ray = RbxRay::fromOriginAndDirection(inside, (outside-inside).direction());
Vector3 tempHitPoint;
for (size_t i = 0; i < numFaces(); ++i) {
const Face* face = getFace(i);
if (rayIntersectsFace(ray, face, tempHitPoint)) {
return face;
}
}
RBXASSERT(0);
return NULL;
}
void Mesh::findFaceIntersections(const Vector3& p0, const Vector3& p1, const Face* &f0, const Face* &f1) const
{
RBXASSERT(!pointInMesh(p0));
RBXASSERT(!pointInMesh(p1));
f0 = NULL;
f1 = NULL;
Line line = Line::fromTwoPoints(p0, p1);
for (size_t i = 0; i < numFaces(); ++i) {
const Face* face = getFace(i);
if (lineIntersectsFace(line, face)) {
if (!f0) {
f0 = face;
}
else {
f1 = face;
return;
}
}
}
}
bool Mesh::rayIntersectsFace(const RbxRay& ray, const Face* face, Vector3& intersection) const
{
const Plane& plane = face->plane();
intersection = ray.intersectionPlane(plane);
if (intersection == Vector3::inf()) {
return false;
}
else {
if (face->pointInFaceBorders(intersection)) {
return true;
}
else {
intersection = Vector3::inf();
return false;
}
}
}
bool Mesh::lineIntersectsFace(const Line& line, const Face* face) const
{
Vector3 point = line.intersection(face->plane());
if (point == Vector3::inf()) {
return false;
}
else {
return face->pointInFaceBorders(point);
}
}
const Vertex* Mesh::farthestVertex(const Vector3& direction) const
{
const Vertex* answer = NULL;
float farthestDistance = -FLT_MAX;
for (size_t i = 0; i < numVertices(); ++i) {
const Vertex* vertex = getVertex(i);
float dot = direction.dot(vertex->getOffset());
if (dot > farthestDistance) {
farthestDistance = dot;
answer = vertex;
}
}
return answer;
}
bool Mesh::hitTest(const RbxRay& ray, Vector3& hitPoint, Vector3& surfaceNormal) const
{
float distance = FLT_MAX;
int intersects = 0;
for (size_t i = 0; i < numFaces(); ++i) {
const Face* face = getFace(i);
Vector3 tempHit;
if (rayIntersectsFace(ray, face, tempHit)) {
intersects++;
float tempDistance = (tempHit - ray.origin()).squaredMagnitude();
RBXASSERT(tempDistance >= 0.0f);
if (tempDistance < distance) {
hitPoint = tempHit;
distance = tempDistance;
surfaceNormal = face->normal();
}
}
}
return (intersects > 0);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Face::initPlane()
{
outwardPlane = Plane(getVertexOffset(0), getVertexOffset(1), getVertexOffset(2));
}
const Face* Vertex::getFace(size_t i) const
{
return edges[i]->getVertexFace(this);
}
Face::Face(size_t id, Edge* e0, Edge* e1, Edge* e2)
: id(id)
{
edges.push_back(e0);
edges.push_back(e1);
edges.push_back(e2);
}
Face::Face(size_t id, Edge* e0, Edge* e1, Edge* e2, Edge* e3)
: id(id)
{
edges.push_back(e0);
edges.push_back(e1);
edges.push_back(e2);
edges.push_back(e3);
}
Face::Face( size_t id, std::vector<Edge*>& edgeList )
: id(id)
{
for( unsigned int i = 0; i < edgeList.size(); i++ )
edges.push_back(edgeList[i]);
}
// TODO _ turn back on after identifying bug here
#pragma optimize( "", off )
bool Face::pointInFaceBorders(const Vector3& point) const
{
for (size_t i = 0; i < numEdges(); ++i) {
const Edge* edge = getEdge(i);
const Face* sideFace = edge->otherFace(this);
if (!sideFace->plane().pointOnOrBehind(point)) {
return false;
}
}
return true;
}
#pragma optimize( "", on )
int Face::findInternalExtrusionIntersection(const Vector3& p0, const Vector3& p1) const
{
for (size_t i = 0; i < numEdges(); ++i) {
if (lineCrossesExtrusionSideBelow(p0, p1, i)) {
return i;
}
}
return -1;
}
int Face::getInternalExtrusionIntersection(const Vector3& pBelowInside, const Vector3& pBelowOutside) const
{
RBXASSERT(pointInInternalExtrusion(pBelowInside));
RBXASSERT(!pointInInternalExtrusion(pBelowOutside));
for (size_t i = 0; i < numEdges(); ++i) {
if (lineCrossesExtrusionSide(pBelowInside, pBelowOutside, i)) {
return i;
}
}
return -1;
}
void Face::findInternalExtrusionIntersections(const Vector3& p0, const Vector3& p1, int& side0, int& side1) const
{
RBXASSERT(!pointInInternalExtrusion(p0));
RBXASSERT(!pointInInternalExtrusion(p1));
side0 = -1;
side1 = -1;
int found = 0;
for (size_t i = 0; i < numEdges(); ++i) {
if (lineCrossesExtrusionSideBelow(p0, p1, i)) {
found++;
if (side0 == -1) {
side0 = i;
}
else {
//RBXASSERT(side1 == -1);
side1 = i;
}
}
}
}
bool Face::lineCrossesExtrusionSideBelow(const Vector3& p0, const Vector3& p1, size_t edgeId) const
{
Plane sidePlane = getSidePlane(edgeId);
if (sidePlane.halfSpaceContains(p0) != sidePlane.halfSpaceContains(p1)) { // points must be on opposite sides!
Line line = Line::fromTwoPoints(p0, p1);
Vector3 pointOnSide = line.intersection(sidePlane);
if (plane().pointOnOrBehind(pointOnSide)) {
return pointInExtrusionSide(pointOnSide, sidePlane, edgeId);
}
}
return false;
}
bool Face::lineCrossesExtrusionSide(const Vector3& p0, const Vector3& p1, size_t edgeId) const
{
Plane sidePlane = getSidePlane(edgeId);
if (sidePlane.halfSpaceContains(p0) != sidePlane.halfSpaceContains(p1)) { // points must be on opposite sides!
Line line = Line::fromTwoPoints(p0, p1);
Vector3 pointOnSide = line.intersection(sidePlane);
return pointInExtrusionSide(pointOnSide, sidePlane, edgeId);
}
return false;
}
bool Face::pointInExtrusionSide(const Vector3& pointOnSide, const Plane& sidePlane, size_t edgeId) const
{
Vector3 sidePlaneV = plane().normal().cross(sidePlane.normal());
Plane sidePlane0 = Plane(sidePlaneV, getEdge(edgeId)->getVertexOffset(this, 0));
if (sidePlane0.halfSpaceContains(pointOnSide)) {
Plane sidePlane1 = Plane(-sidePlaneV, getEdge(edgeId)->getVertexOffset(this, 1));
if (sidePlane1.halfSpaceContains(pointOnSide)) {
return true;
}
}
return false;
}
Vector3 Face::getCentroid( void ) const
{
Vector3 centroid = Vector3::zero();
for( size_t i = 0; i < numVertices(); ++i )
centroid += getVertex(i)->getOffset();
centroid /= (float)numVertices();
return centroid;
}
void Face::getOrientedBoundingBox( const Vector3& xDir, const Vector3& yDir, Vector3& boxMin, Vector3& boxMax, Vector3& boxCenter ) const
{
// This function finds a bounding box that is oriented with the x and y vector passed in. It computes the min corner,
// max corner, and the center of this box, in body coords.
size_t numVerts = numVertices();
Vector3 centroid = getCentroid();
boxMin = Vector3::zero();
boxMax = Vector3::zero();
float xMax = -1e10f;
float yMax = -1e10f;
float xMin = 1e10f;
float yMin = 1e10f;
for( size_t i = 0; i < numVerts; i++ )
{
// max vector
if( (getVertex(i)->getOffset() - centroid).dot(xDir) > xMax )
xMax = (getVertex(i)->getOffset() - centroid).dot(xDir);
if( (getVertex(i)->getOffset() - centroid).dot(yDir) > yMax )
yMax = (getVertex(i)->getOffset() - centroid).dot(yDir);
boxMax = centroid + xDir * xMax + yDir * yMax;
// Min vector
if( (getVertex(i)->getOffset() - centroid).dot(xDir) < xMin )
xMin = (getVertex(i)->getOffset() - centroid).dot(xDir);
if( (getVertex(i)->getOffset() - centroid).dot(yDir) < yMin )
yMin = (getVertex(i)->getOffset() - centroid).dot(yDir);
boxMin = centroid + xDir * xMin + yDir * yMin;
}
boxCenter = (boxMax + boxMin) * 0.5;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Edge* Vertex::findEdge(const Vertex* other)
{
for (size_t i = 0; i < edges.size(); ++i) {
Edge* e = edges[i];
RBXASSERT(e->contains(this));
if (e->contains(other)) {
return e;
}
}
return NULL;
}
const Edge* Vertex::recoverEdge(const Vertex* v0, const Vertex* v1) {
for (size_t i = 0; i < v0->numEdges(); ++i) {
Edge* edge = v0->getEdge(i);
if (edge->contains(v1)) {
return edge;
}
}
RBXASSERT(0);
return NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Edge::pointInVaronoi(const Vector3& point) const
{
const Vector3& v0 = getVertexOffset(NULL, 0);
const Vector3& v1 = getVertexOffset(NULL, 1);
Vector3 v0v1 = v1 - v0;
Vector3 v0p = point - v0;
Vector3 v1p = point - v1;
if (v0v1.dot(v0p) < 0.0) {
return false;
}
else if (v0v1.dot(v1p) > 0.0) {
return false;
}
return true;
}
} // namespace POLY
} // namespace RBX