map3drendering/LandblockExtraction/LandBlockExtractor/LandBlockExtrator.cs
2024-03-01 14:03:04 +01:00

314 lines
15 KiB
C#

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<int, int> testTerr = new Dictionary<int, int>();
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<int> indices = new List<int>();
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<Vector3> newPositions = new List<Vector3>();
List<Vector3> newNormals = new List<Vector3>();
List<Vector4> newColors = new List<Vector4>();
List<Vector4> newFarColors = new List<Vector4>();
List<Vector2> newTexCoord = new List<Vector2>();
List<Vector4> newTerrainTypes = new List<Vector4>();
List<float> newRealTerrainType = new List<float>();
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<int> indices = new List<int>();
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();
}
}
}