#pragma once #include #include #include #include #include "../Defines.h" #include "../Serializer.h" // Path stores a recording detailing any type. // Interpolator should be a functor with a method specification: // T operator()(const T& a, const T& b, double time) // Where a and b should be interpolated between, and time is a value between 0 and 1, indicating the interpolation value template class Path { private: std::vector mFrames; std::vector mFrameTimes; public: Path() : mFrames(std::vector()), mFrameTimes(std::vector()) {} ~Path() {} void SetStateAtTime(const double& time, const T& state) { // Find the position of this new state: auto pos = std::lower_bound(mFrameTimes.begin(), mFrameTimes.end(), time); size_t idx = pos - mFrameTimes.begin(); mFrames.insert(mFrames.begin() + idx, state); mFrameTimes.insert(pos, time); } T GetStateAtTime(const double& time) const { // Find the frames between which the requested time takes place size_t afterIdx = std::upper_bound(mFrameTimes.begin(), mFrameTimes.end(), time) - mFrameTimes.begin(); size_t beforeIdx = afterIdx - 1; if (afterIdx == mFrameTimes.size()) // End of the recording, return the last camera state return mFrames.back(); if (afterIdx == 0) return mFrames.front(); // Now linearly interpolate the frames: double t = ((time - mFrameTimes[beforeIdx]) / (mFrameTimes[afterIdx] - mFrameTimes[beforeIdx])); const T& before = mFrames[beforeIdx]; const T& after = mFrames[afterIdx]; return Interpolator()(before, after, t); } double GetLength() const { if (Empty()) return 0; return mFrameTimes.back() - mFrameTimes.front(); } size_t Size() const { return mFrames.size(); } /// Removes the camera path node at index i void RemoveAt(size_t i) { mFrames.erase(mFrames.begin() + i); mFrameTimes.erase(mFrames.begin() + i); } /// Removes the last stored camera path node void RemoveLast() { mFrames.pop_back(); mFrameTimes.pop_back(); } // Makes sure the frametimes go from 0 to the length of the recording void Normalize() { if (Empty()) return; double offset = mFrameTimes[0]; for (size_t i = 0; i < mFrameTimes.size(); i++) mFrameTimes[i] = mFrameTimes[i] - offset; } bool Empty() const { return mFrames.empty(); } void Clear() { mFrames.clear(); mFrameTimes.clear(); } void WriteToFile(const std::string& filename) { std::ofstream file(filename, std::ios::binary); unsigned32 recordingLength = (unsigned32)mFrames.size(); Serializer::Serialize(recordingLength, file); if (recordingLength > 0) { Serializer::Serialize(&mFrames[0], mFrames.size(), file); Serializer::Serialize(&mFrameTimes[0], mFrames.size(), file); } file.close(); } bool ReadFromFile(const std::string& filename) { std::ifstream file(filename, std::ios::binary); if (file.good()) { unsigned32 recordingLength = 0; Serializer::Deserialize(recordingLength, file); mFrames.resize(recordingLength); mFrameTimes.resize(recordingLength); if (recordingLength > 0) { Serializer::Deserialize(&mFrames[0], mFrames.size(), file); Serializer::Deserialize(&mFrameTimes[0], mFrames.size(), file); } file.close(); return true; } return false; } };