/**
 * Copyright (c) 2021 Dominic Masters
 * 
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */

#include "chunk.h"

void chunkLoad(chunk_t *chunk, int32_t x, int32_t y, int32_t z) {
  tileid_t tileId;
  tiledef_t *tileDef;
  int32_t i, indiceCount, verticeCount, tx, ty, tz;

  for(ty = 0; ty < CHUNK_HEIGHT; ty++) {
    for(tx = 0; tx < CHUNK_WIDTH; tx++) {
      if(z != 0) break;
      chunk->tiles[ty*CHUNK_WIDTH + tx] = ty == 5 ? 2 : 1;
    }
  }

  // Start by loading the tiles and figuring out how big we need to make the
  // primitive that the chunk uses.
  indiceCount = 0, verticeCount = 0;
  for(i = 0; i < CHUNK_TILE_COUNT; i++) {
    //TODO: Actually load the tileId here
    tileId = chunk->tiles[i];
    if(tileId == TILE_NULL) continue;

    // Increment the primitive size.
    tileDef = MAP_STATE.tileDefinitions + tileId;
    verticeCount += tileDef->verticeCount;
    indiceCount += tileDef->indiceCount;
  }

  // Do we even need to create a primitive?
  if(indiceCount == 0) return;
  chunk->primitive = primitiveCreate(verticeCount, indiceCount);

  // Render each tile. The ZYX order is important for ordering.
  i = 0;
  verticeCount = 0, indiceCount = 0;
  for(tz = 0; tz < CHUNK_DEPTH; tz++) {
    for(ty = 0; ty < CHUNK_HEIGHT; ty++) {
      for(tx = 0; tx < CHUNK_WIDTH; tx++) {
        tileId = chunk->tiles[i];
        if(tileId == TILE_NULL) {
          i++;
          continue;
        }
        tileDef = MAP_STATE.tileDefinitions + tileId;

        tileRender(
          chunk, tileId, tileDef,
          i, tx, ty, tz, 
          verticeCount, indiceCount
        );
        
        // Prepare for the next render.
        verticeCount += tileDef->verticeCount;
        indiceCount += tileDef->indiceCount;
        i++;
      }
    }
  }
}

void chunkUnload(chunk_t *chunk) {
  // Load chunks to zero. TODO: Necessary?
  memset(chunk->tiles, TILE_NULL, CHUNK_TILE_COUNT);

  // Unload the primitive. TODO: Can we salvage this and resize instead?
  if(chunk->primitive == NULL) return;
  primitiveDispose(chunk->primitive);
  chunk->primitive = NULL;
}

int32_t chunkGet(int32_t x, int32_t y, int32_t z) {
  int32_t i = (
    mathMod(x - MAP_STATE.x, MAP_WIDTH) +
    (mathMod(y - MAP_STATE.y, MAP_HEIGHT) * MAP_WIDTH) +
    (mathMod(z - MAP_STATE.z, MAP_DEPTH) * MAP_WIDTH * MAP_HEIGHT)
  );
  if(i < 0 || i > MAP_CHUNK_COUNT) return -1;
  return i;
}

int32_t chunkGetTile(int32_t x, int32_t y, int32_t z) {
  return x + (y * CHUNK_WIDTH) + (z * CHUNK_WIDTH * CHUNK_HEIGHT);
}