/// <summary> /// Initializes a new instance of the <see cref="Scene" /> class. /// </summary> public Scene() { _perFrameData = new CBPerFrame(); this.TransformMode2D = Graphics2DTransformMode.Custom; this.CustomTransform2D = Matrix3x2.Identity; this.VirtualScreenSize2D = new SizeF(); _sceneComponents = new SceneComponentFlyweight(this); _sceneLayers = new UnsafeList <SceneLayer>(); _sceneLayers.Add(new SceneLayer(DEFAULT_LAYER_NAME, this)); this.Layers = new ReadOnlyCollection <SceneLayer>(_sceneLayers); _drawing2DLayers = new List <Custom2DDrawingLayer>(); _asyncInvokesBeforeUpdate = new ConcurrentQueue <Action>(); _asyncInvokesUpdateBesideRendering = new ConcurrentQueue <Action>(); _registeredResourceDicts = new IndexBasedDynamicCollection <ResourceDictionary>(); _registeredViews = new IndexBasedDynamicCollection <ViewInformation>(); _renderParameters = new IndexBasedDynamicCollection <SceneRenderParameters>(); this.CachedUpdateState = new SceneRelatedUpdateState(); // Try to initialize this scene object this.InitializeResourceDictionaries(); }
/// <summary> /// Performs "update-beside-render" for this layer. /// </summary> /// <param name="updateState">Current update state.</param> internal void UpdateBesideRender(SceneRelatedUpdateState updateState) { updateState.SceneLayer = this; _isInUpdateBeside = true; try { // Now update all view specific references foreach (var actViewSubset in _viewSubsets) { actViewSubset.UpdateBesideRender(updateState, _sceneObjectsForSingleUpdateCall); } } finally { updateState.SceneLayer = null; _isInUpdateBeside = false; // Some work after whole update processes _sceneObjectsForSingleUpdateCall.Clear(); } }
/// <summary> /// Update logic beside rendering. /// </summary> /// <param name="updateState">The update state.</param> /// <param name="sceneObjectsForSingleUpdateCall">A collection of scene objects for a single update call. These are normally a list of newly inserted static objects.</param> internal void UpdateBesideRender(SceneRelatedUpdateState updateState, Queue <SceneObject> sceneObjectsForSingleUpdateCall) { var filters = this.ViewInformation.FiltersInternal; _tmpChangedVisibilities.Clear(); // Perform some pre-logic on filters var anyFilterChanged = false; foreach (var actFilter in filters) { actFilter.SetEnvironmentData(_sceneLayer, this.ViewInformation); if (actFilter.ConfigurationChangedInternal) { anyFilterChanged = true; } } // Check whether we have to update all objects var refreshAllObjects = this.ViewInformation.Camera.StateChanged || anyFilterChanged; // Perform filtering for all standard objects var allObjects = _sceneLayer.ObjectsInternal; var allObjectsLength = allObjects.Count; if (allObjectsLength > 0) { var allObjectsArray = allObjects.BackingArray; for (var loop = 0; loop < allObjectsLength; loop++) { var actObject = allObjectsArray[loop]; if (actObject == null) { continue; } // Don't handle static objects here if we don't want to handle them if (!refreshAllObjects) { switch (actObject.VisibilityTestMethod) { case VisibilityTestMethod.ByObjectFilters: if (actObject.IsStatic) { continue; } if ((!actObject.TransformationChanged) && (!actObject.VisibilityTestMethodChanged)) { continue; } break; } } // Perform culling this.PerformViewDependentFiltering(actObject, filters); } } // Update objects which are passed for a single update call (normally newly inserted static objects) var singleUpdateCallCount = sceneObjectsForSingleUpdateCall.Count; if (!refreshAllObjects && singleUpdateCallCount > 0) { var singleUpdateArray = sceneObjectsForSingleUpdateCall.GetBackingArray(); for (var loop = 0; loop < singleUpdateCallCount; loop++) { // Perform culling this.PerformViewDependentFiltering(singleUpdateArray[loop], filters); } } // Handle changed visibility in standard update logic if (_tmpChangedVisibilities.Count > 0) { var startingScene = _scene; _changedVisibilitiesAction = () => { if (_disposed) { return; } if (startingScene != _scene) { return; } foreach (var actChangedVisibility in _tmpChangedVisibilities) { // Check whether this object is still here.. if (actChangedVisibility.Item1.Scene != _scene) { continue; } if (actChangedVisibility.Item1.SceneLayer != _sceneLayer) { continue; } // Handle changed visibility this.HandleObjectVisibilityChanged( actChangedVisibility.Item1, actChangedVisibility.Item3); } }; } }
/// <summary> /// Executes view update using the given update state object. /// </summary> /// <param name="updateState">The update state.</param> internal void UpdateForView(SceneRelatedUpdateState updateState) { if (_disposed) { throw new ObjectDisposedException("ViewRelatedLayerSubset"); } var anyOrderChanges = false; var camera = this.ViewInformation.Camera; _objectsPassTransparentRender.Subscriptions.Sort((left, right) => { var leftSpacial = left.SceneObject as SceneSpacialObject; var rightSpacial = right.SceneObject as SceneSpacialObject; if (leftSpacial != null && rightSpacial != null) { var leftDistance = (camera.Position - leftSpacial.Position).LengthSquared(); var rightDistance = (camera.Position - rightSpacial.Position).LengthSquared(); anyOrderChanges = true; return(rightDistance.CompareTo(leftDistance)); } if (leftSpacial != null) { anyOrderChanges = true; return(-1); } if (rightSpacial != null) { anyOrderChanges = true; return(1); } { return(0); } }); if (anyOrderChanges) { // Synchronize ordering changes with corresponding scene object for (var loop = 0; loop < _objectsPassTransparentRender.Subscriptions.Count; loop++) { var actSubscription = _objectsPassTransparentRender.Subscriptions[loop]; actSubscription.SubscriptionIndex = loop; actSubscription.SceneObject.UpdateSubscription(actSubscription, this); _objectsPassTransparentRender.Subscriptions[loop] = actSubscription; } } // Update all objects related to this view _isSubscribeUnsubscribeAllowed = true; try { // Update subscriptions based on visibility check result if (_changedVisibilitiesAction != null) { _changedVisibilitiesAction(); _changedVisibilitiesAction = null; } // Unsubscribe all invalid objects while (_invalidObjectsToDeregister.Count > 0) { var actInvalidObject = _invalidObjectsToDeregister.Dequeue(); actInvalidObject.UnsubsribeFromAllPasses(this); } // Update subscriptions based on object state var allObjects = _sceneLayer.ObjectsInternal; var allObjectsLength = allObjects.Count; _countVisibleObjects = 0; for (var loop = 0; loop < allObjectsLength; loop++) { var actSceneObject = allObjects[loop]; if (_invalidObjects.ContainsKey(actSceneObject)) { continue; } if (actSceneObject.IsLayerViewSubsetRegistered(ViewIndex) && actSceneObject.IsVisible(this.ViewInformation)) { actSceneObject.UpdateForView(updateState, this); _countVisibleObjects++; } } } finally { _isSubscribeUnsubscribeAllowed = false; } // Reorganize subscriptions if there is anything unsubscribed if (_anythingUnsubscribed) { _anythingUnsubscribed = false; foreach (var actPassProperties in _objectsPerPass) { if (actPassProperties.UnsubscribeCallCount <= 0) { continue; } // Variables for consistency checking var givenUnsubscribeCount = actPassProperties.UnsubscribeCallCount; var trueUnsubscribeCount = 0; // Handle case where we have unsubscribed some // => Build new subscription list and ignore all with 'IsSubscribed' == false var newSubscriptionList = actPassProperties.SubscriptionsTemp; for (var loop = 0; loop < actPassProperties.Subscriptions.Count; loop++) { var actSubscription = actPassProperties.Subscriptions[loop]; if (!actSubscription.IsSubscribed) { actSubscription.SceneObject.ClearSubscriptionsWithoutUnsubscribeCall(this, actSubscription); trueUnsubscribeCount++; continue; } // AddObject this item to new subscription list actSubscription.SubscriptionIndex = newSubscriptionList.Count; newSubscriptionList.Add(actSubscription); actSubscription.SceneObject.UpdateSubscription(actSubscription, this); } actPassProperties.SubscriptionsTemp = actPassProperties.Subscriptions; actPassProperties.SubscriptionsTemp.Clear(); actPassProperties.Subscriptions = newSubscriptionList; actPassProperties.UnsubscribeCallCount = 0; // Check for consistency: Does unsubscribe-count match true unsubscriptions using IsSubscribed flag if (givenUnsubscribeCount != trueUnsubscribeCount) { throw new SeeingSharpException("Inconsistency: Given unsubscribe count does not mach true count of unsubscriptions!"); } } } }
protected sealed override void UpdateForViewInternal(SceneRelatedUpdateState updateState, ViewRelatedSceneLayerSubset layerViewSubset) { // No resources, so nothing to be done }
protected override void UpdateInternal(SceneRelatedUpdateState updateState) { }
internal override void UpdateInternal(SceneRelatedUpdateState updateState, ViewInformation?correspondingView, object?componentContext) { this.Update(updateState, correspondingView); }
/// <summary> /// This update method gets called on each update pass for each scenes /// this component is attached to. /// </summary> /// <param name="updateState">Current update state.</param> /// <param name="correspondingView">The view which attached this component (may be null).</param> protected virtual void Update(SceneRelatedUpdateState updateState, ViewInformation?correspondingView) { }
/// <summary> /// Updates the layer. /// </summary> /// <param name="updateState">Current update state.</param> internal void Update(SceneRelatedUpdateState updateState) { updateState.SceneLayer = this; _isInUpdate = true; try { // Update all objects which are registered for initial update call var initialUpdateCallCount = _sceneObjectsForSingleUpdateCall.Count; if (initialUpdateCallCount > 0) { var initialUpdateCallItems = _sceneObjectsForSingleUpdateCall.GetBackingArray(); for (var loop = 0; loop < initialUpdateCallCount; loop++) { initialUpdateCallItems[loop].Update(updateState); } } // Call default update method for each object var updateListLength = _sceneObjectsNotStatic.Count; var updateList = _sceneObjectsNotStatic.BackingArray; for (var actIndex = 0; actIndex < updateListLength; actIndex++) { var actObject = updateList[actIndex]; if (actObject == null) { continue; } if (!actObject.HasParent) { actObject.Update(updateState); } } // Call overall updates on all objects for (var actIndex = 0; actIndex < updateListLength; actIndex++) { var actObject = updateList[actIndex]; if (actObject == null) { continue; } if (!actObject.HasParent) { actObject.UpdateOverall(updateState); } } // Now update all view specific references foreach (var actViewSubset in _viewSubsets) { actViewSubset.UpdateForView(updateState); } } finally { updateState.SceneLayer = null; _isInUpdate = false; } }
/// <summary> /// Internal method for updating all scene components. /// </summary> /// <param name="updateState">Current update state.</param> internal void UpdateSceneComponents(SceneRelatedUpdateState updateState) { // Update all components var attachedComponentsCount = _attachedComponents.Count; for (var loop = 0; loop < attachedComponentsCount; loop++) { _attachedComponents[loop].Component.UpdateInternal( updateState, _attachedComponents[loop].CorrespondingView, _attachedComponents[loop].Context); } // Attach all components which are coming in while (_componentRequests.TryDequeue(out var actRequest)) { SceneComponentInfo actComponent; int actComponentIndex; switch (actRequest.RequestType) { case SceneComponentRequestType.Attach: if (actRequest.Component == null) { continue; } if (this.TryGetAttachedComponent( actRequest.Component, actRequest.CorrespondingView, out actComponent, out actComponentIndex)) { // We've already attached this component, so skip this request continue; } // Trigger removing of all components with the same group like the new one // (new components replace old components with same group name) if (!string.IsNullOrEmpty(actRequest.Component.ComponentGroup)) { foreach (var actObsoleteComponent in this.GetExistingComponentsByGroup( actRequest.Component.ComponentGroup, actRequest.Component.IsViewSpecific ? actRequest.CorrespondingView : null)) { _componentRequests.Enqueue(new SceneComponentRequest { RequestType = SceneComponentRequestType.Detach, Component = actObsoleteComponent.Component, CorrespondingView = actObsoleteComponent.CorrespondingView }); } } var actManipulator = new SceneManipulator(_owner); actManipulator.IsValid = true; try { var newRegisteredComponentInfo = new SceneComponentInfo { Component = actRequest.Component, CorrespondingView = actRequest.CorrespondingView, Context = actRequest.Component.AttachInternal( actManipulator, actRequest.CorrespondingView) }; // Register the component on local list of attached ones _attachedComponents.Add(newRegisteredComponentInfo); } finally { actManipulator.IsValid = false; } break; case SceneComponentRequestType.Detach: if (actRequest.Component == null) { continue; } if (!this.TryGetAttachedComponent( actRequest.Component, actRequest.CorrespondingView, out actComponent, out actComponentIndex)) { // We don't have any component that is like the requested one continue; } actManipulator = new SceneManipulator(_owner); actManipulator.IsValid = true; try { actComponent.Component.DetachInternal( actManipulator, actComponent.CorrespondingView, actComponent.Context); // RemoveObject the component _attachedComponents.RemoveAt(actComponentIndex); } finally { actManipulator.IsValid = false; } break; case SceneComponentRequestType.DetachAll: while (_attachedComponents.Count > 0) { actManipulator = new SceneManipulator(_owner) { IsValid = true }; try { actComponent = _attachedComponents[0]; actComponent.Component.DetachInternal( actManipulator, actComponent.CorrespondingView, actComponent.Context); // RemoveObject the component _attachedComponents.RemoveAt(0); } finally { actManipulator.IsValid = false; } } break; default: throw new SeeingSharpException($"Unknown {nameof(SceneComponentRequestType)}: {actRequest.RequestType}"); } } }