GameSprite3D.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // GameSprite3D.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Text;
  13. using Microsoft.Xna.Framework;
  14. using Microsoft.Xna.Framework.Content;
  15. using Microsoft.Xna.Framework.Graphics;
  16. using RobotGameData.Render;
  17. using RobotGameData.Resource;
  18. using RobotGameData.Collision;
  19. using RobotGameData.GameInterface;
  20. using RobotGameData.Helper;
  21. #endregion
  22. namespace RobotGameData.GameObject
  23. {
  24. /// <summary>
  25. /// this sprite constantly looks at the view matrix at anywhere in the 3D world.
  26. /// A rotation feature, which allows the rotation around the axis that
  27. /// is pointing toward the view, is provided.
  28. /// </summary>
  29. public class GameSprite3D : GameMesh
  30. {
  31. #region Sprite3DObject
  32. /// <summary>
  33. /// this structure the information of 3D sprite object.
  34. /// </summary>
  35. public class Sprite3DObject : INamed
  36. {
  37. [Flags]
  38. public enum UpdateTypes
  39. {
  40. None = 0x00000000,
  41. Position = 0x00000001,
  42. Texturecoord = 0x00000002,
  43. Color = 0x00000004,
  44. Rotation = 0x00000010,
  45. Flip = 0x00000040,
  46. }
  47. String name = String.Empty;
  48. bool enable = true;
  49. Vector3 center = new Vector3(0, 0, 0);
  50. float width = 1.0f;
  51. float height = 1.0f;
  52. Color color = new Color(255, 255, 255, 255);
  53. float rotation = 0.0f;
  54. Vector2[] uv = new Vector2[2]
  55. {
  56. Vector2.Zero,
  57. Vector2.One,
  58. };
  59. bool flipX = false;
  60. bool flipY = false;
  61. uint updateFlag = 0;
  62. public string Name
  63. {
  64. get { return name; }
  65. set { name = value; }
  66. }
  67. public bool Enable
  68. {
  69. get { return this.enable; }
  70. set { this.enable = value; }
  71. }
  72. public Vector3 Center
  73. {
  74. get { return this.center; }
  75. set { this.center = value; }
  76. }
  77. public float Width
  78. {
  79. get { return this.width; }
  80. set { this.width = value; }
  81. }
  82. public float Height
  83. {
  84. get { return this.height; }
  85. set { this.height = value; }
  86. }
  87. public Color Color
  88. {
  89. get { return this.color; }
  90. set { this.color = value; }
  91. }
  92. public float Rotation
  93. {
  94. get { return this.rotation; }
  95. set { this.rotation = value; }
  96. }
  97. public bool FlipX
  98. {
  99. get { return this.flipX; }
  100. set { this.flipX = value; }
  101. }
  102. public bool FlipY
  103. {
  104. get { return this.flipY; }
  105. set { this.flipY = value; }
  106. }
  107. public void AddUpdateType(UpdateTypes updateType)
  108. {
  109. this.updateFlag |= (uint)updateType;
  110. }
  111. public void RemoveUpdateType(UpdateTypes updateType)
  112. {
  113. this.updateFlag &= ~(uint)updateType;
  114. }
  115. public Vector2 MinUV
  116. {
  117. get { return this.uv[0]; }
  118. set { this.uv[0] = value; }
  119. }
  120. public Vector2 MaxUV
  121. {
  122. get { return this.uv[1]; }
  123. set { this.uv[1] = value; }
  124. }
  125. }
  126. #endregion
  127. #region Fields
  128. const int vertexStride = 4;
  129. const int indexStride = 6;
  130. List<Sprite3DObject> spriteList = new List<Sprite3DObject>();
  131. RenderingSpace renderingSpace = RenderingSpace.World;
  132. Matrix lastViewMatrix;
  133. int count = 0;
  134. bool needToUpdate = false;
  135. bool alwaysUpdate = false;
  136. #endregion
  137. #region Properties
  138. public int Count
  139. {
  140. get { return this.count; }
  141. }
  142. #endregion
  143. /// <summary>
  144. /// updates the vertex data and draws
  145. /// </summary>
  146. /// <param name="renderTracer">render information</param>
  147. protected override void OnDraw(RenderTracer renderTracer)
  148. {
  149. int objectCount = 0;
  150. for (int i = 0; i < this.count; i++)
  151. {
  152. if (spriteList[i].Enable == false) continue;
  153. objectCount++;
  154. }
  155. if (objectCount == 0) return;
  156. PrimitiveCount = objectCount * 2;
  157. UpdateVertexCount = this.count * vertexStride;
  158. // needs to update?
  159. if (renderTracer.View != lastViewMatrix)
  160. {
  161. needToUpdate = true;
  162. this.lastViewMatrix = renderTracer.View;
  163. }
  164. if (alwaysUpdate || needToUpdate)
  165. {
  166. int vertexOffset = 0;
  167. int indexOffset = 0;
  168. for (int i = 0; i < this.count; i++)
  169. {
  170. Sprite3DObject obj = spriteList[i];
  171. if (obj.Enable == false) continue;
  172. // rotates the paticle by z-axis. (Sprite3D can rotate)
  173. Matrix transformMatrix = Matrix.CreateRotationZ(obj.Rotation) *
  174. Helper3D.Transpose(
  175. this.TransformedMatrix * renderTracer.View);
  176. // updates vertex positions.
  177. SetBufferPosition(ref vertexData, obj, vertexOffset,
  178. transformMatrix, this.renderingSpace);
  179. // updates texture coordinates.
  180. SetBufferTextureCoord(ref vertexData, obj, vertexOffset,
  181. this.renderingSpace);
  182. // updates vertex colors.
  183. SetBufferColor(ref vertexData, obj, vertexOffset);
  184. indexData[indexOffset + 0] = (short)(vertexOffset + 0);
  185. indexData[indexOffset + 1] = (short)(vertexOffset + 2);
  186. indexData[indexOffset + 2] = (short)(vertexOffset + 1);
  187. indexData[indexOffset + 3] = (short)(vertexOffset + 1);
  188. indexData[indexOffset + 4] = (short)(vertexOffset + 2);
  189. indexData[indexOffset + 5] = (short)(vertexOffset + 3);
  190. vertexOffset += vertexStride;
  191. indexOffset += indexStride;
  192. }
  193. if (userPrimitive == false)
  194. {
  195. // binds the vertex buffer.
  196. BindVertexBuffer();
  197. // binds the index buffer.
  198. BindIndexBuffer();
  199. }
  200. if (needToUpdate)
  201. needToUpdate = false;
  202. }
  203. // draws mesh
  204. base.OnDraw(renderTracer);
  205. }
  206. /// <summary>
  207. /// create 3D sprite objects using the texture.
  208. /// </summary>
  209. /// <param name="count">sprite object count</param>
  210. /// <param name="fileName">texture file name</param>
  211. /// <param name="space">3D render space</param>
  212. /// <param name="bAlwaysUpdate"></param>
  213. public void Create(int count, string fileName, RenderingSpace space,
  214. bool bAlwaysUpdate)
  215. {
  216. // Load texture
  217. GameResourceTexture2D resource =
  218. FrameworkCore.ResourceManager.LoadTexture(fileName);
  219. Create(count, resource.Texture2D, space, bAlwaysUpdate);
  220. }
  221. /// <summary>
  222. /// create 3D sprite objects using the texture.
  223. /// </summary>
  224. /// <param name="count">sprite object count</param>
  225. /// <param name="texture">texture resource</param>
  226. /// <param name="space">3D render space</param>
  227. /// <param name="bAlwaysUpdate"></param>
  228. public void Create(int count, Texture2D texture, RenderingSpace space,
  229. bool bAlwaysUpdate)
  230. {
  231. this.count = count;
  232. this.renderingSpace = space;
  233. alwaysUpdate = bAlwaysUpdate;
  234. for (int i = 0; i < count; i++)
  235. spriteList.Add(new Sprite3DObject());
  236. base.Create(count * vertexStride, count * indexStride, texture);
  237. }
  238. protected override void UnloadContent()
  239. {
  240. spriteList.Clear();
  241. base.UnloadContent();
  242. }
  243. /// <summary>
  244. /// enables/disables all sprite objects.
  245. /// </summary>
  246. /// <param name="enable"></param>
  247. public void SetObjectEnable(bool enable)
  248. {
  249. for (int i = 0; i < spriteList.Count; i++)
  250. SetObjectEnable(i, enable);
  251. }
  252. /// <summary>
  253. /// enables/disables an individual sprite object.
  254. /// </summary>
  255. public void SetObjectEnable(int index, bool enable)
  256. {
  257. if (spriteList.Count <= index || 0 > index)
  258. throw new ArgumentException("Invalid index.");
  259. if (spriteList[index].Enable != enable)
  260. {
  261. spriteList[index].Enable = enable;
  262. needToUpdate = true;
  263. }
  264. }
  265. /// <summary>
  266. /// configures a center position of each sprite object.
  267. /// </summary>
  268. /// <param name="index">an index of sprite object</param>
  269. /// <param name="position">a center position</param>
  270. public void SetCenter(int index, Vector3 position)
  271. {
  272. if (spriteList.Count <= index || 0 > index)
  273. throw new ArgumentException("Invalid index.");
  274. spriteList[index].Center = position;
  275. spriteList[index].AddUpdateType(Sprite3DObject.UpdateTypes.Position);
  276. needToUpdate = true;
  277. }
  278. /// <summary>
  279. /// gets a left top position of each sprite object.
  280. /// </summary>
  281. /// <param name="index">an index of sprite object</param>
  282. /// <param name="vec">out vector</param>
  283. public void GetLeftTop(int index, ref Vector3 vec)
  284. {
  285. if (spriteList.Count <= index || 0 > index)
  286. throw new ArgumentException("Invalid index.");
  287. vec.X = spriteList[index].Center.X - (spriteList[index].Width * 0.5f);
  288. vec.Y = spriteList[index].Center.Y - (spriteList[index].Height * 0.5f);
  289. vec.Z = spriteList[index].Center.Z;
  290. }
  291. /// <summary>
  292. /// gets a right down position of each sprite object.
  293. /// </summary>
  294. /// <param name="index">an index of sprite object</param>
  295. /// <param name="vec">out vector</param>
  296. public void GetRightBottom(int index, ref Vector3 vec)
  297. {
  298. if (spriteList.Count <= index || 0 > index)
  299. throw new ArgumentException("Invalid index.");
  300. vec.X = spriteList[index].Center.X + (spriteList[index].Width * 0.5f);
  301. vec.Y = spriteList[index].Center.Y + (spriteList[index].Height * 0.5f);
  302. vec.Z = spriteList[index].Center.Z;
  303. }
  304. /// <summary>
  305. /// configures a rotation value of each sprite object.
  306. /// </summary>
  307. /// <param name="index">an index of sprite object</param>
  308. /// <param name="rotation">rotation angle</param>
  309. public void SetRotation(int index, float amount)
  310. {
  311. if (spriteList.Count <= index || 0 > index)
  312. throw new ArgumentException("Invalid index.");
  313. spriteList[index].Rotation = amount;
  314. spriteList[index].AddUpdateType(Sprite3DObject.UpdateTypes.Rotation);
  315. needToUpdate = true;
  316. }
  317. /// <summary>
  318. /// flips each sprite object around x-axis and/or y-axis.
  319. /// </summary>
  320. /// <param name="index">an index of sprite object</param>
  321. /// <param name="flipX">specifies whether to rotate around x-axis</param>
  322. /// <param name="flipY">specifies whether to rotate around y-axis</param>
  323. public void SetFlip(int index, bool flipX, bool flipY)
  324. {
  325. if (spriteList.Count <= index || 0 > index)
  326. throw new ArgumentException("Invalid index.");
  327. spriteList[index].FlipX = flipX;
  328. spriteList[index].FlipY = flipY;
  329. spriteList[index].AddUpdateType(Sprite3DObject.UpdateTypes.Flip);
  330. needToUpdate = true;
  331. }
  332. /// <summary>
  333. /// configures the size of each sprite object.
  334. /// </summary>
  335. /// <param name="index">an index of sprite object</param>
  336. /// <param name="size">size vector</param>
  337. public void SetSize(int index, Vector2 size)
  338. {
  339. if (spriteList.Count <= index || 0 > index)
  340. throw new ArgumentException("Invalid index.");
  341. spriteList[index].Width = size.X;
  342. spriteList[index].Height = size.Y;
  343. spriteList[index].AddUpdateType(Sprite3DObject.UpdateTypes.Position);
  344. needToUpdate = true;
  345. }
  346. /// <summary>
  347. /// configures the size of each sprite object.
  348. /// </summary>
  349. /// <param name="index">an index of sprite object</param>
  350. /// <param name="width">size of width</param>
  351. /// <param name="height">size of height</param>
  352. public void SetSize(int index, float width, float height)
  353. {
  354. SetSize(index, new Vector2(width, height));
  355. }
  356. /// <summary>
  357. /// configures the texture coordinates of each sprite object.
  358. /// </summary>
  359. /// <param name="index">an index of sprite object</param>
  360. /// <param name="min">texture coordinates of minimum</param>
  361. /// <param name="max">texture coordinates of maximum</param>
  362. public void SetTextureCoord(int index, Vector2 min, Vector2 max)
  363. {
  364. if (spriteList.Count <= index || 0 > index)
  365. throw new ArgumentException("Invalid index.");
  366. spriteList[index].MinUV = min;
  367. spriteList[index].MaxUV = max;
  368. spriteList[index].AddUpdateType(Sprite3DObject.UpdateTypes.Texturecoord);
  369. needToUpdate = true;
  370. }
  371. /// <summary>
  372. /// configures the texture coordinates of each sprite object.
  373. /// </summary>
  374. /// <param name="index">an index of sprite object</param>
  375. /// <param name="u1">texture "u1" coordinate</param>
  376. /// <param name="v1">texture "v1" coordinate</param>
  377. /// <param name="u2">texture "u2" coordinate</param>
  378. /// <param name="v2">texture "v2" coordinate</param>
  379. public void SetTextureCoord(int index, float u1, float v1, float u2, float v2)
  380. {
  381. SetTextureCoord(index, new Vector2(u1, v1), new Vector2(u2, v2));
  382. }
  383. /// <summary>
  384. /// configures the vertex color of each sprite object.
  385. /// </summary>
  386. /// <param name="index">an index of sprite object</param>
  387. /// <param name="color">color</param>
  388. public void SetColor(int index, Color color)
  389. {
  390. if (spriteList.Count <= index || 0 > index)
  391. throw new ArgumentException("Invalid index.");
  392. spriteList[index].Color = color;
  393. spriteList[index].AddUpdateType(Sprite3DObject.UpdateTypes.Color);
  394. needToUpdate = true;
  395. }
  396. /// <summary>
  397. /// configures the vertex color of each sprite object.
  398. /// </summary>
  399. /// <param name="index">an index of sprite object</param>
  400. /// <param name="r">a red component of color</param>
  401. /// <param name="g">a green component of color</param>
  402. /// <param name="b">a blue component of color</param>
  403. /// <param name="a">an alpha component of color</param>
  404. public void SetColor(int index, byte r, byte g, byte b, byte a)
  405. {
  406. SetColor(index, new Color(r,g,b,a));
  407. }
  408. /// <summary>
  409. /// configures a transformed matrix to the vertex component data
  410. /// using the sprite object.
  411. /// </summary>
  412. /// <param name="vertexData">target vertex component data</param>
  413. /// <param name="obj">source sprite object</param>
  414. /// <param name="startIndex">start index of the vertex component data</param>
  415. /// <param name="transformMatrix">transformed matrix</param>
  416. /// <param name="space">3D render space</param>
  417. private static void SetBufferPosition(
  418. ref VertexPositionColorTexture[] vertexData, Sprite3DObject obj,
  419. int startIndex, Matrix transformMatrix, RenderingSpace space)
  420. {
  421. float cx = obj.Width * 0.5f;
  422. float cy = obj.Height * 0.5f;
  423. vertexData[startIndex + 0].Position = new Vector3(-cx, +cy, 0.0f);
  424. vertexData[startIndex + 1].Position = new Vector3(+cx, +cy, 0.0f);
  425. vertexData[startIndex + 2].Position = new Vector3(-cx, -cy, 0.0f);
  426. vertexData[startIndex + 3].Position = new Vector3(+cx, -cy, 0.0f);
  427. for (int i = 0; i < 4; i++)
  428. {
  429. int arrayIndex = startIndex + i;
  430. Vector3.TransformNormal(ref vertexData[arrayIndex].Position,
  431. ref transformMatrix,
  432. out vertexData[arrayIndex].Position);
  433. vertexData[arrayIndex].Position += obj.Center;
  434. if (space == RenderingSpace.Screen)
  435. vertexData[arrayIndex].Position =
  436. HelperMath.Make2DCoord(vertexData[arrayIndex].Position);
  437. }
  438. }
  439. /// <summary>
  440. /// configures texture coordinates to the vertex component data
  441. /// using the sprite object.
  442. /// </summary>
  443. /// <param name="vertexData">target vertex component data</param>
  444. /// <param name="obj">source sprite object</param>
  445. /// <param name="startIndex">start index of the vertex component data</param>
  446. /// <param name="space">3D render space</param>
  447. private static void SetBufferTextureCoord(
  448. ref VertexPositionColorTexture[] vertexData, Sprite3DObject obj,
  449. int startIndex, RenderingSpace space)
  450. {
  451. float u1 = 0.0f, v1 = 0.0f, u2 = 0.0f, v2 = 0.0f;
  452. // Differ Y axis of the 3D and 2D
  453. bool flipY = (space == RenderingSpace.Screen ? !obj.FlipY : obj.FlipY);
  454. if (obj.FlipX)
  455. {
  456. if (flipY)
  457. {
  458. u1 = obj.MaxUV.X;
  459. v1 = obj.MaxUV.Y;
  460. u2 = obj.MinUV.X;
  461. v2 = obj.MinUV.Y;
  462. }
  463. else
  464. {
  465. u1 = obj.MaxUV.X;
  466. v1 = obj.MinUV.Y;
  467. u2 = obj.MinUV.X;
  468. v2 = obj.MaxUV.Y;
  469. }
  470. }
  471. else
  472. {
  473. if (flipY)
  474. {
  475. u1 = obj.MinUV.X;
  476. v1 = obj.MaxUV.Y;
  477. u2 = obj.MaxUV.X;
  478. v2 = obj.MinUV.Y;
  479. }
  480. else
  481. {
  482. u1 = obj.MinUV.X;
  483. v1 = obj.MinUV.Y;
  484. u2 = obj.MaxUV.X;
  485. v2 = obj.MaxUV.Y;
  486. }
  487. }
  488. vertexData[startIndex + 0].TextureCoordinate = new Vector2(u1, v1);
  489. vertexData[startIndex + 1].TextureCoordinate = new Vector2(u2, v1);
  490. vertexData[startIndex + 2].TextureCoordinate = new Vector2(u1, v2);
  491. vertexData[startIndex + 3].TextureCoordinate = new Vector2(u2, v2);
  492. }
  493. /// <summary>
  494. /// configures vertex color to the vertex component data using the sprite object.
  495. /// </summary>
  496. /// <param name="vertexData">target vertex component data</param>
  497. /// <param name="obj">source sprite object</param>
  498. /// <param name="startIndex">start index of the vertex component data</param>
  499. private static void SetBufferColor(ref VertexPositionColorTexture[] vertexData,
  500. Sprite3DObject obj, int startIndex)
  501. {
  502. for( int i = 0; i < 4; i++)
  503. vertexData[startIndex + i].Color = obj.Color;
  504. }
  505. }
  506. }