using AC2RE.Definitions; using LandblockExtraction.AtlasMaker; using LandblockExtraction.DatEngine; using LandblockExtraction.Tools; using System; using System.Numerics; namespace LandblockExtraction.LandBlockExtractor { public class LandBlockExtrator { private PortalEngine portalEngine; private CellEngine cellEngine; private TerrainAtlasManager terrainAtlasManager; private readonly int NumberLandBlocks = 255; private readonly int BlockSize = 17; private readonly int cellSize = 8; public LandBlockExtrator(PortalEngine portalEngine, CellEngine cellEngine) { this.portalEngine = portalEngine; this.cellEngine = cellEngine; terrainAtlasManager = new TerrainAtlasManager(portalEngine); terrainAtlasManager.ExtractTexture(); terrainAtlasManager.GenerateUV(); terrainAtlasManager.SaveAllTerrain(); } public BlockStruct? GetBlock(int landX, int landY) { CellId landBlockId = new CellId((byte)landX, (byte)landY, 0xFF, 0xFF); var landBlock = cellEngine.GetLandBlockData(landBlockId.id); if (landBlock == null) return null; return GenerateBlockStructByData(landBlock, landX, landY); } public BlockStruct GenerateBlockStructByData(CLandBlockData blockData, int landX, int landY) { BlockStruct blockStruct = new BlockStruct(); for (int y = 0; y < BlockSize; y++) { for (int x = 0; x < BlockSize; x++) { var indice = y * BlockSize + x; blockStruct.verticesStruct.position[indice] = GenerateVertexPosition(landX, landY, x, y, blockData.heights[indice]); blockStruct.verticesStruct.color[indice] = GenerateVertexColor(blockData.cellInfos[indice]); blockStruct.verticesStruct.farcolor[indice] = GenerateVertexFarColor(blockData.cellInfos[indice]); blockStruct.verticesStruct.terraintype[indice] = GenerateVertexTerrainType(blockData.cellInfos[indice]); blockStruct.verticesStruct.texturecoord[indice] = GenerateUVForSubTile(x, y); blockStruct.indices = GenerateBasicIndices(); } } //blockStruct.verticesStruct.texturecoord = GenerateBasicUVTest(blockStruct); blockStruct.verticesStruct.normal = GenerateBasicNormal(blockStruct); //DoubleEdgeVertices(blockStruct); Dictionary testTerr = new Dictionary(); foreach (var test in blockStruct.verticesStruct.terraintype) { var type = (int)test.X; if (testTerr.ContainsKey(type)) { testTerr[type]++; } else { testTerr.Add(type, 1); } } return blockStruct; } private Vector2 GenerateBasicUV(int x, int y) { float u = (float)x / (BlockSize - 1) * 8; float v = (float)y / (BlockSize - 1) * 8; return new Vector2(u, v); } private Vector2 GenerateUVForSubTile(int x, int y) { // Taille d'une "mini-tuile" en termes de coordonnées UV float miniTileSize = 1f / BlockSize - 1; // Comme la sous-grille est 5x5 // Calcul des coordonnées UV basées sur la position (x, y) dans la sous-grille float u = x * miniTileSize; float v = y * miniTileSize; return new Vector2(u, v); } private Vector2[] GenerateBasicUVTest(BlockStruct blockStruct) { Vector2[] uvs = new Vector2[blockStruct.verticesStruct.position.Length]; for (int i = 0; i < uvs.Length; i++) { uvs[i] = new Vector2(0, 0); } for (int i = 0; i < blockStruct.indices.Length; i += 6) { int index1 = blockStruct.indices[i]; int index2 = blockStruct.indices[i + 1]; int index3 = blockStruct.indices[i + 2]; int index4 = blockStruct.indices[i + 5]; uvs[index1] = new(0, 0); uvs[index2] = new(0, 1); uvs[index3] = new(1, 0); uvs[index4] = new(1, 1); } return uvs; } private Vector3[] GenerateBasicNormal(BlockStruct blockStruct) { Vector3[] normals = new Vector3[blockStruct.verticesStruct.position.Length]; // Initialise tous les vecteurs normaux à zéro for (int i = 0; i < normals.Length; i++) { normals[i] = new Vector3(0, 0, 0); } // Parcourt tous les indices et calcule les normales pour chaque triangle for (int i = 0; i < blockStruct.indices.Length; i += 6) { int index1 = blockStruct.indices[i]; int index2 = blockStruct.indices[i + 1]; int index3 = blockStruct.indices[i + 2]; int index4 = blockStruct.indices[i + 5]; Vector3 vertex1 = blockStruct.verticesStruct.position[index1]; Vector3 vertex2 = blockStruct.verticesStruct.position[index2]; Vector3 vertex3 = blockStruct.verticesStruct.position[index3]; Vector3 vertex4 = blockStruct.verticesStruct.position[index4]; // Calcule la normale du triangle /*Vector3 edge1 = vertex2 - vertex1; Vector3 edge2 = vertex3 - vertex1; Vector3 normal = Vector3.Cross(edge1, edge2); normal = Vector3.Normalize(normal);*/ var normal = MathOperations.CalculateQuadNormal(vertex1, vertex2, vertex3, vertex4); // Ajoute la normale du triangle aux normales des sommets du triangle normals[index1] += normal; normals[index2] += normal; normals[index3] += normal; normals[index4] += normal; } // Normalise toutes les normales de sommets pour qu'elles soient de longueur unitaire for (int i = 0; i < normals.Length; i++) { normals[i] = Vector3.Normalize(normals[i]); } return normals; } private int[] GenerateBasicIndices() { List indices = new List(); for (int y = 0; y < BlockSize - 1; y++) { for (int x = 0; x < BlockSize - 1; x++) { // Indices des sommets du premier triangle indices.Add(y * BlockSize + x); indices.Add((y + 1) * BlockSize + x); indices.Add(y * BlockSize + x + 1); // Indices des sommets du deuxième triangle indices.Add(y * BlockSize + x + 1); indices.Add((y + 1) * BlockSize + x); indices.Add((y + 1) * BlockSize + x + 1); } } return indices.ToArray(); } private Vector4 GenerateVertexTerrainType(uint cellInfo) { var terrain = MathOperations.GetTerrainInCellInfo(cellInfo); return new(terrain, 0f, 0f, 0f); } private Vector3 GenerateVertexPosition(int landx, int landy, int x, int y, byte height) { int tmpx = (landx * BlockSize + y) * cellSize; int tmpy = (BlockSize * NumberLandBlocks * cellSize) - ((landy * BlockSize + x) * cellSize) - 1; var newX = (tmpx - (NumberLandBlocks * BlockSize * cellSize / 2)); var newY = (tmpy - ((NumberLandBlocks * BlockSize * cellSize) - (NumberLandBlocks * BlockSize * cellSize / 2) - 1)); return new Vector3(newX, portalEngine.landScapeDefs.landHeightTable[height], newY); } private Vector4 GenerateVertexColor(uint cellInfo) { var terrain = MathOperations.GetTerrainInCellInfo(cellInfo); foreach (var terrainType in portalEngine.cTerrainDesc.terrains) { if (terrainType.terrainIndex == terrain) { foreach (var surfaceIndex in portalEngine.cSurfaceDesc.surfaces) { if (surfaceIndex.surfIndex == terrainType.surfaceInfo) { var color = surfaceIndex.terrainMaterials.First().vertexColor.First().vertexColor; return MathOperations.RGBAColorToVector4(color); } } } } return Vector4.One; } private Vector4 GenerateVertexFarColor(uint cellInfo) { var terrain = MathOperations.GetTerrainInCellInfo(cellInfo); foreach (var terrainType in portalEngine.cTerrainDesc.terrains) { if (terrainType.terrainIndex == terrain) { foreach (var surfaceIndex in portalEngine.cSurfaceDesc.surfaces) { if (surfaceIndex.surfIndex == terrainType.surfaceInfo) { var color = surfaceIndex.terrainMaterials.First().vertexColor.First().farVertexColor; return MathOperations.RGBAColorToVector4(color); } } } } return Vector4.One; } //TEST public void DoubleEdgeVertices(BlockStruct blockStruct) { List newPositions = new List(); List newNormals = new List(); List newColors = new List(); List newFarColors = new List(); List newTexCoord = new List(); List newTerrainTypes = new List(); List newRealTerrainType = new List(); int originalVertexCount = blockStruct.verticesStruct.position.Length; int originalIndicesCount = blockStruct.indices.Length; // Doubler les sommets sur le bord supérieur et inférieur for (int i = 0; i < originalIndicesCount; i = i + 6) { var one = blockStruct.indices[i + 0]; var two = blockStruct.indices[i + 1]; var three = blockStruct.indices[i + 2]; var foor = blockStruct.indices[i + 5]; newPositions.Add(blockStruct.verticesStruct.position[one]); newColors.Add(blockStruct.verticesStruct.color[one]); newFarColors.Add(blockStruct.verticesStruct.farcolor[one]); newTerrainTypes.Add(new Vector4(blockStruct.verticesStruct.terraintype[one].X, blockStruct.verticesStruct.terraintype[two].X, blockStruct.verticesStruct.terraintype[three].X, blockStruct.verticesStruct.terraintype[foor].X)); newRealTerrainType.Add(blockStruct.verticesStruct.terraintype[one].X); /*newPositions.Add(blockStruct.verticesStruct.position[two]); newColors.Add(blockStruct.verticesStruct.color[two]); newFarColors.Add(blockStruct.verticesStruct.farcolor[two]); newTerrainTypes.Add(new Vector4(blockStruct.verticesStruct.terraintype[one].X, blockStruct.verticesStruct.terraintype[two].X, blockStruct.verticesStruct.terraintype[three].X, blockStruct.verticesStruct.terraintype[foor].X)); newRealTerrainType.Add(blockStruct.verticesStruct.terraintype[two].X); newPositions.Add(blockStruct.verticesStruct.position[three]); newColors.Add(blockStruct.verticesStruct.color[three]); newFarColors.Add(blockStruct.verticesStruct.farcolor[three]); newTerrainTypes.Add(new Vector4(blockStruct.verticesStruct.terraintype[one].X, blockStruct.verticesStruct.terraintype[two].X, blockStruct.verticesStruct.terraintype[three].X, blockStruct.verticesStruct.terraintype[foor].X)); newRealTerrainType.Add(blockStruct.verticesStruct.terraintype[three].X); newPositions.Add(blockStruct.verticesStruct.position[foor]); newColors.Add(blockStruct.verticesStruct.color[foor]); newFarColors.Add(blockStruct.verticesStruct.farcolor[foor]); newTerrainTypes.Add(new Vector4(blockStruct.verticesStruct.terraintype[one].X, blockStruct.verticesStruct.terraintype[two].X, blockStruct.verticesStruct.terraintype[three].X, blockStruct.verticesStruct.terraintype[foor].X)); newRealTerrainType.Add(blockStruct.verticesStruct.terraintype[foor].X); newTexCoord.Add(new(0, 0)); newTexCoord.Add(new(0, 1)); newTexCoord.Add(new(1, 0)); newTexCoord.Add(new(1, 1));*/ var normal = MathOperations.CalculateQuadNormal(blockStruct.verticesStruct.position[one], blockStruct.verticesStruct.position[two], blockStruct.verticesStruct.position[three], blockStruct.verticesStruct.position[foor]); newNormals.Add(normal); //newNormals.Add(normal); //newNormals.Add(normal); //newNormals.Add(normal); } // Ajouter les nouveaux sommets à la structure BlockStruct (étape 2) // Vous devez également mettre à jour les indices dans blockStruct.indices blockStruct.verticesStruct.position = newPositions.ToArray(); blockStruct.verticesStruct.normal = newNormals.ToArray(); blockStruct.verticesStruct.color = newColors.ToArray(); blockStruct.verticesStruct.farcolor = newFarColors.ToArray(); blockStruct.verticesStruct.texturecoord = newTexCoord.ToArray(); blockStruct.verticesStruct.terraintype = newTerrainTypes.ToArray(); blockStruct.verticesStruct.realtype = newRealTerrainType.ToArray(); blockStruct.indices = GenerateNewsIndices(newPositions.Count); } private int[] GenerateNewsIndices(int count) { List indices = new List(); for (int i = 0; i < count; i = i + 4) { indices.Add(i); indices.Add(i + 1); indices.Add(i + 2); indices.Add(i + 2); indices.Add(i + 1); indices.Add(i + 3); } return indices.ToArray(); } } }