/// <inheritdoc />
        protected override void OnRenderState()
        {
            // We're not calling the base implementation, because the default is to
            // render the scene from the view of an editing camera. The Game View, however,
            // is in the special position to render the actual game and completely ignore
            // any editing camera.
            //
            // base.OnRenderState();

            Point2 clientSize = new Point2(this.RenderableControl.ClientSize.Width, this.RenderableControl.ClientSize.Height);
            Point2 targetSize = this.TargetRenderSize;
            Rect   windowRect = this.LocalGameWindowRect;

            Vector2 imageSize;
            Rect    viewportRect;

            DualityApp.CalculateGameViewport(targetSize, out viewportRect, out imageSize);

            // Render the game view background using a background color matching editor UI,
            // so users can discern between an area that isn't rendered to and a rendered
            // area of the game that happens to be black or outside the game viewport.
            DrawDevice.RenderVoid(new Rect(clientSize), new ColorRgba(64, 64, 64));

            if (this.UseOffscreenBuffer)
            {
                // Render the scene to an offscreen buffer of matching size first
                this.SetupOutputRenderTarget();
                DualityApp.Render(this.outputTarget, viewportRect, imageSize);

                // Blit the offscreen buffer to the window area
                this.SetupBlitDevice();
                this.blitDevice.TargetSize   = clientSize;
                this.blitDevice.ViewportRect = new Rect(clientSize);

                BatchInfo blitMaterial = this.blitDevice.RentMaterial();
                blitMaterial.Technique   = DrawTechnique.Solid;
                blitMaterial.MainTexture = this.outputTexture;

                TargetResize blitResize = this.TargetSizeFitsClientArea ?
                                          TargetResize.None :
                                          TargetResize.Fit;

                this.blitDevice.PrepareForDrawcalls();
                this.blitDevice.AddFullscreenQuad(blitMaterial, blitResize);
                this.blitDevice.Render();
            }
            else
            {
                Rect windowViewportRect = new Rect(
                    windowRect.X + viewportRect.X,
                    windowRect.Y + viewportRect.Y,
                    viewportRect.W,
                    viewportRect.H);

                // Render the scene centered into the designated viewport area
                this.CleanupRenderTarget();
                DrawDevice.RenderVoid(windowRect);
                DualityApp.Render(null, windowViewportRect, imageSize);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Resizes rect boundaries to match the specified target size.
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="baseSize"></param>
        /// <param name="targetSize"></param>
        /// <returns></returns>
        public static Vector2 Apply(this TargetResize mode, Vector2 baseSize, Vector2 targetSize)
        {
            Vector2 sizeRatio;
            float   scale;

            switch (mode)
            {
            default:
            case TargetResize.None:
                return(baseSize);

            case TargetResize.Stretch:
                return(targetSize);

            case TargetResize.Fit:
                if (baseSize == Vector2.Zero)
                {
                    baseSize = Vector2.One;
                }
                sizeRatio = targetSize / baseSize;
                if (sizeRatio.Y < sizeRatio.X)
                {
                    scale = sizeRatio.Y;
                }
                else
                {
                    scale = sizeRatio.X;
                }
                return(baseSize * scale);

            case TargetResize.Fill:
                if (baseSize == Vector2.Zero)
                {
                    baseSize = Vector2.One;
                }
                sizeRatio = targetSize / baseSize;
                if (sizeRatio.Y > sizeRatio.X)
                {
                    scale = sizeRatio.Y;
                }
                else
                {
                    scale = sizeRatio.X;
                }
                return(baseSize * scale);
            }
        }
Beispiel #3
0
        protected override void OnRenderScene(Scene scene, ContentRef <RenderTarget> target, Rect viewportRect, Vector2 imageSize)
        {
            // Render the entire scene into an internal offscreen target matching settings
            this.SetupSceneTarget();
            base.OnRenderScene(
                scene,
                this.sceneTarget,
                new Rect(this.sceneTarget.Size),
                this.renderingSize);

            // Ensure we have a drawing device for screen space operations
            if (this.drawDevice == null)
            {
                this.drawDevice            = new DrawDevice();
                this.drawDevice.Projection = ProjectionMode.Screen;
            }

            // Configure the drawing device to match parameters and settings
            this.drawDevice.Target       = target;
            this.drawDevice.TargetSize   = imageSize;
            this.drawDevice.ViewportRect = viewportRect;

            // Blit the results to screen
            BatchInfo blitMaterial = this.drawDevice.RentMaterial();

            blitMaterial.Technique   = DrawTechnique.Solid;
            blitMaterial.MainTexture = this.sceneTargetTex;
            bool sceneTargetFitsOutput =
                this.sceneTarget.Size.X <= imageSize.X &&
                this.sceneTarget.Size.Y <= imageSize.Y;
            TargetResize blitResize = sceneTargetFitsOutput ?
                                      TargetResize.None :
                                      TargetResize.Fit;

            this.drawDevice.ClearFlags = ClearFlag.All;
            this.drawDevice.PrepareForDrawcalls();
            this.drawDevice.AddFullscreenQuad(blitMaterial, blitResize);
            this.drawDevice.Render();

            // Draw a screen space diagnostic overlay
            this.drawDevice.ClearFlags = ClearFlag.Depth;
            this.drawDevice.PrepareForDrawcalls();
            this.DrawDiagnosticOverlay(scene);
            this.drawDevice.Render();
        }
Beispiel #4
0
        /// <summary>
        /// Given the specified window size, this method calculates the window rectangle of the rendered
        /// viewport, as well as the game's rendered image size while taking into account application settings
        /// regarding forced rendering sizes.
        /// </summary>
        /// <param name="windowSize"></param>
        /// <param name="windowViewport"></param>
        /// <param name="renderTargetSize"></param>
        public static void CalculateGameViewport(Point2 windowSize, out Rect windowViewport, out Vector2 renderTargetSize)
        {
            Point2       forcedSize       = DualityApp.AppData.Instance.ForcedRenderSize;
            TargetResize forcedResizeMode = DualityApp.AppData.Instance.ForcedRenderResizeMode;

            renderTargetSize = windowSize;
            windowViewport   = new Rect(renderTargetSize);

            bool forcedResizeActive =
                forcedResizeMode != TargetResize.None &&
                forcedSize.X > 0 && forcedSize.Y > 0 &&
                forcedSize != renderTargetSize;

            if (forcedResizeActive)
            {
                Vector2 adjustedViewportSize = forcedResizeMode.Apply(forcedSize, windowViewport.Size);

                // Clip viewport and target size, so they don't exceed the window size.
                // This, strictly speaking, violates the forced rendering size, but for
                // resize modes like Fill, there is no other way to solve this.
                if (adjustedViewportSize.X > windowSize.X)
                {
                    forcedSize.X           = MathF.RoundToInt((float)forcedSize.X * (float)windowSize.X / (float)adjustedViewportSize.X);
                    adjustedViewportSize.X = windowSize.X;
                }
                if (adjustedViewportSize.Y > windowSize.Y)
                {
                    forcedSize.Y           = MathF.RoundToInt((float)forcedSize.Y * (float)windowSize.Y / (float)adjustedViewportSize.Y);
                    adjustedViewportSize.Y = windowSize.Y;
                }

                renderTargetSize = forcedSize;
                windowViewport   = Rect.Align(
                    Alignment.Center,
                    windowViewport.Size.X * 0.5f,
                    windowViewport.Size.Y * 0.5f,
                    adjustedViewportSize.X,
                    adjustedViewportSize.Y);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Generates a single drawcall that renders a fullscreen quad using the specified material.
        /// Assumes that the <see cref="DrawDevice"/> is set up to render in screen space.
        /// </summary>
        /// <param name="material"></param>
        /// <param name="resizeMode"></param>
        public void AddFullscreenQuad(BatchInfo material, TargetResize resizeMode)
        {
            Texture tex       = material.MainTexture.Res;
            Vector2 uvRatio   = tex != null ? tex.UVRatio : Vector2.One;
            Point2  inputSize = tex != null ? tex.ContentSize : Point2.Zero;

            // Fit the input material rect to the output size according to rendering step config
            Vector2 targetSize = resizeMode.Apply(inputSize, this.TargetSize);
            Rect    targetRect = Rect.Align(
                Alignment.Center,
                this.TargetSize.X * 0.5f,
                this.TargetSize.Y * 0.5f,
                targetSize.X,
                targetSize.Y);

            // Fit the target rect to actual pixel coordinates to avoid unnecessary filtering offsets
            targetRect.X = (int)targetRect.X;
            targetRect.Y = (int)targetRect.Y;
            targetRect.W = MathF.Ceiling(targetRect.W);
            targetRect.H = MathF.Ceiling(targetRect.H);

            VertexC1P3T2[] vertices = new VertexC1P3T2[4];

            vertices[0].Pos = new Vector3(targetRect.LeftX, targetRect.TopY, 0.0f);
            vertices[1].Pos = new Vector3(targetRect.RightX, targetRect.TopY, 0.0f);
            vertices[2].Pos = new Vector3(targetRect.RightX, targetRect.BottomY, 0.0f);
            vertices[3].Pos = new Vector3(targetRect.LeftX, targetRect.BottomY, 0.0f);

            vertices[0].TexCoord = new Vector2(0.0f, 0.0f);
            vertices[1].TexCoord = new Vector2(uvRatio.X, 0.0f);
            vertices[2].TexCoord = new Vector2(uvRatio.X, uvRatio.Y);
            vertices[3].TexCoord = new Vector2(0.0f, uvRatio.Y);

            vertices[0].Color = ColorRgba.White;
            vertices[1].Color = ColorRgba.White;
            vertices[2].Color = ColorRgba.White;
            vertices[3].Color = ColorRgba.White;

            this.AddVertices(material, VertexMode.Quads, vertices);
        }