Minimal example of drawing a quad into 2d space?

Good morning!

I’m looking to draw some images with arbitrarily-located corners into an otherwise 2d game. My understanding is that one of the ways to do this is with quads. Examples of drawing quads exist, but I can’t seem to find a good way to put them into 2d space without hours of messing around with numbers to get the scale and orientation right. (“right”: I could line up the corners of my quad with the same coordinates of a rectangle drawn with spritebatch, and have all the edges match up perfectly.) Is anyone aware of a minimal example of this that I could use?

1 Like

Re : edit.

Ok i just thought i re-edit this and post up a couple better examples that i am more satisfied with myself and for posterity’s sake. Though there is still plenty of room to improve these they are pretty basic (look at the draw methods) with some extra stuff tossed in.

They will be in two posts.

The difference will be that one will use a spritebatch effect
The other will use a custom effect.
The custom effect will also have a very basic effect file.

The similarity will be that they will both for the most part, use the same draw code and that will just draw a textured vertice colored rectangle drawn in two different ways.
This is done either with DrawUserIndexedPrimitives or DrawPrimitives.

The example also shows…
How you can switch the winding or culling direction fairly easily.
How you can scroll around your world very easily with a view matrix.
How you can generate a texture with setdata.
That you can alter each individual vertices color and shade it.
A basic VertexPositionColorTexture shader as well.
There is some start up code to show basic instancing at the bottom of each class as well though it really would need its own example as the way you use it properly isn’t really shown. It shows a lot of stuff but ive compacted it down as most all of it goes hand in hand.

Note that this can easily be made into a non rectangular polygon a triangle or even a surface or a hand made model composed of triangles. Another thing is that the vertices are defined then drawn you can actually build up a bunch of these into the same array that is called batching you can also more often then not make the arrays just once though i didnt show that here to keep it straight forward,

Both class’s output the below…

I like to rename the Program.cs class so its up at the top of the solution explorer sometimes i put more then one game1 in there too.

using System;

namespace HowToQuadDraw
{
#if WINDOWS || LINUX
    /// <summary>
    /// The main class.
    /// </summary>
    public static class AppMainEntryPoint
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            using (var game = new ExampleWithBasicEffect()) game.Run();
            //using (var game = new ExampleWithEffect())game.Run();
        }
    }
#endif
}

