Search code examples
c#monogame

MonoGame - ScissorRectangle not working


I'm trying to create a scrollable log window with RenderTarget2D and ScissorRectangle. The ScissorRectangle, however, does not seem to work. Here's the code:

spriteBatch.End();

spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, new RasterizerState() { ScissorTestEnable = true });

Rectangle scissor = new Rectangle(0, Constants.GAME_AREA_HEIGHT, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT);
Rectangle scissorBackup = this.graphicsDevice.ScissorRectangle;
this.graphicsDevice.ScissorRectangle = scissor;

spriteBatch.Draw(logRenderTarget,
    new Rectangle(0, Constants.GAME_AREA_HEIGHT, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT),
    Color.White
);

this.graphicsDevice.ScissorRectangle = scissorBackup;

spriteBatch.End();

spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null);

Solution

  • I decided to switch to using a Viewport. It seems, however, that MonoGame uses the last set-up Viewport before the call to spriteBatch.End(). It also seems that it is the same with the ScissorRectangle, so I could have made it also work. I have added the ScissorRectangle-specific code here in comments. Here's my new class:

    public class LogWriter
    {
        private GraphicsDevice graphicsDevice;
    
        private Viewport defaultViewport, logViewport;
        //private Rectangle scissor, scissorBackup;
    
        public void Init(GraphicsDevice graphicsDevice)
        {
            this.graphicsDevice = graphicsDevice;
    
            defaultViewport = this.graphicsDevice.Viewport;
            logViewport = new Viewport(0, Constants.GAME_AREA_HEIGHT, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT);
    
            //scissor = new Rectangle(0, Constants.GAME_AREA_HEIGHT, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT);
            //scissorBackup = this.graphicsDevice.ScissorRectangle;
        }
    
        public void WriteLog(SpriteBatch spriteBatch)
        {
            this.graphicsDevice.Viewport = logViewport;
            //this.graphicsDevice.ScissorRectangle = scissor;
    
            spriteBatch.Begin();
            //spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, new RasterizerState() { ScissorTestEnable = true });
    
            for (int i = 0; i < Log.Count; i++)
            {
                spriteBatch.DrawString(Scavenger.AssetManager.Font12,
                    Log.Entries[i],
                    new Vector2(
                        Constants.LOG_MARGIN,
                        Constants.LOG_MARGIN + i * Scavenger.AssetManager.Font12.LineSpacing),
                    Color.GreenYellow
                );
            }
    
            spriteBatch.End();
    
            this.graphicsDevice.Viewport = defaultViewport;
            //this.graphicsDevice.ScissorRectangle = scissorBackup;
        }
    }
    

    Init() is called in the LoadContent() function. WriteLog() is called in the Draw() function after End() has been called on the spriteBatch after drawing all the other things.