Search code examples
c#xnaspritebatch

Is it possible to write new SpriteBatch.Begin function?


I am creating a game with an isometric view. I have a structure which is currently working quite effectively, using two matrices. This requires additional members and functions that I would like to do without, though. One of the SpriteBatch.Begin functions accepts a transformation matrix as a parameter. I would like to write a new SpriteBatch.Begin function to accept two matrices (one for camera transformation, and one for isometric transformation). I don't know how the actual SpriteBatch.Begin function works, and I don't know if there is any source available. Does anyone have an idea?


Solution

  • Ok, after the edit I searched for the source code for the SpriteBatch.begin() function. I found the source code for monogame which is an open-source implementation of XNA.

    So here it is:

    using System;
    using System.Text;
    
    namespace Microsoft.Xna.Framework.Graphics
    {
        public class SpriteBatch : GraphicsResource
        {
            readonly SpriteBatcher _batcher;
    
                SpriteSortMode _sortMode;
                BlendState _blendState;
                SamplerState _samplerState;
                DepthStencilState _depthStencilState; 
                RasterizerState _rasterizerState;                
                Effect _effect;
                bool _beginCalled;
    
                Effect _spriteEffect;
                readonly EffectParameter _matrixTransform;
                readonly EffectPass _spritePass;
    
                Matrix _matrix;
                Rectangle _tempRect = new Rectangle (0,0,0,0);
                Vector2 _texCoordTL = new Vector2 (0,0);
                Vector2 _texCoordBR = new Vector2 (0,0);
    
                public SpriteBatch (GraphicsDevice graphicsDevice)
                {
                    if (graphicsDevice == null) 
                    {
                            throw new ArgumentException ("graphicsDevice");
                    }        
    
                    this.GraphicsDevice = graphicsDevice;
    
                    // Use a custom SpriteEffect so we can control the transformation matrix
                    _spriteEffect = new Effect(graphicsDevice, SpriteEffect.Bytecode);
                    _matrixTransform = _spriteEffect.Parameters["MatrixTransform"];
                    _spritePass = _spriteEffect.CurrentTechnique.Passes[0];
    
                    _batcher = new SpriteBatcher(graphicsDevice);
    
                    _beginCalled = false;
                }
    
                public void Begin ()
                {
                    Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise, null, Matrix.Identity);        
                }
    
                public void Begin (SpriteSortMode sortMode, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, RasterizerState rasterizerState, Effect effect, Matrix transformMatrix)
                {
                    if (_beginCalled)
                        throw new InvalidOperationException("Begin cannot be called again until End has been successfully called.");
    
                    // defaults
                    _sortMode = sortMode;
                    _blendState = blendState ?? BlendState.AlphaBlend;
                    _samplerState = samplerState ?? SamplerState.LinearClamp;
                    _depthStencilState = depthStencilState ?? DepthStencilState.None;
                    _rasterizerState = rasterizerState ??   RasterizerState.CullCounterClockwise;
    
                    _effect = effect;
    
                    _matrix = transformMatrix;
    
                    // Setup things now so a user can chage them.
                    if (sortMode == SpriteSortMode.Immediate)
                        Setup();
    
                    _beginCalled = true;
                }
    
                public void Begin (SpriteSortMode sortMode, BlendState blendState)
                {
                    Begin (sortMode, blendState, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise, null, Matrix.Identity);                        
                }
    
                public void Begin (SpriteSortMode sortMode, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, RasterizerState rasterizerState)
                {
                    Begin (sortMode, blendState, samplerState, depthStencilState, rasterizerState, null, Matrix.Identity);        
                }
    
                public void Begin (SpriteSortMode sortMode, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, RasterizerState rasterizerState, Effect effect)
                {
                    Begin (sortMode, blendState, samplerState, depthStencilState, rasterizerState, effect, Matrix.Identity);                        
                }
    
                public void End ()
                {        
                    _beginCalled = false;
    
                    if (_sortMode != SpriteSortMode.Immediate)
                            Setup();
    
    #if PSM   
            GraphicsDevice.BlendState = _blendState;
            _blendState.ApplyState(GraphicsDevice);
    #endif
    
            _batcher.DrawBatch(_sortMode);
        }
    

    The file is not complete, i didn't paste after the end function but if you want to read the entire file. The link is : https://github.com/mono/MonoGame/blob/7ec1ec8a0e924eca60588e770121ed3e2593e74d/MonoGame.Framework/Graphics/SpriteBatch.cs

    I hope this was the source code you were looking for.

    Good luck!

    This is my other answer:

    You need to call spriteBatch.Begin() and spriteBatch.End() in your main Draw() function so you can actually draw.

    Here is an example:

    The Draw() function in Game1.cs :

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
    
        // Start drawing
        spriteBatch.Begin();
    
        player.Draw(spriteBatch);
    
        // Stop drawing
        spriteBatch.End();
    
        base.Draw(gameTime);
    }
    

    The Draw() function in Player.cs :

    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(playerTexture, playerPosition, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);
    }
    

    This will draw the player to the screen with the Draw() function out of Player.cs . The spriteBatch is initialized in the LoadContent() function of Game1.cs .

    I hope this Helps!