the game class

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace HowToQuadDraw
{
    public class ExampleWithBasicEffect : Game
    {
        public static GraphicsDeviceManager graphics;
        public static SpriteBatch spriteBatch;
        public static BasicEffect basicEffect;
        public static Texture2D generatedTexture;

        public static Vector3 camera2DScrollPosition = new Vector3(0, 0, -1);
        public static Vector3 camera2DScrollLookAt = new Vector3(0, 0, 0);
        public static float camera2DrotationZ = 0f;

        public ExampleWithBasicEffect()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.GraphicsProfile = GraphicsProfile.HiDef;
        }

        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = 500;
            graphics.PreferredBackBufferHeight = 500;
            graphics.ApplyChanges();

            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            basicEffect = new BasicEffect(this.GraphicsDevice);
            generatedTexture = GenerateTexture2DWithTopLeftDiscoloration();
        }
        public Texture2D GenerateTexture2DWithTopLeftDiscoloration()
        {
            Texture2D t = new Texture2D(this.GraphicsDevice, 250, 250);
            var cdata = new Color[250 * 250];
            for (int i = 0; i < 250; i++)
            {
                for (int j = 0; j < 250; j++)
                {
                    if (i < 50 && j < 50)
                        cdata[i * 250 + j] = new Color(120, 120, 120, 250);
                    else
                        cdata[i * 250 + j] = Color.White;
                }
            }
            t.SetData(cdata);
            return t;
        }

        protected override void UnloadContent()
        {
            generatedTexture.Dispose();
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();
            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
                DrawWithBasicEffects(gameTime);
        }

        protected void DrawWithBasicEffects(GameTime gameTime)
        {
            this.GraphicsDevice.Clear(Color.Transparent);

            SetCameraPosition2D(0, 0);

            Rectangle drawingRectangle = new Rectangle(10, 40, 450, 260);

            SetStates();
            SetUpBasicEffect();

            //DrawVertexRectangle(r);

            DrawUserIndexedVertexRectangle(drawingRectangle);

            base.Draw(gameTime);
        }

        public void SetCameraPosition2D(int x, int y)
        {
            camera2DScrollPosition.X = x;
            camera2DScrollPosition.Y = y;
            camera2DScrollPosition.Z = -1;
            camera2DScrollLookAt.X = x;
            camera2DScrollLookAt.Y = y;
            camera2DScrollLookAt.Z = 0;
        }

        public void SetStates()
        {
            GraphicsDevice.BlendState = BlendState.Opaque;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;
            GraphicsDevice.SamplerStates[0] = SamplerState.PointWrap;
            GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
        }

        public void SetUpBasicEffect()
        {
            basicEffect.VertexColorEnabled = true;
            basicEffect.TextureEnabled = true;
            basicEffect.Texture = generatedTexture;

            // set up our matrix to match basic effect.
            Viewport viewport = GraphicsDevice.Viewport;
            //
            basicEffect.World = Matrix.Identity;
            Vector3 cameraUp = Vector3.Transform(new Vector3(0, -1, 0), Matrix.CreateRotationZ(camera2dRotationZ));
            basicEffect.View = Matrix.CreateLookAt(camera2DScrollPosition, camera2DScrollLookAt, cameraUp);
            // We could set up the world maxtrix this way and get the expected rotation but its not really proper.
            //basicEffect.World = Matrix.Identity * Matrix.CreateRotationZ(camera2DrotationZ);
            //basicEffect.View = Matrix.CreateLookAt(camera2DScrollPosition, camera2DScrollLookAt, new Vector3(0, -1, 0));
            basicEffect.Projection = Matrix.CreateScale(1, -1, 1) * Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1);
        }

        public void DrawVertexRectangle(Rectangle r)
        {
            VertexPositionColorTexture[] quad = new VertexPositionColorTexture[6];
            //
            if (GraphicsDevice.RasterizerState == RasterizerState.CullClockwise)
            {
                quad[0] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f));  // p1
                quad[1] = new VertexPositionColorTexture(new Vector3(r.Left, r.Bottom, 0f), Color.Red, new Vector2(0f, 1f)); // p0
                quad[2] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));// p3

                quad[3] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));// p3
                quad[4] = new VertexPositionColorTexture(new Vector3(r.Right, r.Top, 0f), Color.Blue, new Vector2(1f, 0f));// p2
                quad[5] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f)); // p1
            }
            else
            {
                quad[0] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f));  // p1
                quad[2] = new VertexPositionColorTexture(new Vector3(r.Left, r.Bottom, 0f), Color.Red, new Vector2(0f, 1f)); // p0
                quad[1] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));// p3

                quad[4] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));// p3
                quad[3] = new VertexPositionColorTexture(new Vector3(r.Right, r.Top, 0f), Color.Blue, new Vector2(1f, 0f));// p2
                quad[5] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f)); // p1
            }

            SetStates();
            SetUpBasicEffect();

            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                this.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, quad, 0, 2);
            }
        }

        public void DrawUserIndexedVertexRectangle(Rectangle r)
        {
            VertexPositionColorTexture[] quad = new VertexPositionColorTexture[6];
            quad[0] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f));
            quad[1] = new VertexPositionColorTexture(new Vector3(r.Left, r.Bottom, 0f), Color.Red, new Vector2(0f, 1f));
            quad[2] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));
            quad[3] = new VertexPositionColorTexture(new Vector3(r.Right, r.Top, 0f), Color.Blue, new Vector2(1f, 0f));

            short[] indices = new short[6];
            if (GraphicsDevice.RasterizerState == RasterizerState.CullClockwise)
            {
                indices[0] = 0; indices[1] = 1; indices[2] = 2;
                indices[3] = 2; indices[4] = 3; indices[5] = 0;
            }
            else
            {
                indices[0] = 0; indices[1] = 2; indices[2] = 1;
                indices[3] = 2; indices[4] = 0; indices[5] = 3;
            }

            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, quad, 0, 4, indices, 0, 2);
            }
        }

        VertexBuffer vertexBuffer;
        IndexBuffer indexBuffer;
        public void SetInstancedIndexedVertexRectangle(Rectangle r)
        {
            VertexPositionColorTexture[] quad = new VertexPositionColorTexture[6];
            quad[0] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f));
            quad[1] = new VertexPositionColorTexture(new Vector3(r.Left, r.Bottom, 0f), Color.Red, new Vector2(0f, 1f));
            quad[2] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));
            quad[3] = new VertexPositionColorTexture(new Vector3(r.Right, r.Top, 0f), Color.Blue, new Vector2(1f, 0f));

            short[] indices = new short[6];
            if (GraphicsDevice.RasterizerState == RasterizerState.CullClockwise)
            {
                indices[0] = 0; indices[1] = 1; indices[2] = 2;
                indices[3] = 2; indices[4] = 3; indices[5] = 0;
            }
            else
            {
                indices[0] = 0; indices[1] = 2; indices[2] = 1;
                indices[3] = 2; indices[4] = 0; indices[5] = 3;
            }

            vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColorTexture), 6, BufferUsage.WriteOnly);
            vertexBuffer.SetData<VertexPositionColorTexture>(quad);

            indexBuffer = new IndexBuffer(graphics.GraphicsDevice, typeof(short), indices.Length, BufferUsage.WriteOnly);
            indexBuffer.SetData(indices);

            GraphicsDevice.SetVertexBuffer(vertexBuffer);
            GraphicsDevice.Indices = indexBuffer;

        }
        public void DrawInstancedIndexedVertexRectangle(Rectangle r)
        {
            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 2);
            }
        }
        //public Matrix CreateSpiteBatchProjection(bool NeedsHalfPixelOffset)
        //{
        //    var projection = Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, -1f);
        //    if (NeedsHalfPixelOffset)
        //    {
        //        projection.M41 += -0.5f * projection.M11;
        //        projection.M42 += -0.5f * projection.M22;
        //    }
        //    return projection;
        //}
    }
}
2 Likes

