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;
//}
}
}