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

#include "vncharacter.h"

void _vnCharacterQuad(primitive_t *primitive, tilesetdiv_t *div) {
  quadInit(primitive, 0,
    -VN_CHARACTER_SIZE, 0,                   div->x0, div->y1,
     VN_CHARACTER_SIZE, VN_CHARACTER_SIZE*2, div->x1, div->y0
  );
}

void vnCharacterInit(vncharacter_t *character,
  texture_t *textureEyes,
  texture_t *textureBody,
  texture_t *textureMouth,
  texture_t *textureFace
) {
  tilesetdiv_t div;

  character->x = 0;
  character->y = 0;
  character->z = 0;

  character->yaw = 0;
  character->pitch = 0;
  character->roll = 0;

  character->scaleX = 1;
  character->scaleY = 1;

  character->talking = false;
  character->blinkStart = randFloatRange(0, VN_CHARACTER_BLINK_TIME_RANGE_MAX);

  character->name = "";

  // Setup Textures
  character->textureEyes = textureEyes;
  character->textureBody = textureBody;
  character->textureMouth = textureMouth;
  character->textureFace = textureFace;

  // Tileset
  tilesetInit(&character->tilesetEyes, 1, 6,
    textureEyes->width, textureEyes->height,
    0, 0, 0, 0
  );
  tilesetInit(&character->tilesetMouth, 1, 11,
    textureMouth->width, textureMouth->height,
    0, 0, 0, 0
  );

  vnCharacterSetEyes(character, 0);
  vnCharacterSetMouth(character, 9);

  div.x0 = 0, div.x1 = 1;
  div.y0 = 0, div.y1 = 1;

  _vnCharacterQuad(&character->primitiveBody, &div);
  _vnCharacterQuad(&character->primitiveFace, &div);
}


void vnCharacterSetEyes(vncharacter_t *character, uint8_t eyes) {
  tilesetdiv_t *div;
  div = character->tilesetEyes.divisions + eyes;
  _vnCharacterQuad(&character->primitiveEyes, div);
}

void vnCharacterSetMouth(vncharacter_t *character, uint8_t mouth) {
  tilesetdiv_t *div;
  div = character->tilesetMouth.divisions + mouth;
  _vnCharacterQuad(&character->primitiveMouth, div);
}

void vnCharacterUpdate(vncharacter_t *character, engine_t *engine) {
  float n;

  // Update the blinking frames
  n = (engine->time.current - character->blinkStart) * 1.5;
  if(n >= 1) {
    character->blinkStart = engine->time.current + randFloatRange(
      1, VN_CHARACTER_BLINK_TIME_RANGE_MAX
    );
  } else if(n > 0) {
    n = easeInQuad(easeTimeToForwardAndBackward(n) * 2);
    vnCharacterSetEyes(character, n * character->tilesetEyes.count);
  }

  // Updating the talking frames
  if(character->talking) {
    vnCharacterSetMouth(character,
      (int32_t)(engine->time.current*12) % character->tilesetMouth.count
    );
  } else {
    vnCharacterSetMouth(character, 9);
  }

  // Update the scale frames
  float speed, amount;
  if(character->talking) {
    speed = 2.5;
    amount = 100;
    n = easeTimeToForwardAndBackward(fmod(engine->time.current, 1 / speed) * speed) * 2;
    n = easeInOutQuad(n) / amount - (1/(amount*2));
    character->scaleX = 1 + n;
    character->scaleY = 1 - n;
  } else {
    speed = 10;
    amount = 50;
    n = easeTimeToForwardAndBackward(fmod(engine->time.current, speed) / speed)*2;
    n = easeInOutCubic(n) / amount - (1/(amount*2));
    character->scaleX = 1 + n;
    character->scaleY = 1 + n*2;
  }
}

void vnCharacterRender(vncharacter_t *character, shader_t *shader) {
  shaderUsePositionAndScale(shader,
    character->x, character->y, character->z,
    character->pitch, character->yaw, character->roll,
    character->scaleX, character->scaleY, 1
  );

  shaderUseTexture(shader, character->textureBody);
  primitiveDraw(&character->primitiveBody, 0, -1);

  shaderUseTexture(shader, character->textureFace);
  primitiveDraw(&character->primitiveFace, 0, -1);

  shaderUseTexture(shader, character->textureEyes);
  primitiveDraw(&character->primitiveEyes, 0, -1);

  shaderUseTexture(shader, character->textureMouth);
  primitiveDraw(&character->primitiveMouth, 0, -1);
}