summaryrefslogtreecommitdiff
path: root/src/animation.c
blob: d7973dcae7a12de45d204e6cfc04431c155c7c5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include "animation.h"
#include "immdraw.h"
#include "log.h"
#include "maths.h"
#include "maths_types.h"
#include "ral_types.h"

Keyframe Animation_Sample(AnimationSampler* sampler, f32 t) {
  size_t previous_index = 0;
  f32 previous_time = 0.0;
  // look forwards
  DEBUG("%d\n", keyframe_kind_strings[sampler->animation.values.kind]);
  TRACE("Total timestamps %d", sampler->animation.n_timestamps);
  for (u32 i = 0; i < sampler->animation.n_timestamps; i++) {
    f32 current_time = sampler->animation.timestamps[i];
    if (current_time > t) {
      break;
    }
    previous_time = sampler->animation.timestamps[i];
    previous_index = i;
  }

  size_t next_index = (previous_index + 1) % sampler->animation.n_timestamps;
  f32 next_time = sampler->animation.timestamps[next_index];
  printf("%d %f %d %f\n", previous_index, previous_time, next_index, next_time);

  Keyframe prev_value = sampler->animation.values.values[previous_index];
  Keyframe next_value = sampler->animation.values.values[next_index];

  printf("%d %d\n", previous_index, next_index);

  f32 time_diff =
      sampler->animation.timestamps[next_index] - sampler->animation.timestamps[previous_index];
  f32 percent = (t - previous_time) / time_diff;

  switch (sampler->animation.values.kind) {
    case KEYFRAME_ROTATION:
      return (Keyframe){ .rotation = quat_slerp(
                             sampler->animation.values.values[previous_index].rotation,
                             sampler->animation.values.values[next_index].rotation, percent) };
    case KEYFRAME_TRANSLATION:
    case KEYFRAME_SCALE:
    case KEYFRAME_WEIGHTS:
      WARN("TODO: other keyframe kind interpolation");
      return prev_value;
  }
}

void Animation_Tick(AnimationClip* clip, Armature* armature, f32 time) {
  TRACE("Ticking animation %s", clip->clip_name);

  for (u32 c_i = 0; c_i < clip->channels->len; c_i++) {
    AnimationSampler* sampler = clip->channels->data;

    // Interpolated keyframe based on time
    Keyframe k = Animation_Sample(sampler, time);

    // Get the joint in the armature
    Joint* joint = &armature->joints->data[sampler->target_joint_idx];
    if (sampler->animation.values.kind == KEYFRAME_ROTATION) {
      // Update the joints rotation
      joint->transform_components.rotation = k.rotation;
    } else {
      WARN("not yet implemented animation kind");
    }
  }
}

void Animation_VisualiseJoints(Armature* armature) {
  for (int j = 0; j < armature->joints->len; j++) {
    Joint joint = armature->joints->data[j];
    Transform tf = joint.transform_components;
    tf.scale = vec3(0.05, 0.05, 0.05);
    Immdraw_Sphere(tf, vec4(0, 1, 1, 1), true);
  }
}

ShaderDataLayout AnimData_GetLayout(void* data) {
  AnimDataUniform* d = data;
  bool has_data = data != NULL;

  ShaderBinding b1 = { .label = "AnimData",
                       .kind = BINDING_BYTES,
                       .data.bytes.size = sizeof(AnimDataUniform) };

  if (has_data) {
    b1.data.bytes.data = d;
  }
  return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 };
}