PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/Rendering/Models/Mesh.cs

#
C# | 572 lines | 263 code | 46 blank | 263 comment | 9 complexity | ddac8929b43d11dd995fb09df3567913 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using Delta.ContentSystem.Rendering;
  3. using Delta.Graphics.Basics;
  4. using Delta.Rendering.Basics.Materials;
  5. using Delta.Utilities;
  6. using Delta.Utilities.Datatypes;
  7. namespace Delta.Rendering.Models
  8. {
  9. /// <summary>
  10. /// Mesh model class for 3d meshes (but 2d meshes also work). Basically
  11. /// a mesh is just a combination of Geometry and Material. Models can
  12. /// consist of multiple meshes.
  13. /// </summary>
  14. public class Mesh
  15. {
  16. #region Constants
  17. /// <summary>
  18. /// Line colors for displaying the bones as lines.
  19. /// </summary>
  20. private static readonly Color[] BoneColors = new[]
  21. {
  22. Color.Blue, Color.Red, Color.Yellow, Color.White, Color.Teal,
  23. Color.Brown, Color.Orange, Color.LightBlue, Color.Green,
  24. Color.Purple,
  25. };
  26. #endregion
  27. #region CreatePlane (Static)
  28. /// <summary>
  29. /// Creates an XY plane.
  30. /// </summary>
  31. /// <param name="setName">Set name</param>
  32. /// <param name="setWidth">Set width</param>
  33. /// <param name="setDepth">Set depth</param>
  34. /// <param name="setColor">Vertex color during creation.</param>
  35. /// <param name="setMaterialData">Set material data</param>
  36. /// <returns>Mesh with the created plane and given material</returns>
  37. public static Mesh CreatePlane(string setName, float setWidth,
  38. float setDepth, Color setColor, MaterialData setMaterialData)
  39. {
  40. // First we still need to get the shader for the required vertex format
  41. Shader shader = Shader.Create(setMaterialData.ShaderName);
  42. // for the plane we create
  43. GeometryData planeData = GeometryData.CreatePlane(shader.VertexFormat,
  44. setWidth, setDepth, setColor);
  45. return new Mesh(setName, planeData, setMaterialData, Vector.Zero);
  46. }
  47. /// <summary>
  48. /// Creates an XY plane
  49. /// </summary>
  50. /// <param name="setName">Set name</param>
  51. /// <param name="setWidth">Set width</param>
  52. /// <param name="setDepth">Set depth</param>
  53. /// <param name="setMaterialData">Set material data</param>
  54. /// <returns>Mesh with the created plane and given material</returns>
  55. public static Mesh CreatePlane(string setName, float setWidth,
  56. float setDepth, MaterialData setMaterialData)
  57. {
  58. // First we still need to get the shader for the required vertex format
  59. Shader shader = Shader.Create(setMaterialData.ShaderName);
  60. // for the plane we create
  61. GeometryData planeData = GeometryData.CreatePlane(shader.VertexFormat,
  62. setWidth, setDepth, setMaterialData.Diffuse);
  63. return new Mesh(setName, planeData, setMaterialData, Vector.Zero);
  64. }
  65. #endregion
  66. #region CreateSegmentedPlane (Static)
  67. /// <summary>
  68. /// Creates an XY plane with segments, which is useful for testing
  69. /// specular and other shader effects with pre-calculated data in the
  70. /// vertex shader (which will not look close up for just a 1x1 plane).
  71. /// </summary>
  72. /// <param name="setName">Name of the set.</param>
  73. /// <param name="setWidth">Width of the set.</param>
  74. /// <param name="setDepth">The set depth.</param>
  75. /// <param name="setSegments">The set segments.</param>
  76. /// <param name="uvForEachSegment">Create new uv from 0-1 for each segment.
  77. /// Useful for tiling (works even without tileable textures)</param>
  78. /// <param name="setColor">Vertex color during creation.</param>
  79. /// <param name="setMaterialData">The set material data.</param>
  80. /// <returns>Mesh containing segmented plane data.</returns>
  81. public static Mesh CreateSegmentedPlane(string setName, float setWidth,
  82. float setDepth, int setSegments, bool uvForEachSegment, Color setColor,
  83. MaterialData setMaterialData)
  84. {
  85. // First we still need to get the shader for the required vertex format
  86. Shader shader = Shader.Create(setMaterialData.ShaderName);
  87. // for the plane we create
  88. GeometryData planeData = GeometryData.CreateSegmentedPlane(
  89. shader.VertexFormat, setWidth, setDepth, setSegments, uvForEachSegment,
  90. setColor);
  91. return new Mesh(setName, planeData, setMaterialData, Vector.Zero);
  92. }
  93. /// <summary>
  94. /// Creates an XY plane with segments, which is useful for testing
  95. /// specular and other shader effects with pre-calculated data in the
  96. /// vertex shader (which will not look close up for just a 1x1 plane).
  97. /// </summary>
  98. /// <param name="setName">Name of the set.</param>
  99. /// <param name="setWidth">Width of the set.</param>
  100. /// <param name="setDepth">The set depth.</param>
  101. /// <param name="setSegments">The set segments.</param>
  102. /// <param name="setMaterialData">The set material data.</param>
  103. /// <returns>
  104. /// The new create Mesh.
  105. /// </returns>
  106. public static Mesh CreateSegmentedPlane(string setName, float setWidth,
  107. float setDepth, int setSegments, MaterialData setMaterialData)
  108. {
  109. return CreateSegmentedPlane(setName, setWidth, setDepth, setSegments,
  110. false, setMaterialData.Diffuse, setMaterialData);
  111. }
  112. #endregion
  113. #region CreateBox (Static)
  114. /// <summary>
  115. /// Create box mesh.
  116. /// </summary>
  117. /// <param name="setName">Name of the set.</param>
  118. /// <param name="setWidth">Width of the set.</param>
  119. /// <param name="setDepth">The set depth.</param>
  120. /// <param name="setHeight">Height of the set.</param>
  121. /// <param name="setColor">Vertex color during creation.</param>
  122. /// <param name="setMaterialData">The set material data.</param>
  123. /// <returns>Mesh containing box data.</returns>
  124. public static Mesh CreateBox(string setName, float setWidth,
  125. float setDepth, float setHeight, Color setColor,
  126. MaterialData setMaterialData)
  127. {
  128. // First we still need to get the shader for the required vertex format
  129. Shader shader = Shader.Create(setMaterialData.ShaderName);
  130. // for the box we create
  131. GeometryData boxData = GeometryData.CreateBox(shader.VertexFormat,
  132. setWidth, setDepth, setHeight, false, setColor);
  133. return new Mesh(setName, boxData, setMaterialData, Vector.Zero);
  134. }
  135. /// <summary>
  136. /// Create box mesh.
  137. /// </summary>
  138. /// <param name="setName">Name of the set.</param>
  139. /// <param name="setWidth">Width of the set.</param>
  140. /// <param name="setDepth">The set depth.</param>
  141. /// <param name="setHeight">Height of the set.</param>
  142. /// <param name="setMaterialData">The set material data.</param>
  143. /// <returns>Mesh containing box data.</returns>
  144. public static Mesh CreateBox(string setName, float setWidth,
  145. float setDepth, float setHeight,
  146. MaterialData setMaterialData)
  147. {
  148. return CreateBox(setName, setWidth, setDepth, setHeight,
  149. setMaterialData.Diffuse, setMaterialData);
  150. }
  151. #endregion
  152. #region CreateCube (Static)
  153. /// <summary>
  154. /// Create cube shape with all 6 faces with equal size.
  155. /// </summary>
  156. /// <param name="setName">Name of the set.</param>
  157. /// <param name="setSize">The size of the faces.</param>
  158. /// <param name="setColor">Vertex color during creation.</param>
  159. /// <param name="setMaterialData">The set material data.</param>
  160. /// <returns>Mesh containing cube data.</returns>
  161. public static Mesh CreateCube(string setName, float setSize,
  162. Color setColor, MaterialData setMaterialData)
  163. {
  164. // First we still need to get the shader for the required vertex format
  165. Shader shader = Shader.Create(setMaterialData.ShaderName);
  166. // for the box we create
  167. GeometryData planeData = GeometryData.CreateCube(shader.VertexFormat,
  168. setSize, setColor);
  169. return new Mesh(setName, planeData, setMaterialData, Vector.Zero);
  170. }
  171. /// <summary>
  172. /// Create cube shape with all 6 faces with equal size.
  173. /// </summary>
  174. /// <param name="setName">Name of the set.</param>
  175. /// <param name="setSize">The size of the faces.</param>
  176. /// <param name="setMaterialData">The set material data.</param>
  177. /// <returns>Mesh containing cube data.</returns>
  178. public static Mesh CreateCube(string setName, float setSize,
  179. MaterialData setMaterialData)
  180. {
  181. return CreateCube(setName, setSize, setMaterialData.Diffuse,
  182. setMaterialData);
  183. }
  184. #endregion
  185. #region CreateInnerBox (Static)
  186. /// <summary>
  187. /// Creates an inner box (-&gt; like the 'CreateBox()' method but in the
  188. /// "inverted" way).
  189. /// Note: This kind of a box is helpful if you want to render something
  190. /// inside a box like a simple (demo) room.
  191. /// </summary>
  192. /// <param name="setName">Name of the set.</param>
  193. /// <param name="setWidth">Width of the set.</param>
  194. /// <param name="setDepth">The set depth.</param>
  195. /// <param name="setHeight">Height of the set.</param>
  196. /// <param name="setColor">Vertex color during creation.</param>
  197. /// <param name="setMaterialData">The set material data.</param>
  198. /// <returns>Mesh containing inner box data.</returns>
  199. public static Mesh CreateInnerBox(string setName, float setWidth,
  200. float setDepth, float setHeight, Color setColor, MaterialData setMaterialData)
  201. {
  202. // First we still need to get the shader for the required vertex format
  203. Shader shader = Shader.Create(setMaterialData.ShaderName);
  204. // for the cube we create
  205. GeometryData planeData = GeometryData.CreateBox(shader.VertexFormat,
  206. setWidth, setDepth, setHeight, true, setColor);
  207. return new Mesh(setName, planeData, setMaterialData, Vector.Zero);
  208. }
  209. /// <summary>
  210. /// Creates an inner box (-&gt; like the 'CreateBox()' method but in the
  211. /// "inverted" way).
  212. /// Note: This kind of a box is helpful if you want to render something
  213. /// inside a box like a simple (demo) room.
  214. /// </summary>
  215. /// <param name="setName">Name of the set.</param>
  216. /// <param name="setWidth">Width of the set.</param>
  217. /// <param name="setDepth">The set depth.</param>
  218. /// <param name="setHeight">Height of the set.</param>
  219. /// <param name="setMaterialData">The set material data.</param>
  220. /// <returns>Mesh containing inner box data.</returns>
  221. public static Mesh CreateInnerBox(string setName, float setWidth,
  222. float setDepth, float setHeight, MaterialData setMaterialData)
  223. {
  224. return CreateInnerBox(setName, setWidth, setDepth, setHeight,
  225. setMaterialData.Diffuse, setMaterialData);
  226. }
  227. #endregion
  228. #region CreateSphere (Static)
  229. /// <summary>
  230. /// Creates a sphere as a Mesh with the given parameters.
  231. /// </summary>
  232. /// <param name="setName">Name of the sphere mesh</param>
  233. /// <param name="setRadius">Radius for the sphere from the center</param>
  234. /// <param name="setColor">
  235. /// Color for the new sphere in case the vertex format supports colored
  236. /// vertices (otherwise ignored).
  237. /// </param>
  238. /// <param name="setMaterialData">The material data for the mesh.</param>
  239. /// <returns>Mesh containing the sphere.</returns>
  240. public static Mesh CreateSphere(string setName, float setRadius,
  241. Color setColor, MaterialData setMaterialData)
  242. {
  243. // First we still need to get the shader for the required vertex format
  244. Shader shader = Shader.Create(setMaterialData.ShaderName);
  245. // for the sphere we create
  246. GeometryData sphereData = GeometryData.CreateSphere(shader.VertexFormat,
  247. setRadius, setColor);
  248. return new Mesh(setName, sphereData, setMaterialData, Vector.Zero);
  249. }
  250. /// <summary>
  251. /// Creates a sphere as a Mesh with the given parameters.
  252. /// </summary>
  253. /// <param name="setName">Name of the sphere mesh</param>
  254. /// <param name="setRadius">Radius for the sphere from the center</param>
  255. /// <param name="setMaterialData">The material data for the mesh.</param>
  256. /// <returns>Mesh containing the sphere.</returns>
  257. public static Mesh CreateSphere(string setName, float setRadius,
  258. MaterialData setMaterialData)
  259. {
  260. return CreateSphere(setName, setRadius, setMaterialData.Diffuse,
  261. setMaterialData);
  262. }
  263. #endregion
  264. #region CreateInnerSphere (Static)
  265. /// <summary>
  266. /// Create sphere with indices inverted (if you want to be inside the
  267. /// sphere, e.g. for a skydome).
  268. /// </summary>
  269. /// <param name="setName">Name of the sphere mesh</param>
  270. /// <param name="setRadius">Radius for the sphere from the center</param>
  271. /// <param name="setColor">
  272. /// Color for the new sphere in case the vertex format supports colored
  273. /// vertices (otherwise ignored).
  274. /// </param>
  275. /// <param name="setMaterialData">The material data for the mesh.</param>
  276. /// <returns>Mesh containing the inner sphere.</returns>
  277. public static Mesh CreateInnerSphere(string setName, float setRadius,
  278. Color setColor, MaterialData setMaterialData)
  279. {
  280. // First we still need to get the shader for the required vertex format
  281. Shader shader = Shader.Create(setMaterialData.ShaderName);
  282. // for the sphere we create
  283. GeometryData sphereData = GeometryData.CreateSphere(shader.VertexFormat,
  284. setRadius, setColor, true);
  285. return new Mesh(setName, sphereData, setMaterialData, Vector.Zero);
  286. }
  287. /// <summary>
  288. /// Create sphere with indices inverted.
  289. /// </summary>
  290. /// <param name="setName">Name of the set.</param>
  291. /// <param name="setRadius">The set radius.</param>
  292. /// <param name="setMaterialData">The set material data.</param>
  293. /// <returns>Mesh containing inner sphere data.</returns>
  294. public static Mesh CreateInnerSphere(string setName, float setRadius,
  295. MaterialData setMaterialData)
  296. {
  297. return CreateInnerSphere(setName, setRadius, setMaterialData.Diffuse,
  298. setMaterialData);
  299. }
  300. #endregion
  301. #region CreateCapsule (Static)
  302. /// <summary>
  303. /// Create capsule mesh.
  304. /// </summary>
  305. /// <param name="setName">Name of the set.</param>
  306. /// <param name="setDiameter">The diameter of cylinder.</param>
  307. /// <param name="setLength">Length of the set.</param>
  308. /// <param name="setColor">Vertex color during creation.</param>
  309. /// <param name="setMaterialData">The set material data.</param>
  310. /// <returns>Mesh containing capsule data.</returns>
  311. public static Mesh CreateCapsule(string setName, float setDiameter,
  312. float setLength, Color setColor, MaterialData setMaterialData)
  313. {
  314. // First we still need to get the shader for the required vertex format
  315. Shader shader = Shader.Create(setMaterialData.ShaderName);
  316. // for the sphere we create
  317. GeometryData capsuleData = GeometryData.CreateCapsule(
  318. shader.VertexFormat, setDiameter, setLength, setColor);
  319. return new Mesh(setName, capsuleData, setMaterialData, Vector.Zero);
  320. }
  321. /// <summary>
  322. /// Create capsule mesh.
  323. /// </summary>
  324. /// <param name="setName">Name of the set.</param>
  325. /// <param name="setDiameter">The diameter of cylinder.</param>
  326. /// <param name="setLength">Length of the set.</param>
  327. /// <param name="setMaterialData">The set material data.</param>
  328. /// <returns>Mesh containing capsule data.</returns>
  329. public static Mesh CreateCapsule(string setName, float setDiameter,
  330. float setLength, MaterialData setMaterialData)
  331. {
  332. return CreateCapsule(setName, setDiameter, setLength,
  333. setMaterialData.Diffuse, setMaterialData);
  334. }
  335. #endregion
  336. #region Create Cylinder
  337. ///// <summary>
  338. ///// Create cylinder
  339. ///// </summary>
  340. //public static Mesh CreateCylinder(string setName, float setHeight,
  341. // float setRadius, MaterialData setMaterialData)
  342. //{
  343. // // First we still need to get the shader for the required vertex format
  344. // Shader shader = Shader.Create(setMaterialData.ShaderName);
  345. // // for the sphere we create
  346. // GeometryData capsuleData = GeometryData.CreateCylinder(
  347. // shader.VertexFormat, setHeight, setRadius, Color.White);
  348. // return new Mesh(setName, capsuleData, setMaterialData, Vector.Zero,
  349. // null);
  350. //}
  351. #endregion
  352. #region Name (Public)
  353. /// <summary>
  354. /// The name of the model. Usually set from content, but can also be a
  355. /// dynamically created model with a custom name.
  356. /// </summary>
  357. public string Name
  358. {
  359. get;
  360. private set;
  361. }
  362. #endregion
  363. #region Geometry (Public)
  364. /// <summary>
  365. /// Gets the geometry which defines the mesh.
  366. /// </summary>
  367. public Geometry Geometry
  368. {
  369. get;
  370. private set;
  371. }
  372. #endregion
  373. #region PositionOffset (Public)
  374. /// <summary>
  375. /// The offset translation of the mesh to represent its local space.
  376. /// Automatically added to rendering when using the Draw method with the
  377. /// matrix overload.
  378. /// </summary>
  379. /// <returns>Vector</returns>
  380. public Vector PositionOffset
  381. {
  382. get;
  383. private set;
  384. }
  385. #endregion
  386. #region Material (Public)
  387. /// <summary>
  388. /// The material which is used to visualize the geometry of the mesh.
  389. /// </summary>
  390. public BaseMaterial Material;
  391. #endregion
  392. #region IsHidden (Public)
  393. /// <summary>
  394. /// Level Editor Property, is true when the mesh should not be rendered.
  395. /// </summary>
  396. public bool IsHidden
  397. {
  398. get;
  399. set;
  400. }
  401. #endregion
  402. #region Private
  403. #region hasPositionOffset (Private)
  404. /// <summary>
  405. /// Remember if we have a position offset, if it is Zero, this is true
  406. /// and the Draw code is a little more optimized (often the case).
  407. /// </summary>
  408. private readonly bool hasPositionOffset;
  409. #endregion
  410. #region cachedRenderMatrix (Private)
  411. /// <summary>
  412. /// Default render matrix when rendering this model without any extra
  413. /// position or render matrix parameters. Usually used for levels and
  414. /// static geometry. Initially Matrix.Identity, but the PositionOffset
  415. /// is also already applied on this. Can be ignored if hasPositionOffset
  416. /// is false.
  417. /// </summary>
  418. private Matrix cachedRenderMatrix = Matrix.Identity;
  419. #endregion
  420. #endregion
  421. #region Constructors
  422. /// <summary>
  423. /// Create model from content name. Will warn about missing materials.
  424. /// </summary>
  425. /// <param name="contentName">Name of the content.</param>
  426. public Mesh(string contentName)
  427. : this(MeshData.Get(contentName))
  428. {
  429. }
  430. /// <summary>
  431. /// Create model from ModelData (usually called from content name
  432. /// constructor above).
  433. /// </summary>
  434. /// <param name="setData">Set mesh data</param>
  435. public Mesh(MeshData setData)
  436. : this(setData.Name, setData.Geometry, setData.Material,
  437. setData.PositionOffset)
  438. {
  439. }
  440. /// <summary>
  441. /// Prevents a default instance of the <see cref="Mesh"/> class from being created.
  442. /// </summary>
  443. /// <param name="setName">Name of the set.</param>
  444. /// <param name="setGeometryData">The set geometry data.</param>
  445. /// <param name="setMaterialData">The set material data.</param>
  446. /// <param name="setPositionOffset">The set position offset.</param>
  447. private Mesh(string setName, GeometryData setGeometryData,
  448. MaterialData setMaterialData, Vector setPositionOffset)
  449. {
  450. // If anything is invalid or empty, create box
  451. if (setGeometryData == null ||
  452. setMaterialData == null)
  453. {
  454. // Use default material (checker map) for the box we create
  455. MaterialData emptyMaterialData = new MaterialData();
  456. BaseMaterial emptyMaterial =
  457. new Material(emptyMaterialData);
  458. GeometryData planeData = GeometryData.CreateCube(
  459. emptyMaterial.shader.VertexFormat, 1);
  460. setName += "_Failed";
  461. setGeometryData = planeData;
  462. setMaterialData = emptyMaterialData;
  463. } // if
  464. Name = setName;
  465. Geometry = Geometry.Create(setGeometryData);
  466. PositionOffset = setPositionOffset;
  467. hasPositionOffset =
  468. PositionOffset.X != 0 ||
  469. PositionOffset.Y != 0 ||
  470. PositionOffset.Z != 0;
  471. cachedRenderMatrix.Translation += PositionOffset;
  472. if (setMaterialData.Diffuse != Color.White)
  473. {
  474. Material = new MaterialColored(setMaterialData);
  475. }
  476. else
  477. {
  478. Material = new Material(setMaterialData);
  479. }
  480. }
  481. #endregion
  482. #region Draw (Public)
  483. /// <summary>
  484. /// Draws the mesh exactly in that way as it was originally exported by the
  485. /// artist (including the computed position offset).
  486. /// </summary>
  487. public void Draw()
  488. {
  489. Material.Draw(Geometry, ref cachedRenderMatrix);
  490. }
  491. /// <summary>
  492. /// Draws the mesh with a custom draw transformation additionally to the
  493. /// original mesh transformation (including the computed position offset).
  494. /// </summary>
  495. /// <param name="customDrawTransformation">The custom draw transformation.</param>
  496. public void Draw(ref Matrix customDrawTransformation)
  497. {
  498. // If we have a position offset, we need to modify the render matrix!
  499. if (hasPositionOffset)
  500. {
  501. // Helper to add render matrices offset quickly, we do not want to
  502. // change the input matrix (it is passed as ref).
  503. Matrix renderMatrix = customDrawTransformation;
  504. // Adding is quicker than multiplying two matrices.
  505. renderMatrix.Translation += PositionOffset;
  506. Material.Draw(Geometry, ref renderMatrix);
  507. }
  508. else
  509. {
  510. Material.Draw(Geometry, ref customDrawTransformation);
  511. }
  512. }
  513. #endregion
  514. #region DrawCentered (Public)
  515. /// <summary>
  516. /// Draws the mesh centered in the world origin or in other words without
  517. /// the position offset computed by the content importer.
  518. /// </summary>
  519. public void DrawCentered()
  520. {
  521. // Note: PositionOffset and cachedRenderMatrix is ignored here on purpose
  522. Material.Draw(Geometry, ref Matrix.Identity);
  523. }
  524. #endregion
  525. }
  526. }