bluecore/ode/src/collision_trimesh_gimpact.cpp

522 lines
15 KiB
C++

/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library 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 files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
// TriMesh code by Erwin de Vries.
#include <ode/collision.h>
#include <ode/matrix.h>
#include <ode/rotation.h>
#include <ode/odemath.h>
#include "collision_util.h"
#define TRIMESH_INTERNAL
#include "collision_trimesh_internal.h"
#if dTRIMESH_ENABLED && dTRIMESH_GIMPACT
void dxTriMeshData::Preprocess()
{
// If this mesh has already been preprocessed, exit
// if (UseFlags)
// return;
//
// udword numTris = Mesh.GetNbTriangles();
// udword numEdges = numTris * 3;
//
// UseFlags = new uint8[numTris];
// memset(UseFlags, 0, sizeof(uint8) * numTris);
//
// EdgeRecord* records = new EdgeRecord[numEdges];
//
// // Make a list of every edge in the mesh
// const IndexedTriangle* tris = Mesh.GetTris();
// for (unsigned int i = 0; i < numTris; i++)
// {
// SetupEdge(&records[i*3], 0, i, tris->mVRef);
// SetupEdge(&records[i*3+1], 1, i, tris->mVRef);
// SetupEdge(&records[i*3+2], 2, i, tris->mVRef);
//
// tris = (const IndexedTriangle*)(((uint8*)tris) + Mesh.GetTriStride());
// }
//
// // Sort the edges, so the ones sharing the same verts are beside each other
// qsort(records, numEdges, sizeof(EdgeRecord), EdgeCompare);
//
// // Go through the sorted list of edges and flag all the edges and vertices that we need to use
// for (unsigned int i = 0; i < numEdges; i++)
// {
// EdgeRecord* rec1 = &records[i];
// EdgeRecord* rec2 = 0;
// if (i < numEdges - 1)
// rec2 = &records[i+1];
//
// if (rec2 &&
// rec1->VertIdx1 == rec2->VertIdx1 &&
// rec1->VertIdx2 == rec2->VertIdx2)
// {
// VertexPointers vp;
// Mesh.GetTriangle(vp, rec1->TriIdx);
//
// // Get the normal of the first triangle
// Point triNorm = (*vp.Vertex[2] - *vp.Vertex[1]) ^ (*vp.Vertex[0] - *vp.Vertex[1]);
// triNorm.Normalize();
//
// // Get the vert opposite this edge in the first triangle
// Point oppositeVert1 = GetOppositeVert(rec1, vp.Vertex);
//
// // Get the vert opposite this edge in the second triangle
// Mesh.GetTriangle(vp, rec2->TriIdx);
// Point oppositeVert2 = GetOppositeVert(rec2, vp.Vertex);
//
// float dot = triNorm.Dot((oppositeVert2 - oppositeVert1).Normalize());
//
// // We let the dot threshold for concavity get slightly negative to allow for rounding errors
// static const float kConcaveThresh = -0.000001f;
//
// // This is a concave edge, leave it for the next pass
// if (dot >= kConcaveThresh)
// rec1->Concave = true;
// // If this is a convex edge, mark its vertices and edge as used
// else
// UseFlags[rec1->TriIdx] |= rec1->Vert1Flags | rec1->Vert2Flags | rec1->EdgeFlags;
//
// // Skip the second edge
// i++;
// }
// // This is a boundary edge
// else
// {
// UseFlags[rec1->TriIdx] |= rec1->Vert1Flags | rec1->Vert2Flags | rec1->EdgeFlags;
// }
// }
//
// // Go through the list once more, and take any edge we marked as concave and
// // clear it's vertices flags in any triangles they're used in
// for (unsigned int i = 0; i < numEdges; i++)
// {
// EdgeRecord& er = records[i];
//
// if (er.Concave)
// {
// for (unsigned int j = 0; j < numEdges; j++)
// {
// EdgeRecord& curER = records[j];
//
// if (curER.VertIdx1 == er.VertIdx1 ||
// curER.VertIdx1 == er.VertIdx2)
// UseFlags[curER.TriIdx] &= ~curER.Vert1Flags;
//
// if (curER.VertIdx2 == er.VertIdx1 ||
// curER.VertIdx2 == er.VertIdx2)
// UseFlags[curER.TriIdx] &= ~curER.Vert2Flags;
// }
// }
// }
//
// delete [] records;
}
dTriMeshDataID dGeomTriMeshDataCreate(){
return new dxTriMeshData();
}
void dGeomTriMeshDataDestroy(dTriMeshDataID g){
delete g;
}
void dGeomTriMeshSetLastTransform( dxGeom* g, dMatrix4 last_trans )
{
// dAASSERT(g)
// dUASSERT(g->type == dTriMeshClass, "geom not trimesh");
// for (int i=0; i<16; i++)
// (((dxTriMesh*)g)->last_trans)[ i ] = last_trans[ i ];
// return;
}
//dReal* dGeomTriMeshGetLastTransform( dxGeom* g )
//{
// dAASSERT(g)
// dUASSERT(g->type == dTriMeshClass, "geom not trimesh");
//
// return (dReal*)(((dxTriMesh*)g)->last_trans);
//}
void dGeomTriMeshDataSet(dTriMeshDataID g, int data_id, void* in_data)
{
// dUASSERT(g, "argument not trimesh data");
//
// double *elem;
//
// switch (data_id) {
// case TRIMESH_FACE_NORMALS:
// g->Normals = (dReal *) in_data;
// break;
//
// case TRIMESH_LAST_TRANSFORMATION:
// elem = (double *) in_data;
// for (int i=0; i<16; i++)
// g->last_trans[i] = (dReal) elem[i];
//
// break;
// default:
// dUASSERT(data_id, "invalid data type");
// break;
// }
//
// return;
}
void* dGeomTriMeshDataGet(dTriMeshDataID g, int data_id)
{
dUASSERT(g, "argument not trimesh data");
// switch (data_id) {
// case TRIMESH_FACE_NORMALS:
// return NULL;
// break;
//
// case TRIMESH_LAST_TRANSFORMATION:
// return NULL;
// break;
// default:
// dUASSERT(data_id, "invalid data type");
// break;
// }
return NULL;
}
void dGeomTriMeshDataBuildSingle1(dTriMeshDataID g,
const void* Vertices, int VertexStride, int VertexCount,
const void* Indices, int IndexCount, int TriStride,
const void* Normals)
{
dUASSERT(g, "argument not trimesh data");
g->Build(Vertices, VertexStride, VertexCount,
Indices, IndexCount, TriStride,
Normals,
true);
}
void dGeomTriMeshDataBuildSingle(dTriMeshDataID g,
const void* Vertices, int VertexStride, int VertexCount,
const void* Indices, int IndexCount, int TriStride)
{
dGeomTriMeshDataBuildSingle1(g, Vertices, VertexStride, VertexCount,
Indices, IndexCount, TriStride, (void*)NULL);
}
void dGeomTriMeshDataBuildDouble1(dTriMeshDataID g,
const void* Vertices, int VertexStride, int VertexCount,
const void* Indices, int IndexCount, int TriStride,
const void* Normals)
{
dUASSERT(g, "argument not trimesh data");
g->Build(Vertices, VertexStride, VertexCount,
Indices, IndexCount, TriStride,
Normals,
false);
}
void dGeomTriMeshDataBuildDouble(dTriMeshDataID g,
const void* Vertices, int VertexStride, int VertexCount,
const void* Indices, int IndexCount, int TriStride) {
dGeomTriMeshDataBuildDouble1(g, Vertices, VertexStride, VertexCount,
Indices, IndexCount, TriStride, NULL);
}
void dGeomTriMeshDataBuildSimple1(dTriMeshDataID g,
const dReal* Vertices, int VertexCount,
const int* Indices, int IndexCount,
const int* Normals){
#ifdef dSINGLE
dGeomTriMeshDataBuildSingle1(g,
Vertices, 4 * sizeof(dReal), VertexCount,
Indices, IndexCount, 3 * sizeof(unsigned int),
Normals);
#else
dGeomTriMeshDataBuildDouble1(g, Vertices, 4 * sizeof(dReal), VertexCount,
Indices, IndexCount, 3 * sizeof(unsigned int),
Normals);
#endif
}
void dGeomTriMeshDataBuildSimple(dTriMeshDataID g,
const dReal* Vertices, int VertexCount,
const int* Indices, int IndexCount) {
dGeomTriMeshDataBuildSimple1(g,
Vertices, VertexCount, Indices, IndexCount,
(const int*)NULL);
}
void dGeomTriMeshDataPreprocess(dTriMeshDataID g)
{
dUASSERT(g, "argument not trimesh data");
g->Preprocess();
}
void dGeomTriMeshDataGetBuffer(dTriMeshDataID g, unsigned char** buf, int* bufLen)
{
dUASSERT(g, "argument not trimesh data");
*buf = NULL;
*bufLen = 0;
}
void dGeomTriMeshDataSetBuffer(dTriMeshDataID g, unsigned char* buf)
{
dUASSERT(g, "argument not trimesh data");
// g->UseFlags = buf;
}
// Trimesh
dxTriMesh::dxTriMesh(dSpaceID Space, dTriMeshDataID Data) : dxGeom(Space, 1){
type = dTriMeshClass;
this->Data = Data;
//Create trimesh
gim_trimesh_create_from_data(&m_collision_trimesh,( vec3f *)(&Data->m_Vertices[0]), Data->m_VertexCount ,0, ( GUINT *)(&Data->m_Indices[0]), Data->m_TriangleCount*3,0,1);
/* TC has speed/space 'issues' that don't make it a clear
win by default on spheres/boxes. */
this->doSphereTC = true;
this->doBoxTC = true;
this->doCapsuleTC = true;
}
dxTriMesh::~dxTriMesh(){
//Terminate Trimesh
gim_trimesh_destroy(&m_collision_trimesh);
}
void dxTriMesh::ClearTCCache(){
}
int dxTriMesh::AABBTest(dxGeom* g, dReal aabb[6]){
return 1;
}
void dxTriMesh::computeAABB()
{
//update trimesh transform
mat4f transform;
IDENTIFY_MATRIX_4X4(transform);
MakeMatrix(this, transform);
gim_trimesh_set_tranform(&m_collision_trimesh,transform);
//Update trimesh boxes
gim_trimesh_update(&m_collision_trimesh);
memcpy(aabb,&m_collision_trimesh.m_aabbset.m_global_bound,6*sizeof(GREAL));
}
void dxTriMeshData::UpdateData()
{
// BVTree.Refit();
}
dGeomID dCreateTriMesh(dSpaceID space,
dTriMeshDataID Data,
dTriCallback* Callback,
dTriArrayCallback* ArrayCallback,
dTriRayCallback* RayCallback)
{
dxTriMesh* Geom = new dxTriMesh(space, Data);
Geom->Callback = Callback;
Geom->ArrayCallback = ArrayCallback;
Geom->RayCallback = RayCallback;
return Geom;
}
void dGeomTriMeshSetCallback(dGeomID g, dTriCallback* Callback)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
((dxTriMesh*)g)->Callback = Callback;
}
dTriCallback* dGeomTriMeshGetCallback(dGeomID g)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
return ((dxTriMesh*)g)->Callback;
}
void dGeomTriMeshSetArrayCallback(dGeomID g, dTriArrayCallback* ArrayCallback)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
((dxTriMesh*)g)->ArrayCallback = ArrayCallback;
}
dTriArrayCallback* dGeomTriMeshGetArrayCallback(dGeomID g)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
return ((dxTriMesh*)g)->ArrayCallback;
}
void dGeomTriMeshSetRayCallback(dGeomID g, dTriRayCallback* Callback)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
((dxTriMesh*)g)->RayCallback = Callback;
}
dTriRayCallback* dGeomTriMeshGetRayCallback(dGeomID g)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
return ((dxTriMesh*)g)->RayCallback;
}
void dGeomTriMeshSetData(dGeomID g, dTriMeshDataID Data)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
((dxTriMesh*)g)->Data = Data;
}
dTriMeshDataID dGeomTriMeshGetData(dGeomID g)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
return ((dxTriMesh*)g)->Data;
}
void dGeomTriMeshEnableTC(dGeomID g, int geomClass, int enable)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
switch (geomClass)
{
case dSphereClass:
((dxTriMesh*)g)->doSphereTC = (1 == enable);
break;
case dBoxClass:
((dxTriMesh*)g)->doBoxTC = (1 == enable);
break;
case dCapsuleClass:
// case dCCylinderClass:
((dxTriMesh*)g)->doCapsuleTC = (1 == enable);
break;
}
}
int dGeomTriMeshIsTCEnabled(dGeomID g, int geomClass)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
switch (geomClass)
{
case dSphereClass:
if (((dxTriMesh*)g)->doSphereTC)
return 1;
break;
case dBoxClass:
if (((dxTriMesh*)g)->doBoxTC)
return 1;
break;
case dCapsuleClass:
if (((dxTriMesh*)g)->doCapsuleTC)
return 1;
break;
}
return 0;
}
void dGeomTriMeshClearTCCache(dGeomID g){
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
dxTriMesh* Geom = (dxTriMesh*)g;
Geom->ClearTCCache();
}
/*
* returns the TriMeshDataID
*/
dTriMeshDataID
dGeomTriMeshGetTriMeshDataID(dGeomID g)
{
dxTriMesh* Geom = (dxTriMesh*) g;
return Geom->Data;
}
// Getting data
void dGeomTriMeshGetTriangle(dGeomID g, int Index, dVector3* v0, dVector3* v1, dVector3* v2)
{
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
dxTriMesh* Geom = (dxTriMesh*)g;
gim_trimesh_locks_work_data(&Geom->m_collision_trimesh);
gim_trimesh_get_triangle_vertices(&Geom->m_collision_trimesh, Index, (*v0),(*v1),(*v2));
gim_trimesh_unlocks_work_data(&Geom->m_collision_trimesh);
}
void dGeomTriMeshGetPoint(dGeomID g, int Index, dReal u, dReal v, dVector3 Out){
dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh");
dxTriMesh* Geom = (dxTriMesh*)g;
dVector3 dv[3];
gim_trimesh_locks_work_data(&Geom->m_collision_trimesh);
gim_trimesh_get_triangle_vertices(&Geom->m_collision_trimesh, Index, dv[0],dv[1],dv[2]);
GetPointFromBarycentric(dv, u, v, Out);
gim_trimesh_unlocks_work_data(&Geom->m_collision_trimesh);
}
int dGeomTriMeshGetTriangleCount (dGeomID g)
{
dxTriMesh* Geom = (dxTriMesh*)g;
return gim_trimesh_get_triangle_count(&Geom->m_collision_trimesh);
}
void dGeomTriMeshDataUpdate(dTriMeshDataID g) {
dUASSERT(g, "argument not trimesh data");
g->UpdateData();
}
#endif