aboutsummaryrefslogtreecommitdiff
path: root/src/poser.c
blob: 499e0fffd779eff21db7992606c09a2fc3441ee8 (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
96
97
98
99
100
101
#include "math.h"
#include <linmath.h>
#include <stdint.h>
#include <stdio.h>
#include <survive.h>

#define _USE_MATH_DEFINES // for C
#include <math.h>

static uint32_t PoserData_timecode(PoserData *poser_data) {
	switch (poser_data->pt) {
	case POSERDATA_LIGHT: {
		PoserDataLight *lightData = (PoserDataLight *)poser_data;
		return lightData->timecode;
	}
	case POSERDATA_FULL_SCENE: {
		PoserDataFullScene *pdfs = (PoserDataFullScene *)(poser_data);
		return -1;
	}
	case POSERDATA_IMU: {
		PoserDataIMU *imuData = (PoserDataIMU *)poser_data;
		return imuData->timecode;
	}
	}
	return -1;
}

void PoserData_poser_pose_func(PoserData *poser_data, SurviveObject *so, SurvivePose *pose) {
	if (poser_data->poseproc) {
		poser_data->poseproc(so, PoserData_timecode(poser_data), pose, poser_data->userdata);
	} else {
		so->ctx->poseproc(so, PoserData_timecode(poser_data), pose);
	}
}

void PoserData_lighthouse_pose_func(PoserData *poser_data, SurviveObject *so, uint8_t lighthouse,
									SurvivePose *objUp2world, SurvivePose *lighthouse_pose, SurvivePose *object_pose) {
	if (poser_data->lighthouseposeproc) {
		poser_data->lighthouseposeproc(so, lighthouse, lighthouse_pose, object_pose, poser_data->userdata);
	} else {
		const FLT up[3] = {0, 0, 1};

		if (quatmagnitude(lighthouse_pose->Rot) == 0) {
			SurviveContext *ctx = so->ctx;
			SV_INFO("Pose func called with invalid pose.");
			return;
		}

		// Assume that the space solved for is valid but completely arbitrary. We are going to do a few things:
		// a) Using the gyro data, normalize it so that gravity is pushing straight down along Z
		// c) Assume the object is at origin
		// b) Place the first lighthouse on the X axis by rotating around Z
		//
		// This calibration setup has the benefit that as long as the user is calibrating on the same flat surface,
		// calibration results will be roughly identical between all posers no matter the orientation the object is
		// lying
		// in.
		//
		// We might want to go a step further and affix the first lighthouse in a given pose that preserves up so that
		// it doesn't matter where on that surface the object is.

		SurvivePose object2arb = {.Rot = {1.}};
		if (object_pose)
			object2arb = *object_pose;
		SurvivePose lighthouse2arb = *lighthouse_pose;

		// Start by just moving from whatever arbitrary space into object space.
		SurvivePose arb2object;
		InvertPose(&arb2object, &object2arb);

		SurvivePose lighthouse2obj;
		ApplyPoseToPose(&lighthouse2obj, &arb2object, &lighthouse2arb);

		// Now find the space with the same origin, but rotated so that gravity is up
		SurvivePose lighthouse2objUp = {0}, object2objUp = {0};
		if (quatmagnitude(so->activations.accel)) {
			quatfrom2vectors(object2objUp.Rot, so->activations.accel, up);
		} else {
			object2objUp.Rot[0] = 1.0;
		}

		// Calculate the pose of the lighthouse in this space
		ApplyPoseToPose(&lighthouse2objUp, &object2objUp, &lighthouse2obj);

		// Purposefully only set this once. It should only depend on the first (calculated) lighthouse
		if (quatmagnitude(objUp2world->Rot) == 0) {
			// Find what angle we need to rotate about Z by to get to 90 degrees.
			FLT ang = atan2(lighthouse2objUp.Pos[1], lighthouse2objUp.Pos[0]);
			FLT euler[3] = {0, 0, M_PI / 2. - ang};

			quatfromeuler(objUp2world->Rot, euler);
		}

		// Find find the poses that map to the above
		SurvivePose obj2world, lighthouse2world;
		ApplyPoseToPose(&obj2world, objUp2world, &object2objUp);
		ApplyPoseToPose(&lighthouse2world, objUp2world, &lighthouse2objUp);

		so->ctx->lighthouseposeproc(so->ctx, lighthouse, &lighthouse2world, &obj2world);
	}
}