Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

History and interpolation #642

Closed
wants to merge 14 commits into from
1 change: 1 addition & 0 deletions libopenage/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pxdgen(
add_subdirectory("audio")
add_subdirectory("console")
add_subdirectory("coord")
add_subdirectory("curve")
add_subdirectory("cvar")
add_subdirectory("datastructure")
add_subdirectory("gui")
Expand Down
2 changes: 2 additions & 0 deletions libopenage/coord/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ add_sources(libopenage
chunk.cpp
phys2.cpp
phys3.cpp
phys3_serialization.cpp
term.cpp
tests.cpp
tile.cpp
tile_serialization.cpp
tile3.cpp
vec2.cpp
vec2f.cpp
Expand Down
30 changes: 30 additions & 0 deletions libopenage/coord/phys3_serialization.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2016-2016 the openage authors. See copying.md for legal info.

#include "phys3_serialization.h"

namespace openage {
namespace coord {

std::ostream& operator<<(std::ostream &o, const phys3 &v) {
o << '(' << v.ne << ',' << v.se << ',' << v.up << ')';
return o;
}

std::ostream& operator<<(std::ostream &o, const phys3_delta &v) {
o << '(' << v.ne << ',' << v.se << ',' << v.up << ')';
return o;
}

std::istream& operator>>(std::istream &i, phys3 &v) {
char c;
i >> c >> v.ne >> c >> v.se >> c >> v.up >> c;
return i;
}

std::istream& operator>>(std::istream &i, phys3_delta &v) {
char c;
i >> c >> v.ne >> c >> v.se >> c >> v.up >> c;
return i;
}

}} // openage::coord
18 changes: 18 additions & 0 deletions libopenage/coord/phys3_serialization.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2016-2016 the openage authors. See copying.md for legal info.

#pragma once

#include <iostream>

#include "phys3.h"

namespace openage {
namespace coord {

std::ostream& operator<<(std::ostream &o, const phys3 &v);
std::ostream& operator<<(std::ostream &o, const phys3_delta &v);

std::istream& operator>>(std::istream &i, phys3 &v);
std::istream& operator>>(std::istream &i, phys3_delta &v);

}} // openage::coord
30 changes: 30 additions & 0 deletions libopenage/coord/tile_serialization.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2016-2016 the openage authors. See copying.md for legal info.

#include "tile_serialization.h"

namespace openage {
namespace coord {

std::ostream& operator<<(std::ostream &o, const tile &v) {
o << '(' << v.ne << ',' << v.se << ')';
return o;
}

std::ostream& operator<<(std::ostream &o, const tile_delta &v) {
o << '(' << v.ne << ',' << v.se << ')';
return o;
}

std::istream& operator>>(std::istream &i, tile &v) {
char c;
i >> c >> v.ne >> c >> v.se >> c;
return i;
}

std::istream& operator>>(std::istream &i, tile_delta &v) {
char c;
i >> c >> v.ne >> c >> v.se >> c;
return i;
}

}} // openage::coord
18 changes: 18 additions & 0 deletions libopenage/coord/tile_serialization.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2016-2016 the openage authors. See copying.md for legal info.

#pragma once

#include <iostream>

#include "tile.h"

namespace openage {
namespace coord {

std::ostream& operator<<(std::ostream &o, const tile &v);
std::ostream& operator<<(std::ostream &o, const tile_delta &v);

std::istream& operator>>(std::istream &i, tile &v);
std::istream& operator>>(std::istream &i, tile_delta &v);

}} // openage::coord
6 changes: 6 additions & 0 deletions libopenage/curve/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_sources(libopenage
curve_record_replay.cpp
entities_conductor.cpp
entities_conductor_interpolator.cpp
occurence_curve.cpp
)
75 changes: 75 additions & 0 deletions libopenage/curve/curve_record_replay.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2016-2016 the openage authors. See copying.md for legal info.

#include "curve_record_replay.h"

#include <iostream>
#include <fstream>

#include "../unit/attribute_setter.h"

namespace openage {
namespace curve {

CurveRecordReplay::CurveRecordReplay(qtsdl::GuiItemLink *gui_link, bool recorder)
:
stream{std::make_unique<std::iostream>(recorder ? std::cerr.rdbuf() : std::cin.rdbuf())},
current_frame{},
recorder{recorder},
gui_link{gui_link} {
}

CurveRecordReplay::~CurveRecordReplay() {

}

std::string CurveRecordReplay::get_file_name() const {
return this->file_name;
}

void CurveRecordReplay::set_file_name(const std::string &file_name) {
if (this->file_name != file_name) {
this->stream = std::make_unique<std::fstream>(file_name, this->recorder ? std::ios_base::out : std::ios_base::in);
this->file_name = file_name;
}
}

CurveRecord::CurveRecord(qtsdl::GuiItemLink *gui_link)
:
CurveRecordReplay{gui_link, true} {
}

CurveRecord::~CurveRecord() {
}

void CurveRecord::perform(UnitContainer &placed_units) {
placed_units.update_all(*this);
++this->current_frame;
}

CurveReplay::CurveReplay(qtsdl::GuiItemLink *gui_link)
:
CurveRecordReplay{gui_link, false},
started{},
next_available_frame{} {
}

CurveReplay::~CurveReplay() {
}

void CurveReplay::perform(UnitContainer &placed_units) {
if (!this->started) {
*this->stream >> this->next_available_frame;
this->started = true;
}

while (this->next_available_frame <= this->current_frame) {
int id;
*this->stream >> id;
read_attr(*this->stream, id, placed_units);
*this->stream >> this->next_available_frame;
}

++this->current_frame;
}

}} // namespace openage::curve
78 changes: 78 additions & 0 deletions libopenage/curve/curve_record_replay.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright 2016-2016 the openage authors. See copying.md for legal info.

#pragma once

#include <cstddef>
#include <string>
#include <iostream>
#include <memory>

namespace qtsdl {
class GuiItemLink;
} // qtsdl

namespace openage {

class UnitContainer;

namespace curve {

class CurveRecord;

class CurveRecordReplay {
public:
explicit CurveRecordReplay(qtsdl::GuiItemLink *gui_link, bool recorder);
virtual ~CurveRecordReplay();

std::string get_file_name() const;
void set_file_name(const std::string &file_name);

virtual void perform(UnitContainer &placed_units) = 0;

virtual CurveRecord* get_record() {
return nullptr;
}

protected:
std::string file_name;
std::unique_ptr<std::iostream> stream;
size_t current_frame;
const bool recorder;

public:
qtsdl::GuiItemLink *gui_link;
};

class CurveRecord : public CurveRecordReplay {
public:
explicit CurveRecord(qtsdl::GuiItemLink *gui_link);
virtual ~CurveRecord();

virtual void perform(UnitContainer &placed_units) override;

virtual CurveRecord* get_record() override {
return this;
}

template<typename T>
void write_out(id_t id, T value, const char *name) {
*this->stream << this->current_frame << " " << id << " " << name << " " << value << "\n";
this->stream->flush();
}

private:
};

class CurveReplay : public CurveRecordReplay {
public:
explicit CurveReplay(qtsdl::GuiItemLink *gui_link);
virtual ~CurveReplay();

virtual void perform(UnitContainer &placed_units) override;

private:
bool started;
size_t next_available_frame;
};

}} // namespace openage::curve
68 changes: 68 additions & 0 deletions libopenage/curve/entities_conductor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2015-2016 the openage authors. See copying.md for legal info.

#include "entities_conductor.h"

#include <algorithm>

#include "../error/error.h"

namespace openage {
namespace curve {

EntitiesConductor::EntitiesConductor(std::function<void(int, int, coord::phys2)> emerge, std::function<void(int)> vanish)
:
emerge{emerge},
vanish{vanish} {
}

void EntitiesConductor::jump(GameClock::moment from, GameClock::moment to) {
// TODO: call appear/vanish for every SPAWN/DIE (depending on the time direction)
// TODO: for each property find closest curve to 'to' that changes it, then apply the last value or a value that is sampled from curve at the 'to' moment
}

Prediction EntitiesConductor::predict_migration(GameClock::moment current_time, GameClock::moment other_time) const {
const auto prior = std::min(current_time, other_time);
const auto forth = std::max(current_time, other_time);

const auto cmp_start_cp = [](const OccurenceCurve &c, GameClock::moment p) { return c.origin.time < p; };
const auto cmp_start_pc = [](GameClock::moment p, const OccurenceCurve &c) { return p < c.origin.time; };

const auto cmp_end_ip = [this](size_t index, GameClock::moment p) { return end_time(this->history[index]) < p; };
const auto cmp_end_pi = [this](GameClock::moment p, size_t index) { return p < end_time(this->history[index]); };

ENSURE(this->history.size() == this->history_sorted_by_ends.size(), "index array out of sync");

const auto occurences_that_start_inside_begin_it = std::lower_bound(std::begin(this->history), std::end(this->history), prior, cmp_start_cp);
const auto occurences_that_start_inside_end_it = std::upper_bound(std::begin(this->history), std::end(this->history), forth, cmp_start_pc);

const auto occurencesthat_finish_inside_begin_it = std::lower_bound(std::begin(this->history_sorted_by_ends), std::end(this->history_sorted_by_ends), prior, cmp_end_ip);
const auto occurencesThat_finish_inside_end_it = std::upper_bound(std::begin(this->history_sorted_by_ends), std::end(this->history_sorted_by_ends), forth, cmp_end_pi);

decltype(this->history_sorted_by_ends) occurences_that_only_finish_inside;
const size_t completely_inside_begin_index = std::distance(std::begin(this->history), occurences_that_start_inside_begin_it);

std::copy_if(occurencesthat_finish_inside_begin_it, occurencesThat_finish_inside_end_it, std::back_inserter(occurences_that_only_finish_inside), [completely_inside_begin_index](size_t index) { return index < completely_inside_begin_index; });
std::sort(std::begin(occurences_that_only_finish_inside), std::end(occurences_that_only_finish_inside));

const auto occurences_that_start_inside_count = std::distance(occurences_that_start_inside_begin_it, occurences_that_start_inside_end_it);
std::vector<OccurenceCurve> trimmed(occurences_that_start_inside_count + occurences_that_only_finish_inside.size());

using namespace std::placeholders;
std::transform(occurences_that_start_inside_begin_it, occurences_that_start_inside_end_it, std::begin(trimmed), std::bind(&trim, _1, prior, forth));
std::transform(std::begin(occurences_that_only_finish_inside), std::end(occurences_that_only_finish_inside), std::begin(trimmed) + occurences_that_start_inside_count, [this, prior, forth](size_t index) {
return trim(this->history[index], prior, forth);
});

return trimmed;
}

void EntitiesConductor::converge(GameClock::moment current_time) {
// TODO: perform silently all rollbacks that unapplied_history causes (simplest: jump() back, fix history, jump() forward)
return;
}

void EntitiesConductor::append_history(const Prediction &unapplied_history) {
this->unapplied_history.insert(std::end(this->unapplied_history), std::begin(unapplied_history), std::end(unapplied_history));
}

}} // namespace openage::curve
Loading