// MIT License // // Copyright (c) 2024 Alexander Malyutin // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // Terrain Chunk Mesh Generator // ._____._____. // |\ | /|\ | /| // |_\|/_|_\|/_| // | /|\ | /|\ | // |/_|_\|/_|_\| // |\ | /|\ | /| // |_\|/_|_\|/_| // | /|\ | /|\ | // |/_|_\|/_|_\| public static class TerrainChunkGenerator { public static int GetChunkDimension(int sections) { return sections * 2 + 1; } public static Vector3[] GenChunkVertices(int dimension) { var vertices = new Vector3[dimension * dimension]; for (int row = 0; row < dimension; row++) { for (int col = 0; col < dimension; col++) { vertices[col + row * dimension] = new Vector3( (float)col / (dimension - 1), 0.0f, (float)row / (dimension - 1) ); } } return vertices; } public static Vector3[] GenChunkNormals(int dimension) { var normals = new Vector3[dimension * dimension]; for (int row = 0; row < dimension; row++) { for (int col = 0; col < dimension; col++) { normals[col + row * dimension] = new Vector3(0.0f, 1.0f, 0.0f); } } return normals; } public static Vector2[] GenChunkTexcoords(int dimension) { var texcoords = new Vector2[dimension * dimension]; for (int row = 0; row < dimension; row++) { for (int col = 0; col < dimension; col++) { texcoords[col + row * dimension] = new Vector2( (float)col / (dimension - 1), (float)row / (dimension - 1) ); } } return texcoords; } public static int[] GenChunkIndexes(int dimension) { int[] indexes = new int[(dimension - 1) * (dimension - 1) * 2 * 3]; var indexesSpan = new Span(indexes, 0, indexes.Length); for (int row = 0; row < dimension - 1; row++) { for (int col = 0; col < dimension - 1; col++) { var temp = indexesSpan.Slice((col + row * (dimension - 1)) * 6, 6); GetQuadIndexes(col + row * dimension + 1, dimension, (col + row * dimension) % 2 == 0, ref temp); } } return indexes; } public static void GetQuadIndexes(int bottomLeftVertexIndex, int chunkDimension, bool antiDiagonal, ref Span arr) { if (antiDiagonal) { // .__. // | /| // |/_| int k = 0; arr[k++] = bottomLeftVertexIndex; arr[k++] = bottomLeftVertexIndex + chunkDimension; arr[k++] = bottomLeftVertexIndex + chunkDimension + 1; arr[k++] = bottomLeftVertexIndex; arr[k++] = bottomLeftVertexIndex + chunkDimension + 1; arr[k++] = bottomLeftVertexIndex + 1; } else { // .__. // |\ | // |_\| int k = 0; arr[k++] = bottomLeftVertexIndex; arr[k++] = bottomLeftVertexIndex + chunkDimension; arr[k++] = bottomLeftVertexIndex + 1; arr[k++] = bottomLeftVertexIndex + 1; arr[k++] = bottomLeftVertexIndex + chunkDimension; arr[k++] = bottomLeftVertexIndex + chunkDimension + 1; } } } public struct Vector2 { public float x, y; public Vector2(float x, float y) : this() { this.x = x; this.y = y; } public string ToObjTexcoord() => $"vt {x:F} {y:F}"; } public struct Vector3 { public float x, y, z; public Vector3(float x, float y, float z) : this() { this.x = x; this.y = y; this.z = z; } public string ToObjVertex() => $"v {x:F} {y:F} {z:F}"; public string ToObjNormal() => $"vn {x:F} {y:F} {z:F}"; }