DragonNest/Common/FMODEngine/FMOD_static/src/fmod_geometryi.cpp

1984 lines
44 KiB
C++
Raw Normal View History

2024-12-19 09:48:26 +08:00
#include "fmod_geometryi.h"
#ifdef FMOD_SUPPORT_GEOMETRY
#include "fmod_3d.h"
#include "fmod_memory.h"
#include "fmod_geometry_mgr.h"
#include "fmod_systemi.h"
#include "fmod_localcriticalsection.h"
#include <string.h>
namespace FMOD
{
#if defined(_DEBUG) && defined(FMOD_GEOMETRY_DEBUGGING)
#define ASSERT(x) do { if (!(x)) __asm { int 3 } } while (false)
#else
#define ASSERT(x)
#endif
// if the sound transsmision drop this low then
// don't bother doing any more ray testing
const float MIN_TRANSMISSION = 0.05f;
static inline float MAX(float x, float y) { return x > y ? x : y; }
static inline float MIN(float x, float y) { return x < y ? x : y; }
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
static inline void cross(const FMOD_VECTOR& a, const FMOD_VECTOR& b, FMOD_VECTOR& result)
{
result.x = a.y * b.z - a.z * b.y;
result.y = a.z * b.x - a.x * b.z;
result.z = a.x * b.y - a.y * b.x;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
static void matrixMult(const float matrix[3][4], const FMOD_VECTOR *src, FMOD_VECTOR *dst)
{
dst->x = matrix[0][0] * src->x + matrix[0][1] * src->y + matrix[0][2] * src->z;
dst->y = matrix[1][0] * src->x + matrix[1][1] * src->y + matrix[1][2] * src->z;
dst->z = matrix[2][0] * src->x + matrix[2][1] * src->y + matrix[2][2] * src->z;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
void GeometryI::calculateMatrix()
{
mMatrix[1][0] = mUp.x * mScale.y;
mMatrix[1][1] = mUp.y * mScale.y;
mMatrix[1][2] = mUp.z * mScale.y;
mMatrix[2][0] = mForward.x * mScale.z;
mMatrix[2][1] = mForward.y * mScale.z;
mMatrix[2][2] = mForward.z * mScale.z;
mMatrix[0][0] = (mUp.y * mForward.z - mUp.z * mForward.y) * mScale.x;
mMatrix[0][1] = (mUp.z * mForward.x - mUp.x * mForward.z) * mScale.x;
mMatrix[0][2] = (mUp.x * mForward.y - mUp.y * mForward.x) * mScale.x;
mInvMatrix[0][1] = mUp.x / mScale.y;
mInvMatrix[1][1] = mUp.y / mScale.y;
mInvMatrix[2][1] = mUp.z / mScale.y;
mInvMatrix[0][2] = mForward.x / mScale.z;
mInvMatrix[1][2] = mForward.y / mScale.z;
mInvMatrix[2][2] = mForward.z / mScale.z;
mInvMatrix[0][0] = (mUp.y * mForward.z - mUp.z * mForward.y) / mScale.x;
mInvMatrix[1][0] = (mUp.z * mForward.x - mUp.x * mForward.z) / mScale.x;
mInvMatrix[2][0] = (mUp.x * mForward.y - mUp.y * mForward.x) / mScale.x;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
void GeometryI::updateSpatialData()
{
// find world aabb
FMOD_VECTOR center;
center.x = (mAABB.xMax + mAABB.xMin) * 0.5f;
center.y = (mAABB.yMax + mAABB.yMin) * 0.5f;
center.z = (mAABB.zMax + mAABB.zMin) * 0.5f;
FMOD_VECTOR newCenter;
matrixMult(mMatrix, &center, &newCenter);
newCenter.x += mPosition.x;
newCenter.y += mPosition.y;
newCenter.z += mPosition.z;
float xExtent = (mAABB.xMax - mAABB.xMin) * 0.5f;
float yExtent = (mAABB.yMax - mAABB.yMin) * 0.5f;
float zExtent = (mAABB.zMax - mAABB.zMin) * 0.5f;
float xNewExtent = (float)fabs(mMatrix[0][0]) * xExtent + (float)fabs(mMatrix[1][0]) * yExtent + (float)fabs(mMatrix[2][0]) * zExtent;
float yNewExtent = (float)fabs(mMatrix[0][1]) * xExtent + (float)fabs(mMatrix[1][1]) * yExtent + (float)fabs(mMatrix[2][1]) * zExtent;
float zNewExtent = (float)fabs(mMatrix[0][2]) * xExtent + (float)fabs(mMatrix[1][2]) * yExtent + (float)fabs(mMatrix[2][2]) * zExtent;
ASSERT(mSpatialData);
mSpatialData->octreeNode.aabb.xMax = newCenter.x + xNewExtent;
mSpatialData->octreeNode.aabb.xMin = newCenter.x - xNewExtent;
mSpatialData->octreeNode.aabb.yMax = newCenter.y + yNewExtent;
mSpatialData->octreeNode.aabb.yMin = newCenter.y - yNewExtent;
mSpatialData->octreeNode.aabb.zMax = newCenter.z + zNewExtent;
mSpatialData->octreeNode.aabb.zMin = newCenter.z - zNewExtent;
if (mActive)
{
mGeometryMgr->mainOctree()->updateItem(&mSpatialData->octreeNode);
}
else
{
mGeometryMgr->mainOctree()->deleteItem(&mSpatialData->octreeNode);
}
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
void GeometryI::setToBeUpdated()
{
mGeometryMgr->mMoved = true;
if (!mToBeUpdated)
{
mToBeUpdated = true;
mNextUpdateItem = mGeometryMgr->mFirstUpdateItem;
mGeometryMgr->mFirstUpdateItem = this;
}
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
bool GeometryI::octreeLineTestCallback(OctreeNode* item, void* data)
{
LineTestData *lineTestData = (LineTestData*)data;
ASSERT(lineTestData);
ASSERT(lineTestData->geometryI);
const FMOD_VECTOR& a = lineTestData->start;
const FMOD_VECTOR& b = lineTestData->end;
FMOD_POLYGON& polygon = *(FMOD_POLYGON*)item;
float dotA = FMOD_Vector_DotProduct(&polygon.normal, &a) - polygon.distance;
float dotB = FMOD_Vector_DotProduct(&polygon.normal, &b) - polygon.distance;
if (dotA >= 0.0f && dotB >= 0.0f || dotA <= 0.0f && dotB <= 0.0f)
{
return true; // no collision
}
if (dotA > 0.0f && (polygon.flags & FMOD_POLYGON_FLAG_DOUBLE_SIDED) == 0)
{
return true; // no collision
}
// find point on plane
float time = dotA / (dotA - dotB);
FMOD_VECTOR collisionPosition;
collisionPosition.x = a.x + (b.x - a.x) * time;
collisionPosition.y = a.y + (b.y - a.y) * time;
collisionPosition.z = a.z + (b.z - a.z) * time;
FMOD_VECTOR* vertices = &polygon.vertices;
// find if point lies inside all edges of polygon
int side;
for (side = 0; side < (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK); side++)
{
FMOD_VECTOR diff;
FMOD_VECTOR edgeVector;
int next = side + 1;
if (next >= (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK))
{
next = 0;
}
diff.x = vertices[next].x - vertices[side].x;
diff.y = vertices[next].y - vertices[side].y;
diff.z = vertices[next].z - vertices[side].z;
cross(diff, polygon.normal, edgeVector);
float dot =
edgeVector.x * (collisionPosition.x - vertices[side].x) +
edgeVector.y * (collisionPosition.y - vertices[side].y) +
edgeVector.z * (collisionPosition.z - vertices[side].z);
if (dot > 0.0f)
{
break; // point is outside polygon so no interestection occured
}
}
if (side == (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK))
{
if (lineTestData->geometryI->mGeometryMgr->mSystem->mFlags & FMOD_INIT_GEOMETRY_USECLOSEST)
{
float newDirectTransmission = (1.0f - polygon.directOcclusion);
float newReverbTransmission = (1.0f - polygon.reverbOcclusion);
if (newDirectTransmission < lineTestData->directTransmission || (newDirectTransmission == lineTestData->directTransmission && newReverbTransmission < lineTestData->reverbTransmission))
{
lineTestData->directTransmission = newDirectTransmission;
lineTestData->reverbTransmission = newReverbTransmission;
}
}
else
{
lineTestData->directTransmission *= (1.0f - polygon.directOcclusion);
lineTestData->reverbTransmission *= (1.0f - polygon.reverbOcclusion);
}
#if defined(FMOD_GEOMETRY_DEBUGGING)
// for function testLineTestForEachPolygon to see if this
// polygon has actually been intersected with
polygon.flags &= ~0x80000000;
#else
if (lineTestData->directTransmission < MIN_TRANSMISSION &&
lineTestData->reverbTransmission < MIN_TRANSMISSION)
{
// sounds level has dropped too low so stop doing line testing
return false;
}
#endif
}
return true;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
GeometryI::GeometryI(GeometryMgr* geometryMgr) : LinkedListNode(), mOctree(geometryMgr->getWorldSize())
{
mGeometryMgr = geometryMgr;
mMaxNumVertices = 0;
mNumVertices = 0;
mMaxNumPolygons = 0;
mNumPolygons = 0;
mPolygonOffsets = 0;
mPolygonDataPos = 0;
mPolygonData = 0;
mForward.x = 0.0f;
mForward.y = 0.0f;
mForward.z = 1.0f;
mUp.x = 0.0f;
mUp.y = 1.0f;
mUp.z = 0.0f;
mPosition.x = 0.0f;
mPosition.y = 0.0f;
mPosition.z = 0.0f;
mScale.x = 1.0f;
mScale.y = 1.0f;
mScale.z = 1.0f;
calculateMatrix();
mPolygonUpdateList = 0;
mNextUpdateItem = 0;
mToBeUpdated = false;
mActive = true;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::release()
{
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
// mGeometryMgr->flushAll();
// find out if we are in the "to be updated" list and remove us.
// Other wise we will try to update a deleted object
GeometryI* geometryI = mGeometryMgr->mFirstUpdateItem;
GeometryI* prevGeometryI = 0;
while (geometryI)
{
if (geometryI == this)
{
if (prevGeometryI)
{
prevGeometryI->mNextUpdateItem = geometryI->mNextUpdateItem;
}
else
{
mGeometryMgr->mFirstUpdateItem = geometryI->mNextUpdateItem;
}
break;
}
prevGeometryI = geometryI;
geometryI = geometryI->mNextUpdateItem;
}
if (mSpatialData)
{
mGeometryMgr->mainOctree()->deleteItem(&mSpatialData->octreeNode);
mGeometryMgr->mainOctree()->removeInternalNode(&mSpatialData->octreeInternalNode);
mGeometryMgr->releaseMainOctree();
FMOD_Memory_Free(mSpatialData);
mSpatialData = 0;
}
if (mPolygonData)
{
FMOD_Memory_Free(mPolygonData);
mPolygonData = 0;
}
if (mPolygonOffsets)
{
FMOD_Memory_Free(mPolygonOffsets);
mPolygonOffsets = 0;
}
mGeometryMgr->mMoved = true; // Make it reset the voices back to unoccluded.
mGeometryMgr->mSystem->update();
if (mGeometryMgr->mSystem->mGeometryList == this)
{
mGeometryMgr->mSystem->mGeometryList = (GeometryI*)getNext();
if (mGeometryMgr->mSystem->mGeometryList == this)
{
mGeometryMgr->mSystem->mGeometryList = 0;
}
}
removeNode();
FMOD_Memory_Free(this);
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::alloc(int maxNumPolygons, int maxNumVertices)
{
FMOD_RESULT result;
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
if (mPolygonData || mPolygonOffsets )
{
return FMOD_ERR_INTERNAL;
}
mMaxNumVertices = maxNumVertices;
mNumVertices = 0;
mMaxNumPolygons = maxNumPolygons;
mNumPolygons = 0;
mPolygonOffsets = (int*)FMOD_Memory_Alloc(mMaxNumVertices * sizeof (int));
if (!mPolygonOffsets)
{
return FMOD_ERR_MEMORY;
}
mPolygonDataPos = 0;
int polygonDataSize = (sizeof(FMOD_POLYGON) - sizeof (FMOD_VECTOR)) * maxNumPolygons;
polygonDataSize += sizeof (FMOD_VECTOR) * maxNumVertices;
mPolygonData = (unsigned char*)FMOD_Memory_Alloc(polygonDataSize);
if (!mPolygonData)
{
return FMOD_ERR_MEMORY;
}
result = mGeometryMgr->aquireMainOctree();
if (result != FMOD_OK)
{
return result;
}
mSpatialData = (SpatialData *)FMOD_Memory_Alloc(sizeof (SpatialData));
if (!mSpatialData)
{
return FMOD_ERR_MEMORY;
}
FMOD_memset(mSpatialData, 0, sizeof (SpatialData));
mSpatialData->geometry = this;
mGeometryMgr->mainOctree()->addInternalNode(&mSpatialData->octreeInternalNode);
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::addPolygon(float directOcclusion, float reverbOcclusion, bool doubleSided, int numVertices, const FMOD_VECTOR *vertices, int *polygonIndex)
{
ASSERT(vertices);
ASSERT(numVertices >= 3);
ASSERT(mNumPolygons < mMaxNumPolygons);
ASSERT(mNumVertices + numVertices <= mMaxNumVertices);
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
if (vertices == 0)
{
return FMOD_ERR_INVALID_PARAM;
}
if (numVertices < 3)
{
return FMOD_ERR_INVALID_PARAM;
}
if (mNumPolygons >= mMaxNumPolygons)
{
return FMOD_ERR_INVALID_PARAM;
}
if (mNumVertices + numVertices > mMaxNumVertices)
{
return FMOD_ERR_INVALID_PARAM;
}
if (polygonIndex)
{
*polygonIndex = mNumPolygons;
}
mNumVertices += numVertices;
mPolygonOffsets[mNumPolygons] = mPolygonDataPos;
FMOD_POLYGON& polygon = *(FMOD_POLYGON*)&mPolygonData[mPolygonDataPos];
mPolygonDataPos += sizeof(FMOD_POLYGON) + (numVertices - 1) * sizeof (FMOD_VECTOR);
mNumPolygons++;
FMOD_memset(&polygon.node, 0, sizeof (OctreeNode));
FMOD_memset(&polygon.nodeInternal, 0, sizeof (OctreeNode));
polygon.directOcclusion = directOcclusion;
polygon.reverbOcclusion = reverbOcclusion;
polygon.flags = numVertices;
if (doubleSided)
polygon.flags |= FMOD_POLYGON_FLAG_DOUBLE_SIDED;
int vertex;
for (vertex = 0; vertex < (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK); vertex++)
(&polygon.vertices)[vertex] = vertices[vertex];
// add to update list
polygon.node.nextItem = mPolygonUpdateList;
mPolygonUpdateList = &polygon.node;
setToBeUpdated();
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getNumPolygons(int *numPolygons)
{
if (!numPolygons)
{
return FMOD_ERR_INVALID_PARAM;
}
*numPolygons = mNumPolygons;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getMaxPolygons(int *maxNumPolygons, int *maxVertices)
{
if (maxNumPolygons)
{
*maxNumPolygons = mMaxNumPolygons;
}
if (maxVertices)
{
*maxVertices = mMaxNumVertices;
}
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getPolygonNumVertices (int polygonIndex, int *numVertices)
{
ASSERT(polygonIndex >= 0);
ASSERT(polygonIndex < mNumPolygons);
ASSERT(mPolygonOffsets[polygonIndex] >= 0);
ASSERT(mPolygonOffsets[polygonIndex] < mPolygonDataPos);
if (polygonIndex < 0 || polygonIndex >= mNumPolygons)
{
return FMOD_ERR_INVALID_PARAM;
}
FMOD_POLYGON& polygon = *(FMOD_POLYGON*)&mPolygonData[mPolygonOffsets[polygonIndex]];
if (numVertices)
{
*numVertices = (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK);
}
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::setPolygonVertex(int polygonIndex, int vertexIndex, const FMOD_VECTOR *vertex)
{
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
ASSERT(polygonIndex >= 0);
ASSERT(polygonIndex < mNumPolygons);
ASSERT(mPolygonOffsets[polygonIndex] >= 0);
ASSERT(mPolygonOffsets[polygonIndex] < mPolygonDataPos);
if (polygonIndex < 0 || polygonIndex >= mNumPolygons)
{
return FMOD_ERR_INVALID_PARAM;
}
FMOD_POLYGON& polygon = *(FMOD_POLYGON*)&mPolygonData[mPolygonOffsets[polygonIndex]];
ASSERT(vertexIndex >= 0);
ASSERT(vertexIndex < (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK));
ASSERT(vertex);
if (vertexIndex < 0 || vertexIndex >= (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK))
{
return FMOD_ERR_INVALID_PARAM;
}
if (vertex == 0)
{
return FMOD_ERR_INVALID_PARAM;
}
if ((&polygon.vertices)[vertexIndex].x == vertex->x &&
(&polygon.vertices)[vertexIndex].y == vertex->y &&
(&polygon.vertices)[vertexIndex].z == vertex->z)
{
return FMOD_OK;
}
(&polygon.vertices)[vertexIndex] = *vertex;
// if we are in the octreee then remove and add to the update list
if (polygon.node.flags & OCTREE_FLAG_INSERTED)
{
mOctree.deleteItem(&polygon.node);
polygon.node.nextItem = mPolygonUpdateList;
mPolygonUpdateList = &polygon.node;
}
setToBeUpdated();
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getPolygonVertex(int polygonIndex, int vertexIndex, FMOD_VECTOR *vertex)
{
ASSERT(polygonIndex >= 0);
ASSERT(polygonIndex < mNumPolygons);
ASSERT(mPolygonOffsets[polygonIndex] >= 0);
ASSERT(mPolygonOffsets[polygonIndex] < mPolygonDataPos);
if (polygonIndex < 0 || polygonIndex >= mNumPolygons || !vertex)
{
return FMOD_ERR_INVALID_PARAM;
}
FMOD_POLYGON& polygon = *(FMOD_POLYGON*)&mPolygonData[mPolygonOffsets[polygonIndex]];
ASSERT(vertexIndex >= 0);
ASSERT(vertexIndex < (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK));
if (vertexIndex < 0 || vertexIndex >= (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK))
{
return FMOD_ERR_INVALID_PARAM;
}
*vertex = (&polygon.vertices)[vertexIndex];
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::setPolygonAttributes(int polygonIndex, float directOcclusion, float reverbOcclusion, bool doubleSided)
{
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
ASSERT(polygonIndex >= 0);
ASSERT(polygonIndex < mNumPolygons);
ASSERT(mPolygonOffsets[polygonIndex] >= 0);
ASSERT(mPolygonOffsets[polygonIndex] < mPolygonDataPos);
if (polygonIndex < 0 || polygonIndex >= mNumPolygons)
{
return FMOD_ERR_INVALID_PARAM;
}
FMOD_POLYGON& polygon = *(FMOD_POLYGON*)&mPolygonData[mPolygonOffsets[polygonIndex]];
polygon.directOcclusion = directOcclusion;
polygon.reverbOcclusion = reverbOcclusion;
if (doubleSided)
{
polygon.flags |= FMOD_POLYGON_FLAG_DOUBLE_SIDED;
}
else
{
polygon.flags &= ~FMOD_POLYGON_FLAG_DOUBLE_SIDED;
}
setToBeUpdated();
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getPolygonAttributes(int polygonIndex, float *directOcclusion, float *reverbOcclusion, bool *doubleSided)
{
ASSERT(polygonIndex >= 0);
ASSERT(polygonIndex < mNumPolygons);
ASSERT(mPolygonOffsets[polygonIndex] >= 0);
ASSERT(mPolygonOffsets[polygonIndex] < mPolygonDataPos);
if (polygonIndex < 0 || polygonIndex >= mNumPolygons)
{
return FMOD_ERR_INVALID_PARAM;
}
{
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
FMOD_POLYGON &polygon = *(FMOD_POLYGON*)&mPolygonData[mPolygonOffsets[polygonIndex]];
if (directOcclusion)
{
*directOcclusion = polygon.directOcclusion;
}
if (reverbOcclusion)
{
*reverbOcclusion = polygon.reverbOcclusion;
}
if (doubleSided)
{
*doubleSided = (polygon.flags & FMOD_POLYGON_FLAG_DOUBLE_SIDED) != 0;
}
}
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::flush()
{
/*
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
*/
int vertex;
// iterate through polygons in the update list, calucate normals, aabb and add to octree.
OctreeNode* node = mPolygonUpdateList;
mPolygonUpdateList = 0;
while (node)
{
OctreeNode* next = node->nextItem;
node->nextItem = 0;
FMOD_POLYGON& polygon = *(FMOD_POLYGON*)node;
FMOD_VECTOR* vertices =& polygon.vertices;
// calculate polygon normal
float xN = 0.0f;
float yN = 0.0f;
float zN = 0.0f;
// todo: return an error if a polygon has less then 3 vertices.
for (vertex = 0; vertex < (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK) - 2; vertex++)
{
float xA = vertices[vertex + 1].x -vertices[0].x;
float yA = vertices[vertex + 1].y -vertices[0].y;
float zA = vertices[vertex + 1].z -vertices[0].z;
float xB = vertices[vertex + 2].x -vertices[0].x;
float yB = vertices[vertex + 2].y -vertices[0].y;
float zB = vertices[vertex + 2].z -vertices[0].z;
// cross product
xN += yA * zB - zA * yB;
yN += zA * xB - xA * zB;
zN += xA * yB - yA * xB;
}
float fMagnidued = (float)sqrt(xN * xN + yN * yN + zN * zN);
if (fMagnidued > 0.0f) // a tollerance here might be called for
{
polygon.flags &= ~FMOD_POLYGON_FLAG_INVALID;
xN /= fMagnidued;
yN /= fMagnidued;
zN /= fMagnidued;
}
else
{
polygon.flags |= FMOD_POLYGON_FLAG_INVALID;
}
polygon.normal.x = xN;
polygon.normal.y = yN;
polygon.normal.z = zN;
polygon.distance = FMOD_Vector_DotProduct(&vertices[0], &polygon.normal);
// add to octree
mOctree.addInternalNode(&polygon.nodeInternal);
FMOD_AABB& aabb = polygon.node.aabb;
aabb.xMax = aabb.xMin = vertices[0].x;
aabb.yMax = aabb.yMin = vertices[0].y;
aabb.zMax = aabb.zMin = vertices[0].z;
for (vertex = 1; vertex < (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK); vertex++)
{
aabb.xMax = MAX(aabb.xMax, vertices[vertex].x);
aabb.xMin = MIN(aabb.xMin, vertices[vertex].x);
aabb.yMax = MAX(aabb.yMax, vertices[vertex].y);
aabb.yMin = MIN(aabb.yMin, vertices[vertex].y);
aabb.zMax = MAX(aabb.zMax, vertices[vertex].z);
aabb.zMin = MIN(aabb.zMin, vertices[vertex].z);
}
// we need to grow the bounding box a little to cope with the
// case of an axis alligned polygon that might be right on the edge of a
// bounding box.
// Becaouse the line is clamped to each box in the tree before testing against
// the polygon, we need to make the boxes a little bit bigger then the
// polygons to make sure the line still passes through them.
float fTollerance = aabb.xMax - aabb.xMin;
fTollerance = MAX(fTollerance, aabb.yMax - aabb.yMin);
fTollerance = MAX(fTollerance, aabb.zMax - aabb.zMin);
fTollerance *= 0.01f;
aabb.xMin -= fTollerance;
aabb.xMax += fTollerance;
aabb.yMin -= fTollerance;
aabb.yMax += fTollerance;
aabb.zMin -= fTollerance;
aabb.zMax += fTollerance;
if ((polygon.flags & FMOD_POLYGON_FLAG_INVALID) == 0)
{
mOctree.insertItem(&polygon.node);
}
node = next;
}
// update spacial data
//mOctree.calculateAverageNodeElements(); // just for testing
mOctree.getAABB(&mAABB);
updateSpatialData();
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::setActive(bool active)
{
setToBeUpdated();
mActive = active;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getActive(bool *active)
{
if (!active)
{
return FMOD_ERR_INVALID_PARAM;
}
*active = mActive;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::setRotation(const FMOD_VECTOR* forward, const FMOD_VECTOR* up)
{
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
if (!forward)
{
return FMOD_ERR_INVALID_PARAM;
}
if (!up)
{
return FMOD_ERR_INVALID_PARAM;
}
if (mForward.x == forward->x &&
mForward.y == forward->y &&
mForward.z == forward->z &&
mUp.x == up->x &&
mUp.y == up->y &&
mUp.z == up->z)
{
return FMOD_OK;
}
mForward = *forward;
mUp = *up;
calculateMatrix();
setToBeUpdated();
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getRotation(FMOD_VECTOR* forward, FMOD_VECTOR* up)
{
if (forward)
{
*forward = mForward;
}
if (up)
{
*up = mUp;
}
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::setPosition(const FMOD_VECTOR* position)
{
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
if (!position)
{
return FMOD_ERR_INVALID_PARAM;
}
if (mPosition.x == position->x && mPosition.y == position->y && mPosition.z == position->z)
{
return FMOD_OK;
}
mPosition = *position;
setToBeUpdated();
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getPosition(FMOD_VECTOR* position)
{
if (!position)
{
return FMOD_ERR_INVALID_PARAM;
}
*position = mPosition;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::setScale(const FMOD_VECTOR* scale)
{
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
if (!scale)
{
return FMOD_ERR_INVALID_PARAM;
}
if (scale->x == 0.0f || scale->y == 0.0f || scale->z == 0.0f)
{
return FMOD_ERR_INVALID_PARAM;
}
if (mScale.x == scale->x &&
mScale.y == scale->y &&
mScale.z == scale->z)
{
return FMOD_OK;
}
mScale = *scale;
calculateMatrix();
setToBeUpdated();
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getScale(FMOD_VECTOR *scale)
{
if (!scale)
{
return FMOD_ERR_INVALID_PARAM;
}
*scale = mScale;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::save(void *data, int *dataSize)
{
FMOD_RESULT result = FMOD_OK;
if (!dataSize)
{
return FMOD_ERR_INVALID_PARAM;
}
if (data)
{
int tmpDataSize = *dataSize;
result = serialiser(data, &tmpDataSize, true, false, saveData);
}
else
{
result = serialiser(data, dataSize, false, false, countData);
}
return result;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::load(const void *data, int dataSize)
{
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
if (!data)
{
return FMOD_ERR_INVALID_PARAM;
}
return serialiser((void*)data, &dataSize, false, true, loadData);
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::saveData(void* fileData, int dataSize, int* fileDataIndex, void* liveData, int liveDataSize)
{
if (*fileDataIndex + liveDataSize > dataSize)
return FMOD_ERR_INVALID_PARAM;
#ifdef PLATFORM_ENDIAN_BIG
if (liveDataSize == 4)
{
*(unsigned int*)&((unsigned char*)fileData)[*fileDataIndex] = *(unsigned int*)liveData;
}
else
{
FMOD_memcpy(&((unsigned char*)fileData)[*fileDataIndex], liveData, liveDataSize);
}
#else
FMOD_memcpy(&((unsigned char*)fileData)[*fileDataIndex], liveData, liveDataSize);
#endif
*fileDataIndex += liveDataSize;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::loadData(void* fileData, int dataSize, int* fileDataIndex, void* liveData, int liveDataSize)
{
if (*fileDataIndex + liveDataSize > dataSize)
return FMOD_ERR_INVALID_PARAM;
#ifdef PLATFORM_ENDIAN_BIG
if (liveDataSize == 4)
{
*(unsigned int*)liveData = *(unsigned int*)&((unsigned char*)fileData)[*fileDataIndex];
}
else
{
FMOD_memcpy(liveData, &((unsigned char*)fileData)[*fileDataIndex], liveDataSize);
}
#else
FMOD_memcpy(liveData, &((unsigned char*)fileData)[*fileDataIndex], liveDataSize);
#endif
*fileDataIndex += liveDataSize;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::countData(void* fileData, int dataSize, int* fileDataIndex, void* liveData, int liveDataSize)
{
*fileDataIndex += liveDataSize;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::serialiser(
void *data,
int *dataSize,
bool bWrite,
bool bRead,
FMOD_RESULT (*serialiseData)(void* fileData, int dataSize, int* fileDataIndex, void* liveData, int liveDataSize))
{
bool bCount = !bWrite && !bRead;
#define _CHECK_RESULT(x) \
{ \
FMOD_RESULT result = (x); \
if (result != FMOD_OK) \
{ \
if (vertexArray) \
FMOD_Memory_Free(vertexArray); \
return result; \
} \
}
FMOD_VECTOR* vertexArray = 0;
int index = 0;
unsigned int header;
const unsigned int realHeader = 'F' + ('M' << 8) + ('O' << 16) + ('D' << 24);
header = realHeader;
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &header, sizeof (int)))
if (header != realHeader)
{
return FMOD_ERR_INVALID_PARAM;
}
int dataSizeCheck = *dataSize;
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &dataSizeCheck, sizeof (int)))
if (bRead)
{
if (*dataSize != dataSizeCheck)
{
return FMOD_ERR_INVALID_PARAM;
}
}
int numPolygons;
if (bWrite || bCount)
{
_CHECK_RESULT(getNumPolygons(&numPolygons))
}
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &numPolygons, sizeof (int)))
int maxPolygons;
int maxVertices;
if (bWrite || bCount)
{
_CHECK_RESULT(getMaxPolygons(&maxPolygons, &maxVertices))
}
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &maxPolygons, sizeof (int)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &maxVertices, sizeof (int)))
int maxNumVerticesInOnPolygon = 64; // not very likely that this will be broken
vertexArray = (FMOD_VECTOR*)FMOD_Memory_Alloc(maxNumVerticesInOnPolygon * sizeof (FMOD_VECTOR));
if (!vertexArray)
return FMOD_ERR_MEMORY;
if (bRead)
{
_CHECK_RESULT(alloc(maxPolygons, maxVertices))
}
for (int polygonIndex = 0; polygonIndex < numPolygons; polygonIndex++)
{
int numVertices;
if (bWrite || bCount)
{
_CHECK_RESULT(getPolygonNumVertices(polygonIndex, &numVertices))
}
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &numVertices, sizeof (int)))
if (maxNumVerticesInOnPolygon < numVertices)
{
// in the unlikly event we have more then 64 vertices in one polygon we need to
// reallocate the array
FMOD_Memory_Free(vertexArray);
vertexArray = (FMOD_VECTOR*)FMOD_Memory_Alloc(maxNumVerticesInOnPolygon * sizeof (FMOD_VECTOR));
if (!vertexArray)
return FMOD_ERR_MEMORY;
}
for (int vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
{
// FMOD_VECTOR vertex = FMOD_Memory_Alloc(mMaxNumVertices * sizeof (int));
if (bWrite)
{
_CHECK_RESULT(getPolygonVertex(polygonIndex, vertexIndex, &vertexArray[vertexIndex]))
}
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &vertexArray[vertexIndex].x, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &vertexArray[vertexIndex].y, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &vertexArray[vertexIndex].z, sizeof (float)))
}
float directOcclusion;
float reverbOcclusion;
bool bDoubleSided = false;;
if (bWrite || bCount)
{
_CHECK_RESULT(getPolygonAttributes(polygonIndex, &directOcclusion, &reverbOcclusion, &bDoubleSided))
}
int doubleSided = bDoubleSided ? 1 : 0;
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &directOcclusion, sizeof (int)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &reverbOcclusion, sizeof (int)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &doubleSided, sizeof (int)))
bDoubleSided = doubleSided != 0;
if (bRead)
{
_CHECK_RESULT(addPolygon(directOcclusion, reverbOcclusion, bDoubleSided, numVertices, vertexArray, 0))
}
}
FMOD_Memory_Free(vertexArray);
vertexArray = 0;
FMOD_VECTOR forward;
FMOD_VECTOR up;
if (bWrite || bCount)
{
_CHECK_RESULT(getRotation(&forward, &up))
}
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &forward.x, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &forward.y, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &forward.z, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &up.x, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &up.y, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &up.z, sizeof (float)))
if (bRead)
{
_CHECK_RESULT(setRotation(&forward, &up))
}
FMOD_VECTOR position;
if (bWrite || bCount)
{
_CHECK_RESULT(getPosition(&position))
}
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &position.x, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &position.y, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &position.z, sizeof (float)))
if (bRead)
{
_CHECK_RESULT(setPosition(&position))
}
FMOD_VECTOR scale;
if (bWrite || bCount)
{
_CHECK_RESULT(getScale(&scale))
}
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &scale.x, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &scale.y, sizeof (float)))
_CHECK_RESULT(serialiseData(data, *dataSize, &index, &scale.z, sizeof (float)))
if (bRead)
{
_CHECK_RESULT(setScale(&scale))
}
#undef _CHECK_RESULT
if (bRead || bWrite)
{
if (*dataSize != index)
{
return FMOD_ERR_INVALID_PARAM;
}
}
else
{
*dataSize = index;
}
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::setUserData(void *userdata)
{
mUserData = userdata;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getUserData(void **userdata)
{
if (!userdata)
{
return FMOD_ERR_INVALID_PARAM;
}
*userdata = mUserData;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
bool GeometryI::lineTest(LineTestData* lineTestData)
{
FMOD_VECTOR startBck = lineTestData->start;
FMOD_VECTOR endBck = lineTestData->end;
FMOD_VECTOR startTmp = lineTestData->start;
startTmp.x -= mPosition.x;
startTmp.y -= mPosition.y;
startTmp.z -= mPosition.z;
FMOD_VECTOR endTmp = lineTestData->end;
endTmp.x -= mPosition.x;
endTmp.y -= mPosition.y;
endTmp.z -= mPosition.z;
matrixMult(mInvMatrix, &startTmp, &lineTestData->start);
matrixMult(mInvMatrix, &endTmp, &lineTestData->end);
bool bResult = mOctree.testLine(octreeLineTestCallback, lineTestData, lineTestData->start, lineTestData->end);
lineTestData->start = startBck;
lineTestData->end = endBck;
lineTestData->geometryI = 0;
return bResult;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::setWorldSize(float worldSize)
{
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
mOctree.setMaxSize(worldSize);
int poly;
for (poly = 0; poly < mNumPolygons; poly++)
{
FMOD_POLYGON& polygon = *(FMOD_POLYGON*)&mPolygonData[mPolygonOffsets[poly]];
mOctree.deleteItem(&polygon.node);
}
for (poly = 0; poly < mNumPolygons; poly++)
{
FMOD_POLYGON& polygon = *(FMOD_POLYGON*)&mPolygonData[mPolygonOffsets[poly]];
polygon.node.nextItem = mPolygonUpdateList;
mPolygonUpdateList = &polygon.node;
}
setToBeUpdated();
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
void GeometryI::removeFromTree()
{
#ifdef FMOD_SUPPORT_GEOMETRY_THREADED
LocalCriticalSection crit(mGeometryMgr->mGeometryCrit, true);
#endif
mGeometryMgr->mainOctree()->deleteItem(&mSpatialData->octreeNode);
}
#if defined(FMOD_GEOMETRY_DEBUGGING)
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
void GeometryI::testLineTestForEachPolygon()
{
for (int poly = 0; poly < mNumPolygons; poly++)
{
FMOD_POLYGON& polygon = *(FMOD_POLYGON*)&mPolygonData[mPolygonOffsets[poly]];
if (polygon.flags & FMOD_POLYGON_FLAG_INVALID)
continue;
FMOD_VECTOR center = { 0.0f, 0.0f, 0.0f };
int numVertices = (polygon.flags & FMOD_POLYGON_NUM_VERTICES_MASK);
ASSERT(numVertices >= 3);
for (int i = 0; i < numVertices; i++)
{
center.x += (&polygon.vertices)[i].x;
center.y += (&polygon.vertices)[i].y;
center.z += (&polygon.vertices)[i].z;
}
center.x /= numVertices;
center.y /= numVertices;
center.z /= numVertices;
FMOD_VECTOR start;
start.x = center.x - polygon.normal.x * 100.0f;
start.y = center.y - polygon.normal.y * 100.0f;
start.z = center.z - polygon.normal.z * 100.0f;
FMOD_VECTOR end;
end.x = center.x + polygon.normal.x * 100.0f;
end.y = center.y + polygon.normal.y * 100.0f;
end.z = center.z + polygon.normal.z * 100.0f;
polygon.flags |= 0x80000000;
float a, b;
mGeometryMgr->lineTestAll(&start, &end, &a, &b);
ASSERT((polygon.flags & 0x80000000) == 0);
polygon.flags &= ~0x80000000;
}
}
#endif
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::validate(Geometry *geometry, GeometryI **geometryi)
{
if (!geometryi)
{
return FMOD_ERR_INVALID_PARAM;
}
if (!geometry)
{
return FMOD_ERR_INVALID_HANDLE;
}
*geometryi = (GeometryI *)geometry;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[SEE_ALSO]
]
*/
FMOD_RESULT GeometryI::getMemoryInfo(unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details)
{
#ifdef FMOD_SUPPORT_MEMORYTRACKER
GETMEMORYINFO_IMPL
#else
return FMOD_ERR_UNIMPLEMENTED;
#endif
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
#ifdef FMOD_SUPPORT_MEMORYTRACKER
FMOD_RESULT GeometryI::getMemoryUsedImpl(MemoryTracker *tracker)
{
//AJS incomplete
tracker->add(false, FMOD_MEMBITS_GEOMETRY, sizeof(*this));
return FMOD_OK;
}
#endif
}
#endif // FMOD_SUPPORT_GEOMETRY