//
// Created by martin on 25.03.22.
//

#include "AnimGraphNodes.h"

#include "ozz/base/log.h"
#include "ozz/animation/runtime/blending_job.h"
#include "ozz/animation/runtime/animation.h"
#include "ozz/base/io/archive.h"
#include "ozz/base/io/stream.h"

void Blend2Node::Evaluate(AnimGraphContext& context) {
  assert (i_input0 != nullptr);
  assert (i_input1 != nullptr);
  assert (i_blend_weight != nullptr);
  assert (o_output != nullptr);

  // perform blend
  ozz::animation::BlendingJob::Layer layers[2];
  layers[0].transform = make_span(i_input0->m_local_matrices);
  layers[0].weight = (1.0f - *i_blend_weight);

  layers[1].transform = make_span(i_input1->m_local_matrices);
  layers[1].weight = (*i_blend_weight);

  ozz::animation::BlendingJob blend_job;
  blend_job.threshold = ozz::animation::BlendingJob().threshold;
  blend_job.layers = layers;
  blend_job.rest_pose = context.m_skeleton->joint_rest_poses();
  blend_job.output = make_span(o_output->m_local_matrices);

  if (!blend_job.Run()) {
    ozz::log::Err() << "Error blending animations." << std::endl;
  }
}

//
// AnimSamplerNode
//
AnimSamplerNode::~AnimSamplerNode() noexcept {
  m_animation = nullptr;
}

bool AnimSamplerNode::Init(AnimGraphContext& context) {
  assert (m_animation == nullptr);
  assert(m_filename.size() != 0);

  AnimGraphContext::AnimationFileMap::const_iterator animation_map_iter;
  animation_map_iter = context.m_animation_map.find(m_filename);
  if (animation_map_iter != context.m_animation_map.end()) {
    m_animation = animation_map_iter->second;
  } else {
    m_animation = new ozz::animation::Animation();
    ozz::io::File file(m_filename.c_str(), "rb");
    if (!file.opened()) {
      ozz::log::Err() << "Failed to open animation file " << m_filename << "."
                      << std::endl;
      return false;
    }
    ozz::io::IArchive archive(&file);
    if (!archive.TestTag<ozz::animation::Animation>()) {
      ozz::log::Err() << "Failed to load animation instance from file "
                      << m_filename << "." << std::endl;
      return false;
    }

    context.m_animation_map[m_filename] = m_animation;
  }

  assert (context.m_skeleton != nullptr);
  m_sampling_context.Resize(context.m_skeleton->num_joints());

  return true;
}

void AnimSamplerNode::Evaluate(AnimGraphContext& context) {
  assert (o_output != nullptr);

  ozz::animation::SamplingJob sampling_job;
  sampling_job.animation = m_animation;
  sampling_job.context = &m_sampling_context;
  sampling_job.ratio = m_time_now;
  sampling_job.output = make_span(o_output->m_local_matrices);

  if (!sampling_job.Run()) {
    ozz::log::Err() << "Error sampling animation." << std::endl;
  }
}