/// Found Object Tests protected override bool _FoundObject(ISceneContainerObject obj, SceneContainerQueryData queryData) { // Check type on objects Assert.Fatal(obj is ISceneObject2D, "Invalid object passed to _FoundObject"); Assert.Fatal(queryData is T2DSceneContainerQueryData, "Invalid query data object passed to _FoundObject"); ISceneObject2D sceneObject = (ISceneObject2D)obj; // this is slow due to not inlined properties below, would be better to use T2DSceneObject, but lights can be in the graph and are not scene objects T2DSceneContainerQueryData query = (T2DSceneContainerQueryData)queryData; if (sceneObject.Visible || query.FindInvisible) { // Check if the Group / Layer masks match. int layerMask = 1 << sceneObject.Layer; if ((layerMask & query._layerMask) != 0) { // Yes, so fetch Clip Rectangle. if (_IntersectsWith(sceneObject, query)) return true; } } return false; }
protected override void _GetBins(SceneContainerQueryData iQueryData, out uint minBinX, out uint minBinY, out uint maxBinX, out uint maxBinY) { // Check type on query data object Assert.Fatal(iQueryData is T2DSceneContainerQueryData, "Invalid query data object passed to _GetBins"); T2DSceneContainerQueryData query = (T2DSceneContainerQueryData)iQueryData; _GetBinRange(query.Rectangle.Point.X, query.Rectangle.Point.X + query.Rectangle.Width, out minBinX, out maxBinX); _GetBinRange(query.Rectangle.Point.Y, query.Rectangle.Point.Y + query.Rectangle.Height, out minBinY, out maxBinY); }
protected override bool _IntersectsWith(ISceneContainerObject obj, SceneContainerQueryData iQueryData) { // Check type on objects Assert.Fatal(obj is ISceneObject2D, "Invalid object passed to _FoundObject"); Assert.Fatal(iQueryData is T2DSceneContainerQueryData, "Invalid query data object passed to _FoundObject"); ISceneObject2D sceneObject = (ISceneObject2D)obj; T2DSceneContainerQueryData query = (T2DSceneContainerQueryData)iQueryData; return _IntersectsWith(sceneObject, query); }
protected abstract void _GetBins(SceneContainerQueryData query, out uint minBinX, out uint minBinY, out uint maxBinX, out uint maxBinY);
protected abstract bool _IntersectsWith(ISceneContainerObject obj, SceneContainerQueryData query);
/// Found Object Tests protected abstract bool _FoundObject(ISceneContainerObject obj, SceneContainerQueryData query);
protected void _FindObjectsInefficientHelper(SceneContainerQueryData query, SceneContainerBinReference bin, ref int objectsFound) { SceneContainerBinReference walk = bin; while (walk != null) { if (walk._sceneObject != null) { // Have we dealt with this object already? if (walk._sceneObject.SceneContainerData._sequenceKey == _currentSequenceKey) { // Move to next bin reference. walk = walk._nextBinReference; continue; } walk._sceneObject.SceneContainerData._sequenceKey = _currentSequenceKey; if (_IntersectsWith(walk._sceneObject, query)) objectsFound++; } walk = walk._nextBinReference; } }
protected void _FindInBin(SceneContainerBinReference bin, SceneContainerQueryData queryData) { object ignoreObject = queryData._ignoreObject; object[] ignoredObjects = queryData._ignoreObjects; ulong typebits = queryData._objectTypes._bits; // Step through Chain. while (bin != null) { // Fetch Scene Object Reference. ISceneContainerObject sceneObjectRef = bin._sceneObject; // Note: the following tries to get the object type directly from a TorqueObject rather than // going through the ISceneContainerObject interface. This ends up being a LOT (a LOT) faster // for T2DSceneObjects even though it adds a branch. It won't help when the object isn't a // TorqueObject as is the case of our T3D code, but we can consider other measures if that // becomes a problem (like making bin ref's point to SceneContainerData instead of scene object // and adding a pointer to iscene object in SceneContainerData as well as object type, but current // scheme is simpler and more effective for T2D). TorqueObject tobj = sceneObjectRef as TorqueObject; ulong ourType = tobj == null ? sceneObjectRef.ObjectType._bits : tobj._objectType; if ((ourType & typebits) == 0) { // Move to next bin reference. bin = bin._nextBinReference; continue; } // get the scene container data for the object SceneContainerData scd = sceneObjectRef.SceneContainerData; // Have we dealt with this object already? if (scd._sequenceKey == _currentSequenceKey) { // Move to next bin reference. bin = bin._nextBinReference; continue; } // Set the container sequence key to indicate that we've dealt with this object. scd._sequenceKey = _currentSequenceKey; // Check for ignored objects bool ignored = false; if (ignoreObject == sceneObjectRef) { ignored = true; } else if (ignoredObjects != null) { foreach (object o in ignoredObjects) if (o == sceneObjectRef) { ignored = true; break; } } // Is the Object Not being ignored? if (!ignored) _FoundObject(sceneObjectRef, queryData); // Move to next bin reference. bin = bin._nextBinReference; } }
/// <summary> /// Inefficient, but always finds all the appropriate objects. Good for verification of FindObjects. /// </summary> /// <param name="query"></param> /// <returns></returns> protected internal int _FindObjectsInefficiently(SceneContainerQueryData query) { int objectsFound = 0; _currentSequenceKey++; foreach (SceneContainerBinReference binRef in _sceneBinArray) if (binRef != null) _FindObjectsInefficientHelper(query, binRef, ref objectsFound); _FindObjectsInefficientHelper(query, _sceneOverflowBin, ref objectsFound); return objectsFound; }
/// <summary> /// Perform a spatial query on the container. Fields on the query will determine /// which objects are found. /// </summary> /// <param name="queryData">Query to perform.</param> public void FindObjects(SceneContainerQueryData queryData) { // Find which bins are covered. uint minX, minY, maxX, maxY; _GetBins(queryData, out minX, out minY, out maxX, out maxY); // Change the Current Sequence Key. _currentSequenceKey++; // ******************************************************************************* // Fetch Standard Container Bins. // ******************************************************************************* SceneContainerBinReference binChain = null; // Step through Bin ranges. for (uint y = minY; y <= maxY; y++) { // Calculate Bin Position. uint offsetY = (y % _binCount) * _binCount; for (uint x = minX; x <= maxX; x++) { // Calculate Bin Position. uint arrayIndex = offsetY + (x % _binCount); // Fetch Bin Chain. if (_sceneBinArray[arrayIndex] == null) continue; // Bin is empty, continue binChain = _sceneBinArray[arrayIndex]._nextBinReference; _FindInBin(binChain, queryData); } } // ******************************************************************************* // Fetch Overflow Bin Chain. // ******************************************************************************* _FindInBin(_sceneOverflowBin._nextBinReference, queryData); #if TORQUE_SCENECONTAINER_DEBUG int count2 = _FindObjectsInefficiently(iQueryData); Assert.Fatal(count2 == objectsFound, "doh!"); #endif }