Program Listing for File GraphicalSceneMovie.cc#
↰ Return to documentation for file (doxygen_docs/GeneralKModels/GraphicalSceneMovie.cc)
#include "Karana/GeneralKModels/GraphicalSceneMovie.h"
#include "Karana/KCore/Allocator.h"
#include <filesystem>
/**
* @file
* @brief GraphicalSceneMovie implementation.
*/
namespace Karana::Models {
namespace ks = Karana::Scene;
namespace km = Karana::Math;
GraphicalSceneMovie::GraphicalSceneMovie(std::string_view name,
const kc::ks_ptr<kd::ModelManager> &mm,
const kc::ks_ptr<ks::ProxyScene> &scene)
: KModel<GraphicalSceneMovie, GraphicalSceneMovieParams>(name, mm)
, _scene(scene) {
params = std::allocate_shared<GraphicalSceneMovieParams>(
kc::Allocator<GraphicalSceneMovieParams>{}, std::format("{}_params", name));
};
kc::ks_ptr<GraphicalSceneMovie>
GraphicalSceneMovie::create(std::string_view name,
const kc::ks_ptr<kd::ModelManager> &mm,
const kc::ks_ptr<ks::ProxyScene> &scene) {
kc::ks_ptr<GraphicalSceneMovie> gsm = std::allocate_shared<GraphicalSceneMovie>(
kc::Allocator<GraphicalSceneMovie>{}, name, mm, scene);
mm->registerModel(gsm);
return gsm;
}
void GraphicalSceneMovie::postModelStep(const km::Ktime &, const km::Vec &) {
_scene->update(*_scene->graphics());
_scene->graphics()->renderToFile(
std::format("{}/{}_{:06d}.png", params->dir, params->filename_prefix, _frame_no));
_frame_no++;
}
GraphicalSceneMovieParams::GraphicalSceneMovieParams(std::string_view name)
: KModelParams(name) {}
bool GraphicalSceneMovieParams::isReady() const {
bool flag = true;
if (dir == "") {
kc::warn("Parameter dir is not ready.");
flag = false;
}
if (filename_prefix == "") {
kc::warn("Parameter filename_prefix is not ready.");
flag = false;
}
return flag;
}
std::string GraphicalSceneMovie::getFfmpegCommand() const {
return std::format(
"ffmpeg -framerate {} -i {}/{}_%06d.png -c:v libx264 -pix_fmt yuv420p output.mp4",
1.0 / km::ktimeToSeconds(_period),
params->dir,
params->filename_prefix);
}
void GraphicalSceneMovie::_registerModel() {
// Call the parent. This will do the normal registration.
KModel<GraphicalSceneMovie, GraphicalSceneMovieParams>::_registerModel();
kc::ks_ptr<Base> dark = shared_from_this();
auto t = kc::static_pointer_cast<GraphicalSceneMovie>(dark);
// Also register a first step to run now if we should render the first frame.
kc::ks_ptr<kd::StatePropagator> sp =
kc::dynamic_pointer_cast<kd::StatePropagator>(model_manager);
if (sp and params->render_first_frame) {
auto te = kd::TimedEvent::create(
std::format("{}_first_step", name()),
model_manager->getTime(),
[t, sp](const km::Ktime &) {
if (!std::filesystem::exists(t->params->dir)) {
if (not std::filesystem::create_directories(t->params->dir)) {
throw std::invalid_argument(
std::format("Failed to create directory {}", t->params->dir));
}
}
return t->postModelStep(sp->getTime(), sp->getIntegrator()->getX());
},
true);
sp->registerTimedEvent(te);
}
};
void GraphicalSceneMovie::_unregisterModel() {
// Call the parent. This will do the normal unregistration.
KModel<GraphicalSceneMovie, GraphicalSceneMovieParams>::_unregisterModel();
// Try and unregister this event regardless of the parameter setting.
// It's possible the parameter has been changed since the last registration.
kc::ks_ptr<kd::StatePropagator> sp =
kc::dynamic_pointer_cast<kd::StatePropagator>(model_manager);
if (sp) {
sp->unregisterTimedEvent(std::format("{}_first_step", name()), true, true);
}
}
// Destructor included for MacOS builds. Must have a key-function out-of-line to avoid dulpicate
// symbols.
GraphicalSceneMovie::~GraphicalSceneMovie(){};
} // namespace Karana::Models