GameBillboard.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // GameBillboard.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.Helper;
  18. using RobotGameData.Resource;
  19. using RobotGameData.Collision;
  20. using RobotGameData.GameInterface;
  21. #endregion
  22. namespace RobotGameData.GameObject
  23. {
  24. #region BillboardObject
  25. public class BillboardObject : INamed
  26. {
  27. [Flags]
  28. public enum UpdateTypes
  29. {
  30. None = 0x00000000,
  31. Position = 0x00000001,
  32. Texturecoord = 0x00000002,
  33. Color = 0x00000004,
  34. Enable = 0x0000008,
  35. Axis = 0x00000010,
  36. }
  37. String name = String.Empty;
  38. uint updateFlag = 0;
  39. bool enable = true;
  40. Vector3 start = Vector3.Zero;
  41. Vector3 end = Vector3.Zero;
  42. float height = 1.0f;
  43. Color color = new Color(255, 255, 255, 255);
  44. Vector2[] uv = new Vector2[2]
  45. {
  46. Vector2.Zero,
  47. Vector2.One,
  48. };
  49. public string Name
  50. {
  51. get { return name; }
  52. set { name = value; }
  53. }
  54. public bool Enable
  55. {
  56. get { return enable; }
  57. set { enable = value; }
  58. }
  59. public Vector3 Start
  60. {
  61. get { return start; }
  62. set { start = value; }
  63. }
  64. public Vector3 End
  65. {
  66. get { return end; }
  67. set { end = value; }
  68. }
  69. public float Size
  70. {
  71. get { return height; }
  72. set { height = value; }
  73. }
  74. public Color Color
  75. {
  76. get { return color; }
  77. set { color = value; }
  78. }
  79. public void AddUpdateType(UpdateTypes billboardUpdate)
  80. {
  81. updateFlag |= (uint)billboardUpdate;
  82. }
  83. public void RemoveUpdateType(UpdateTypes billboardUpdate)
  84. {
  85. updateFlag &= ~(uint)billboardUpdate;
  86. }
  87. public Vector2 MinUV
  88. {
  89. get { return this.uv[0]; }
  90. set { this.uv[0] = value; }
  91. }
  92. public Vector2 MaxUV
  93. {
  94. get { return this.uv[1]; }
  95. set { this.uv[1] = value; }
  96. }
  97. }
  98. #endregion
  99. /// <summary>
  100. /// this sprite always looks at the view matrix in the 3D world.
  101. /// It has a begin point and an end point in the 3D world.
  102. /// </summary>
  103. public class GameBillboard : GameMesh
  104. {
  105. #region Fields
  106. const int vertexStride = 4;
  107. const int indexStride = 6;
  108. List<BillboardObject> billboardList = new List<BillboardObject>();
  109. RenderingSpace renderingSpace = RenderingSpace.World;
  110. Matrix lastViewMatrix;
  111. int objectCount = 0;
  112. bool needToUpdate = false;
  113. bool alwaysUpdate = false;
  114. #endregion
  115. #region Properties
  116. public int ObjectCount
  117. {
  118. get { return objectCount; }
  119. }
  120. public RenderingSpace RenderingSpace
  121. {
  122. get { return renderingSpace; }
  123. }
  124. public static int VertexStride
  125. {
  126. get { return vertexStride; }
  127. }
  128. public static int IndexStride
  129. {
  130. get { return indexStride; }
  131. }
  132. #endregion
  133. /// <summary>
  134. /// updates the vertex data and draws
  135. /// It always looks at the view matrix at the center between
  136. /// the begin point and the end point of the billboard.
  137. /// </summary>
  138. /// <param name="renderTracer">render information</param>
  139. protected override void OnDraw(RenderTracer renderTracer)
  140. {
  141. int count = 0;
  142. for (int i = 0; i < objectCount; i++)
  143. {
  144. if (billboardList[i].Enable == false) continue;
  145. count++;
  146. }
  147. if (count == 0) return;
  148. PrimitiveCount = count * 2;
  149. UpdateVertexCount = objectCount * vertexStride;
  150. // needs to update?
  151. if (renderTracer.View != lastViewMatrix)
  152. {
  153. needToUpdate = true;
  154. this.lastViewMatrix = renderTracer.View;
  155. }
  156. if (alwaysUpdate || needToUpdate)
  157. {
  158. int vertexOffset = 0;
  159. int indexOffset = 0;
  160. // calculates inverse view matrix.
  161. Matrix billboardMatrix = this.TransformedMatrix * renderTracer.View;
  162. billboardMatrix = Helper3D.Transpose(billboardMatrix);
  163. // gets inverse view direction.
  164. Vector3 invertViewAt = billboardMatrix.Forward;
  165. invertViewAt.Normalize();
  166. for (int i = 0; i < objectCount; i++)
  167. {
  168. BillboardObject obj = billboardList[i];
  169. if (obj.Enable == false) continue;
  170. Vector3 vec = Vector3.Zero;
  171. Vector3 dir = Vector3.Zero;
  172. dir = obj.End - obj.Start;
  173. dir.Normalize();
  174. Vector3.Cross(ref dir, ref invertViewAt, out vec);
  175. vec.Normalize();
  176. // updates vertex positions.
  177. SetBufferPosition(ref vertexData, obj, vertexOffset, vec);
  178. // updates texture coordinates.
  179. SetBufferTextureCoord(ref vertexData, obj, vertexOffset,
  180. renderingSpace);
  181. // updates vertex colors.
  182. SetBufferColor(ref vertexData, obj, vertexOffset);
  183. indexData[indexOffset + 0] = (short)(vertexOffset + 0);
  184. indexData[indexOffset + 1] = (short)(vertexOffset + 2);
  185. indexData[indexOffset + 2] = (short)(vertexOffset + 1);
  186. indexData[indexOffset + 3] = (short)(vertexOffset + 1);
  187. indexData[indexOffset + 4] = (short)(vertexOffset + 2);
  188. indexData[indexOffset + 5] = (short)(vertexOffset + 3);
  189. vertexOffset += vertexStride;
  190. indexOffset += indexStride;
  191. }
  192. if (userPrimitive == false)
  193. {
  194. // binds the vertex buffer.
  195. BindVertexBuffer();
  196. // binds the index buffer.
  197. BindIndexBuffer();
  198. }
  199. if (needToUpdate)
  200. needToUpdate = false;
  201. }
  202. // draws mesh
  203. base.OnDraw(renderTracer);
  204. }
  205. /// <summary>
  206. /// create billboard objects using the texture.
  207. /// </summary>
  208. /// <param name="count">billboard object count</param>
  209. /// <param name="fileName">texture file name</param>
  210. /// <param name="renderingSpace">3D render space</param>
  211. /// <param name="alwaysUpdate"></param>
  212. public void Create(int count, string fileName, RenderingSpace renderingSpace,
  213. bool alwaysUpdate)
  214. {
  215. // load a texture.
  216. GameResourceTexture2D resource =
  217. FrameworkCore.ResourceManager.LoadTexture(fileName);
  218. Create(count, resource.Texture2D, renderingSpace, alwaysUpdate);
  219. }
  220. /// <summary>
  221. /// create billboard objects using the texture.
  222. /// </summary>
  223. /// <param name="count">billboard object count</param>
  224. /// <param name="texture">texture resource</param>
  225. /// <param name="renderingSpace">3D render space</param>
  226. /// <param name="alwaysUpdate"></param>
  227. public void Create(int count, Texture2D texture, RenderingSpace renderingSpace,
  228. bool alwaysUpdate)
  229. {
  230. this.objectCount = count;
  231. this.renderingSpace = renderingSpace;
  232. this.alwaysUpdate = alwaysUpdate;
  233. // create billboard objects.
  234. for (int i = 0; i < count; i++)
  235. {
  236. BillboardObject obj = new BillboardObject();
  237. obj.AddUpdateType(BillboardObject.UpdateTypes.Enable);
  238. billboardList.Add(obj);
  239. }
  240. base.Create(count * vertexStride, count * indexStride, texture);
  241. }
  242. protected override void UnloadContent()
  243. {
  244. billboardList.Clear();
  245. base.UnloadContent();
  246. }
  247. /// <summary>
  248. /// enables/disables all billboard objects.
  249. /// </summary>
  250. public void SetUpdateType(bool billboardUpdate)
  251. {
  252. for (int i = 0; i < billboardList.Count; i++)
  253. SetUpdateType(i, billboardUpdate);
  254. }
  255. /// <summary>
  256. /// enables/disables an individual billboard object.
  257. /// </summary>
  258. public void SetUpdateType(int index, bool billboardUpdate)
  259. {
  260. if (billboardList.Count <= index || 0 > index)
  261. throw new ArgumentException("Invalid index.");
  262. if (billboardList[index].Enable != billboardUpdate)
  263. {
  264. billboardList[index].Enable = billboardUpdate;
  265. needToUpdate = true;
  266. }
  267. }
  268. /// <summary>
  269. /// configures the begin position of each billboard object.
  270. /// </summary>
  271. /// <param name="index">an index of billboard object</param>
  272. /// <param name="position">begin position of the billboard object</param>
  273. public void SetStart(int index, Vector3 position)
  274. {
  275. if (billboardList.Count <= index || 0 > index)
  276. throw new ArgumentException("Invalid index.");
  277. billboardList[index].Start = position;
  278. billboardList[index].AddUpdateType(
  279. BillboardObject.UpdateTypes.Position);
  280. needToUpdate = true;
  281. }
  282. /// <summary>
  283. /// configures the begin position of each billboard object.
  284. /// </summary>
  285. /// <param name="index">an index of billboard object</param>
  286. /// <param name="x">x-component of begin position of the billboard object</param>
  287. /// <param name="y">y-component of begin position of the billboard object</param>
  288. /// <param name="z">z-component of begin position of the billboard object</param>
  289. public void SetStart(int index, float x, float y, float z)
  290. {
  291. SetStart(index, x, y, z);
  292. }
  293. /// <summary>
  294. /// configures the end position of each billboard object.
  295. /// </summary>
  296. /// <param name="index">an index of billboard object</param>
  297. /// <param name="position">end position of the billboard object</param>
  298. public void SetEnd(int index, Vector3 position)
  299. {
  300. if (billboardList.Count <= index || 0 > index)
  301. throw new ArgumentException("Invalid index.");
  302. billboardList[index].End = position;
  303. billboardList[index].AddUpdateType(
  304. BillboardObject.UpdateTypes.Position);
  305. needToUpdate = true;
  306. }
  307. /// <summary>
  308. /// configures the end position of each billboard object.
  309. /// </summary>
  310. /// <param name="index">an index of billboard object</param>
  311. /// <param name="x">x-component of end position of the billboard object</param>
  312. /// <param name="y">y-component of end position of the billboard object</param>
  313. /// <param name="z">z-component of end position of the billboard object</param>
  314. public void SetEnd(int index, float x, float y, float z)
  315. {
  316. SetEnd(index, x, y, z);
  317. }
  318. /// <summary>
  319. /// configures the size of each billboard object.
  320. /// </summary>
  321. /// <param name="index">an index of billboard object</param>
  322. /// <param name="height">the height of billboard object</param>
  323. public void SetSize(int index, float height)
  324. {
  325. if (billboardList.Count <= index || 0 > index)
  326. throw new ArgumentException("Invalid index.");
  327. billboardList[index].Size = height;
  328. billboardList[index].AddUpdateType(
  329. BillboardObject.UpdateTypes.Position);
  330. needToUpdate = true;
  331. }
  332. /// <summary>
  333. /// configures the texture coordinates of each billboard object.
  334. /// </summary>
  335. /// <param name="index">an index of billboard object</param>
  336. /// <param name="min">texture coordinates of minimum</param>
  337. /// <param name="max">texture coordinates of maximum</param>
  338. public void SetTextureCoord(int index, Vector2 min, Vector2 max)
  339. {
  340. if (billboardList.Count <= index || 0 > index)
  341. throw new ArgumentException("Invalid index.");
  342. billboardList[index].MinUV = min;
  343. billboardList[index].MaxUV = max;
  344. billboardList[index].AddUpdateType(
  345. BillboardObject.UpdateTypes.Texturecoord);
  346. needToUpdate = true;
  347. }
  348. /// <summary>
  349. /// configures the texture coordinates of each billboard object.
  350. /// </summary>
  351. /// <param name="index">an index of billboard object</param>
  352. /// <param name="u1">texture "u1" coordinate</param>
  353. /// <param name="v1">texture "v1" coordinate</param>
  354. /// <param name="u2">texture "u2" coordinate</param>
  355. /// <param name="v2">texture "v2" coordinate</param>
  356. public void SetTextureCoord(int index, float u1, float v1, float u2, float v2)
  357. {
  358. SetTextureCoord(index, new Vector2(u1, v1), new Vector2(u2, v2));
  359. }
  360. /// <summary>
  361. /// configures the vertex color of each billboard object.
  362. /// </summary>
  363. /// <param name="index">an index of billboard object</param>
  364. /// <param name="color">color</param>
  365. public void SetColor(int index, Color color)
  366. {
  367. if (billboardList.Count <= index || 0 > index)
  368. throw new ArgumentException("Invalid index.");
  369. billboardList[index].Color = color;
  370. billboardList[index].AddUpdateType(
  371. BillboardObject.UpdateTypes.Color);
  372. needToUpdate = true;
  373. }
  374. /// <summary>
  375. /// configures the vertex color of each billboard object.
  376. /// </summary>
  377. /// <param name="index">an index of billboard object</param>
  378. /// <param name="r">a red component of color</param>
  379. /// <param name="g">a green component of color</param>
  380. /// <param name="b">a blue component of color</param>
  381. /// <param name="a">an alpha component of color</param>
  382. public void SetColor(int index, byte r, byte g, byte b, byte a)
  383. {
  384. SetColor(index, new Color(r, g, b, a));
  385. }
  386. /// <summary>
  387. /// configures a position vector to the vertex component data
  388. /// using the billboard object.
  389. /// </summary>
  390. /// <param name="vertexData">target vertex component data</param>
  391. /// <param name="obj">source billboard object</param>
  392. /// <param name="startIndex">start index of the vertex component data</param>
  393. /// <param name="ay">position vector</param>
  394. private static void SetBufferPosition(
  395. ref VertexPositionColorTexture[] vertexData, BillboardObject obj,
  396. int startIndex, Vector3 ay)
  397. {
  398. Vector3 by = Vector3.Zero;
  399. float cy = obj.Size * 0.5f;
  400. by = ay * cy;
  401. // [0] [1]
  402. // +-------------+
  403. // | |
  404. // +c |
  405. // | |
  406. // +-------------+
  407. // [2] [3]
  408. // 0 2 1 - 1 2 3
  409. vertexData[startIndex + 0].Position = obj.Start - by;
  410. vertexData[startIndex + 1].Position = obj.End - by;
  411. vertexData[startIndex + 2].Position = obj.Start + by;
  412. vertexData[startIndex + 3].Position = obj.End + by;
  413. }
  414. /// <summary>
  415. /// configures texture coordinates to the vertex component data
  416. /// using the billboard object.
  417. /// </summary>
  418. /// <param name="vertexData">target vertex component data</param>
  419. /// <param name="obj">source billboard object</param>
  420. /// <param name="startIndex">start index of the vertex component data</param>
  421. /// <param name="renderingSpace">3D render space</param>
  422. private static void SetBufferTextureCoord(
  423. ref VertexPositionColorTexture[] vertexData, BillboardObject obj,
  424. int startIndex, RenderingSpace renderingSpace)
  425. {
  426. float u1 = 0.0f, v1 = 0.0f, u2 = 0.0f, v2 = 0.0f;
  427. u1 = obj.MinUV.X;
  428. v1 = obj.MinUV.Y;
  429. u2 = obj.MaxUV.X;
  430. v2 = obj.MaxUV.Y;
  431. if (renderingSpace == RenderingSpace.Screen)
  432. {
  433. float swap = v1;
  434. v1 = v2;
  435. v2 = swap;
  436. }
  437. vertexData[startIndex + 0].TextureCoordinate = new Vector2(u1, v2);
  438. vertexData[startIndex + 1].TextureCoordinate = new Vector2(u1, v1);
  439. vertexData[startIndex + 2].TextureCoordinate = new Vector2(u2, v2);
  440. vertexData[startIndex + 3].TextureCoordinate = new Vector2(u2, v1);
  441. }
  442. /// <summary>
  443. /// configures vertex color to the vertex component data
  444. /// using the billboard object.
  445. /// </summary>
  446. /// <param name="vertexData">target vertex component data</param>
  447. /// <param name="obj">source billboard object</param>
  448. /// <param name="startIndex">start index of the vertex component data</param>
  449. private static void SetBufferColor(ref VertexPositionColorTexture[] vertexData,
  450. BillboardObject obj, int startIndex)
  451. {
  452. for (int i = 0; i < 4; i++)
  453. vertexData[startIndex + i].Color = obj.Color;
  454. }
  455. }
  456. }