PageRenderTime 248ms CodeModel.GetById 61ms app.highlight 119ms RepoModel.GetById 52ms app.codeStats 0ms

/ContentSystem/Rendering/GeometryData.cs

#
C# | 1805 lines | 1008 code | 155 blank | 642 comment | 63 complexity | 69a8189ae9f3a714d289af3d194777ae MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1using System;
   2using System.Collections.Generic;
   3using System.IO;
   4using Delta.ContentSystem.Rendering.Helpers;
   5using Delta.Engine.Dynamic;
   6using Delta.Utilities;
   7using Delta.Utilities.Datatypes;
   8using Delta.Utilities.Graphics;
   9using Delta.Utilities.Helpers;
  10using NUnit.Framework;
  11
  12namespace Delta.ContentSystem.Rendering
  13{
  14	/// <summary>
  15	/// Geometry data class, just contains vertices and indices for rendering.
  16	/// Geometry meshes are highly dependant on the underlying type for the
  17	/// vertices. Some helper methods can be used to generate simple meshes
  18	/// (boxes, spheres, etc.). Data is stored in binary format for quick access
  19	/// and the used material data is also stored internally in here. Please note
  20	/// that rendering a level or a complex model usually consists of multiple
  21	/// meshes, a geometry mesh is just the lowest underlying 3D type in the
  22	/// engine! Meshes are even used for dynamic vertex buffers, lines and all 2D
  23	/// UI drawing, but those meshes are usually not saved out to content files.
  24	/// <para />
  25	/// While this is not directly a content type, it is pretty much what defines
  26	/// a mesh, which is used in many other content types as well (Models, Levels
  27	/// and also important for MeshAnimations, which are linked up in Models
  28	/// too). You can of course also use this class for your own dynamically
  29	/// created data (e.g. landscape rendering, BSP trees, or any other type of
  30	/// rendering)
  31	/// <para />
  32	/// Note: Geometry data can get quite big and while we need this class and
  33	/// all the internal data for dynamic geometry data that needs to be updated
  34	/// from time to time, it is not needed for static geometry data after the
  35	/// internal data structure has been created on the graphic card (vertex
  36	/// and index buffer objects). To save memory we can dispose this object
  37	/// and just in case it is needed again, we need to notify the owner to
  38	/// make sure that the data is reloaded again.
  39	/// </summary>
  40	/// <remarks>
  41	/// Vertex data. Note: Filling data into this is up to 5 times slower than
  42	/// directly filling a struct array. For setting this once or even loading
  43	/// from a file, this class is perfectly fine (loading from a file is even
  44	/// about 2 times faster than using struct arrays). However, for dynamic
  45	/// vertex buffers it is a good optimization to have a native struct
  46	/// representing the data and setting that instead with SetData (e.g. see
  47	/// the DrawManager implementation for line rendering using ColoredVertex).
  48	/// Please note that even with the slower speed of GeometryData it is still
  49	/// a very good idea to use for our engine because we want to use vertex
  50	/// and index buffers, which is only possible with a generic byte data
  51	/// stream and thus much faster as converting data types or not using
  52	/// vertex buffers. So rendering is as quick as it gets, especially for
  53	/// static geometry data (which is what we will use 99% of the time) and
  54	/// dynamic geometry is also rendered very quickly (in fact as fast as
  55	/// possible on each platform), just setting the data is a little slow on
  56	/// the CPU because of all the reader/writer stuff involved here.
  57	/// </remarks>
  58	public class GeometryData : ISaveLoadBinary, IDisposable
  59	{
  60		#region Constants
  61		/// <summary>
  62		/// Version number for this MeshData. If this goes above 1, we need
  63		/// to support loading older versions as well. Saving is always going
  64		/// to be the latest version (this one).
  65		/// </summary>
  66		private const int VersionNumber = 2;
  67		#endregion
  68
  69		#region CreateCube (Static)
  70		/// <summary>
  71		/// Generate a cube mesh with the same size in all dimensions. Box meshes
  72		/// have their pivot point at Vector.Zero (to make them easier to place).
  73		/// Note: The GeometryHelper in Delta.Rendering.Models has many more
  74		/// Create methods to create spheres, cones, cylinders, etc.
  75		/// </summary>
  76		/// <param name="vertexFormat">The vertex format for this geometry</param>
  77		/// <param name="size">Size of the box in all dimensions</param>
  78		/// <param name="setColor">Vertex color during creation.</param>
  79		/// <returns>
  80		/// Geometry Data containing all vertices and indices for this box
  81		/// </returns>
  82		public static GeometryData CreateCube(VertexFormat vertexFormat,
  83			float size, Color setColor)
  84		{
  85			return CreateBox(vertexFormat, size, size, size, false, setColor);
  86		}
  87
  88		/// <summary>
  89		/// Generate a cube mesh with the same size in all dimensions. Box meshes
  90		/// have their pivot point at Vector.Zero (to make them easier to place).
  91		/// Note: The GeometryHelper in Delta.Rendering.Models has many more
  92		/// Create methods to create spheres, cones, cylinders, etc.
  93		/// </summary>
  94		/// <param name="vertexFormat">The vertex format for this geometry</param>
  95		/// <param name="size">Size of the box in all dimensions</param>
  96		/// <returns>
  97		/// Geometry Data containing all vertices and indices for this box
  98		/// </returns>
  99		public static GeometryData CreateCube(VertexFormat vertexFormat, float size)
 100		{
 101			return CreateBox(vertexFormat, size, size, size, false, Color.White);
 102		}
 103		#endregion
 104
 105		#region CreateBox (Static)
 106		/// <summary>
 107		/// Generates a box mesh with the given sizes and a material. Box meshes
 108		/// have their pivot point at Vector.Zero (to make them easier to place).
 109		/// </summary>
 110		/// <param name="vertexFormat">The vertex format.</param>
 111		/// <param name="width">The width in the X dimension</param>
 112		/// <param name="depth">The depth in the Y dimension</param>
 113		/// <param name="height">The height in the Z dimension</param>
 114		/// <param name="invertWinding">Whether to invert indices order</param>
 115		/// <param name="setColor">Vertex color during creation.</param>
 116		/// <returns>
 117		/// Geometry Data containing all vertices and indices for this box
 118		/// </returns>
 119		public static GeometryData CreateBox(VertexFormat vertexFormat,
 120			float width, float depth, float height, bool invertWinding, Color setColor)
 121		{
 122			return CreateBox(vertexFormat, width, depth, height, invertWinding,
 123				"<GeneratedBox(" + width + ", " + depth + ", " + height + ")>",
 124				setColor);
 125		}
 126
 127		/// <summary>
 128		/// Generates a box mesh with a given pivot point height (usually used
 129		/// to generate the box at Vector.Zero, see other overloads).
 130		/// </summary>
 131		/// <param name="vertexFormat">The vertex format.</param>
 132		/// <param name="width">The width in the X dimension</param>
 133		/// <param name="depth">The depth in the Y dimension</param>
 134		/// <param name="height">The height in the Z dimension</param>
 135		/// <param name="invertWinding">Whether to invert indices order</param>
 136		/// <param name="meshName">Name of the mesh.</param>
 137		/// <param name="setColor">Vertex color during creation.</param>
 138		/// <returns>
 139		/// Geometry Data containing all vertices and indices for this box
 140		/// </returns>
 141		public static GeometryData CreateBox(VertexFormat vertexFormat,
 142			float width, float depth, float height, bool invertWinding,
 143			string meshName, Color setColor)
 144		{
 145			// The box has 8 positions, but we need 24 vertices (4 for each of the
 146			// 6 sides, each side has its own texture coordinates, see ordering)
 147			// Texture coordinates begin at the left upper corner (0, 0)
 148			GeometryData geometry = new GeometryData(
 149				meshName, 24, vertexFormat, 36, true, false);
 150
 151			Vector cubeHalfSize = new Vector(width, height, depth) / 2;
 152			// Create each face in turn.
 153			int vertexIndex = 0;
 154
 155			// front side
 156			geometry.SetVertexData(vertexIndex++,
 157				new Vector(-cubeHalfSize.X, -cubeHalfSize.Y, cubeHalfSize.Z),
 158				Point.UnitY, setColor, Vector.UnitZ, Vector.UnitZ);
 159
 160			geometry.SetVertexData(vertexIndex++,
 161				new Vector(cubeHalfSize.X, -cubeHalfSize.Y, cubeHalfSize.Z),
 162				Point.One, setColor, Vector.UnitZ, Vector.UnitZ);
 163
 164			geometry.SetVertexData(vertexIndex++,
 165				new Vector(cubeHalfSize.X, cubeHalfSize.Y, cubeHalfSize.Z),
 166				Point.UnitX, setColor, Vector.UnitZ, Vector.UnitZ);
 167
 168			geometry.SetVertexData(vertexIndex++,
 169				new Vector(-cubeHalfSize.X, cubeHalfSize.Y, cubeHalfSize.Z),
 170				Point.Zero, setColor, Vector.UnitZ, Vector.UnitZ);
 171
 172			// back side
 173			geometry.SetVertexData(vertexIndex++,
 174				new Vector(cubeHalfSize.X, -cubeHalfSize.Y, -cubeHalfSize.Z),
 175				Point.UnitY, setColor, -Vector.UnitZ, -Vector.UnitZ);
 176
 177			geometry.SetVertexData(vertexIndex++,
 178				new Vector(-cubeHalfSize.X, -cubeHalfSize.Y, -cubeHalfSize.Z),
 179				Point.One, setColor, -Vector.UnitZ, -Vector.UnitZ);
 180
 181			geometry.SetVertexData(vertexIndex++,
 182				new Vector(-cubeHalfSize.X, cubeHalfSize.Y, -cubeHalfSize.Z),
 183				Point.UnitX, setColor, -Vector.UnitZ, -Vector.UnitZ);
 184
 185			geometry.SetVertexData(vertexIndex++,
 186				new Vector(cubeHalfSize.X, cubeHalfSize.Y, -cubeHalfSize.Z),
 187				Point.Zero, setColor, -Vector.UnitZ, -Vector.UnitZ);
 188
 189			// left side
 190			geometry.SetVertexData(vertexIndex++,
 191				new Vector(-cubeHalfSize.X, -cubeHalfSize.Y, -cubeHalfSize.Z),
 192				Point.UnitY, setColor, -Vector.UnitX, -Vector.UnitX);
 193
 194			geometry.SetVertexData(vertexIndex++,
 195				new Vector(-cubeHalfSize.X, -cubeHalfSize.Y, cubeHalfSize.Z),
 196				Point.One, setColor, -Vector.UnitX, -Vector.UnitX);
 197
 198			geometry.SetVertexData(vertexIndex++,
 199				new Vector(-cubeHalfSize.X, cubeHalfSize.Y, cubeHalfSize.Z),
 200				Point.UnitX, setColor, -Vector.UnitX, -Vector.UnitX);
 201
 202			geometry.SetVertexData(vertexIndex++,
 203				new Vector(-cubeHalfSize.X, cubeHalfSize.Y, -cubeHalfSize.Z),
 204				Point.Zero, setColor, -Vector.UnitX, -Vector.UnitX);
 205
 206			// right side
 207			geometry.SetVertexData(vertexIndex++,
 208				new Vector(cubeHalfSize.X, -cubeHalfSize.Y, cubeHalfSize.Z),
 209				Point.UnitY, setColor, Vector.UnitX, Vector.UnitX);
 210
 211			geometry.SetVertexData(vertexIndex++,
 212				new Vector(cubeHalfSize.X, -cubeHalfSize.Y, -cubeHalfSize.Z),
 213				Point.One, setColor, Vector.UnitX, Vector.UnitX);
 214
 215			geometry.SetVertexData(vertexIndex++,
 216				new Vector(cubeHalfSize.X, cubeHalfSize.Y, -cubeHalfSize.Z),
 217				Point.UnitX, setColor, Vector.UnitX, Vector.UnitX);
 218
 219			geometry.SetVertexData(vertexIndex++,
 220				new Vector(cubeHalfSize.X, cubeHalfSize.Y, cubeHalfSize.Z),
 221				Point.Zero, setColor, Vector.UnitX, Vector.UnitX);
 222
 223			// up side
 224			geometry.SetVertexData(vertexIndex++,
 225				new Vector(-cubeHalfSize.X, cubeHalfSize.Y, cubeHalfSize.Z),
 226				Point.UnitY, setColor, Vector.UnitY, Vector.UnitY);
 227
 228			geometry.SetVertexData(vertexIndex++,
 229				new Vector(cubeHalfSize.X, cubeHalfSize.Y, cubeHalfSize.Z),
 230				Point.One, setColor, Vector.UnitY, Vector.UnitY);
 231
 232			geometry.SetVertexData(vertexIndex++,
 233				new Vector(cubeHalfSize.X, cubeHalfSize.Y, -cubeHalfSize.Z),
 234				Point.UnitX, setColor, Vector.UnitY, Vector.UnitY);
 235
 236			geometry.SetVertexData(vertexIndex++,
 237				new Vector(-cubeHalfSize.X, cubeHalfSize.Y, -cubeHalfSize.Z),
 238				Point.Zero, setColor, Vector.UnitY, Vector.UnitY);
 239
 240			// down side
 241			geometry.SetVertexData(vertexIndex++,
 242				new Vector(-cubeHalfSize.X, -cubeHalfSize.Y, -cubeHalfSize.Z),
 243				Point.UnitY, setColor, -Vector.UnitY, -Vector.UnitY);
 244
 245			geometry.SetVertexData(vertexIndex++,
 246				new Vector(cubeHalfSize.X, -cubeHalfSize.Y, -cubeHalfSize.Z),
 247				Point.One, setColor, -Vector.UnitY, -Vector.UnitY);
 248
 249			geometry.SetVertexData(vertexIndex++,
 250				new Vector(cubeHalfSize.X, -cubeHalfSize.Y, cubeHalfSize.Z),
 251				Point.UnitX, setColor, -Vector.UnitY, -Vector.UnitY);
 252
 253			geometry.SetVertexData(vertexIndex++,
 254				new Vector(-cubeHalfSize.X, -cubeHalfSize.Y, cubeHalfSize.Z),
 255				Point.Zero, setColor, -Vector.UnitY, -Vector.UnitY);
 256
 257			if (invertWinding)
 258			{
 259				geometry.Indices = new ushort[]
 260				{
 261					// front
 262					2, 1, 0,
 263					3, 2, 0,
 264					// back
 265					6, 5, 4,
 266					7, 6, 4,
 267					// left
 268					10, 9, 8,
 269					11, 10, 8,
 270					// right
 271					14, 13, 12,
 272					15, 14, 12,
 273					// up
 274					18, 17, 16,
 275					19, 18, 16,
 276					// down
 277					22, 21, 20,
 278					23, 22, 20
 279				};
 280			}
 281			else
 282			{
 283				geometry.Indices = new ushort[]
 284				{
 285					// front
 286					0, 1, 2,
 287					0, 2, 3,
 288					// back
 289					4, 5, 6,
 290					4, 6, 7,
 291					// left
 292					8, 9, 10,
 293					8, 10, 11,
 294					// right
 295					12, 13, 14,
 296					12, 14, 15,
 297					// up
 298					16, 17, 18,
 299					16, 18, 19,
 300					// down
 301					20, 21, 22,
 302					20, 22, 23
 303				};
 304			}
 305
 306			return geometry;
 307		}
 308		#endregion
 309
 310		#region CreateSphere (Static)
 311		/// <summary>
 312		/// Creates a sphere as an GeometryData object with the given parameters.
 313		/// </summary>
 314		/// <param name="vertexFormat">The vertex format to use.</param>
 315		/// <param name="radius">The radius for the sphere from the center</param>
 316		/// <param name="setColor">
 317		/// Color for the new sphere in case the vertex format supports colored
 318		/// vertices (otherwise ignored).
 319		/// </param>
 320		/// <param name="invertWinding">
 321		/// Whether to invert winding order (usually false, except you want to be
 322		/// inside the sphere).
 323		/// </param>
 324		/// <returns>The geometry data of the specified sphere.</returns>
 325		public static GeometryData CreateSphere(VertexFormat vertexFormat,
 326			float radius, Color setColor, bool invertWinding = false)
 327		{
 328			// Set up the subdivision in which we build the geometry of the sphere.
 329			// The tessellation indicates in how many segments the sphere is
 330			// interpolated, smaller spheres have less tessellation, bigger spheres
 331			// use more tessellation, but we keep it between 4 and 32.
 332			int tessellation = (int)(MathHelper.Sqrt(radius) * 6.0f);
 333			tessellation = MathHelper.Clamp(tessellation, 6, 32);
 334			// Make multiple of 3 for better fitting texturing
 335			tessellation = (tessellation / 3) * 3;
 336			int verticalSegments = tessellation;
 337			// Add one horizontal segment to fit around a circle, good for UVs
 338			int horizontalSegments = tessellation * 2 + 1;
 339
 340			// Create rings of vertices at progressively higher latitudes.
 341			GeometryData geometry = new GeometryData(
 342				"<GeneratedSphere(" + radius + ")>",
 343				verticalSegments * horizontalSegments,
 344				vertexFormat, 6 * (verticalSegments - 1) * horizontalSegments,
 345				true, false);
 346			for (int index = 0; index < verticalSegments; index++)
 347			{
 348				// Lets begin with the latitude and divide each segment. As we are
 349				// using circular surface, we will split each position along the
 350				// vertical axis with the cosine. That is every position in the
 351				// vertical segment creates a ring with a maximum width stated by the
 352				// cosine (at the top width=0, in the medium reaches the maximum
 353				// width = 1, and at the bottom width=0).
 354				float latitude = index * 180.0f / (verticalSegments - 1) - 90.0f;
 355				float dy = MathHelper.Sin(latitude);
 356				float dxz = MathHelper.Cos(latitude);
 357
 358				// Create a single ring of vertices at this latitude.
 359				for (int j = 0; j < horizontalSegments; j++)
 360				{
 361					// Next step is tessellation along horizontal axis in which we just 
 362					// simple indicates the position of each vertex in the ring with the
 363					// previously established width along the surface of the sphere
 364					float longitude = j * 360.0f / (horizontalSegments - 1);
 365
 366					float dx = MathHelper.Cos(longitude) * dxz;
 367					float dz = MathHelper.Sin(longitude) * dxz;
 368
 369					// finally we got the correct position 
 370					Vector normal = new Vector(dx, dy, dz);
 371
 372					// and we assign the corresponding U,V coordinate of the texture
 373					// in a way that for each circle of the sphere it contains a line
 374					// of the texture image
 375					geometry.SetVertexData(
 376						index * horizontalSegments + j,
 377						normal * radius,
 378						new Point(j / (float)(horizontalSegments - 1),
 379							index / (float)(verticalSegments - 1)), setColor, normal,
 380						Vector.Cross(normal, Vector.UnitZ));
 381				}
 382			}
 383
 384			// Create a fan connecting the bottom vertex to the bottom latitude ring
 385			// and finally set up the indices connecting each vertex.
 386			// Fill the sphere body with triangles joining each pair of rings.
 387			int num = 0;
 388			for (int index = 0; index < verticalSegments - 1; index++)
 389			{
 390				for (int j = 0; j < horizontalSegments; j++)
 391				{
 392					int nextI = (index + 1);
 393					int nextJ = (j + 1) % horizontalSegments;
 394
 395					if (invertWinding)
 396					{
 397						geometry.Indices[num++] =
 398							(ushort)(index * horizontalSegments + nextJ);
 399						geometry.Indices[num++] =
 400							(ushort)(nextI * horizontalSegments + j);
 401						geometry.Indices[num++] =
 402							(ushort)(index * horizontalSegments + j);
 403
 404						geometry.Indices[num++] =
 405							(ushort)(nextI * horizontalSegments + nextJ);
 406						geometry.Indices[num++] =
 407							(ushort)(nextI * horizontalSegments + j);
 408						geometry.Indices[num++] =
 409							(ushort)(index * horizontalSegments + nextJ);
 410					}
 411					else
 412					{
 413						geometry.Indices[num++] =
 414							(ushort)(index * horizontalSegments + j);
 415						geometry.Indices[num++] =
 416							(ushort)(nextI * horizontalSegments + j);
 417						geometry.Indices[num++] =
 418							(ushort)(index * horizontalSegments + nextJ);
 419
 420						geometry.Indices[num++] =
 421							(ushort)(index * horizontalSegments + nextJ);
 422						geometry.Indices[num++] =
 423							(ushort)(nextI * horizontalSegments + j);
 424						geometry.Indices[num++] =
 425							(ushort)(nextI * horizontalSegments + nextJ);
 426					}
 427				}
 428			}
 429
 430			return geometry;
 431		}
 432		#endregion
 433
 434		#region CreatePlane (Static)
 435		/// <summary>
 436		/// Create plane
 437		/// </summary>
 438		/// <param name="vertexFormat">The vertex format.</param>
 439		/// <param name="setWidth">Width of the set.</param>
 440		/// <param name="setHeight">Height of the set.</param>
 441		/// <returns>The geometry data of the specified plane.</returns>
 442		public static GeometryData CreatePlane(VertexFormat vertexFormat,
 443			float setWidth, float setHeight)
 444		{
 445			return CreatePlane(vertexFormat, setWidth, setHeight, Color.White);
 446		}
 447
 448		/// <summary>
 449		/// Creates an XY plane in the specified vertex format (you can use
 450		/// one of the predefined vertex formats from VertexData).
 451		/// </summary>
 452		/// <param name="vertexFormat">The vertex format.</param>
 453		/// <param name="setWidth">Set width.</param>
 454		/// <param name="setHeight">Set Height.</param>
 455		/// <param name="setColor">Set Color.</param>
 456		/// <returns>The geometry data of the specified plane.</returns>
 457		public static GeometryData CreatePlane(VertexFormat vertexFormat,
 458			float setWidth, float setHeight, Color setColor)
 459		{
 460			float halfWidth = setWidth * 0.5f;
 461			float halfDepth = setHeight * 0.5f;
 462			float height = 0;
 463
 464			// We use 4 vertices with 6 indices (0, 1, 2, 2, 1, 3):
 465			// 0 - 1
 466			// | / |
 467			// 2 - 3
 468			GeometryData geometry = new GeometryData(
 469				"<GeneratedPlane(" + setWidth + "x" + setHeight + ")>",
 470				4, vertexFormat, 6, true, false);
 471			Vector planeNormal = new Vector(0, 0, 1);
 472			Vector planeTangent = new Vector(1, 0, 0);
 473			// Front left
 474			geometry.SetVertexData(0,
 475				new Vector(-halfWidth, halfDepth, height),
 476				new Point(0, 0), setColor, planeNormal, planeTangent);
 477			// Front right
 478			geometry.SetVertexData(1,
 479				new Vector(halfWidth, halfDepth, height),
 480				new Point(1, 0), setColor, planeNormal, planeTangent);
 481			// Rear left
 482			geometry.SetVertexData(2,
 483				new Vector(-halfWidth, -halfDepth, height),
 484				new Point(0, 1), setColor, planeNormal, planeTangent);
 485			// Rear right
 486			geometry.SetVertexData(3,
 487				new Vector(halfWidth, -halfDepth, height),
 488				new Point(1, 1), setColor, planeNormal, planeTangent);
 489
 490			// Top left polygon (Note: Counter-Clockwise is front)
 491			geometry.Indices[0] = 0;
 492			geometry.Indices[1] = 2;
 493			geometry.Indices[2] = 1;
 494			// Bottom right polygon
 495			geometry.Indices[3] = 2;
 496			geometry.Indices[4] = 3;
 497			geometry.Indices[5] = 1;
 498
 499			return geometry;
 500		}
 501		#endregion
 502
 503		#region CreateSegmentedPlane (Static)
 504		/// <summary>
 505		/// Creates an XY plane in the specified vertex format (you can use
 506		/// one of the predefined vertex formats from VertexData).
 507		/// </summary>
 508		/// <param name="vertexFormat">The vertex format.</param>
 509		/// <param name="setWidth">Sets Width.</param>
 510		/// <param name="setHeight">Sets Height.</param>
 511		/// <param name="segments">The segments.</param>
 512		/// <param name="uvForEachSegment">Create new uv from 0-1 for each segment.
 513		/// Useful for tiling (works even without tileable textures)</param>
 514		/// <param name="setColor">Sets Color.</param>
 515		public static GeometryData CreateSegmentedPlane(VertexFormat vertexFormat,
 516			float setWidth, float setHeight, int segments, bool uvForEachSegment,
 517			Color setColor)
 518		{
 519			if (segments < 1)
 520			{
 521				throw new InvalidOperationException(
 522					"You need at least one segment for CreateSegmentedPlane!");
 523			}
 524
 525			float halfWidth = setWidth * 0.5f;
 526			float halfDepth = setHeight * 0.5f;
 527			float height = 0;
 528
 529			// We use 4 vertices with 6 indices (0, 1, 2, 2, 1, 3):
 530			// 0 - 1
 531			// | / |
 532			// 2 - 3
 533			// But duplicate this many times for as many segments in each direction.
 534			int totalSegments = segments * segments;
 535			int segmentStride = segments + 1;
 536			int totalPoints =
 537				uvForEachSegment
 538					? totalSegments * 4
 539					: segmentStride * segmentStride;
 540			GeometryData geometry = new GeometryData(
 541				"<GeneratedSegmentedPlane(" + setWidth + "x" + setHeight + ")>",
 542				totalPoints, vertexFormat, 6 * totalSegments, true, false);
 543			Vector planeNormal = new Vector(0, 0, 1);
 544			Vector planeTangent = new Vector(1, 0, 0);
 545			// For each segment + 1, build the points
 546			if (uvForEachSegment)
 547			{
 548				// For each segment, build up the 2 triangles
 549				int index = 0;
 550				int pointIndex = 0;
 551				for (int ySegment = 0; ySegment < segments; ySegment++)
 552				{
 553					for (int xSegment = 0; xSegment < segments; xSegment++)
 554					{
 555						float xFactor = xSegment / (float)segments;
 556						float yFactor = ySegment / (float)segments;
 557						float xFactor2 = (xSegment + 1) / (float)segments;
 558						float yFactor2 = (ySegment + 1) / (float)segments;
 559						geometry.SetVertexData(pointIndex + 0,
 560							new Vector(-halfWidth + xFactor * setWidth,
 561								halfDepth - yFactor * setHeight, height),
 562							new Point(0, 0), setColor, planeNormal, planeTangent);
 563						geometry.SetVertexData(pointIndex + 1,
 564							new Vector(-halfWidth + xFactor2 * setWidth,
 565								halfDepth - yFactor * setHeight, height),
 566							new Point(1, 0), setColor, planeNormal, planeTangent);
 567						geometry.SetVertexData(pointIndex + 2,
 568							new Vector(-halfWidth + xFactor * setWidth,
 569								halfDepth - yFactor2 * setHeight, height),
 570							new Point(0, 1), setColor, planeNormal, planeTangent);
 571						geometry.SetVertexData(pointIndex + 3,
 572							new Vector(-halfWidth + xFactor2 * setWidth,
 573								halfDepth - yFactor2 * setHeight, height),
 574							new Point(1, 1), setColor, planeNormal, planeTangent);
 575
 576						// Top left polygon (Note: Counter-Clockwise is front)
 577						geometry.Indices[index++] = //0,0
 578							(ushort)(pointIndex + 0);
 579						geometry.Indices[index++] = //0,1
 580							(ushort)(pointIndex + 2);
 581						geometry.Indices[index++] = //1,0
 582							(ushort)(pointIndex + 1);
 583						// Bottom right polygon
 584						geometry.Indices[index++] = //0,1
 585							(ushort)(pointIndex + 2);
 586						geometry.Indices[index++] = //1,1
 587							(ushort)(pointIndex + 3);
 588						geometry.Indices[index++] = //1,0
 589							(ushort)(pointIndex + 1);
 590
 591						pointIndex += 4;
 592					}
 593				}
 594			}
 595			else
 596			{
 597				int pointIndex = 0;
 598				for (int ySegment = 0; ySegment < segments + 1; ySegment++)
 599				{
 600					for (int xSegment = 0; xSegment < segments + 1; xSegment++)
 601					{
 602						float xFactor = xSegment / (float)segments;
 603						float yFactor = ySegment / (float)segments;
 604						geometry.SetVertexData(pointIndex++,
 605							new Vector(-halfWidth + xFactor * setWidth,
 606								halfDepth - yFactor * setHeight, height),
 607							new Point(xFactor, yFactor),
 608							setColor, planeNormal, planeTangent);
 609					}
 610				}
 611
 612				// For each segment, build up the 2 triangles
 613				int index = 0;
 614				for (int ySegment = 0; ySegment < segments; ySegment++)
 615				{
 616					for (int xSegment = 0; xSegment < segments; xSegment++)
 617					{
 618						// Top left polygon (Note: Counter-Clockwise is front)
 619						geometry.Indices[index++] = //0,0
 620							(ushort)(xSegment + 0 + (ySegment + 0) * segmentStride);
 621						geometry.Indices[index++] = //0,1
 622							(ushort)(xSegment + 0 + (ySegment + 1) * segmentStride);
 623						geometry.Indices[index++] = //1,0
 624							(ushort)(xSegment + 1 + (ySegment + 0) * segmentStride);
 625						// Bottom right polygon
 626						geometry.Indices[index++] = //0,1
 627							(ushort)(xSegment + 0 + (ySegment + 1) * segmentStride);
 628						geometry.Indices[index++] = //1,1
 629							(ushort)(xSegment + 1 + (ySegment + 1) * segmentStride);
 630						geometry.Indices[index++] = //1,0
 631							(ushort)(xSegment + 1 + (ySegment + 0) * segmentStride);
 632					}
 633				}
 634			}
 635
 636			return geometry;
 637		}
 638
 639		/// <summary>
 640		/// Create segmented plane.
 641		/// </summary>
 642		/// <param name="vertexFormat">The vertex format.</param>
 643		/// <param name="setWidth">Width of the set.</param>
 644		/// <param name="setHeight">Height of the set.</param>
 645		/// <param name="segments">The segments.</param>
 646		/// <returns></returns>
 647		public static GeometryData CreateSegmentedPlane(VertexFormat vertexFormat,
 648			float setWidth, float setHeight, int segments)
 649		{
 650			return CreateSegmentedPlane(vertexFormat, setWidth, setHeight, segments,
 651				false, Color.White);
 652		}
 653		#endregion
 654
 655		#region CreateCapsule (Static)
 656		/// <summary>
 657		/// Creates a capsule geometry in the specified vertex format (you can use
 658		/// one of the predefined vertex formats from VertexData).
 659		/// </summary>
 660		/// <param name="vertexFormat">The vertex format.</param>
 661		/// <param name="setDiameter">Diameter of the capsule</param>
 662		/// <param name="setLength">Length of the capsule</param>
 663		/// <returns>The geometry data of the specified capsule.</returns>
 664		public static GeometryData CreateCapsule(VertexFormat vertexFormat,
 665			float setDiameter, float setLength)
 666		{
 667			return CreateCapsule(vertexFormat, setDiameter, setLength,
 668				Color.White);
 669		}
 670
 671		/// <summary>
 672		/// Creates a capsule geometry in the specified vertex format (you can use
 673		/// one of the predefined vertex formats from VertexData).
 674		/// </summary>
 675		/// <param name="vertexFormat">The vertex format.</param>
 676		/// <param name="setDiameter">Diameter of the capsule</param>
 677		/// <param name="setLength">Length of the capsule</param>
 678		/// <param name="setColor">Color for the capsule</param>
 679		/// <returns>
 680		/// Geometry Data with the capsule, using tessellation of 12.
 681		/// </returns>
 682		public static GeometryData CreateCapsule(VertexFormat vertexFormat,
 683			float setDiameter, float setLength, Color setColor)
 684		{
 685			int tessellation = 12;
 686
 687			int verticalSegments = tessellation;
 688			int horizontalSegments = tessellation * 2;
 689
 690			float radius = setDiameter / 2;
 691
 692			int vertexCount = horizontalSegments * (verticalSegments - 1) + 2;
 693
 694			GeometryData geometry = new GeometryData(
 695				"<GeneratedSegmentedPlane(" + setDiameter + "x" + setLength + ")>",
 696				vertexCount, vertexFormat, 6 * vertexCount, true, false);
 697
 698			Vector down = -Vector.UnitZ;
 699
 700			// For each segment + 1, build the points
 701			int pointIndex = 0;
 702			// Start with a single vertex at the bottom of the sphere.
 703			geometry.SetVertexData(pointIndex++,
 704				down * radius + down * 0.5f * setLength,
 705				Point.Zero, setColor, down, down);
 706
 707			// Create rings of vertices at progressively higher latitudes.
 708			for (int i = 0; i < verticalSegments - 1; i++)
 709			{
 710				float latitude = ((i + 1) * MathHelper.Pi /
 711				                  verticalSegments) - MathHelper.PiHalf;
 712				float dy = (float)Math.Sin(latitude);
 713				float dxz = (float)Math.Cos(latitude);
 714
 715				bool bla = false;
 716
 717				if (i > (verticalSegments - 2) / 2)
 718				{
 719					bla = true;
 720				}
 721
 722				// Create a single ring of vertices at this latitude.
 723				for (int j = 0; j < horizontalSegments; j++)
 724				{
 725					float longitude = j * MathHelper.PiDouble / horizontalSegments;
 726
 727					float dx = (float)Math.Cos(longitude) * dxz;
 728					float dz = (float)Math.Sin(longitude) * dxz;
 729
 730					Vector normal = new Vector(dx, dy, dz);
 731					Vector position = normal * radius;
 732
 733					if (bla)
 734					{
 735						position += Vector.UnitZ * 0.5f * setLength;
 736					}
 737					else
 738					{
 739						position += down * 0.5f * setLength;
 740					}
 741
 742					geometry.SetVertexData(pointIndex++,
 743						position,
 744						new Point(1.0f, 0.0f), setColor, normal, normal);
 745				}
 746			}
 747
 748			// Finish with a single vertex at the top of the sphere.
 749			geometry.SetVertexData(pointIndex++,
 750				Vector.UnitZ * radius + Vector.UnitZ * 0.5f * setLength,
 751				new Point(0.0f, 1.0f), setColor, Vector.UnitZ, Vector.UnitZ);
 752
 753			int index = 0;
 754			// Create a fan connecting the bottom vertex to the bottom latitude ring.
 755			for (int i = 0; i < horizontalSegments; i++)
 756			{
 757				geometry.Indices[index++] = (ushort)(1 + i);
 758				geometry.Indices[index++] = (ushort)(1 + (i + 1) % horizontalSegments);
 759				geometry.Indices[index++] = 0;
 760			}
 761
 762			// Fill the sphere body with triangles joining each pair of latitude rings.
 763			for (int i = 0; i < verticalSegments - 2; i++)
 764			{
 765				for (int j = 0; j < horizontalSegments; j++)
 766				{
 767					int nextI = i + 1;
 768					int nextJ = (j + 1) % horizontalSegments;
 769
 770					geometry.Indices[index++] =
 771						(ushort)(1 + nextI * horizontalSegments + j);
 772					geometry.Indices[index++] =
 773						(ushort)(1 + i * horizontalSegments + nextJ);
 774					geometry.Indices[index++] =
 775						(ushort)(1 + i * horizontalSegments + j);
 776
 777					geometry.Indices[index++] =
 778						(ushort)(1 + nextI * horizontalSegments + j);
 779					geometry.Indices[index++] =
 780						(ushort)(1 + nextI * horizontalSegments + nextJ);
 781					geometry.Indices[index++] =
 782						(ushort)(1 + i * horizontalSegments + nextJ);
 783				}
 784			}
 785
 786			// Create a fan connecting the top vertex to the top latitude ring.
 787			for (int i = 0; i < horizontalSegments; i++)
 788			{
 789				geometry.Indices[index++] =
 790					(ushort)(vertexCount - 2 - i);
 791				geometry.Indices[index++] =
 792					(ushort)(vertexCount - 2 - (i + 1) % horizontalSegments);
 793				geometry.Indices[index++] =
 794					(ushort)(vertexCount - 1);
 795			}
 796
 797			return geometry;
 798		}
 799		#endregion
 800
 801		#region Create (Static)
 802		/// <summary>
 803		/// Helper method to create a geometry out of position vectors, indices
 804		/// and a color for each position. Will use VertexFormat.Position3DColor.
 805		/// </summary>
 806		/// <param name="positions">3D positions for the new geometry.</param>
 807		/// <param name="colors">
 808		/// Colors for each of the positions, must match the length of the
 809		/// positions list.
 810		/// </param>
 811		/// <param name="indices">
 812		/// Indices to connect the triangles, must be at least 3 for one triangle
 813		/// or a multiple of 3 for more.
 814		/// </param>
 815		/// <returns>
 816		/// A newly created GeometryData, which can be passed to MeshData to be
 817		/// used for rendering.
 818		/// </returns>
 819		public static GeometryData Create(List<Vector> positions,
 820			List<Color> colors, List<ushort> indices)
 821		{
 822			if (colors.Count != positions.Count)
 823			{
 824				throw new ArgumentException(
 825					"The colors list length=" + colors.Count + " must match the " +
 826					"positions list length=" + positions.Count);
 827			}
 828			if (indices.Count < 3 ||
 829				indices.Count % 3 != 0)
 830			{
 831				throw new ArgumentException(
 832					"The indices list length=" + indices.Count + " must be at least 3 " +
 833					"for one triangle or a multiple of 3 for more.");
 834			}
 835
 836			// And finally create the geometry out of the custom positions
 837			GeometryData geometry = new GeometryData(
 838				"<CustomColoredGeometry>", positions.Count,
 839				VertexFormat.Position3DColor, indices.Count, true, false);
 840
 841			// Add all vertices from the positions
 842			for (int num = 0; num < positions.Count; num++)
 843			{
 844				// Note: Only position and color is used here, rest is ignored.
 845				geometry.SetVertexData(num, positions[num], Point.Zero, colors[num],
 846					Vector.UnitZ, Vector.UnitZ);
 847			}
 848			// Set the indices
 849			geometry.Indices = indices.ToArray();
 850
 851			return geometry;
 852		}
 853		#endregion
 854
 855		#region Create (Static)
 856		/// <summary>
 857		/// Helper method to create a geometry out of position vectors, indices
 858		/// and a uv for each position. Will use VertexFormat.Position3DTextured.
 859		/// </summary>
 860		/// <param name="positions">3D positions for the new geometry.</param>
 861		/// <param name="uvs">
 862		/// Texture uvs for each of the positions, must match the length of the
 863		/// positions list.
 864		/// </param>
 865		/// <param name="indices">
 866		/// Indices to connect the triangles, must be at least 3 for one triangle
 867		/// or a multiple of 3 for more.
 868		/// </param>
 869		/// <returns>
 870		/// A newly created GeometryData, which can be passed to MeshData to be
 871		/// used for rendering.
 872		/// </returns>
 873		public static GeometryData Create(List<Vector> positions, List<Point> uvs,
 874			List<ushort> indices)
 875		{
 876			if (uvs.Count != positions.Count)
 877			{
 878				throw new ArgumentException(
 879					"The uvs list length=" + uvs.Count + " must match the " +
 880					"positions list length=" + positions.Count);
 881			}
 882			if (indices.Count < 3 ||
 883				indices.Count % 3 != 0)
 884			{
 885				throw new ArgumentException(
 886					"The indices list length=" + indices.Count + " must be at least 3 " +
 887					"for one triangle or a multiple of 3 for more.");
 888			}
 889
 890			// And finally create the geometry out of the custom positions
 891			GeometryData geometry = new GeometryData(
 892				"<CustomColoredGeometry>", positions.Count,
 893				VertexFormat.Position3DTextured, indices.Count, true, false);
 894
 895			// Add all vertices from the positions
 896			for (int num = 0; num < positions.Count; num++)
 897			{
 898				// Note: Only position and uv is used here, rest is ignored.
 899				geometry.SetVertexData(num, positions[num], uvs[num], Color.White,
 900					Vector.UnitZ, Vector.UnitZ);
 901			}
 902			// Set the indices
 903			geometry.Indices = indices.ToArray();
 904
 905			return geometry;
 906		}
 907		#endregion
 908
 909		#region DefaultBox (Static)
 910		/// <summary>
 911		/// Default box (created on demand) with the size (1, 1). Usually using
 912		/// the default material and used to display fallback content if loading
 913		/// failed (e.g. if mesh content file was not found).
 914		/// </summary>
 915		public static GeometryData DefaultBox
 916		{
 917			get
 918			{
 919				if (defaultBoxMesh == null)
 920				{
 921					defaultBoxMesh = CreateCube(VertexFormat.Position3DTextured, 1);
 922				}
 923				return defaultBoxMesh;
 924			}
 925		}
 926		#endregion
 927
 928		#region Name (Public)
 929		/// <summary>
 930		/// Name of the geometry, useful for debugging or identify warnings.
 931		/// </summary>
 932		public string Name
 933		{
 934			get;
 935			private set;
 936		}
 937		#endregion
 938
 939		#region writer (Public)
 940		/// <summary>
 941		/// Writer to directly manipulate the vertex data (use Seek and Write).
 942		/// You can also just define or use an existing vertex struct and use
 943		/// SetData to store it into this GeometryData.
 944		/// </summary>
 945		public BinaryWriter writer;
 946		#endregion
 947
 948		#region reader (Public)
 949		/// <summary>
 950		/// Reader to get data back. For debugging you could also use the Get
 951		/// methods defined below (GetPosition, etc.), but they are slower.
 952		/// </summary>
 953		public BinaryReader reader;
 954		#endregion
 955
 956		#region MaxNumberOfVertices (Public)
 957		/// <summary>
 958		/// Number of vertices this VertexData currently can hold. We usually only
 959		/// increase this if the buffer needs to get bigger (e.g. via SetData or
 960		/// IncreaseVertices). Normally this should be set once in the constructor
 961		/// however (for static meshes we know beforehand)! This value is usually
 962		/// the same as NumberOfUsedVertices, but for dynamic vertex data (e.g.
 963		/// in DrawManager for lines or in MaterialManager for 2D UI vertices)
 964		/// the number of used vertices can be lower and increase over time!
 965		/// </summary>
 966		public int MaxNumberOfVertices
 967		{
 968			get;
 969			private set;
 970		}
 971		#endregion
 972
 973		#region NumberOfUsedVertices (Public)
 974		/// <summary>
 975		/// Number of used vertices, must always be the same (for static meshes)
 976		/// or lower than MaxNumberOfVertices. For dynamic vertex data this can
 977		/// go up to more than MaxNumberOfVertices can handle, then just call
 978		/// IncreaseMaxVertices to increase MaxNumberOfVertices!
 979		/// </summary>
 980		public int NumberOfUsedVertices
 981		{
 982			get
 983			{
 984				return numberOfUsedVerticesInternal;
 985			}
 986		}
 987		#endregion
 988
 989		#region Format (Public)
 990		/// <summary>
 991		/// Vertex element format as specified in the constructor. Everything
 992		/// else here depends on it, so changing this is not possible, create
 993		/// a new VertexData instance to convert vertex formats.
 994		/// </summary>
 995		public VertexFormat Format
 996		{
 997			get;
 998			private set;
 999		}
1000		#endregion
1001
1002		#region VertexDataLengthInBytes (Public)
1003		/// <summary>
1004		/// Vertex data length for each of the vertices in bytes.
1005		/// </summary>
1006		public int VertexDataLengthInBytes
1007		{
1008			get;
1009			private set;
1010		}
1011		#endregion
1012
1013		#region Indices (Public)
1014		/// <summary>
1015		/// And all the indices that link into the vertices. For 2D, UI or
1016		/// effect billboards these indices can be pre-calculated (e.g.
1017		/// 0, 1, 2, 0, 2, 3) and be used with whatever vertices are used.
1018		/// </summary>
1019		public ushort[] Indices;
1020		#endregion
1021
1022		#region NumberOfUsedIndices (Public)
1023		/// <summary>
1024		/// Number of used indices, only used for dynamic vertex and index data.
1025		/// Note: Not in Indices because that struct only contains the indices
1026		/// arrays as unions.
1027		/// </summary>
1028		public int NumberOfUsedIndices;
1029		#endregion
1030
1031
1032		#region Bones (Public)
1033		/// <summary>
1034		/// Flat list of bones, the first bone is always the root bone, all
1035		/// children can be accessed from here. The main reason for having a flat
1036		/// list is easy access to all bones for showing bone previous and of
1037		/// course to quickly access all animation matrices.
1038		/// </summary>
1039		public BoneData[] Bones = new BoneData[0];
1040		#endregion
1041
1042		#region IsStatic (Public)
1043		/// <summary>
1044		/// Is the data in this Mesh static or dynamic? Only dynamic data can
1045		/// be changed at runtime and will force a dynamic vertex buffer update.
1046		/// Always true for loaded content, sometimes false for generated content.
1047		/// </summary>
1048		public bool IsStatic
1049		{
1050			get;
1051			private set;
1052		}
1053		#endregion
1054
1055		#region IsStaticAndLoadedFromContent (Public)
1056		/// <summary>
1057		/// For static geometry we can get rid of the vertices and indices as we
1058		/// have them now on the GPU. This saves memory and the content can be
1059		/// reloaded at any time too.
1060		/// </summary>
1061		public bool IsStaticAndLoadedFromContent
1062		{
1063			get
1064			{
1065				return IsStatic &&
1066				       reloadContent != null;
1067			}
1068		}
1069		#endregion
1070
1071		#region HasDataChanged (Public)
1072		/// <summary>
1073		/// This value is used to check if the data has changed for dynamic
1074		/// geometry objects. Only if this is true we actually need to update the
1075		/// native objects on the GPU (VBO and IBO), which is slow and should be
1076		/// avoided if nothing has changed (e.g. no new lines were added).
1077		/// </summary>
1078		public bool HasDataChanged = true;
1079		#endregion
1080
1081		#region IsLineData (Public)
1082		/// <summary>
1083		/// Is line data in the vertex stream? Only used for dynamic mesh data
1084		/// for the DrawManager. Only used without indices.
1085		/// </summary>
1086		public bool IsLineData
1087		{
1088			get;
1089			private set;
1090		}
1091		#endregion
1092
1093		#region IsSky (Public)
1094		/// <summary>
1095		/// Is sky
1096		/// </summary>
1097		public bool IsSky
1098		{
1099			get;
1100			private set;
1101		}
1102		#endregion
1103
1104		#region PolygonCount (Public)
1105		/// <summary>
1106		/// Gets the number of polygons for this mesh (indices / 3)
1107		/// </summary>
1108		public int PolygonCount
1109		{
1110			get
1111			{
1112				return Indices.Length / 3;
1113			}
1114		}
1115		#endregion
1116
1117		#region BoundingBox (Public)
1118		/// <summary>
1119		/// Get bounding box of all vertices (in whatever space they are). Only
1120		/// calculated once and also used for the BoundingSphere calculation.
1121		/// </summary>
1122		public BoundingBox BoundingBox
1123		{
1124			get
1125			{
1126				// Was this bounding box initialized before? Note: Normally it is
1127				// already initialized at creation time for all processed content (from
1128				// the content-pipeline), only code-generated won't be initialized.
1129				if (IsStatic &&
1130				    (boundingBox.Max.X != 0 ||
1131				     boundingBox.Max.Y != 0 ||
1132				     boundingBox.Max.Z != 0))
1133				{
1134					// Then just return it.
1135					return boundingBox;
1136				}
1137
1138				// Else just get all vertex positions to compute it
1139				Vector[] positions = new Vector[numberOfUsedVerticesInternal];
1140				for (int index = 0; index < numberOfUsedVerticesInternal; index++)
1141				{
1142					positions[index] = GetPosition(index);
1143				}
1144
1145				// before we return it
1146				boundingBox = BoundingBox.Create(positions);
1147				return boundingBox;
1148			}
1149		}
1150		#endregion
1151
1152		#region BoundingSphere (Public)
1153		/// <summary>
1154		/// Bounding radius
1155		/// </summary>
1156		public BoundingSphere BoundingSphere
1157		{
1158			get
1159			{
1160				// Only calculate bounding radius once.
1161				if (IsStatic == false ||
1162				    sphere.Radius == 0.0f)
1163				{
1164					sphere = BoundingBox.ToBoundingSphere();
1165				}
1166				return sphere;
1167			}
1168		}
1169		#endregion
1170
1171		#region CheckFirstPlaneId (Public)
1172		/// <summary>
1173		/// The ID of the plane that the box was outside last in the
1174		/// frustum check. Most of the time the frustum check will fail at the
1175		/// same plane again so checking that one first makes it faster.
1176		/// </summary>
1177		public byte CheckFirstPlaneId
1178		{
1179			get;
1180			set;
1181		}
1182		#endregion
1183
1184		#region Private
1185
1186		#region defaultBoxMesh (Private)
1187		/// <summary>
1188		/// Cached default box mesh data.
1189		/// </summary>
1190		private static GeometryData defaultBoxMesh;
1191		#endregion
1192
1193		#region numberOfUsedVerticesInternal (Private)
1194		/// <summary>
1195		/// Optimization to make the NumberOfUsedVertices property as fast as
1196		/// possible, especially in debug mode and when profiling the property
1197		/// set slows us down.
1198		/// </summary>
1199		private int numberOfUsedVerticesInternal;
1200		#endregion
1201
1202		#region boundingBox (Private)
1203		/// <summary>
1204		/// Box
1205		/// </summary>
1206		private BoundingBox boundingBox;
1207		#endregion
1208
1209		#region sphere (Private)
1210		/// <summary>
1211		/// Sphere
1212		/// </summary>
1213		private BoundingSphere sphere = new BoundingSphere(Vector.Zero, 0.0f);
1214		#endregion
1215
1216		#region stream (Private)
1217		/// <summary>
1218		/// Data stream for all the data.
1219		/// </summary>
1220		private MemoryStream stream;
1221		#endregion
1222
1223		#region reloadContent (Private)
1224		/// <summary>
1225		/// Helper delegate to reload this geometry content after it has been
1226		/// disposed. Usually used for static geometry, which can be disposed
1227		/// after the GPU VBO and IBO have been created to save memory.
1228		/// </summary>
1229		private readonly RunDelegate reloadContent;
1230		#endregion
1231
1232		#endregion
1233
1234		#region Constructors
1235		/// <summary>
1236		/// Create geometry data with a predefined number of vertices. This way all
1237		/// the vertex data is already allocated and future writes to this vertex
1238		/// data are fast. Use the writer directly to write up to 2000 vertices,
1239		/// for more use the SetData method below.
1240		/// Note: When rendering this is always send to the native vertex buffer
1241		/// (e.g. in Xna DynamicVertexBuffer is used). The index buffer is not used
1242		/// if setNumberOfIndices is 0, else you must fill the indices yourself
1243		/// after filling in the vertices.
1244		/// </summary>
1245		/// <param name="setName">
1246		/// Set name for this geometry for identification. Should start with &gt;
1247		/// for dynamically created geometry to not confuse it with loaded gometry
1248		/// from content, which uses content names.
1249		/// </param>
1250		/// <param name="setMaxNumberOfVertices">
1251		/// Set maximum number of vertices to be used, can be increased if the
1252		/// geometry is dynamic (not static).
1253		/// </param>
1254		/// <param name="setVertexFormat">
1255		/// Set vertex format (usually from a shader).
1256		/// </param>
1257		/// <param name="setNumberOfIndices">Set number of indices</param>
1258		/// <param name="setIsStaticData">
1259		/// Is static data? Faster to render because does not need to be modified.
1260		/// </param>
1261		/// <param name="setIsLineData">
1262		/// Set if line data is used in this vertex stream. Only used for dynamic
1263		/// mesh data for the DrawManager. Only used without indices.
1264		/// </param>
1265		public GeometryData(string setName, int setMaxNumberOfVertices,
1266			VertexFormat setVertexFormat, int setNumberOfIndices,
1267			bool setIsStaticData, bool setIsLineData)
1268			: this(setName, setMaxNumberOfVertices, setVertexFormat,
1269				setNumberOfIndices, setIsStaticData, setIsLineData,
1270				new BoundingBox(Vector.Zero, Vector.Zero))
1271		{
1272		}
1273
1274		/// <summary>
1275		/// Create geometry data with a predefined number of vertices. This way all
1276		/// the vertex data is already allocated and future writes to this vertex
1277		/// data are fast. Use the writer directly to write up to 2000 vertices,
1278		/// for more use the SetData method below.
1279		/// Note: When rendering this is always send to the native vertex buffer
1280		/// (e.g. in Xna DynamicVertexBuffer is used). The index buffer is not used
1281		/// if setNumberOfIndices is 0, else you must fill the indices yourself
1282		/// after filling in the vertices.
1283		/// </summary>
1284		/// <param name="setName">
1285		/// Set name for this geometry for identification. Should start with &gt;
1286		/// for dynamically created geometry to not confuse it with loaded gometry
1287		/// from content, which uses content names.
1288		/// </param>
1289		/// <param name="setMaxNumberOfVertices">
1290		/// Set maximum number of vertices to be used, can be increased if the
1291		/// geometry is dynamic (not static).
1292		/// </param>
1293		/// <param name="setVertexFormat">
1294		/// Set vertex format (usually from a shader).
1295		/// </param>
1296		/// <param name="setNumberOfIndices">Set number of indices</param>
1297		/// <param name="setIsStaticData">
1298		/// Is static data? Faster to render because does not need to be modified.
1299		/// </param>
1300		/// <param name="setIsLineData">
1301		/// Set if line data is used in this vertex stream. Only used for dynamic
1302		/// mesh data for the DrawManager. Only used without indices.
1303		/// </param>
1304		/// <param name="setBoundingBox">
1305		/// Set bounding box with given data, useful for physics and displaying
1306		/// the boundings in debug mode. For content this is usually calculated
1307		/// already in the content system, for generated geometry it will not be
1308		/// set usually and will be calculated automatically when first needed.
1309		/// </param>
1310		public GeometryData(string setName, int setMaxNumberOfVertices,
1311			VertexFormat setVertexFormat, int setNumberOfIndices,
1312			bool setIsStaticData, bool setIsLineData, BoundingBox setBoundingBox)
1313		{
1314			Name = setName;
1315			IsStatic = setIsStaticData;
1316			IsLineData = setIsLineData;
1317			// Both the Skydome model and the generated sky box contain "Sky"
1318			IsSky = Name.Contains("Sky");
1319
1320			Format = setVertexFormat;
1321			VertexDataLengthInBytes = Format.LengthInBytes;
1322			MaxNumberOfVertices = setMaxNumberOfVertices;
1323			// Dynamic vertex data is empty by default
1324			numberOfUsedVerticesInternal =
1325				setIsStaticData
1326					? MaxNumberOfVertices
1327					: 0;
1328
1329			stream = new MemoryStream(MaxNumberOfVertices * VertexDataLengthInBytes);
1330			stream.SetLength(stream.Capacity);
1331			writer = new BinaryWriter(stream);
1332			reader = new BinaryReader(stream);
1333
1334			Indices = new ushort[setNumberOfIndices];
1335			NumberOfUsedIndices =
1336				setIsStaticData
1337					? setNumberOfIndices
1338					: 0;
1339
1340			boundingBox = setBoundingBox;
1341		}
1342
1343		/// <summary>
1344		/// Create geometry data from a binary stream (e.g. as part of ModelData).
1345		/// This constructor requires the binary stream data and a way to reload
1346		/// the content when Dispose was called. This is used for static geometry
1347		/// to save memory and this constructor is always used for static geometry.
1348		/// </summary>
1349		/// <param name="dataReader">
1350		/// The data reader which contains the stored content data internally.
1351		/// </param>
1352		/// <param name="setReloadContent">
1353		/// The delegate which contains the code for reloading the content.
1354		/// </param>
1355		public GeometryData(BinaryReader dataReader, RunDelegate setReloadContent)
1356		{
1357			// Loaded data is always static
1358			IsStatic = true;
1359			IsLineData = false;
1360			reloadContent = setReloadContent;
1361			// All data is filled in Load
1362			Load(dataReader);
1363			// Both the Skydome model and the generated sky box contain "Sky"
1364			IsSky = Name.Contains("Sky");
1365		}
1366		#endregion
1367
1368		#region IDisposable Members
1369		/// <summary>
1370		/// Dispose all internal data (vertices and indices). The lists are still
1371		/// valid, just empty. This is mainly used for static geometry data, which
1372		/// can be disposed after the native objects have been created.
1373		/// </summary>
1374		public void Dispose()
1375		{
1376			if (reader != null)
1377			{
1378				reader.Dispose();
1379				reader = null;
1380			}
1381			if (writer != null)
1382			{
1383				writer.Dispose();
1384				writer = null;
1385			}
1386			if (stream != null)
1387			{
1388				stream.Dispose();
1389				stream = null;
1390			}
1391			Indices = new ushort[0];
1392			numberOfUsedVerticesInternal = 0;
1393			// Note: Do not touch NumberOfUsedIndices or MaxNumberOfVertices as
1394			// these are still used even for disposed geometry data objects to
1395			// perform different re…

Large files files are truncated, but you can click here to view the full file