16#include <simgear/compiler.h>
17#include <simgear/scene/util/OsgMath.hxx>
18#include <simgear/props/props_io.hxx>
19#include <simgear/screen/video-encoder.hxx>
20#include <simgear/structure/commands.hxx>
45 SG_LOG(SG_VIEW, SG_WARN,
"duplicate init of view manager");
54 SGPropertyNode* chase_distance_node =
fgGetNode(
"/sim/chase-distance-m");
55 if (chase_distance_node) {
56 double chase_distance = chase_distance_node->getDoubleValue();
57 if (chase_distance > 0) {
58 chase_distance = -chase_distance;
59 SG_LOG(SG_VIEW, SG_ALERT,
"sim/chase-distance-m is positive; correcting to " << chase_distance);
60 chase_distance_node->setDoubleValue(chase_distance);
64 config_list =
fgGetNode(
"/sim",
true)->getChildren(
"view");
65 _current =
fgGetInt(
"/sim/current-view/view-number");
66 if (_current != 0 && (_current < 0 || _current >= (
int) views.size())) {
67 SG_LOG(SG_VIEW, SG_ALERT,
68 "Invalid /sim/current-view/view-number=" << _current
69 <<
". views.size()=" << views.size()
75 for (
unsigned int i = 0;
i < config_list.size();
i++) {
76 SGPropertyNode* n = config_list[
i];
77 SGPropertyNode* config = n->getChild(
"config", 0,
true);
83 SG_LOG(SG_VIEW, SG_DEV_WARN,
"Failed to create view from:" << config->getPath());
90 SG_LOG(SG_VIEW, SG_DEV_WARN,
"FGViewMgr::init: current view " << _current <<
" failed to create");
116 viewer_list::iterator it;
117 for (it = views.begin(); it != views.end(); ++it) {
118 (*it)->resetOffsetsAndFOV();
126 _tiedProperties.setRoot(
fgGetNode(
"/sim/current-view",
true));
129 _tiedProperties.Tie(
"view-number",
this,
131 &FGViewMgr::setCurrentViewIndex,
false);
132 _viewNumberProp = _tiedProperties.getRoot()->getNode(
"view-number");
133 _viewNumberProp->setAttribute(SGPropertyNode::ARCHIVE,
false);
134 _viewNumberProp->setAttribute(SGPropertyNode::PRESERVE,
true);
135 _viewNumberProp->setAttribute(SGPropertyNode::LISTENER_SAFE,
true);
147 _tiedProperties.Untie();
148 _viewNumberProp.clear();
156 SGPropertyNode_ptr args(
new SGPropertyNode);
157 args->setStringValue(
"label", message);
158 args->setIntValue(
"delay", (delay) ? delay : 15);
159 SG_LOG(SG_GENERAL, SG_ALERT, message);
160 globals->get_commands()->execute(
"show-message", args);
168 bool encoding = (path !=
"");
169 fgSetBool(
"/sim/video/is-encoding", encoding);
174 globals->get_props()->setIntValue(
"/sim/video/error", 1);
193 cameraGroup->setCameraParameters(currentView->
get_v_fov(),
194 cameraGroup->getMasterAspectRatio());
205 for (
auto& camera_info : camera_group->
getCameras())
208 osg::GraphicsContext* gc = camera_info->compositor->getGraphicsContext();
211 _video_encoder->encode(dt, gc);
213 catch (std::exception& e)
216 _video_encoder.reset();
222 std::string callsign =
globals->get_props()->getStringValue(
"/sim/log-multiplayer-callsign");
225 auto multiplayers =
globals->get_props()->getNode(
"/ai/models")->getChildren(
"multiplayer");
226 for (
auto mutiplayer: multiplayers)
228 std::string callsign2 = mutiplayer->getStringValue(
"callsign");
229 if (callsign2 == callsign)
231 static SGVec3d pos_prev;
233 SGGeod pos_geod = SGGeod::fromDegFt(
234 mutiplayer->getDoubleValue(
"position/longitude-deg"),
235 mutiplayer->getDoubleValue(
"position/latitude-deg"),
236 mutiplayer->getDoubleValue(
"position/altitude-ft")
238 SGVec3d pos = SGVec3d::fromGeod(pos_geod);
239 double distance = length(pos - pos_prev);
240 double speed = distance / dt;
242 SGPropertyNode* item =
fgGetNode(
"/sim/log-multiplayer",
true )->addChild(
"mp");
243 item->setDoubleValue(
"distance", distance);
244 item->setDoubleValue(
"speed", speed);
245 item->setDoubleValue(
"dt", dt);
246 item->setDoubleValue(
"t", t);
247 item->setDoubleValue(
"ubody", mutiplayer->getDoubleValue(
"velocities/uBody-fps"));
248 item->setDoubleValue(
"vbody", mutiplayer->getDoubleValue(
"velocities/vBody-fps"));
249 item->setDoubleValue(
"wbody", mutiplayer->getDoubleValue(
"velocities/wBody-fps"));
268 if (_current < 0 || _current >= (
int) views.size()) {
269 SG_LOG(SG_VIEW, SG_ALERT,
"Invalid _current=" << _current
270 <<
". views.size()=" << views.size()
271 <<
". Will use zero."
275 return views[_current];
288 const auto lastView =
static_cast<int>(views.size()) - 1;
289 const int c = std::clamp(
i, 0, lastView);
296 const auto lastView =
static_cast<int>(views.size()) - 1;
297 const int c = std::clamp(
i, 0, lastView);
304 const auto numViews =
static_cast<int>(views.size());
305 setCurrentViewIndex((_current + 1) % numViews);
306 _viewNumberProp->fireValueChanged();
313 const auto numViews =
static_cast<int>(views.size());
317 setCurrentViewIndex((_current - 1 + numViews) % numViews);
318 _viewNumberProp->fireValueChanged();
329 SGPropertyNode_ptr config2 =
new SGPropertyNode;
330 copyProperties(config, config2);
331 config2->setStringValue(
"type", type);
355#include <simgear/scene/util/SGReaderWriterOptions.hxx>
365 const std::string& name_in,
366 const std::string& codec_in,
372 SG_LOG(SG_GENERAL, SG_ALERT,
"FGViewMgr::video_start():"
373 <<
" name_in=" << name_in
374 <<
" codec_in=" << codec_in
375 <<
" quality=" << quality
376 <<
" speed=" << speed
377 <<
" bitrate=" << bitrate
379 globals->get_props()->setIntValue(
"/sim/video/error", 0);
382 std::string name_link;
388 time_t calendar_time = time(NULL);
389 struct tm* local_tm = localtime(&calendar_time);
390 char time_string[256];
391 strftime(time_string,
sizeof(time_string),
"-%Y%m%d-%H%M%S", local_tm);
393 std::string suffix =
"." +
fgGetString(
"/sim/video/container",
"mpeg");
396 name_link =
name + suffix;
397 name += time_string + suffix;
406 std::string codec = codec_in;
408 std::string directory =
fgGetString(
"/sim/video/directory");
409 SGPath path = SGPath(directory);
413 videoEncodingError(
"Video encoding failure, output file already exists: " + path.str());
419 path_link = SGPath(directory);
420 path_link.append(name_link);
422 bool ok = path_link.makeLink(path.file());
425 SG_LOG(SG_SYSTEMS, SG_ALERT,
"Failed to create link "
426 << path_link.c_str() <<
" => " << path.file()
430 if (codec ==
"") codec =
fgGetString(
"/sim/video/codec");
431 if (quality == -1) quality =
fgGetDouble(
"/sim/video/quality");
432 if (speed == -1) speed =
fgGetDouble(
"/sim/video/speed");
433 if (bitrate == 0) bitrate =
fgGetInt(
"/sim/video/bitrate");
436 if (quality != -1 && (quality < 0 || quality > 1))
438 warning +=
"Ignoring quality=" + std::to_string(quality) +
" because should be -1 or in range 0-1.\n";
441 if (speed != -1 && (speed < 0 || speed > 1))
443 warning +=
"Ignoring speed=" + std::to_string(speed) +
" because should be -1 or in range 0-1.\n";
448 warning +=
"Ignoring bitrate=" + std::to_string(bitrate) +
" because should be >= 0.\n";
456 SG_LOG(SG_SYSTEMS, SG_ALERT,
"Video encoding starting."
457 <<
" codec=" << codec
458 <<
" quality=" << quality
459 <<
" speed=" << speed
460 <<
" bitrate=" << bitrate
462 <<
" path_link=" << path_link
464 bool log_sws_scale_stats =
globals->get_props()->getNode(
"/sim/video/log_sws_scale_stats",
true )->getBoolValue();
467 _video_encoder.reset(
468 new simgear::VideoEncoder(path.str(), codec, quality, speed, bitrate, log_sws_scale_stats)
471 catch (std::exception& e)
485 _video_encoder.reset();
500void FGViewMgr::setCurrentViewIndex(
int newview)
502 if (newview == _current) {
507 for (
int i = 0;
i < (int)config_list.size();
i++) {
508 int index = -config_list[
i]->getIndex();
509 if (index == newview)
513 SG_LOG(SG_VIEW, SG_ALERT,
"Failed to find -ve newview=" << newview);
517 if (newview < 0 || newview >= (
int) views.size()) {
518 SG_LOG(SG_VIEW, SG_ALERT,
"Ignoring invalid newview=" << newview
519 <<
". views.size()=" << views.size()
538 SGSubsystemMgr::DISPLAY);
void view_new(const SGPropertyNode *config)
void update(double dt) override
flightgear::View * next_view()
flightgear::View * prev_view()
int getCurrentViewIndex() const
void clone_current_view(const SGPropertyNode *config)
void clone_last_pair_double(const SGPropertyNode *config)
flightgear::View * get_view(int i)
bool video_start(const std::string &name="", const std::string &codec="", double quality=-1, double speed=-1, int bitrate=0)
flightgear::View * get_current_view()
void clone_last_pair(const SGPropertyNode *config)
void add_view(flightgear::View *v)
static CameraGroup * getDefault()
Get the default CameraGroup.
const CameraList & getCameras()
const SGQuatd & getViewOrientation()
void update(double dt) override
const SGVec3d & getViewPosition()
static View * createFromProperties(SGPropertyNode_ptr props, int view_index=-1)
int fgGetInt(const char *name, int defaultValue)
Get an int value for a property.
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
bool fgSetBool(char const *name, bool val)
Set a bool value for a property.
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
bool fgSetString(char const *name, char const *str)
Set a string value for a property.
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
@ GUI
Camera draws the GUI.
std::shared_ptr< SviewView > SviewCreate(SGPropertyNode *config)
void SviewUpdate(double dt)
static void videoEncodingError(const std::string &message)
SGSubsystemMgr::Registrant< FGViewMgr > registrantFGViewMgr(SGSubsystemMgr::DISPLAY)
static void vidoEncodingUpdateStatus(const std::string &path)
static void videoEncodingPopup(const std::string &message, int delay)
void s_clone_internal(const SGPropertyNode *config, const std::string &type)