#region File Description //----------------------------------------------------------------------------- // GameSprite3D.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, which allows the rotation around the axis that /// is pointing toward the view, is provided. /// public class GameSprite3D : GameMesh { #region Sprite3DObject /// /// this structure the information of 3D sprite object. /// public class Sprite3DObject : INamed { [Flags] public enum UpdateTypes { None = 0x00000000, Position = 0x00000001, Texturecoord = 0x00000002, Color = 0x00000004, Rotation = 0x00000010, Flip = 0x00000040, } String name = String.Empty; bool enable = true; Vector3 center = new Vector3(0, 0, 0); float width = 1.0f; float height = 1.0f; Color color = new Color(255, 255, 255, 255); float rotation = 0.0f; 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 float 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 spriteList = new List(); RenderingSpace renderingSpace = 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 (spriteList[i].Enable == false) continue; objectCount++; } if (objectCount == 0) return; PrimitiveCount = objectCount * 2; UpdateVertexCount = this.count * vertexStride; // needs to update? if (renderTracer.View != lastViewMatrix) { needToUpdate = true; this.lastViewMatrix = renderTracer.View; } if (alwaysUpdate || needToUpdate) { int vertexOffset = 0; int indexOffset = 0; for (int i = 0; i < this.count; i++) { Sprite3DObject obj = spriteList[i]; if (obj.Enable == false) continue; // rotates the paticle by z-axis. (Sprite3D can rotate) Matrix transformMatrix = Matrix.CreateRotationZ(obj.Rotation) * Helper3D.Transpose( this.TransformedMatrix * renderTracer.View); // updates vertex positions. SetBufferPosition(ref vertexData, obj, vertexOffset, transformMatrix, this.renderingSpace); // updates texture coordinates. SetBufferTextureCoord(ref vertexData, obj, vertexOffset, this.renderingSpace); // updates vertex colors. SetBufferColor(ref vertexData, obj, vertexOffset); indexData[indexOffset + 0] = (short)(vertexOffset + 0); indexData[indexOffset + 1] = (short)(vertexOffset + 2); indexData[indexOffset + 2] = (short)(vertexOffset + 1); indexData[indexOffset + 3] = (short)(vertexOffset + 1); indexData[indexOffset + 4] = (short)(vertexOffset + 2); indexData[indexOffset + 5] = (short)(vertexOffset + 3); 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 3D sprite objects using the texture. /// /// sprite object count /// texture file name /// 3D render space /// public void Create(int count, string fileName, RenderingSpace space, bool bAlwaysUpdate) { // Load texture GameResourceTexture2D resource = FrameworkCore.ResourceManager.LoadTexture(fileName); Create(count, resource.Texture2D, space, bAlwaysUpdate); } /// /// create 3D sprite objects using the texture. /// /// sprite object count /// texture resource /// 3D render space /// public void Create(int count, Texture2D texture, RenderingSpace space, bool bAlwaysUpdate) { this.count = count; this.renderingSpace = space; alwaysUpdate = bAlwaysUpdate; for (int i = 0; i < count; i++) spriteList.Add(new Sprite3DObject()); base.Create(count * vertexStride, count * indexStride, texture); } protected override void UnloadContent() { spriteList.Clear(); base.UnloadContent(); } /// /// enables/disables all sprite objects. /// /// public void SetObjectEnable(bool enable) { for (int i = 0; i < spriteList.Count; i++) SetObjectEnable(i, enable); } /// /// enables/disables an individual sprite object. /// public void SetObjectEnable(int index, bool enable) { if (spriteList.Count <= index || 0 > index) throw new ArgumentException("Invalid index."); if (spriteList[index].Enable != enable) { spriteList[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 (spriteList.Count <= index || 0 > index) throw new ArgumentException("Invalid index."); spriteList[index].Center = position; spriteList[index].AddUpdateType(Sprite3DObject.UpdateTypes.Position); needToUpdate = true; } /// /// 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 (spriteList.Count <= index || 0 > index) throw new ArgumentException("Invalid index."); vec.X = spriteList[index].Center.X - (spriteList[index].Width * 0.5f); vec.Y = spriteList[index].Center.Y - (spriteList[index].Height * 0.5f); vec.Z = spriteList[index].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 (spriteList.Count <= index || 0 > index) throw new ArgumentException("Invalid index."); vec.X = spriteList[index].Center.X + (spriteList[index].Width * 0.5f); vec.Y = spriteList[index].Center.Y + (spriteList[index].Height * 0.5f); vec.Z = spriteList[index].Center.Z; } /// /// configures a rotation value of each sprite object. /// /// an index of sprite object /// rotation angle public void SetRotation(int index, float amount) { if (spriteList.Count <= index || 0 > index) throw new ArgumentException("Invalid index."); spriteList[index].Rotation = amount; spriteList[index].AddUpdateType(Sprite3DObject.UpdateTypes.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 (spriteList.Count <= index || 0 > index) throw new ArgumentException("Invalid index."); spriteList[index].FlipX = flipX; spriteList[index].FlipY = flipY; spriteList[index].AddUpdateType(Sprite3DObject.UpdateTypes.Flip); needToUpdate = true; } /// /// configures the size of each sprite object. /// /// an index of sprite object /// size vector public void SetSize(int index, Vector2 size) { if (spriteList.Count <= index || 0 > index) throw new ArgumentException("Invalid index."); spriteList[index].Width = size.X; spriteList[index].Height = size.Y; spriteList[index].AddUpdateType(Sprite3DObject.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)); } /// /// 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 (spriteList.Count <= index || 0 > index) throw new ArgumentException("Invalid index."); spriteList[index].MinUV = min; spriteList[index].MaxUV = max; spriteList[index].AddUpdateType(Sprite3DObject.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 (spriteList.Count <= index || 0 > index) throw new ArgumentException("Invalid index."); spriteList[index].Color = color; spriteList[index].AddUpdateType(Sprite3DObject.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, Sprite3DObject obj, int startIndex, Matrix transformMatrix, RenderingSpace space) { float cx = obj.Width * 0.5f; float cy = obj.Height * 0.5f; 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); 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, Sprite3DObject 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(u1, v2); vertexData[startIndex + 3].TextureCoordinate = new Vector2(u2, 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, Sprite3DObject obj, int startIndex) { for( int i = 0; i < 4; i++) vertexData[startIndex + i].Color = obj.Color; } } }