about summary refs log tree commit diff
path: root/src/game/client/animstate.cpp
blob: d8c20decd1d988e8c2ebbc3e00056ed07650938b (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
91
92
93
94
95

#include <base/math.hpp>
#include <engine/e_client_interface.h>
#include <game/generated/g_protocol.hpp>
#include <game/generated/gc_data.hpp>

#include "animstate.hpp"

static void anim_seq_eval(ANIM_SEQUENCE *seq, float time, ANIM_KEYFRAME *frame)
{
	if(seq->num_frames == 0)
	{
		frame->time = 0;
		frame->x = 0;
		frame->y = 0;
		frame->angle = 0;
	}
	else if(seq->num_frames == 1)
	{
		*frame = seq->frames[0];
	}
	else
	{
		//time = max(0.0f, min(1.0f, time / duration)); // TODO: use clamp
		ANIM_KEYFRAME *frame1 = 0;
		ANIM_KEYFRAME *frame2 = 0;
		float blend = 0.0f;

		// TODO: make this smarter.. binary search
		for (int i = 1; i < seq->num_frames; i++)
		{
			if (seq->frames[i-1].time <= time && seq->frames[i].time >= time)
			{
				frame1 = &seq->frames[i-1];
				frame2 = &seq->frames[i];
				blend = (time - frame1->time) / (frame2->time - frame1->time);
				break;
			}
		}

		if (frame1 && frame2)
		{
			frame->time = time;
			frame->x = mix(frame1->x, frame2->x, blend);
			frame->y = mix(frame1->y, frame2->y, blend);
			frame->angle = mix(frame1->angle, frame2->angle, blend);
		}
	}
}

static void anim_add_keyframe(ANIM_KEYFRAME *seq, ANIM_KEYFRAME *added, float amount)
{
	seq->x += added->x*amount;
	seq->y += added->y*amount;
	seq->angle += added->angle*amount;
}

static void anim_add(ANIMSTATE *state, ANIMSTATE *added, float amount)
{
	anim_add_keyframe(&state->body, &added->body, amount);
	anim_add_keyframe(&state->back_foot, &added->back_foot, amount);
	anim_add_keyframe(&state->front_foot, &added->front_foot, amount);
	anim_add_keyframe(&state->attach, &added->attach, amount);
}


void ANIMSTATE::set(ANIMATION *anim, float time)
{
	anim_seq_eval(&anim->body, time, &body);
	anim_seq_eval(&anim->back_foot, time, &back_foot);
	anim_seq_eval(&anim->front_foot, time, &front_foot);
	anim_seq_eval(&anim->attach, time, &attach);
}

void ANIMSTATE::add(ANIMATION *anim, float time, float amount)
{
	ANIMSTATE add;
	add.set(anim, time);
	anim_add(this, &add, amount);
}

ANIMSTATE *ANIMSTATE::get_idle()
{
	static ANIMSTATE state;
	static bool init = true;
	
	if(init)
	{
		state.set(&data->animations[ANIM_BASE], 0);
		state.add(&data->animations[ANIM_IDLE], 0, 1.0f);
		init = false;
	}
	
	return &state;
}