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

#include "vnscene.h"

void vnSceneInit(vnscene_t *scene, font_t *font, texture_t *text) {
  // Init the conversation
  vnConversationInit(&scene->conversation, font, text);
  scene->conversation.textbox.linesMax = 3;

  // Init the animation
  timelineInit(&scene->timeline);

  // Reset Camera
  scene->cameraLook.x = 0;
  scene->cameraLook.y = 0;
  scene->cameraLook.z = 0;
  scene->cameraLook.lookX = 0;
  scene->cameraLook.lookY = 0;
  scene->cameraLook.lookZ = VN_SCENE_DISTANCE_DEFAULT;

  // Reset character count
  scene->characterCount = 0x00;
}

void vnSceneUpdate(vnscene_t *scene, engine_t *engine) {
  uint8_t i;

  // Tick the animations.
  timelineUpdate(&scene->timeline, engine->time.delta);

  // Update the conversation
  vnConversationUpdate(&scene->conversation, engine);

  // Update the character states
  for(i = 0; i < scene->characterCount; i++) {
    vnCharacterUpdate(scene->characters + i, engine);
  }
}

void vnSceneDispose(vnscene_t *scene) {
  vnConversationDispose(&scene->conversation);
}

void vnSceneRenderWorld(vnscene_t *scene, engine_t *engine, shader_t *shader) {
  // Adjust Camera Position.
  cameraLookAtStruct(&scene->camera, scene->cameraLook);

  // Set Camera Perspective
  cameraPerspective(&scene->camera, 45,
    engine->render.width/engine->render.height,
    0.01f, 1000.0f
  );

  // Update Shader
  shaderUseCamera(shader, &scene->camera);
}

void vnSceneRenderCharacters(vnscene_t *scene, shader_t *shader) {
  uint8_t i;
  
  // Render each character
  for(i = 0; i < scene->characterCount; i++) {
    vnCharacterRender(scene->characters + i, shader);
  }
}

void vnSceneRenderGui(vnscene_t *scene, engine_t *engine, shader_t *shader) {
  // Do we need to update the width of the GUI element(s) ?
  if(engine->render.width != scene->conversation.textbox.widthMax) {
    scene->conversation.textbox.widthMax = engine->render.width;
    vnTextBoxRebuffer(&scene->conversation.textbox);
  }

  // Move the camera in space
  cameraLookAt(&scene->camera,
    0, 0, 10,
    0, 0, 0
  );

  // Orthogonalize Camera
  cameraOrtho(&scene->camera,
    0, engine->render.width,
    engine->render.height, 0,
    0.01f, 1000.0f
  );

  // Update Shader
  shaderUseCamera(shader, &scene->camera);

  // Render Conversation Element
  vnConversationRender(&scene->conversation, engine, shader);
}

void vnSceneLookAt(vnscene_t *scene,
  float x, float y, float z, float lookX, float lookY, float lookZ
) {
  float d, s;
  timeline_t *t;
  easefunction_t *f;

  d = 0.7f;
  s = scene->timeline.current;
  t = &scene->timeline;
  f = &easeOutQuad;

  // Clear the timeline
  timelineClear(t);

  // Positions
  timelineAddDeltaActionTo(t, s, d,
    scene->cameraLook.x, x, f, &scene->cameraLook.x
  );
  timelineAddDeltaActionTo(t, s, d,
    scene->cameraLook.y, y, f, &scene->cameraLook.y
  );
  timelineAddDeltaActionTo(t, s, d,
    scene->cameraLook.z, z, f, &scene->cameraLook.z
  );

  timelineAddDeltaActionTo(t, s, d,
    scene->cameraLook.lookX, lookX, f, &scene->cameraLook.lookX
  );
  timelineAddDeltaActionTo(t, s, d,
    scene->cameraLook.lookY, lookY, f, &scene->cameraLook.lookY
  );
  timelineAddDeltaActionTo(t, s, d,
    scene->cameraLook.lookZ, lookZ, f, &scene->cameraLook.lookZ
  );
}

void vnSceneLookAtCharacter(vnscene_t *scene, uint8_t c, float distance) {
  vncharacter_t *character = scene->characters + c;
  vnSceneLookAt(scene,
    -distance * sinf(character->yaw) + character->x,
    scene->cameraLook.y,
    -distance * cosf(character->yaw) + character->z,
    character->x,
    scene->cameraLook.lookY,
    character->z
  );
}