using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace QuadRotationProblem
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Effect Billboard;
TexturedQuad Quad;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
RasterizerState rs = new RasterizerState();
rs.CullMode = CullMode.None;
GraphicsDevice.RasterizerState = rs;
Camera.Instance.Initialize(GraphicsDevice);
Quad = new TexturedQuad(GraphicsDevice, Content.Load<Texture2D>("Claudius"), new Vector3(0, 0, 0), 32, 64);
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
Billboard = Content.Load<Effect>("Billboard");
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
KeyboardState KBState = Keyboard.GetState();
if (KBState.IsKeyDown(Keys.Escape))
this.Exit();
if (KBState.IsKeyDown(Keys.R))
Camera.Instance.Rotation = 0;
else if (KBState.IsKeyDown(Keys.Left))
{
Camera.Instance.Rotate(.05f);
}
else if (KBState.IsKeyDown(Keys.Right))
{
Camera.Instance.Rotate(-.05f);
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
Quad.Draw(GraphicsDevice, ref Billboard);
base.Draw(gameTime);
}
}
class TexturedQuad
{
public Texture2D Texture;
public VertexPositionTexture[] Vertices;
public float Width { get; set; }
public float Height { get; set; }
private Vector3 position;
public Vector3 Position
{
get
{
return position;
}
set
{
position = value;
Vector3 difference = position - Vertices[0].Position;
Vertices[0].Position = position;
Vertices[1].Position += difference;
Vertices[2].Position += difference;
Vertices[3].Position += difference;
}
}
public TexturedQuad(GraphicsDevice GFX, Texture2D texture, Vector3 origin, float width, float height, int frameNum = 0, int frameRow = 0)
{
Texture = texture;
position = origin;
Width = width;
Height = height;
Vertices = new VertexPositionTexture[4];
Vertices[0] = new VertexPositionTexture(Position, new Vector2((Width * frameNum) / Texture.Width, (Height * frameRow) / Texture.Height));
Vertices[1] = new VertexPositionTexture(new Vector3(Position.X + Width, Position.Y, Position.Z),
new Vector2(((Width * frameNum) + Width) / Texture.Width, 0));
Vertices[2] = new VertexPositionTexture(new Vector3(Position.X, Position.Y + Height, Position.Z), new Vector2(0, ((Height * frameRow) + Height) / Texture.Height));
Vertices[3] = new VertexPositionTexture(new Vector3(Position.X + Width, Position.Y + Height, Position.Z),
new Vector2(((Width * frameNum) + Width) / Texture.Width, ((Height * frameRow) + Height) / Texture.Height));
}
public void Draw(GraphicsDevice GFX, ref Effect Effect)
{
Effect.CurrentTechnique = Effect.Techniques["BasicShader"];
Effect.Parameters["WorldView"].SetValue(Matrix.Identity * Camera.Instance.View);
Effect.Parameters["Projection"].SetValue(Camera.Instance.Projection);
foreach (EffectPass pass in Effect.CurrentTechnique.Passes)
{
pass.Apply();
GFX.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleStrip, Vertices, 0, 2);
}
}
}
public sealed class Camera
{
private static readonly Camera instance = new Camera();
private static BasicEffect effect;
private static Viewport viewport;
private static Matrix orthographic;
private static Vector3 translatedModifier;
private float zoom;
public static Camera Instance { get { return instance; } }
public void Initialize(GraphicsDevice gfx)
{
viewport = gfx.Viewport;
orthographic = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1);
effect = new BasicEffect(gfx) { TextureEnabled = true, VertexColorEnabled = true };
effect.World = effect.View = Matrix.Identity;
Zoom = 1f;
translatedModifier = new Vector3(gfx.Viewport.Width / 2, gfx.Viewport.Height / 2, 0);
}
public Effect Effect
{
get
{
effect.Projection = Projection;
return effect;
}
}
public Vector3 Position { set; get; }
public Matrix Projection { get { return Transformation * orthographic; } }
public float Rotation { get; set; }
public Matrix Transformation
{
get
{
return Matrix.CreateTranslation(new Vector3(-Position.X - .5f, -Position.Y - .5f, 0))
* Matrix.CreateRotationY(Rotation)
* Matrix.CreateScale(new Vector3(Zoom, Zoom, 0))
* Matrix.CreateTranslation(translatedModifier);
}
}
public Matrix View { get { return effect.View; } }
public float Zoom
{
get
{
// Prevent flipping
if (zoom < 0.01f) zoom = 0.01f;
return zoom;
}
set
{
zoom = value;
}
}
public void Rotate(float radians)
{
Rotation = MathHelper.WrapAngle(Rotation + radians);
}
public void Translate(Vector3 amount)
{
Position += amount;
}
}
}
/*****Billboard.fx*****
float4x4 WorldView : WorldView;
float4x4 Projection : Projection;
texture texture0 : DIFFUSE <
string ResourceName = "default_color.dds";
string UIName = "Diffuse Texture";
string ResourceType = "2D";
>;
sampler2D colorMap = sampler_state
{
Texture = <texture0>;
MagFilter = Linear;
MinFilter = Anisotropic;
MipFilter = Linear;
MaxAnisotropy = 16;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 TextureCoordinate : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 TextureCoordinate : TEXCOORD0;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput IN)
{
VertexShaderOutput OUT;
OUT.Position = mul(IN.Position + float4(WorldView[3].xyz, 0), Projection);
OUT.TextureCoordinate = IN.TextureCoordinate;
return OUT;
}
float4 PixelShaderFunction(VertexShaderOutput IN) : COLOR0
{
return tex2D(colorMap, IN.TextureCoordinate);
}
technique BasicShader
{
pass Pass1
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
*****/