using LandblockExtraction.AtlasMaker; using LandblockExtraction.DatEngine; using LandblockExtraction.LandBlockExtractor; using Map3DRendering.Common; using OpenTK.Graphics.OpenGL4; using OpenTK.Mathematics; namespace Map3DRendering { public class MapRender { private PortalEngine portalEngine; private CellEngine cellEngine; private LandBlockExtrator landblockExtraction; private TerrainAtlasManager terrainAtlasManager; private readonly int NumberLandBlocks = 255; private readonly int BlockSize = 17; private readonly int allBlocks = 255 * 17 * 255 * 17; private readonly int cellSize = 8; private readonly int radius = 0x10; // Rayon du voisinage public int[,] _vertexArrayObject; public int[,] _vertexBufferObject; public int[,] _elementBufferObject; public bool[,] _mapExiste; public int currentLandBlockX { get; private set; } // Position X du landblock actuel public int currentLandBlockY { get; private set; } // Position Y du landblock actuel public int startX { get; private set; } public int startY { get; private set; } public int endX { get; private set; } public int endY { get; private set; } public MapRender() { portalEngine = new PortalEngine(); cellEngine = new CellEngine(); terrainAtlasManager = new(portalEngine); terrainAtlasManager.ExtractTexture(); terrainAtlasManager.GenerateAtlas(); landblockExtraction = new(portalEngine, cellEngine); _vertexArrayObject = new int[0xFE, 0xFE]; _vertexBufferObject = new int[0xFE, 0xFE]; _elementBufferObject = new int[0xFE, 0xFE]; _mapExiste = new bool[0xFE, 0xFE]; currentLandBlockX = 0x7F; currentLandBlockY = 0x7F; CalculeRadius(currentLandBlockX, currentLandBlockY); } public int GetIndiceLenght() { return (17 - 1) * (17 - 1) * 6; //Always that. } public void CalculeRadius(int x, int y) { currentLandBlockX = x; currentLandBlockY = y; startX = Math.Max(0, currentLandBlockX - radius); startY = Math.Max(0, currentLandBlockY - radius); endX = Math.Min(NumberLandBlocks - 1, currentLandBlockX + radius); endY = Math.Min(NumberLandBlocks - 1, currentLandBlockY + radius); } public void OnLoad(Shader _shader) { for (int landY = startY; landY <= endY; landY++) { for (int landX = startX; landX <= endX; landX++) { if (!_mapExiste[landX, landY]) { var block = landblockExtraction.GetBlock(landX, landY); if (block != null) { InitializeBlock(landX, landY, block, _shader); _mapExiste[landX, landY] = true; } } } } } private void InitializeBlock(int x, int y, BlockStruct block, Shader _shader) { int lenghPacket = 11; // Initialisez le VAO, VBO et EBO pour le bloc à (x, y)... // Utilisez le code de votre méthode OnLoad originale pour configurer le VAO, VBO et EBO. int tempVertexArray = GL.GenVertexArray(); GL.BindVertexArray(tempVertexArray); _vertexArrayObject[x, y] = tempVertexArray; int tmpVertexBuffer = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, tmpVertexBuffer); GL.BufferData(BufferTarget.ArrayBuffer, block.verticesStruct.Vertices().Length * sizeof(float), block.verticesStruct.Vertices(), BufferUsageHint.StaticDraw); _vertexBufferObject[x, y] = tmpVertexBuffer; GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, lenghPacket * sizeof(float), 0); int tmpElementBuffer = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, tmpElementBuffer); GL.BufferData(BufferTarget.ElementArrayBuffer, block.indices.Length * sizeof(int), block.indices, BufferUsageHint.StaticDraw); _elementBufferObject[x, y] = tmpElementBuffer; var vertexLocation = _shader.GetAttribLocation("aPos"); GL.EnableVertexAttribArray(vertexLocation); GL.VertexAttribPointer(vertexLocation, 3, VertexAttribPointerType.Float, false, lenghPacket * sizeof(float), 0); var colorLocation = _shader.GetAttribLocation("aColor"); GL.EnableVertexAttribArray(colorLocation); GL.VertexAttribPointer(colorLocation, 4, VertexAttribPointerType.Float, false, lenghPacket * sizeof(float), 3 * sizeof(float)); var farcolorLocation = _shader.GetAttribLocation("aColorFar"); GL.EnableVertexAttribArray(farcolorLocation); GL.VertexAttribPointer(farcolorLocation, 4, VertexAttribPointerType.Float, false, lenghPacket * sizeof(float), 7 * sizeof(float)); } public void Render(Shader shader) { for (int y = startY; y <= endY; y++) { for (int x = startX; x <= endX; x++) { if (_mapExiste[x, y]) { var model = Matrix4.Identity;//CreateTranslation(x * BlockSize, 0, y * BlockSize); // Ajustez selon votre système de coordonnées shader.SetMatrix4("model", model); GL.BindVertexArray(_vertexArrayObject[x, y]); GL.DrawElements(PrimitiveType.Lines, GetIndiceLenght(), DrawElementsType.UnsignedInt, 0); } } } } public void CleanupBlock(int x, int y) { if (_mapExiste[x, y]) { GL.DeleteBuffer(_vertexBufferObject[x, y]); GL.DeleteBuffer(_elementBufferObject[x, y]); GL.DeleteVertexArray(_vertexArrayObject[x, y]); _mapExiste[x, y] = false; } } public void UpdateBlocks(Vector3 cameraPosition, Shader shader) { // Convertir la position de la caméra en coordonnées de landblock int newLandBlockX = ConvertPositionToLandBlockCoord(cameraPosition.X); int newLandBlockY = (0xFF) - ConvertPositionToLandBlockCoord(cameraPosition.Z); // Vérifier si la caméra a déplacé suffisamment pour nécessiter une mise à jour des blocs if (newLandBlockX != currentLandBlockX || newLandBlockY != currentLandBlockY) { // Nettoyer les blocs qui ne sont plus dans la nouvelle zone visible for (int y = startY; y <= endY; y++) { for (int x = startX; x <= endX; x++) { if (!IsInNewRadius(x, y, newLandBlockX, newLandBlockY)) { CleanupBlock(x, y); } } } // Mettre à jour les coordonnées du rayon pour la nouvelle position CalculeRadius(newLandBlockX, newLandBlockY); // Initialiser les nouveaux blocs dans la nouvelle zone visible OnLoad(shader); } } private int ConvertPositionToLandBlockCoord(float position) { // Convertir la position en coordonnée de landblock, ajuster selon la mise en échelle de votre carte return (int)(position / 128) + 0x7f; // Ajustez cette conversion en fonction de votre mise en échelle } private bool IsInNewRadius(int x, int y, int newLandBlockX, int newLandBlockY) { // Calculer le nouveau startX, startY, endX, et endY basé sur newLandBlockX, newLandBlockY int newStartX = Math.Max(0, newLandBlockX - radius); int newStartY = Math.Max(0, newLandBlockY - radius); int newEndX = Math.Min(NumberLandBlocks - 1, newLandBlockX + radius); int newEndY = Math.Min(NumberLandBlocks - 1, newLandBlockY + radius); // Vérifier si (x, y) est dans la nouvelle zone définie par newStartX, newStartY, newEndX, et newEndY return x >= newStartX && x <= newEndX && y >= newStartY && y <= newEndY; } } }