26template <
size_t size,
typename T>
27bool array_contains(
const T* container,
const T& element) {
30 if (container[i] == element) {
40void tokenize(std::string& line, C& buffer) {
41 std::istringstream l(line);
43 while (std::getline(l, text,
',')) {
44 if (text.size()>0 && text.c_str()[0] ==
'{') {
46 t.type = token::COMPOUND;
47 size_t end = text.find_first_of(
"}");
48 if (end != std::string::npos) {
49 t.text = text.substr(1, end-1);
53 throw std::string(
"parsing error: missing \"}\"");
56 else if (text.size() > 0 && text.find_first_of(
"abcdefghijklmnopqrstuvwxyz") != std::string::npos) {
62 else if (text.size() > 0 && text.find_first_of(
"0123456789") != std::string::npos) {
64 t.type = token::VALUE;
71const std::string filter_to_string(vr::vr_log::Filter f){
73 case vr::vr_log::F_AXES:
75 case vr::vr_log::F_BUTTON:
77 case vr::vr_log::F_HMD:
79 case vr::vr_log::F_POSE:
81 case vr::vr_log::F_VIBRATION:
84 return "UNKNOWN_FILTER";
88const std::unordered_map<std::string, vr::vr_log::Filter> filter_map = {
89 {
"AXES", vr::vr_log::F_AXES},
90 {
"BUTTON", vr::vr_log::F_BUTTON},
91 {
"HMD", vr::vr_log::F_HMD },
92 {
"POSE", vr::vr_log::F_POSE},
93 {
"VIBRATION", vr::vr_log::F_VIBRATION},
94 {
"UNKNOWN_FILTER", vr::vr_log::F_NONE}
98const vr::vr_log::Filter filter_from_string(
const std::string& f) {
99 const auto it = filter_map.find(f);
100 if (it != filter_map.cend()) {
103 return vr::vr_log::F_NONE;
109 log_storage_mode = SM_NONE;
111 log_stream =
nullptr;
118 log_storage_mode = log_storage_mode | SM_IN_MEMORY;
125 log_stream->precision(std::numeric_limits<double>::max_digits10);
126 log_storage_mode = log_storage_mode | SM_OSTREAM;
129vr::vr_log::vr_log(std::istringstream& is) {
139 if (mode & SM_IN_MEMORY) {
140 this->time_stamp.push_back(time);
142 if (mode & SM_OSTREAM) {
143 *(log_stream) << time;
145 if (mode != SM_NONE) {
152 if (mode & SM_IN_MEMORY) {
153 if (filter & F_VIBRATION) {
155 this->controller_vibration[ci].push_back(vibration);
157 if (filter & F_AXES) {
162 this->controller_axes[ci].push_back(axes);
164 if (filter & F_POSE) {
166 this->controller_pose[ci].push_back(pose);
168 if (filter & F_BUTTON) {
172 if (mode & SM_OSTREAM) {
176 *(log_stream) <<
",{C " << ci;
177 if (filter & F_POSE) {
178 *(log_stream) <<
" P";
179 for (
int j = 0; j < 12; ++j)
182 if (filter & F_BUTTON) {
185 if (filter & F_AXES) {
186 *(log_stream) <<
" A";
190 if (filter & F_VIBRATION) {
191 *(log_stream) <<
" V";
192 for (
int j = 0; j < 2; ++j)
195 *(log_stream) <<
"}";
201 if (filter & F_HMD) {
203 if (mode & SM_IN_MEMORY) {
204 hmd_pose.push_back(pose);
207 if ((mode & SM_OSTREAM) && log_stream) {
209 *(log_stream) <<
",{H ";
210 for (
int j = 0; j < 12; ++j)
211 *(log_stream) <<
' ' << state.
hmd.
pose[j];
212 *(log_stream) <<
'}';
217 if ((mode & SM_OSTREAM) && log_stream) {
218 *(log_stream) <<
'\n';
222template <
typename T,
unsigned SIZE>
223void parse_array(std::istringstream& line,T* storage) {
224 for (
int i = 0; i < SIZE; ++i) {
229int parse_filter_string(std::istringstream& line) {
231 while (!line.eof()) {
234 filters |= filter_from_string(filter);
242 std::string cinfo_type;
244 while (!line.eof()) {
246 if (cinfo_type ==
"P") {
247 filter |= vr::vr_log::F_POSE;
248 parse_array<float, 12>(line, state.
pose);
250 else if (cinfo_type ==
"A") {
251 filter |= vr::vr_log::F_AXES;
252 parse_array<float, vr::max_nr_controller_axes>(line, state.
axes);
254 else if (cinfo_type ==
"B") {
255 filter |= vr::vr_log::F_BUTTON;
258 else if (cinfo_type ==
"V") {
259 filter |= vr::vr_log::F_VIBRATION;
260 parse_array<float, 2>(line, state.
vibration);
267template <
typename iterator>
268unsigned parse_vr_kit_state(iterator it, iterator last,
vr::vr_kit_state& state,
double& time) {
273 if (it->type == token::COMPOUND) {
275 std::istringstream line(it->text);
281 filter |= parse_controller_state(line, state.
controller[cid]);
283 throw std::string(
"invalid controller id");
285 else if (type ==
"H") {
286 filter |= vr::vr_log::F_HMD;
287 parse_array<float, 12>(line, state.
hmd.
pose);
291 throw std::string(
"unexpected token");
302 setting_locked =
true;
304 if (log_storage_mode & SM_OSTREAM) {
305 *(log_stream) <<
"filters,{";
308 while (fil < F_ALL) {
311 *(log_stream) <<
" ";
315 *(log_stream) << filter_to_string(
static_cast<vr::vr_log::Filter
>(fil));
319 *(log_stream) <<
"}\n";
328 log_storage_mode = SM_IN_MEMORY;
332 std::vector<token> tokens;
333 bool found_filters =
false;
338 std::getline(is, line);
340 tokenize(line, tokens);
343 if (tokens[0].type == token::VALUE) {
344 if (!found_filters) {
347 double time = std::stod(tokens[0].text);
349 parse_vr_kit_state(tokens.cbegin() + 1, tokens.cend(), state, time);
350 log_vr_state(state, time);
352 else if (tokens[0].type == token::NAME) {
353 if (tokens.size() >= 2 && tokens[0].text ==
"filters" && tokens[1].type == token::COMPOUND) {
354 found_filters =
true;
355 auto text = std::istringstream(tokens[1].text);
356 filters = parse_filter_string(text);
360 throw std::string(
"parsing error expected time got " + tokens[0].text);
365 catch (std::string err) {
void enable_in_memory_log()
enable in memory log
void lock_settings()
prevent changes to settings and enables log_vr_state methods
void disable_log()
disable logging
void enable_ostream_log(const std::shared_ptr< std::ostream > &stream)
enable writing to ostream.
void log_vr_state(const vr::vr_kit_state &state, const int mode, const int filter, const double time, std::ostream *log_stream)
record state
bool load_state(std::istringstream &is)
read log from stream
cgv::math::fvec< float, 2 > vec2
declare type of 2d single precision floating point vectors
cgv::math::fmat< float, 3, 4 > mat3x4
declare type of 3x4 matrices which are often used to store a pose
const unsigned max_nr_controller_axes
maximum number of axes per controller
@ VRS_TRACKED
trackable is connected and tracked
const unsigned max_nr_controllers
maximum number of attachable controller and tracker devices
Extends the trackable state by information on the buttons, input axes and vibration strengths.
float axes[max_nr_controller_axes]
up to vr::max_nr_controller_axes axis values in the range [-1,1] or [0,1] (VIVE: 0|1....
float vibration[2]
strength of the vibration motors
unsigned button_flags
combination of flags in VRButtonStateFlags combined with the OR operation
structure that stores all information describing the state of a VR kit
vr_controller_state controller[max_nr_controllers]
status, pose, button, axes, and vibration information of up to vr::max_nr_controllers controller and ...
vr_trackable_state hmd
status and pose of hmd
VRStatus status
whether trackable is currently tracked, only in case of true, the pose member contains useful informa...
float pose[12]
pose as 3x4 matrix in column major format, where each column is a vector in world coordinates