This class is very similar to the above but uses a user made custom effect (shown at the botom) both output the same thing in the end.

To run this one you will need to create the effect file with the same name and copy paste the effect in. The first example can just be all copy pasted in with the namespaces changed to your projects namespace.

using System;

namespace HowToQuadDraw
{
#if WINDOWS || LINUX
    /// <summary>
    /// The main class.
    /// </summary>
    public static class AppMainEntryPoint
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            //using (var game = new ExampleWithBasicEffect()) game.Run();
            using (var game = new ExampleWithEffect())game.Run();
        }
    }
#endif
}

The game class that uses a custom effect

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace HowToQuadDraw
{
    public class ExampleWithEffect : Game
    {
        public static GraphicsDeviceManager graphics;
        public static SpriteBatch spriteBatch;
        public static Effect effect;
        public static Texture2D generatedTexture;

        public static Vector3 camera2DScrollPosition = new Vector3(0, 0, -1);
        public static Vector3 camera2DScrollLookAt = new Vector3(0, 0, 0);
        public static float camera2DrotationZ = 0f;

        public ExampleWithEffect()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.GraphicsProfile = GraphicsProfile.HiDef;
        }

        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = 500;
            graphics.PreferredBackBufferHeight = 500;
            graphics.ApplyChanges();

            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            effect = Content.Load<Effect>("TestingEffect");
            generatedTexture = GenerateTexture2DWithTopLeftDiscoloration();
        }
        public Texture2D GenerateTexture2DWithTopLeftDiscoloration()
        {
            Texture2D t = new Texture2D(this.GraphicsDevice, 250, 250);
            var cdata = new Color[250 * 250];
            for (int i = 0; i < 250; i++)
            {
                for (int j = 0; j < 250; j++)
                {
                    if (i < 50 && j < 50)
                        cdata[i * 250 + j] = new Color(120, 120, 120, 250);
                    else
                        cdata[i * 250 + j] = Color.White;
                }
            }
            t.SetData(cdata);
            return t;
        }

        protected override void UnloadContent()
        {
            generatedTexture.Dispose();
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();
            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
                DrawWithEffects(gameTime);
        }

        protected void DrawWithEffects(GameTime gameTime)
        {
            this.GraphicsDevice.Clear(Color.Transparent);

            SetCameraPosition2D(0, 0);

            Rectangle drawingRectangle = new Rectangle(10, 40, 450, 260);

            SetStates();
            SetUpEffect();

            //DrawVertexRectangle(r);

            DrawUserIndexedVertexRectangle(drawingRectangle);

            base.Draw(gameTime);
        }

        public void SetCameraPosition2D(int x, int y)
        {
            camera2DScrollPosition.X = x;
            camera2DScrollPosition.Y = y;
            camera2DScrollPosition.Z = -1;
            camera2DScrollLookAt.X = x;
            camera2DScrollLookAt.Y = y;
            camera2DScrollLookAt.Z = 0;
        }

        public void SetStates()
        {
            GraphicsDevice.BlendState = BlendState.Opaque;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;
            GraphicsDevice.SamplerStates[0] = SamplerState.PointWrap;
            GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
        }

        public void SetUpEffect()
        {
            effect.CurrentTechnique = effect.Techniques["QuadDraw"];//["BasicDrawing"];

            Viewport viewport = GraphicsDevice.Viewport;
            Matrix halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
            Matrix World = Matrix.Identity;
            Matrix View = Matrix.CreateLookAt(camera2DScrollPosition, camera2DScrollLookAt, cameraUp);
            // We can set up the matrices this way to get the expected rotation but it is improper the view is the camera.
            //Matrix World = Matrix.Identity * Matrix.CreateRotationZ(camera2DrotationZ);
            //Matrix View = Matrix.CreateLookAt(camera2DScrollPosition, camera2DScrollLookAt, new Vector3(0, -1, 0));
            Matrix Projection = Matrix.CreateScale(1, -1, 1) * Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1); // nans

            Matrix wvp = World * View * Projection;
            effect.Parameters["World"].SetValue(World);
            effect.Parameters["View"].SetValue(View);
            effect.Parameters["Projection"].SetValue(Projection);
            effect.Parameters["TextureA"].SetValue(generatedTexture);
        }

        public void DrawVertexRectangle(Rectangle r)
        {
            VertexPositionColorTexture[] quad = new VertexPositionColorTexture[6];
            //
            if (GraphicsDevice.RasterizerState == RasterizerState.CullClockwise)
            {
                quad[0] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f));  // p1
                quad[1] = new VertexPositionColorTexture(new Vector3(r.Left, r.Bottom, 0f), Color.Red, new Vector2(0f, 1f)); // p0
                quad[2] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));// p3

                quad[3] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));// p3
                quad[4] = new VertexPositionColorTexture(new Vector3(r.Right, r.Top, 0f), Color.Blue, new Vector2(1f, 0f));// p2
                quad[5] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f)); // p1
            }
            else
            {
                quad[0] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f));  // p1
                quad[2] = new VertexPositionColorTexture(new Vector3(r.Left, r.Bottom, 0f), Color.Red, new Vector2(0f, 1f)); // p0
                quad[1] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));// p3

                quad[4] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));// p3
                quad[3] = new VertexPositionColorTexture(new Vector3(r.Right, r.Top, 0f), Color.Blue, new Vector2(1f, 0f));// p2
                quad[5] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f)); // p1
            }

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                this.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, quad, 0, 2);
            }
        }

        public void DrawUserIndexedVertexRectangle(Rectangle r)
        {
            VertexPositionColorTexture[] quad = new VertexPositionColorTexture[6];
            quad[0] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f));
            quad[1] = new VertexPositionColorTexture(new Vector3(r.Left, r.Bottom, 0f), Color.Red, new Vector2(0f, 1f));
            quad[2] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));
            quad[3] = new VertexPositionColorTexture(new Vector3(r.Right, r.Top, 0f), Color.Blue, new Vector2(1f, 0f));

            short[] indices = new short[6];
            if (GraphicsDevice.RasterizerState == RasterizerState.CullClockwise)
            {
                indices[0] = 0; indices[1] = 1; indices[2] = 2;
                indices[3] = 2; indices[4] = 3; indices[5] = 0;
            }
            else
            {
                indices[0] = 0; indices[1] = 2; indices[2] = 1;
                indices[3] = 2; indices[4] = 0; indices[5] = 3;
            }

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, quad, 0, 4, indices, 0, 2);
            }
        }

        VertexBuffer vertexBuffer;
        IndexBuffer indexBuffer;
        public void SetInstancedIndexedVertexRectangle(Rectangle r)
        {
            VertexPositionColorTexture[] quad = new VertexPositionColorTexture[6];
            quad[0] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f));
            quad[1] = new VertexPositionColorTexture(new Vector3(r.Left, r.Bottom, 0f), Color.Red, new Vector2(0f, 1f));
            quad[2] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));
            quad[3] = new VertexPositionColorTexture(new Vector3(r.Right, r.Top, 0f), Color.Blue, new Vector2(1f, 0f));

            short[] indices = new short[6];
            if (GraphicsDevice.RasterizerState == RasterizerState.CullClockwise)
            {
                indices[0] = 0; indices[1] = 1; indices[2] = 2;
                indices[3] = 2; indices[4] = 3; indices[5] = 0;
            }
            else
            {
                indices[0] = 0; indices[1] = 2; indices[2] = 1;
                indices[3] = 2; indices[4] = 0; indices[5] = 3;
            }

            vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColorTexture), 6, BufferUsage.WriteOnly);
            vertexBuffer.SetData<VertexPositionColorTexture>(quad);

            indexBuffer = new IndexBuffer(graphics.GraphicsDevice, typeof(short), indices.Length, BufferUsage.WriteOnly);
            indexBuffer.SetData(indices);

            GraphicsDevice.SetVertexBuffer(vertexBuffer);
            GraphicsDevice.Indices = indexBuffer;

        }
        public void DrawInstancedIndexedVertexRectangle(Rectangle r)
        {
            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 2);
            }
        }
    }
}

