bool CollisionManager::checkLineOfSightWorldToCell(const Vector3& rayOrigin, const Vector3& rayEnd, float distance, CellObject* cellObject) {
	ManagedReference<SceneObject*> building = cellObject->getParent();

	if (building == NULL)
		return true;

	SharedObjectTemplate* objectTemplate = building->getObjectTemplate();
	PortalLayout* portalLayout = objectTemplate->getPortalLayout();

	if (portalLayout == NULL)
		return true;

	Ray ray = convertToModelSpace(rayOrigin, rayEnd, building);

	if (cellObject->getCellNumber() >= portalLayout->getAppearanceTemplatesSize())
		return true;

	MeshAppearanceTemplate* app = portalLayout->getMeshAppearanceTemplate(cellObject->getCellNumber());

	AABBTree* aabbTree = app->getAABBTree();

	if (aabbTree == NULL)
		return true;

	float intersectionDistance;
	Triangle* triangle = NULL;

	if (aabbTree->intersects(ray, distance, intersectionDistance, triangle, true))
		return false;

	return true;
}
TriangleNode* CollisionManager::getTriangle(const Vector3& point, FloorMesh* floor) {
	/*PathGraph* graph = node->getPathGraph();
	FloorMesh* floor = graph->getFloorMesh();*/

	AABBTree* aabbTree = floor->getAABBTree();

	//Vector3 nodePosition = node->getPosition();

	Vector3 rayOrigin(point.getX(), point.getZ() + 0.5, point.getY());
	//Vector3 rayOrigin(point.getX(), point.getY(), point.getZ() + 0.2);
	Vector3 direction(0, -1, 0);

	Ray ray(rayOrigin, direction);

	float intersectionDistance = 0;
	Triangle* triangle = NULL;

	aabbTree->intersects(ray, 4, intersectionDistance, triangle, true);

	TriangleNode* triangleNode = dynamic_cast<TriangleNode*>(triangle);

	if (triangleNode == NULL) {
		//System::out << "CollisionManager::getTriangle triangleNode NULL" << endl;

		return floor->findNearestTriangle(rayOrigin);
	}

	return triangleNode;
}
bool CollisionManager::checkLineOfSightInParentCell(SceneObject* object, Vector3& endPoint) {
	ManagedReference<SceneObject*> parent = object->getParent();

	if (parent == NULL || !parent->isCellObject())
		return true;

	CellObject* cell = cast<CellObject*>( parent.get());

	SharedObjectTemplate* objectTemplate = parent->getRootParent().get()->getObjectTemplate();
	PortalLayout* portalLayout = objectTemplate->getPortalLayout();
	MeshAppearanceTemplate* appearanceMesh = NULL;

	if (portalLayout == NULL)
		return true;

	try {
		appearanceMesh = portalLayout->getMeshAppearanceTemplate(cell->getCellNumber());
	} catch (Exception& e) {
		return true;
	}

	if (appearanceMesh == NULL) {
		//info("null appearance mesh ");
		return true;
	}

	AABBTree* aabbTree = appearanceMesh->getAABBTree();

	if (aabbTree == NULL)
		return true;

	//switching Y<->Z, adding 0.1 to account floor
	Vector3 startPoint = object->getPosition();
	startPoint.set(startPoint.getX(), startPoint.getY(), startPoint.getZ() + 0.1f);

	endPoint.set(endPoint.getX(), endPoint.getY(), endPoint.getZ() + 0.1f);

	Vector3 dir = endPoint - startPoint;
	dir.normalize();

	float distance = endPoint.distanceTo(startPoint);
	float intersectionDistance;

	Ray ray(startPoint, dir);

	Triangle* triangle = NULL;

	//nothing in the middle
	if (aabbTree->intersects(ray, distance, intersectionDistance, triangle, true))
		return false;

	Ray ray2(endPoint, Vector3(0, -1, 0));

	//check if we are in the cell with dir (0, -1, 0)
	if (!aabbTree->intersects(ray2, 64000.f, intersectionDistance, triangle, true))
		return false;

	return true;
}
bool CollisionManager::checkMovementCollision(CreatureObject* creature, float x, float z, float y, Zone* zone) {
	SortedVector<ManagedReference<QuadTreeEntry*> > closeObjects;
	zone->getInRangeObjects(x, y, 128, &closeObjects, true);

	//Vector3 rayStart(x, z + 0.25, y);
	//Vector3 rayStart(creature->getWorldPositionX(), creature->getWorldPositionZ(), creature->getPos)
	Vector3 rayStart = creature->getWorldPosition();
	rayStart.set(rayStart.getX(), rayStart.getY(), rayStart.getZ() + 0.25f);
	//Vector3 rayEnd(x + System::random(512), z + 0.3f, y + System::random(512));

	/*Vector3 rayEnd;
	rayEnd.set(targetPosition.getX(), targetPosition.getY(), targetPosition.getZ());*/

	Vector3 rayEnd(x, z + 0.25, y);

	float maxDistance = rayEnd.distanceTo(rayStart);

	if (maxDistance == 0)
		return false;

	printf("%f\n", maxDistance);

	SortedVector<IntersectionResult> results;
	results.setAllowDuplicateInsertPlan();

	printf("starting test\n");

	Triangle* triangle;

	for (int i = 0; i < closeObjects.size(); ++i) {
		SceneObject* object = dynamic_cast<SceneObject*>(closeObjects.get(i).get());

		if (object == NULL)
			continue;

		AABBTree* tree = getAABBTree(object, 255);

		if (tree == NULL)
			continue;

		Ray ray = convertToModelSpace(rayStart, rayEnd, object);

		//results.removeAll(10, 10);

		//ordered by intersection distance
		//tree->intersects(ray, maxDistance, results);

		float intersectionDistance;

		if (tree->intersects(ray, maxDistance, intersectionDistance, triangle, true)) {
			String str = object->getObjectTemplate()->getFullTemplateString();

			object->info("intersecting with me " + str, true);
			return true;
		}
	}

	return false;
}
Vector<float>* CollisionManager::getCellFloorCollision(float x, float y, CellObject* cellObject) {
	Vector<float>* collisions = NULL;

	ManagedReference<SceneObject*> rootObject = cellObject->getRootParent();

	if (rootObject == NULL)
		return NULL;

	SharedObjectTemplate* templateObject = rootObject->getObjectTemplate();

	if (templateObject == NULL)
		return NULL;

	PortalLayout* portalLayout = templateObject->getPortalLayout();

	if (portalLayout == NULL)
		return NULL;

	FloorMesh* mesh = portalLayout->getFloorMesh(cellObject->getCellNumber());

	if (mesh == NULL)
		return NULL;

	AABBTree* tree = mesh->getAABBTree();

	if (tree == NULL)
		return NULL;

	Vector3 rayStart(x, 16384.f, y);
	Vector3 rayEnd(x, -16384.f, y);

	Vector3 norm = rayEnd - rayStart;
	norm.normalize();

	Ray ray(rayStart, norm);

	SortedVector<IntersectionResult> results(3, 2);

	tree->intersects(ray, 16384 * 2, results);

	if (results.size() == 0)
		return NULL;

	collisions = new Vector<float>(results.size(), 1);

	for (int i = 0; i < results.size(); ++i) {
		float floorHeight = 16384 - results.get(i).getIntersectionDistance();

		collisions->add(floorHeight);
	}

	return collisions;
}
Beispiel #6
0
void CollisionManager::getWorldFloorCollisions(float x, float y, Zone* zone, SortedVector<IntersectionResult>* result, const Vector<QuadTreeEntry*>& inRangeObjects) {
	Vector3 rayStart(x, 16384.f, y);
	Vector3 rayEnd(x, -16384.f, y);

	for (int i = 0; i < inRangeObjects.size(); ++i) {
		SceneObject* sceno = static_cast<SceneObject*>(inRangeObjects.get(i));

		AABBTree* aabbTree = getAABBTree(sceno, 255);

		if (aabbTree == NULL)
			continue;

		Ray ray = convertToModelSpace(rayStart, rayEnd, sceno);

		aabbTree->intersects(ray, 16384 * 2, *result);
	}
}
bool CollisionManager::checkSphereCollision(const Vector3& origin, float radius, Zone* zone) {
	Vector3 sphereOrigin(origin.getX(), origin.getZ(), origin.getY());

	SortedVector<ManagedReference<QuadTreeEntry*> > objects(512, 512);
	zone->getInRangeObjects(origin.getX(), origin.getY(), 512, &objects, true);

	for (int i = 0; i < objects.size(); ++i) {
		AABBTree* aabbTree = NULL;

		SceneObject* scno = cast<SceneObject*>(objects.get(i).get());

		try {
			aabbTree = getAABBTree(scno, -1);

			if (aabbTree == NULL)
				continue;

		} catch (Exception& e) {
			aabbTree = NULL;
		} catch (...) {
			throw;
		}

		if (aabbTree != NULL) {
			//moving ray to model space

			try {
				Sphere sphere(convertToModelSpace(sphereOrigin, scno), radius);
				//structure->info("checking ray with building dir" + String::valueOf(structure->getDirectionAngle()), true);

				if (aabbTree->testCollide(sphere)) {
					return true;
				}
			} catch (Exception& e) {
				scno->error(e.getMessage());
			} catch (...) {
				throw;
			}
		}
	}

	return false;
}
bool CollisionManager::checkLineOfSightInBuilding(SceneObject* object1, SceneObject* object2, SceneObject* building) {
	SharedObjectTemplate* objectTemplate = building->getObjectTemplate();
	PortalLayout* portalLayout = objectTemplate->getPortalLayout();

	if (portalLayout == NULL)
		return true;

	//we are in model space... in cells
	Vector3 rayOrigin = object1->getPosition();
	rayOrigin.set(rayOrigin.getX(), rayOrigin.getY(), rayOrigin.getZ() + 1.f);

	Vector3 rayEnd = object2->getPosition();
	rayEnd.set(rayEnd.getX(), rayEnd.getY(), rayEnd.getZ() + 1.f);

	Vector3 direction(Vector3(rayEnd - rayOrigin));
	direction.normalize();

	float distance = rayEnd.distanceTo(rayOrigin);
	float intersectionDistance;

	Ray ray(rayOrigin, direction);
	Triangle* triangle = NULL;

	// we check interior cells
	for (int i = 1; i < portalLayout->getAppearanceTemplatesSize(); ++i) {
		MeshAppearanceTemplate* app = portalLayout->getMeshAppearanceTemplate(i);

		AABBTree* aabbTree = app->getAABBTree();

		if (aabbTree == NULL)
			continue;

		if (aabbTree->intersects(ray, distance, intersectionDistance, triangle, true))
			return false;
	}

	return true;
}
Beispiel #9
0
bool HybridModel::Build(const OPCODECREATE& create)
{
    // 1) Checkings
    if(!create.mIMesh || !create.mIMesh->IsValid())	return false;

    // Look for degenerate faces.
    udword NbDegenerate = create.mIMesh->CheckTopology();
    if(NbDegenerate)	OpcodeLog("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate);
    // We continue nonetheless....

    Release();	// Make sure previous tree has been discarded

    // 1-1) Setup mesh interface automatically
    SetMeshInterface(create.mIMesh);

    bool Status = false;
    AABBTree* LeafTree = null;
    Internal Data;

    // 2) Build a generic AABB Tree.
    mSource = new AABBTree;
    CHECKALLOC(mSource);

    // 2-1) Setup a builder. Our primitives here are triangles from input mesh,
    // so we use an AABBTreeOfTrianglesBuilder.....
    {
        AABBTreeOfTrianglesBuilder TB;
        TB.mIMesh			= create.mIMesh;
        TB.mNbPrimitives	= create.mIMesh->GetNbTriangles();
        TB.mSettings		= create.mSettings;
        TB.mSettings.mLimit	= 16;	// ### Hardcoded, but maybe we could let the user choose 8 / 16 / 32 ...
        if(!mSource->Build(&TB))	goto FreeAndExit;
    }

    // 2-2) Here's the trick : create *another* AABB tree using the leaves of the first one (which are boxes, this time)
    struct Local
    {
        // A callback to count leaf nodes
        static bool CountLeaves(const AABBTreeNode* current, udword depth, void* user_data)
        {
            if(current->IsLeaf())
            {
                Internal* Data = (Internal*)user_data;
                Data->mNbLeaves++;
            }
            return true;
        }

        // A callback to setup leaf nodes in our internal structures
        static bool SetupLeafData(const AABBTreeNode* current, udword depth, void* user_data)
        {
            if(current->IsLeaf())
            {
                Internal* Data = (Internal*)user_data;

                // Get current leaf's box
                Data->mLeaves[Data->mNbLeaves] = *current->GetAABB();

                // Setup leaf data
                udword Index = (size_t(current->GetPrimitives()) - size_t(Data->mBase)) / sizeof(size_t);
                Data->mTriangles[Data->mNbLeaves].SetData(current->GetNbPrimitives(), Index);

                Data->mNbLeaves++;
            }
            return true;
        }
    };

    // Walk the tree & count number of leaves
    Data.mNbLeaves = 0;
    mSource->Walk(Local::CountLeaves, &Data);
    mNbLeaves = Data.mNbLeaves;	// Keep track of it

    // Special case for 1-leaf meshes
    if(mNbLeaves==1)
    {
        mModelCode |= OPC_SINGLE_NODE;
        Status = true;
        goto FreeAndExit;
    }

    // Allocate our structures
    Data.mLeaves = new IceMaths::AABB[Data.mNbLeaves];
    CHECKALLOC(Data.mLeaves);
    mTriangles = new LeafTriangles[Data.mNbLeaves];
    CHECKALLOC(mTriangles);

    // Walk the tree again & setup leaf data
    Data.mTriangles	= mTriangles;
    Data.mBase		= mSource->GetIndices();
    Data.mNbLeaves	= 0;	// Reset for incoming walk
    mSource->Walk(Local::SetupLeafData, &Data);

    // Handle source indices
    {
        bool MustKeepIndices = true;
        if(create.mCanRemap)
        {
            // We try to get rid of source indices (saving more ram!) by reorganizing triangle arrays...
            // Remap can fail when we use callbacks => keep track of indices in that case (it still
            // works, only using more memory)
            if(create.mIMesh->RemapClient(mSource->GetNbPrimitives(), mSource->GetIndices()))
            {
                MustKeepIndices = false;
            }
        }

        if(MustKeepIndices)
        {
            // Keep track of source indices (from vanilla tree)
            mNbPrimitives = mSource->GetNbPrimitives();
            mIndices = new udword[mNbPrimitives];
            CopyMemory(mIndices, mSource->GetIndices(), mNbPrimitives*sizeof(udword));
        }
    }

    // Now, create our optimized tree using previous leaf nodes
    LeafTree = new AABBTree;
    CHECKALLOC(LeafTree);
    {
        AABBTreeOfAABBsBuilder TB;	// Now using boxes !
        TB.mSettings		= create.mSettings;
        TB.mSettings.mLimit	= 1;	// We now want a complete tree so that we can "optimize" it
        TB.mNbPrimitives	= Data.mNbLeaves;
        TB.mAABBArray		= Data.mLeaves;
        if(!LeafTree->Build(&TB))	goto FreeAndExit;
    }

    // 3) Create an optimized tree according to user-settings
    if(!CreateTree(create.mNoLeaf, create.mQuantized))	goto FreeAndExit;

    // 3-2) Create optimized tree
    if(!mTree->Build(LeafTree))	goto FreeAndExit;

    // Finally ok...
    Status = true;

FreeAndExit:	// Allow me this one...
    DELETESINGLE(LeafTree);

    // 3-3) Delete generic tree if needed
    if(!create.mKeepOriginal)	DELETESINGLE(mSource);

    return Status;
}
bool CollisionManager::checkShipCollision(ShipObject* ship, const Vector3& targetPosition, Vector3& collisionPoint) {
	Zone* zone = ship->getZone();

	if (zone == NULL)
		return false;

	TerrainManager* terrainManager = zone->getPlanetManager()->getTerrainManager();

	if (terrainManager->getProceduralTerrainAppearance() != NULL) {
		float height = terrainManager->getHeight(targetPosition.getX(), targetPosition.getY());

		float waterHeight = -16368.f;

		if (terrainManager->getWaterHeight(targetPosition.getY(), targetPosition.getY(), waterHeight))
			height = MAX(waterHeight, height);

		if (height > targetPosition.getZ()) {
			collisionPoint = targetPosition;
			collisionPoint.setZ(height);
			//ship->info("colliding with terrain", true);
			return true;
		}
	}

	Vector3 rayOrigin = ship->getWorldPosition();

	rayOrigin.set(rayOrigin.getX(), rayOrigin.getY(), rayOrigin.getZ());

	Vector3 rayEnd;
	rayEnd.set(targetPosition.getX(), targetPosition.getY(), targetPosition.getZ());

	float dist = rayEnd.distanceTo(rayOrigin);
	float intersectionDistance;
	Triangle* triangle = NULL;

	SortedVector<ManagedReference<QuadTreeEntry*> > objects(512, 512);
	zone->getInRangeObjects(targetPosition.getX(), targetPosition.getY(), 512, &objects, true);

	for (int i = 0; i < objects.size(); ++i) {
		AABBTree* aabbTree = NULL;

		SceneObject* scno = cast<SceneObject*>(objects.get(i).get());

		try {
			aabbTree = getAABBTree(scno, -1);

			if (aabbTree == NULL)
				continue;

		} catch (Exception& e) {
			aabbTree = NULL;
		} catch (...) {
			throw;
		}

		if (aabbTree != NULL) {
			//moving ray to model space

			try {
				Ray ray = convertToModelSpace(rayOrigin, rayEnd, scno);

				//structure->info("checking ray with building dir" + String::valueOf(structure->getDirectionAngle()), true);

				if (aabbTree->intersects(ray, dist, intersectionDistance, triangle, true)) {

					//rayOrigin.set(rayOrigin.getX(), rayOrigin.getY(), rayOrigin.getZ());
					Vector3 direction = rayEnd - rayOrigin;
					direction.normalize();
					//intersectionDistance -= 0.5f;

					collisionPoint.set(rayOrigin.getX() + (direction.getX() * intersectionDistance), rayOrigin.getY() + (direction.getY() * intersectionDistance), rayOrigin.getZ() + (direction.getZ() * intersectionDistance));
					//ship->info("colliding with building", true);

					return true;
				}
			} catch (Exception& e) {
				ship->error(e.getMessage());
			} catch (...) {
				throw;
			}


		}
	}

	return false;
}
bool CollisionManager::checkLineOfSight(SceneObject* object1, SceneObject* object2) {
	Zone* zone = object1->getZone();

	if (zone == NULL)
		return false;

	if (object2->getZone() != zone)
		return false;

	if (object1->isAiAgent() || object2->isAiAgent()) {
		Vector<WorldCoordinates>* path = PathFinderManager::instance()->findPath(object1, object2);

		if (path == NULL)
			return false;
		else
			delete path;
	}

	ManagedReference<SceneObject*> rootParent1 = object1->getRootParent();
	ManagedReference<SceneObject*> rootParent2 = object2->getRootParent();

	if (rootParent1 != NULL || rootParent2 != NULL) {
		if (rootParent1 == rootParent2) {
			return CollisionManager::checkLineOfSightInBuilding(object1, object2, rootParent1);
		} else if (rootParent1 != NULL && rootParent2 != NULL)
			return false; //different buildings
	}

	//switching z<->y, adding player height (head)
	Vector3 rayOrigin = object1->getWorldPosition();

	float heightOrigin = 1.f;
	float heightEnd = 1.f;

	Reference<SortedVector<ManagedReference<QuadTreeEntry*> >*> closeObjects = new SortedVector<ManagedReference<QuadTreeEntry*> >();
	// = object1->getCloseObjects();

	int maxInRangeObjectCount = 0;

	if (object1->getCloseObjects() == NULL) {
		object1->info("Null closeobjects vector in CollisionManager::checkLineOfSight", true);
//		closeObjectsCopy = new SortedVector<ManagedReference<QuadTreeEntry*> >();
		zone->getInRangeObjects(object1->getPositionX(), object1->getPositionY(), 512, closeObjects, true);
	} else {
		CloseObjectsVector* vec = (CloseObjectsVector*) object1->getCloseObjects();
		vec->safeCopyTo(*closeObjects);		
	}

	if (object1->isCreatureObject())
		heightOrigin = getRayOriginPoint(cast<CreatureObject*>(object1));

	if (object2->isCreatureObject())
		heightEnd = getRayOriginPoint(cast<CreatureObject*>(object2));

	rayOrigin.set(rayOrigin.getX(), rayOrigin.getY(), rayOrigin.getZ() + heightOrigin);

	Vector3 rayEnd = object2->getWorldPosition();
	rayEnd.set(rayEnd.getX(), rayEnd.getY(), rayEnd.getZ() + heightEnd);

	float dist = rayEnd.distanceTo(rayOrigin);
	float intersectionDistance;
	Triangle* triangle = NULL;

//	zone->rlock();

	try {
		for (int i = 0; i < closeObjects->size(); ++i) {
			AABBTree* aabbTree = NULL;

			SceneObject* scno = cast<SceneObject*>(closeObjects->get(i).get());

			try {
				aabbTree = getAABBTree(scno, 255);

				if (aabbTree == NULL)
					continue;

			} catch (Exception& e) {
				aabbTree = NULL;
			} catch (...) {
//				zone->runlock();

				throw;
			}

			if (aabbTree != NULL) {
				//moving ray to model space
//				zone->runlock();

				try {
					Ray ray = convertToModelSpace(rayOrigin, rayEnd, scno);

					//structure->info("checking ray with building dir" + String::valueOf(structure->getDirectionAngle()), true);

					if (aabbTree->intersects(ray, dist, intersectionDistance, triangle, true)) {
						return false;
					}
				} catch (...) {
					throw;
				}

//				zone->rlock();

			}
		}
	} catch (Exception& e) {
		Logger::console.error("unreported exception caught in bool CollisionManager::checkLineOfSight(SceneObject* object1, SceneObject* object2) ");
		Logger::console.error(e.getMessage());
	}

//	zone->runlock();

	ManagedReference<SceneObject*> parent1 = object1->getParent();
	ManagedReference<SceneObject*> parent2 = object2->getParent();

	if (parent1 != NULL || parent2 != NULL) {
		CellObject* cell = NULL;

		if (parent1 != NULL && parent1->isCellObject()) {
			cell = cast<CellObject*>(parent1.get());
		} else if (parent2 != NULL && parent2->isCellObject()) {
			cell = cast<CellObject*>(parent2.get());
		}

		if (cell != NULL) {
			return checkLineOfSightWorldToCell(rayOrigin, rayEnd, dist, cell);
		}
	}

	return true;
}
float CollisionManager::getWorldFloorCollision(float x, float y, Zone* zone, bool testWater) {
	SortedVector<ManagedReference<QuadTreeEntry*> > closeObjects;
	zone->getInRangeObjects(x, y, 128, &closeObjects, true);

	PlanetManager* planetManager = zone->getPlanetManager();

	if (planetManager == NULL)
		return 0.f;

	float height = 0;

	TerrainManager* terrainManager = planetManager->getTerrainManager();

	//need to include exclude affectors in the terrain calcs
	height = terrainManager->getHeight(x, y);

	Vector3 rayStart(x, 16384.f, y);
	Vector3 rayEnd(x, -16384.f, y);

	Triangle* triangle = NULL;

	if (testWater) {
		float waterHeight;

		if (terrainManager->getWaterHeight(x, y, waterHeight))
			if (waterHeight > height)
				height = waterHeight;
	}

	float intersectionDistance;

	for (int i = 0; i < closeObjects.size(); ++i) {
		BuildingObject* building = dynamic_cast<BuildingObject*>(closeObjects.get(i).get());

		if (building == NULL)
			continue;

		//building->getObjectTemplate()->get

		SharedObjectTemplate* templateObject = building->getObjectTemplate();

		if (templateObject == NULL)
			continue;

		PortalLayout* portalLayout = templateObject->getPortalLayout();

		if (portalLayout == NULL)
			continue;

		if (portalLayout->getFloorMeshNumber() == 0)
			continue;

		//find nearest entrance
		FloorMesh* exteriorFloorMesh = portalLayout->getFloorMesh(0); // get outside layout
		AABBTree* aabbTree = exteriorFloorMesh->getAABBTree();

		if (aabbTree == NULL)
			continue;

		Ray ray = convertToModelSpace(rayStart, rayEnd, building);

		if (aabbTree->intersects(ray, 16384 * 2, intersectionDistance, triangle, true)) {
			float floorHeight = 16384 - intersectionDistance;

			if (floorHeight > height)
				height = floorHeight;
		}
	}

	return height;
}