#region File Description
//-----------------------------------------------------------------------------
// GamePointSprite.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using RobotGameData.Render;
using RobotGameData.Resource;
using RobotGameData.Collision;
using RobotGameData.GameInterface;
using RobotGameData.Helper;
#endregion
namespace RobotGameData.GameObject
{
///
/// This sprite constantly looks at the view matrix at anywhere in the 3D world.
/// A rotation feature is not provided.
///
public class GamePointSprite : GameMesh
{
#region PointSpriteObject
public class PointSpriteObject : INamed
{
[Flags]
public enum UpdateTypes
{
None = 0x00000000,
Position = 0x00000001,
Texturecoord = 0x00000002,
Color = 0x00000004,
Rotation = 0x00000010,
}
public enum RotationAngle
{
Angle0 = 0,
Angle90,
Angle180,
Angle270,
}
String name = String.Empty;
bool enable = true;
Vector3 center = Vector3.Zero;
float width = 1.0f;
float height = 1.0f;
Color color = new Color(255, 255, 255, 255);
RotationAngle rotation = RotationAngle.Angle0;
Vector2[] uv = new Vector2[2]
{
Vector2.Zero,
Vector2.One,
};
bool flipX = false;
bool flipY = false;
uint updateFlag = 0;
public string Name
{
get { return name; }
set { name = value; }
}
public bool Enable
{
get { return this.enable; }
set { this.enable = value; }
}
public Vector3 Center
{
get { return this.center; }
set { this.center = value; }
}
public float Width
{
get { return this.width; }
set { this.width = value; }
}
public float Height
{
get { return this.height; }
set { this.height = value; }
}
public Color Color
{
get { return this.color; }
set { this.color = value; }
}
public RotationAngle Rotation
{
get { return this.rotation; }
set { this.rotation = value; }
}
public bool FlipX
{
get { return this.flipX; }
set { this.flipX = value; }
}
public bool FlipY
{
get { return this.flipY; }
set { this.flipY = value; }
}
public void AddUpdateType(UpdateTypes updateType)
{
this.updateFlag |= (uint)updateType;
}
public void RemoveUpdateType(UpdateTypes updateType)
{
this.updateFlag &= ~(uint)updateType;
}
public Vector2 MinUV
{
get { return this.uv[0]; }
set { this.uv[0] = value; }
}
public Vector2 MaxUV
{
get { return this.uv[1]; }
set { this.uv[1] = value; }
}
}
#endregion
#region Fields
const int vertexStride = 4;
const int indexStride = 6;
List pointSpriteList = new List();
RenderingSpace space = RenderingSpace.World;
Matrix lastViewMatrix;
int count = 0;
bool needToUpdate = false;
bool alwaysUpdate = false;
#endregion
#region Properties
public int Count
{
get { return this.count; }
}
#endregion
///
/// updates the vertex data and draws
///
/// render information
protected override void OnDraw(RenderTracer renderTracer)
{
int objectCount = 0;
for (int i = 0; i < this.count; i++)
{
if (pointSpriteList[i].Enable == false) continue;
objectCount++;
}
if (objectCount == 0) return;
PrimitiveCount = objectCount * 2;
UpdateVertexCount = this.count * vertexStride;
this.alwaysUpdate = true;
// needs to update?
if (renderTracer.View != lastViewMatrix)
{
needToUpdate = true;
this.lastViewMatrix = renderTracer.View;
}
if (this.alwaysUpdate || needToUpdate)
{
int vertexOffset = 0;
int indexOffset = 0;
// calculates inverse view matrix.
Matrix transformMatrix =
Helper3D.Transpose(this.TransformedMatrix * renderTracer.View);
for (int i = 0; i < this.count; i++)
{
PointSpriteObject obj = pointSpriteList[i];
if (obj.Enable == false) continue;
// updates vertex positions.
SetBufferPosition(ref vertexData, obj, vertexOffset,
transformMatrix, this.space);
// updates texture coordinates.
SetBufferTextureCoord(ref vertexData, obj,
vertexOffset, this.space);
// updates vertex colors.
SetBufferColor(ref vertexData, obj, vertexOffset);
indexData[indexOffset + 0] = (short)(vertexOffset + 0);
indexData[indexOffset + 1] = (short)(vertexOffset + 1);
indexData[indexOffset + 2] = (short)(vertexOffset + 2);
indexData[indexOffset + 3] = (short)(vertexOffset + 3);
indexData[indexOffset + 4] = (short)(vertexOffset + 0);
indexData[indexOffset + 5] = (short)(vertexOffset + 2);
vertexOffset += vertexStride;
indexOffset += indexStride;
}
if (userPrimitive == false)
{
// binds the vertex buffer.
BindVertexBuffer();
// binds the index buffer.
BindIndexBuffer();
}
if (needToUpdate)
needToUpdate = false;
}
// draws mesh
base.OnDraw(renderTracer);
}
///
/// create point sprite objects using the texture.
///
/// sprite object count
/// texture file name
/// 3D render space
///
public void Create(int count, string fileName,
RenderingSpace space, bool alwaysUpdate)
{
// load a texture.
GameResourceTexture2D resource =
FrameworkCore.ResourceManager.LoadTexture(fileName);
Create(count, resource.Texture2D, space, alwaysUpdate);
}
///
/// create point sprite objects using the texture.
///
/// sprite object count
/// rexture resource
/// 3D render space
///
public void Create(int count, Texture2D texture,
RenderingSpace space, bool alwaysUpdate)
{
this.count = count;
this.space = space;
this.alwaysUpdate = alwaysUpdate;
// create sprite objects.
for (int i = 0; i < count; i++)
pointSpriteList.Add(new PointSpriteObject());
base.Create(this.count * vertexStride, this.count * indexStride, texture);
}
protected override void UnloadContent()
{
pointSpriteList.Clear();
base.UnloadContent();
}
///
/// enables/disables all sprite objects.
///
public void SetObjectEnable(bool enable)
{
for (int i = 0; i < pointSpriteList.Count; i++)
SetObjectEnable(i, enable);
}
///
/// enables/disables an individual sprite object.
///
public void SetObjectEnable(int index, bool enable)
{
if (pointSpriteList.Count <= index || 0 > index)
throw new ArgumentException("Invalid index.");
if (pointSpriteList[index].Enable != enable)
{
pointSpriteList[index].Enable = enable;
needToUpdate = true;
}
}
///
/// configures a center position of each sprite object.
///
/// an index of sprite object
/// a center position
public void SetCenter(int index, Vector3 position)
{
if (pointSpriteList.Count <= index || 0 > index)
throw new ArgumentException("Invalid index.");
pointSpriteList[index].Center = position;
pointSpriteList[index].AddUpdateType(PointSpriteObject.UpdateTypes.Position);
needToUpdate = true;
}
///
/// configures a center position of each sprite object.
///
/// an index of sprite object
/// x-component of center position of the sprite object
/// y-component of center position of the sprite object
/// z-component of center position of the sprite object
public void SetCenter(int index, float x, float y, float z)
{
SetCenter(index, new Vector3(x, y, z));
}
///
/// gets a left top position of each sprite object.
///
/// an index of sprite object
/// out vector
public void GetLeftTop(int index, ref Vector3 vec)
{
if (pointSpriteList.Count <= index || 0 > index)
throw new ArgumentException("Invalid index.");
PointSpriteObject obj = pointSpriteList[index];
vec.X = obj.Center.X - (obj.Width * 0.5f);
vec.Y = obj.Center.Y - (obj.Height * 0.5f);
vec.Z = obj.Center.Z;
}
///
/// gets a right down position of each sprite object.
///
/// an index of sprite object
/// out vector
public void GetRightBottom(int index, ref Vector3 vec)
{
if (pointSpriteList.Count <= index || 0 > index)
throw new ArgumentException("Invalid index.");
PointSpriteObject obj = pointSpriteList[index];
vec.X = obj.Center.X + (obj.Width * 0.5f);
vec.Y = obj.Center.Y + (obj.Height * 0.5f);
vec.Z = obj.Center.Z;
}
///
/// configures a rotation value of each sprite object.
///
/// an index of sprite object
/// rotation angle
public void SetRotation(int index, PointSpriteObject.RotationAngle rotation)
{
if (pointSpriteList.Count <= index || 0 > index)
throw new ArgumentException("Invalid index.");
pointSpriteList[index].Rotation = rotation;
needToUpdate = true;
}
///
/// flips each sprite object around x-axis and/or y-axis.
///
/// an index of sprite object
/// specifies whether to rotate around x-axis
/// specifies whether to rotate around y-axis
public void SetFlip(int index, bool flipX, bool flipY)
{
if (pointSpriteList.Count <= index || 0 > index)
throw new ArgumentException("Invalid index.");
pointSpriteList[index].FlipX = flipX;
pointSpriteList[index].FlipY = flipY;
needToUpdate = true;
}
///
/// configures the size of each sprite object.
///
/// an index of sprite object
/// size vector
public void SetSize(int index, Vector2 size)
{
if (pointSpriteList.Count <= index || 0 > index)
throw new ArgumentException("Invalid index.");
pointSpriteList[index].Width = size.X;
pointSpriteList[index].Height = size.Y;
pointSpriteList[index].AddUpdateType(PointSpriteObject.UpdateTypes.Position);
needToUpdate = true;
}
///
/// configures the size of each sprite object.
///
/// an index of sprite object
/// size of width
/// size of height
public void SetSize(int index, float width, float height)
{
SetSize(index, new Vector2(width, height));
}
///
/// gets the size of each sprite object
///
/// an index of sprite object
/// size vector
public Vector2 GetSize(int index)
{
if (pointSpriteList.Count <= index || 0 > index)
throw new ArgumentException("Invalid index.");
return new Vector2(pointSpriteList[index].Width,
pointSpriteList[index].Height);
}
///
/// configures the texture coordinates of each sprite object.
///
/// an index of sprite object
/// texture coordinates of minimum
/// texture coordinates of maximum
public void SetTextureCoord(int index, Vector2 min, Vector2 max)
{
if (pointSpriteList.Count <= index || 0 > index)
throw new ArgumentException("Invalid index.");
pointSpriteList[index].MinUV = min;
pointSpriteList[index].MaxUV = max;
pointSpriteList[index].AddUpdateType(
PointSpriteObject.UpdateTypes.Texturecoord);
needToUpdate = true;
}
///
/// configures the texture coordinates of each sprite object.
///
/// an index of sprite object
/// texture "u1" coordinate
/// texture "v1" coordinate
/// texture "u2" coordinate
/// texture "v2" coordinate
public void SetTextureCoord(int index, float u1, float v1, float u2, float v2)
{
SetTextureCoord(index, new Vector2(u1, v1), new Vector2(u2, v2));
}
///
/// configures the vertex color of each sprite object.
///
/// an index of sprite object
/// color
public void SetColor(int index, Color color)
{
if (pointSpriteList.Count <= index || 0 > index)
throw new ArgumentException("Invalid index.");
pointSpriteList[index].Color = color;
pointSpriteList[index].AddUpdateType(PointSpriteObject.UpdateTypes.Color);
needToUpdate = true;
}
///
/// configures the vertex color of each sprite object.
///
/// an index of sprite object
/// a red component of color
/// a green component of color
/// a blue component of color
/// an alpha component of color
public void SetColor(int index, byte r, byte g, byte b, byte a)
{
SetColor(index, new Color(r, g, b, a));
}
///
/// configures a transformed matrix to the vertex component data
/// using the sprite object.
///
/// target vertex component data
/// source sprite object
/// start index of the vertex component data
/// transformed matrix
/// 3D render space
private static void SetBufferPosition(
ref VertexPositionColorTexture[] vertexData, PointSpriteObject obj,
int startIndex, Matrix transformMatrix, RenderingSpace space)
{
float cx = obj.Width * 0.5f;
float cy = obj.Height * 0.5f;
switch (obj.Rotation)
{
case PointSpriteObject.RotationAngle.Angle0:
{
vertexData[startIndex + 0].Position =
new Vector3(-cx, -cy, 0.0f);
vertexData[startIndex + 1].Position =
new Vector3(+cx, -cy, 0.0f);
vertexData[startIndex + 2].Position =
new Vector3(+cx, +cy, 0.0f);
vertexData[startIndex + 3].Position =
new Vector3(-cx, +cy, 0.0f);
}
break;
case PointSpriteObject.RotationAngle.Angle90:
{
vertexData[startIndex + 0].Position =
new Vector3(+cx, -cy, 0.0f);
vertexData[startIndex + 1].Position =
new Vector3(+cx, +cy, 0.0f);
vertexData[startIndex + 2].Position =
new Vector3(-cx, +cy, 0.0f);
vertexData[startIndex + 3].Position =
new Vector3(-cx, -cy, 0.0f);
}
break;
case PointSpriteObject.RotationAngle.Angle180:
{
vertexData[startIndex + 0].Position =
new Vector3(+cx, +cy, 0.0f);
vertexData[startIndex + 1].Position =
new Vector3(-cx, +cy, 0.0f);
vertexData[startIndex + 2].Position =
new Vector3(-cx, -cy, 0.0f);
vertexData[startIndex + 3].Position =
new Vector3(+cx, -cy, 0.0f);
}
break;
case PointSpriteObject.RotationAngle.Angle270:
{
vertexData[startIndex + 0].Position =
new Vector3(-cx, +cy, 0.0f);
vertexData[startIndex + 1].Position =
new Vector3(-cx, -cy, 0.0f);
vertexData[startIndex + 2].Position =
new Vector3(+cx, -cy, 0.0f);
vertexData[startIndex + 3].Position =
new Vector3(+cx, +cy, 0.0f);
}
break;
}
for (int i = 0; i < 4; i++)
{
int arrayIndex = startIndex + i;
Vector3.TransformNormal(ref vertexData[arrayIndex].Position,
ref transformMatrix,
out vertexData[arrayIndex].Position);
vertexData[arrayIndex].Position += obj.Center;
if (space == RenderingSpace.Screen)
{
vertexData[arrayIndex].Position =
HelperMath.Make2DCoord(vertexData[arrayIndex].Position);
}
}
}
///
/// configures texture coordinates to the vertex component data
/// using the sprite object.
///
/// target vertex component data
/// source sprite object
/// start index of the vertex component data
/// 3D render space
private static void SetBufferTextureCoord(
ref VertexPositionColorTexture[] vertexData, PointSpriteObject obj,
int startIndex, RenderingSpace space)
{
float u1 = 0.0f, v1 = 0.0f, u2 = 0.0f, v2 = 0.0f;
// Differ Y axis of the 3D and 2D
bool flipY = (space == RenderingSpace.Screen ? !obj.FlipY : obj.FlipY);
if (obj.FlipX)
{
if (flipY)
{
u1 = obj.MaxUV.X;
v1 = obj.MaxUV.Y;
u2 = obj.MinUV.X;
v2 = obj.MinUV.Y;
}
else
{
u1 = obj.MaxUV.X;
v1 = obj.MinUV.Y;
u2 = obj.MinUV.X;
v2 = obj.MaxUV.Y;
}
}
else
{
if (flipY)
{
u1 = obj.MinUV.X;
v1 = obj.MaxUV.Y;
u2 = obj.MaxUV.X;
v2 = obj.MinUV.Y;
}
else
{
u1 = obj.MinUV.X;
v1 = obj.MinUV.Y;
u2 = obj.MaxUV.X;
v2 = obj.MaxUV.Y;
}
}
vertexData[startIndex + 0].TextureCoordinate = new Vector2(u1, v1);
vertexData[startIndex + 1].TextureCoordinate = new Vector2(u2, v1);
vertexData[startIndex + 2].TextureCoordinate = new Vector2(u2, v2);
vertexData[startIndex + 3].TextureCoordinate = new Vector2(u1, v2);
}
///
/// configures vertex color to the vertex component data using the sprite object.
///
/// target vertex component data
/// source sprite object
/// start index of the vertex component data
private static void SetBufferColor(ref VertexPositionColorTexture[] vertexData,
PointSpriteObject obj, int startIndex)
{
for (int i = 0; i < 4; i++)
vertexData[startIndex + i].Color = obj.Color;
}
}
}