/// 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; }
private bool _NotInNewList(ISceneContainerObject obj) { return !_nearbyObjects.Contains(obj); }
protected override void _GetBins(ISceneContainerObject obj, out uint minBinX, out uint minBinY, out uint maxBinX, out uint maxBinY) { // Check type on object Assert.Fatal(obj is ISceneObject2D, "Invalid object passed to _GetBins"); RectangleF rectangle = ((ISceneObject2D)obj).WorldCollisionClipRectangle; _GetBinRange(rectangle.X, rectangle.X + rectangle.Width, out minBinX, out maxBinX); _GetBinRange(rectangle.Y, rectangle.Y + 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 bool _IntersectsWith(ISceneContainerObject obj, SceneContainerQueryData query);
public void Reset() { _sceneObject = null; _nextBinReference = null; _previousBinReference = null; _objectLink = null; }
/// Found Object Tests protected abstract bool _FoundObject(ISceneContainerObject obj, SceneContainerQueryData query);
/// Get Bin Range protected abstract void _GetBins(ISceneContainerObject obj, out uint minBinX, out uint minBinY, out uint maxBinX, out uint maxBinY);
protected void _CheckSceneObjectBins(ISceneContainerObject obj, SceneContainerData scd, uint minBinX, uint minBinY, uint maxBinX, uint maxBinY) { // Check everything is fine! Assert.Fatal(obj != null, "Invalid Object"); // Is the Scene Object in the container? if (scd._binReferenceChain == null) { // No, so add to the Scene Container. _AddSceneObject(obj); // Finish here. return; } // Check to see if the object has moved outside its allocated bins... // Should the bin allocation change? if (minBinX != scd._minBinX || minBinY != scd._minBinY || maxBinX != scd._maxBinX || maxBinY != scd._maxBinY) { // Yes, so remove scene object. RemoveSceneObject(obj); // Add the scene object back. _AddSceneObjectDirect(obj, minBinX, minBinY, maxBinX, maxBinY); } }
/// Add Scene Object to Container Directly (via Bin Bounds). protected void _AddSceneObjectDirect(ISceneContainerObject obj, uint minX, uint minY, uint maxX, uint maxY) { // Check everything is fine! Assert.Fatal(obj != null, "SceneContainer::addSceneObject() - Invalid Object"); SceneContainerData scd = obj.SceneContainerData; Assert.Fatal(scd._binReferenceChain == null, "SceneContainer::addSceneObject() - Object is already within a Container System!"); // Update Scene Object. scd._minBinX = minX; scd._minBinY = minY; scd._maxBinX = maxX; scd._maxBinY = maxY; // Very Large Objects got into the Scene Overflow bin. Overflow bin? if ((maxX - minX + 1) * (maxY - minY + 1) < MaxBinsPerObject) { // Not in overflow bin 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); // Allocate Scene Bin Reference. SceneContainerBinReference freeRef = _AllocateSceneBinReference(); // Insert into Scene Bin Array. if (_sceneBinArray[arrayIndex] == null) _sceneBinArray[arrayIndex] = _AllocateSceneBinReference(); freeRef._sceneObject = obj; freeRef._nextBinReference = _sceneBinArray[arrayIndex]._nextBinReference; freeRef._previousBinReference = _sceneBinArray[arrayIndex]; freeRef._objectLink = null; // Finalise the link. if (_sceneBinArray[arrayIndex]._nextBinReference != null) _sceneBinArray[arrayIndex]._nextBinReference._previousBinReference = freeRef; _sceneBinArray[arrayIndex]._nextBinReference = freeRef; // Insert Current Object Reference. // JMQ: note, the following method of insertion results in a // list ordering that is reversed from T2D. Don't think it matters. if (scd._binReferenceChain == null) { scd._binReferenceChain = freeRef; } else { freeRef._objectLink = scd._binReferenceChain; scd._binReferenceChain = freeRef; } } } } else { // Yes, so allocate Scene Bin Reference. SceneContainerBinReference freeRef = _AllocateSceneBinReference(); // Insert into Scene Overflow Bin. freeRef._sceneObject = obj; freeRef._nextBinReference = _sceneOverflowBin._nextBinReference; freeRef._previousBinReference = _sceneOverflowBin; freeRef._objectLink = null; // Finalise the link. if (_sceneOverflowBin._nextBinReference != null) _sceneOverflowBin._nextBinReference._previousBinReference = freeRef; _sceneOverflowBin._nextBinReference = freeRef; // Set Current Object Reference. scd._binReferenceChain = freeRef; } }
/// Add Scene Object to Container. protected void _AddSceneObject(ISceneContainerObject obj) { // Check everything is fine! Assert.Fatal(obj != null, "SceneContainer::addSceneObject() - Invalid Object"); SceneContainerData scd = obj.SceneContainerData; Assert.Fatal(scd._binReferenceChain == null, "SceneContainer::addSceneObject() - Object is already within a Container System!"); // Find which bins we cover. uint minX, minY, maxX, maxY; _GetBins(obj, out minX, out minY, out maxX, out maxY); // Add the Scene Object Directly. _AddSceneObjectDirect(obj, minX, minY, maxX, maxY); }
/// <summary> /// Remove Scene Object from Container. /// </summary> /// <param name="obj">Object to remove.</param> public void RemoveSceneObject(ISceneContainerObject obj) { // Check everything is fine! Assert.Fatal(obj != null, "SceneContainer::removeSceneObject() - Invalid Object"); // Get bin data SceneContainerData scd = obj.SceneContainerData; // Fetch Bin Chain Reference. SceneContainerBinReference refChain = scd._binReferenceChain; // Cut Chain from Object. scd._binReferenceChain = null; // Free Chain Scene Bin References. while (refChain != null) { // Fetch Free Reference. SceneContainerBinReference freeRef = refChain; // Move to next link. refChain = refChain._objectLink; // Remove Reference from Chain. if (freeRef._nextBinReference != null) freeRef._nextBinReference._previousBinReference = freeRef._previousBinReference; freeRef._previousBinReference._nextBinReference = freeRef._nextBinReference; // Free Reference. _FreeSceneBinReference(freeRef); } }
/// <summary> /// Checks to make sure the given object is in the right bins and updates the /// object if not. /// </summary> /// <param name="obj">Object to check.</param> public void CheckSceneObjectBins(ISceneContainerObject obj) { // Check everything is fine! Assert.Fatal(obj != null, "Invalid Object"); // Get the object's SceneContainerData SceneContainerData scd = obj.SceneContainerData; // Find which bins we cover. uint minBinX, minBinY, maxBinX, maxBinY; _GetBins(obj, out minBinX, out minBinY, out maxBinX, out maxBinY); _CheckSceneObjectBins(obj, scd, minBinX, minBinY, maxBinX, maxBinY); }