The corresponding effect (.fx created with the pipeline tool).
This goes with the above example.

    // TestingEffect.fx
    #if OPENGL
    #define SV_POSITION POSITION
    #define VS_SHADERMODEL vs_3_0
    #define PS_SHADERMODEL ps_3_0
#else
    #define VS_SHADERMODEL vs_4_0     //_level_9_1
    #define PS_SHADERMODEL ps_4_0     //_level_9_1
#endif

matrix World;
matrix View;
matrix Projection;

Texture TextureA; // primary texture.
sampler TextureSamplerA = sampler_state
{
    texture = <TextureA>;
    //magfilter = LINEAR; //minfilter = LINEAR; //mipfilter = LINEAR; //AddressU = mirror; //AddressV = mirror; 
};
//_______________________________________________________________
// techniques 
// Quad Draw  Position Color Texture
//_______________________________________________________________
struct VsInputQuad
{
    float4 Position : POSITION0;
    float4 Color : COLOR0;
    float2 TexureCoordinateA : TEXCOORD0;
};
struct VsOutputQuad
{
    float4 Position : SV_Position;
    float4 Color : COLOR0;
    float2 TexureCoordinateA : TEXCOORD0;
};
struct PsOutputQuad
{
    float4 Color : COLOR0;
};
// ____________________________
VsOutputQuad VertexShaderQuadDraw(VsInputQuad input)
{
    VsOutputQuad output;
    float4x4 wvp = mul(World, mul(View, Projection));
    output.Position = mul(input.Position, wvp); // Transform by WorldViewProjection
    output.Color = input.Color;
    output.TexureCoordinateA = input.TexureCoordinateA;
    return output;
}
PsOutputQuad PixelShaderQuadDraw(VsOutputQuad input)
{
    PsOutputQuad output;
    output.Color = tex2D(TextureSamplerA, input.TexureCoordinateA) * input.Color;
    return output;
}

technique QuadDraw
{
    pass
    {
        VertexShader = compile VS_SHADERMODEL VertexShaderQuadDraw();
        PixelShader = compile PS_SHADERMODEL PixelShaderQuadDraw();
    }
}
2 Likes

Thank you! I will try this at the nearest opportunity, and endeavor to report back once I have.

I updated this with a couple better examples.
For other people who might run across this or as a reference.

Holy moly, man, you’re awesome! Thank you. I’ve stared working with the first example, but haven’t had the time to parse it fully yet. This weekend, I hope.

Worked perfectly; thank you.