#region CPL License /* Nuclex Framework Copyright (C) 2002-2009 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace Nuclex.Graphics.SpecialEffects.Water { /// Creates and manages a segmented grid of vertices public class WaterGrid : StaticMesh { /// Initializes a new grid drawn as a single quad /// Graphics device the grid will be created on /// /// Lesser coordinates of the world region that will be covered by the grid /// /// /// Greater coordinates of the world region that will be covered by the grid /// public WaterGrid(GraphicsDevice graphicsDevice, Vector2 min, Vector2 max) : this(graphicsDevice, min, max, 1, 1) { } /// Initializes a new grid consisting of one or more quads /// Graphics device the grid will be created on /// /// Lesser coordinates of the world region that will be covered by the grid /// /// /// Greater coordinates of the world region that will be covered by the grid /// /// /// Number of segments the grid will have on the X axis /// /// /// Number of segments the grid will have on the Z axis /// public WaterGrid( GraphicsDevice graphicsDevice, Vector2 min, Vector2 max, int segmentsX, int segmentsZ ) : base(graphicsDevice, getIndexCount(segmentsX, segmentsZ)) { this.graphicsDevice = graphicsDevice; // Create and fill the vertex buffer { WaterVertex[] vertices = buildVertexArray(min, max, segmentsX, segmentsZ); this.vertexCount = vertices.Length; this.vertexBuffer = new VertexBuffer( graphicsDevice, typeof(WaterVertex), vertices.Length, BufferUsage.None ); this.vertexBuffer.SetData(vertices); } // Create and fill the index buffer { short[] indices = TriangleStripIndexBuilder.BuildAlternatingStrip( segmentsX, segmentsZ ); this.indexCount = indices.Length; this.indexBuffer = new IndexBuffer( graphicsDevice, typeof(short), indices.Length, BufferUsage.None ); this.indexBuffer.SetData(indices); } } /// /// Immediately releases all resources owned by the instance /// public override void Dispose() { if(this.vertexDeclaration != null) { this.vertexDeclaration.Dispose(); this.vertexDeclaration = null; } if(this.indexBuffer != null) { this.indexBuffer.Dispose(); this.indexBuffer = null; } if(this.vertexBuffer != null) { this.vertexBuffer.Dispose(); this.vertexBuffer = null; } base.Dispose(); } /// Number of vertices in the grid public int VertexCount { get { return this.vertexCount; } } /// Number of indices required to draw the grid public int IndexCount { get { return this.indexCount; } } /// Number of primitives that need to be drawn for the grid public int PrimitiveCount { get { return this.indexCount - 2; } } /// The type of primitive used to render the grid public PrimitiveType PrimitiveType { get { return PrimitiveType.TriangleStrip; } } /// Vertex buffer containing the vertices making up the plane public new VertexBuffer VertexBuffer { get { return this.vertexBuffer; } } /// Index buffer used to build polygons from the vertices public IndexBuffer IndexBuffer { get { return this.indexBuffer; } } /// /// Creates a flat plane of vertices optimized for triangle strip drawing /// /// X and Y coordinates for the upper left side of the plane /// X and Y coordinates for the lower right side of the plane /// Number of horizontal subdivisions in the plane /// Number of vertical subdivisions in the plane private static WaterVertex[] buildVertexArray( Vector2 min, Vector2 max, int segmentsX, int segmentsZ ) { int verticesX = segmentsX + 1; int verticesZ = segmentsZ + 1; WaterVertex[] vertices = new WaterVertex[verticesX * verticesZ]; int vertexIndex = 0; Vector3 position = Vector3.Zero; for(int z = segmentsZ; z >= 0; --z) { float relativeZ = (float)z / (float)segmentsZ; position.Z = MathHelper.Lerp(min.Y, max.Y, relativeZ); for(int x = 0; x <= segmentsX; ++x) { float relativeX = (float)x / (float)segmentsX; position.X = MathHelper.Lerp(min.X, max.X, relativeX); vertices[vertexIndex].Position = position; vertices[vertexIndex].TextureCoordinate = new Vector2( relativeX * 100.0f, relativeZ * 100.0f // TODO: Magic number here. Implement configurable texture coordinate scale ); ++vertexIndex; } } return vertices; } /// /// Calculates the number of indices required for the water surface /// /// Number of segments in X direction /// Number of segments in Z direction /// The number of indices required private static int getIndexCount(int segmentsX, int segmentsZ) { return TriangleStripIndexBuilder.CountAlternatingStripIndices(segmentsX, segmentsZ); } /// Number of vertices in the grid private int vertexCount; /// Number of indices required to draw the grid private int indexCount; /// Vertex declaration for the vertices in the grid private VertexDeclaration vertexDeclaration; /// Vertex buffer containing the grid vertices private VertexBuffer vertexBuffer; /// Index buffer containing the indices to the vertex buffer private IndexBuffer indexBuffer; /// Graphics device the grid will be rendered with private GraphicsDevice graphicsDevice; } } // namespace Nuclex.Graphics.SpecialEffects.Water