private async Task Execute() { MicrothreadLocalDatabases.MountCommonDatabase(); while (game.IsRunning) { await game.Script.NextFrame(); if (IsActive) { // TODO: code largely duplicated in EditorGameMaterialHighlightService. Factorize! var screenSize = new Vector2(game.GraphicsDevice.Presenter.BackBuffer.Width, game.GraphicsDevice.Presenter.BackBuffer.Height); if (game.Input.IsMouseButtonPressed(MouseButton.Left)) { mouseMoveAccumulator = Vector2.Zero; } mouseMoveAccumulator += new Vector2(Math.Abs(game.Input.MouseDelta.X * screenSize.X), Math.Abs(game.Input.MouseDelta.Y * screenSize.Y)); if (IsMouseAvailable && game.Input.IsMouseButtonReleased(MouseButton.Left) && !game.Input.IsMouseButtonDown(MouseButton.Right)) { if (mouseMoveAccumulator.Length() >= TransformationGizmo.TransformationStartPixelThreshold) { continue; } var addToSelection = game.Input.IsKeyDown(Keys.LeftCtrl) || game.Input.IsKeyDown(Keys.RightCtrl); var entityUnderMouse = Gizmos.GetContentEntityUnderMouse(); if (entityUnderMouse == null) { var entityPicked = Pick(); entityUnderMouse = entityPicked.Entity; } // Ctrl + click on an empty area: do nothing if (entityUnderMouse == null && addToSelection) { continue; } // Click on an empty area: clear selection if (entityUnderMouse == null) { Clear(); } // Click on an entity: select this entity else if (!addToSelection) { Set(entityUnderMouse); } // Ctrl + click on an already selected entity: unselect this entity else if (Contains(entityUnderMouse)) { Remove(entityUnderMouse); } // Ctrl + click on an entity: add this entity to the selection else { Add(entityUnderMouse); } } } } }
/// <summary> /// The micro-thread in charge of processing the thumbnail build requests and creating the thumbnails. /// </summary> private ResultStatus ProcessThumbnailRequests(ThumbnailBuildRequest request) { var status = ResultStatus.Successful; // Global lock so that only one rendering happens at the same time lock (lockObject) { try { lock (AssetBuilderService.OutOfMicrothreadDatabaseLock) { MicrothreadLocalDatabases.MountCommonDatabase(); // set the master output var renderTarget = GraphicsContext.Allocator.GetTemporaryTexture2D(request.Size.X, request.Size.Y, request.ColorSpace == ColorSpace.Linear ? PixelFormat.R8G8B8A8_UNorm_SRgb : PixelFormat.R8G8B8A8_UNorm, TextureFlags.ShaderResource | TextureFlags.RenderTarget); var depthStencil = GraphicsContext.Allocator.GetTemporaryTexture2D(request.Size.X, request.Size.Y, PixelFormat.D24_UNorm_S8_UInt, TextureFlags.DepthStencil); try { // Fake presenter // TODO GRAPHICS REFACTOR: Try to remove that GraphicsDevice.Presenter = new RenderTargetGraphicsPresenter(GraphicsDevice, renderTarget, depthStencil.ViewFormat); // Always clear the state of the GraphicsDevice to make sure a scene doesn't start with a wrong setup GraphicsCommandList.ClearState(); // Setup the color space when rendering a thumbnail GraphicsDevice.ColorSpace = request.ColorSpace; // render the thumbnail thumbnailScene.Children.Add(request.Scene); // Store the graphics compositor to use, so we can dispose it when disposing this ThumbnailGenerator thumbnailGraphicsCompositors.Add(request.GraphicsCompositor); sceneSystem.GraphicsCompositor = request.GraphicsCompositor; // Render once to setup render processors // TODO GRAPHICS REFACTOR: Should not require two rendering GraphicsContext.ResourceGroupAllocator.Reset(GraphicsContext.CommandList); gameSystems.Draw(nullGameTime); // Draw gameSystems.Update(nullGameTime); GraphicsContext.ResourceGroupAllocator.Reset(GraphicsContext.CommandList); gameSystems.Draw(nullGameTime); // write the thumbnail to the file using (var thumbnailImage = renderTarget.GetDataAsImage(GraphicsCommandList)) using (var outputImageStream = request.FileProvider.OpenStream(request.Url, VirtualFileMode.Create, VirtualFileAccess.Write)) { request.PostProcessThumbnail?.Invoke(thumbnailImage); ThumbnailBuildHelper.ApplyThumbnailStatus(thumbnailImage, request.DependencyBuildStatus); thumbnailImage.Save(outputImageStream, ImageFileType.Png); request.Logger.Info($"Thumbnail creation successful [{request.Url}] to ({thumbnailImage.Description.Width}x{thumbnailImage.Description.Height},{thumbnailImage.Description.Format})"); } } finally { // Cleanup the scene thumbnailScene.Children.Clear(); sceneSystem.GraphicsCompositor = null; GraphicsContext.Allocator.ReleaseReference(depthStencil); GraphicsContext.Allocator.ReleaseReference(renderTarget); } MicrothreadLocalDatabases.UnmountDatabase(); } } catch (Exception e) { status = ResultStatus.Failed; request.Logger.Error("An exception occurred while processing thumbnail request.", e); } } return(status); }
protected override Task <bool> Initialize(EditorServiceGame editorGame) { game = (EntityHierarchyEditorGame)editorGame; editorScene = game.EditorScene; var transformMainGizmoRenderStage = new RenderStage("TransformGizmoOpaque", "Main"); var transformTransparentGizmoRenderStage = new RenderStage("TransformGizmoTransparent", "Main") { SortMode = new BackToFrontSortMode() }; game.EditorSceneSystem.GraphicsCompositor.RenderStages.Add(transformMainGizmoRenderStage); game.EditorSceneSystem.GraphicsCompositor.RenderStages.Add(transformTransparentGizmoRenderStage); var meshRenderFeature = game.EditorSceneSystem.GraphicsCompositor.RenderFeatures.OfType <MeshRenderFeature>().First(); // Reset all stages for TransformationGrizmoGroup meshRenderFeature.RenderStageSelectors.Add(new SimpleGroupToRenderStageSelector { RenderGroup = TransformationGizmo.TransformationGizmoGroupMask, }); meshRenderFeature.RenderStageSelectors.Add(new MeshTransparentRenderStageSelector { EffectName = EditorGraphicsCompositorHelper.EditorForwardShadingEffect, RenderGroup = TransformationGizmo.TransformationGizmoGroupMask, OpaqueRenderStage = transformMainGizmoRenderStage, TransparentRenderStage = transformTransparentGizmoRenderStage, }); meshRenderFeature.PipelineProcessors.Add(new MeshPipelineProcessor { TransparentRenderStage = transformTransparentGizmoRenderStage }); var editorCompositor = (EditorTopLevelCompositor)game.EditorSceneSystem.GraphicsCompositor.Game; editorCompositor.PostGizmoCompositors.Add(new ClearRenderer { ClearFlags = ClearRendererFlags.DepthOnly }); editorCompositor.PostGizmoCompositors.Add(new SingleStageRenderer { RenderStage = transformMainGizmoRenderStage, Name = "Transform Opaque Gizmos" }); editorCompositor.PostGizmoCompositors.Add(new SingleStageRenderer { RenderStage = transformTransparentGizmoRenderStage, Name = "Transform Transparent Gizmos" }); TranslationGizmo = new TranslationGizmo(); RotationGizmo = new RotationGizmo(); ScaleGizmo = new ScaleGizmo(); TranslationGizmo.TransformationEnded += OnGizmoTransformationFinished; ScaleGizmo.TransformationEnded += OnGizmoTransformationFinished; RotationGizmo.TransformationEnded += OnGizmoTransformationFinished; transformationGizmos.Add(TranslationGizmo); transformationGizmos.Add(RotationGizmo); transformationGizmos.Add(ScaleGizmo); Services.Get <IEditorGameEntitySelectionService>().SelectionUpdated += UpdateModifiedEntitiesList; // Initialize and add the Gizmo entities to the gizmo scene MicrothreadLocalDatabases.MountCommonDatabase(); // initialize the gizmo foreach (var gizmo in transformationGizmos) { gizmo.Initialize(game.Services, editorScene); } // Deactivate all transformation gizmo by default foreach (var gizmo in transformationGizmos) { gizmo.IsEnabled = false; } // set the default active transformation gizmo ActiveTransformationGizmo = TranslationGizmo; // Start update script (with priority 1 so that it happens after UpdateModifiedEntitiesList is called -- which usually happens from a EditorGameComtroller.PostAction() which has a default priority 0) game.Script.AddTask(Update, 1); return(Task.FromResult(true)); }
/// <inheritdoc /> protected override async Task LoadContent() { await base.LoadContent(); // mount the common database in this micro-thread to have access to the built effects, etc. MicrothreadLocalDatabases.MountCommonDatabase(); // Create fallback effect to use when material is still loading fallbackColorMaterial = Material.New(GraphicsDevice, new MaterialDescriptor { Attributes = { Diffuse = new MaterialDiffuseMapFeature(new ComputeTextureColor()), DiffuseModel = new MaterialDiffuseLambertModelFeature() } }); fallbackTextureMaterial = Material.New(GraphicsDevice, new MaterialDescriptor { Attributes = { Diffuse = new MaterialDiffuseMapFeature(new ComputeTextureColor { FallbackValue = null }), // Do not use fallback value, we want a DiffuseMap DiffuseModel = new MaterialDiffuseLambertModelFeature() } }); // Listen to all Renderer Initialized to plug dynamic effect compilation RenderContext.GetShared(Services).RendererInitialized += SceneGameRendererInitialized; // Update the marker render target setter viewport //OnClientSizeChanged(this, EventArgs.Empty); // Initialize the services var initialized = new List <IEditorGameService>(); foreach (var service in EditorServices.OrderByDependency()) { // Check that the current service dependencies have been initialized foreach (var dependency in service.Dependencies) { if (!initialized.Any(x => dependency.IsInstanceOfType(x))) { throw new InvalidOperationException($"The service [{service.GetType().Name}] requires a service of type [{dependency.Name}] to be initialized first."); } } if (await service.InitializeService(this)) { initialized.Add(service); } var mouseService = service as EditorGameMouseServiceBase; mouseService?.RegisterMouseServices(EditorServices); } // TODO: Maybe define this scene default graphics compositor as an asset? var defaultGraphicsCompositor = GraphicsCompositorHelper.CreateDefault(true, EditorGraphicsCompositorHelper.EditorForwardShadingEffect); // Add UI (engine doesn't depend on it) defaultGraphicsCompositor.RenderFeatures.Add(new UIRenderFeature { RenderStageSelectors = { new SimpleGroupToRenderStageSelector { RenderStage = defaultGraphicsCompositor.RenderStages.First(x => x.Name == "Transparent"), EffectName = "Test", RenderGroup = GizmoBase.DefaultGroupMask } } }); // Make the game switch to this graphics compositor UpdateGraphicsCompositor(defaultGraphicsCompositor); gameContentLoadedTaskSource.SetResult(true); }