48#include <simgear/debug/logstream.hxx>
49#include <simgear/math/SGMath.hxx>
50#include <simgear/props/props.hxx>
51#include <simgear/props/props_io.hxx>
52#include <simgear/scene/util/OsgMath.hxx>
53#include <simgear/scene/viewer/Compositor.hxx>
55#include <osg/CameraView>
56#include <osg/GraphicsContext>
57#include <osgViewer/CompositeViewer>
59static const double pi = 3.141592653589793238463;
61static std::ostream&
operator << (std::ostream& out,
const osg::Vec3f& vec)
63 return out <<
"Vec3f{"
70static std::ostream&
operator << (std::ostream& out,
const osg::Quat& quat)
73 <<
" x=" << quat._v[0]
74 <<
" y=" << quat._v[1]
75 <<
" z= " << quat._v[2]
76 <<
" w=" << quat._v[3]
80static std::ostream&
operator << (std::ostream& out,
const osg::Matrixd& matrix)
82 osg::Vec3f translation;
86 matrix.decompose(translation, rotation,
scale, so);
87 return out <<
"Matrixd {"
88 <<
" translation=" << translation
89 <<
" rotation=" << rotation
129 out <<
"SviewPosDir {"
131 <<
" heading=" << posdir.
heading
132 <<
" pitch=" << posdir.
pitch
133 <<
" roll=" << posdir.
roll
134 <<
" target=" << posdir.
target
152 Damping(
double damping_time,
double wrap_max=0,
double current=0)
154 m_damping_time(damping_time),
162 const double e = 2.718281828459045;
163 double delta = target - m_current;
165 if (delta < -m_wrap_max/2) delta += m_wrap_max;
166 if (delta >= m_wrap_max/2) delta -= m_wrap_max;
168 m_current = target - delta * pow(e, -dt/m_damping_time);
170 if (m_current < 0) m_current += m_wrap_max;
171 if (m_current >= m_wrap_max) m_current -= m_wrap_max;
184 double m_damping_time;
197 virtual void mouse_drag(
double delta_x_deg,
double delta_y_deg)
201 virtual void stream(std::ostream& out)
const
203 out <<
" <SviewStep>";
212 out <<
' ' <<
typeid(step).
name();
242 SGPropertyNode* c =
globals->get_props()->getNode(
"ai/models/callsigns")->getNode(
m_callsign);
244 int i = c->getIntValue();
245 m_root =
globals->get_props()->getNode(
"ai/models/multiplayer",
i);
273 if (m_callsign.update()) {
274 m_longitude = m_callsign.m_root->getNode(
"position/longitude-deg");
275 m_latitude = m_callsign.m_root->getNode(
"position/latitude-deg");
276 m_altitude = m_callsign.m_root->getNode(
"position/altitude-ft");
277 m_heading = m_callsign.m_root->getNode(
"orientation/true-heading-deg");
278 m_pitch = m_callsign.m_root->getNode(
"orientation/pitch-deg");
279 m_roll = m_callsign.m_root->getNode(
"orientation/roll-deg");
281 posdir.
position = SGGeod::fromDegFt(
282 m_longitude->getDoubleValue(),
283 m_latitude->getDoubleValue(),
284 m_altitude->getDoubleValue()
287 posdir.
heading = m_heading->getDoubleValue();
288 posdir.
pitch = m_pitch->getDoubleValue();
289 posdir.
roll = m_roll->getDoubleValue();
292 virtual void stream(std::ostream& out)
const
294 out <<
" <SviewStepAircraft:" + m_callsign.m_callsign +
">";
301 SGPropertyNode_ptr m_longitude;
302 SGPropertyNode_ptr m_latitude;
303 SGPropertyNode_ptr m_altitude;
305 SGPropertyNode_ptr m_heading;
306 SGPropertyNode_ptr m_pitch;
307 SGPropertyNode_ptr m_roll;
318 m_offset(-right, -up, -forward)
320 SG_LOG(SG_VIEW, SG_INFO,
"forward=" << forward <<
" up=" << up <<
" right=" << right);
329 SGQuatd hlOr = SGQuatd::fromLonLat(posdir.
position);
333 SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(posdir.
heading, posdir.
pitch, posdir.
roll);
337 SGQuatd ec2body = hlOr * hlToBody;
340 SGVec3d position = SGVec3d::fromGeod(posdir.
position);
345 SGQuatd q(-0.5, -0.5, 0.5, 0.5);
347 position += (ec2body * q).backTransform(m_offset);
348 posdir.
position = SGGeod::fromCart(position);
351 virtual void stream(std::ostream& out)
const
353 out <<
" <SviewStepMove>" << m_offset;
371 double damping_heading = 0,
372 double damping_pitch = 0,
373 double damping_roll = 0
379 m_damping_heading(damping_heading, 360 ),
380 m_damping_pitch(damping_pitch, 360 ),
381 m_damping_roll(damping_roll, 360 )
383 SG_LOG(SG_VIEW, SG_INFO,
"heading=" << heading <<
" pitch=" << pitch <<
" roll=" << roll);
388 posdir.
heading = m_damping_heading.update(dt, posdir.
heading + m_heading);
389 posdir.
pitch = m_damping_pitch.update(dt, posdir.
pitch + m_pitch);
390 posdir.
roll = m_damping_roll.update(dt, posdir.
roll + m_roll);
393 virtual void stream(std::ostream& out)
const
395 out <<
" <SviewStepRotate>"
426 void mouse_drag(
double delta_x_deg,
double delta_y_deg)
override
447 SG_LOG(SG_VIEW, SG_INFO,
"heading=" << heading <<
" pitch=" << pitch <<
" roll=" << roll);
453 posdir.
pitch *= m_pitch;
454 posdir.
roll *= m_roll;
457 virtual void stream(std::ostream& out)
const
459 out <<
" <SviewStepDirectionMultiply>"
484 virtual void stream(std::ostream& out)
const
486 out <<
" <SviewStepCopyToTarget>";
507 posdir.
position = SGGeod::fromDegFt(
515 SG_LOG(SG_VIEW, SG_BULK,
"moved posdir.postion to: " << posdir.
position);
518 virtual void stream(std::ostream& out)
const
520 out <<
" <SviewStepNearestTower:" +
m_callsign.m_callsign +
">";
551 SGQuatd eye_position_direction = SGQuatd::fromLonLat(posdir.
position);
555 SGQuatd eye_local_direction = SGQuatd::fromYawPitchRollDeg(posdir.
heading, posdir.
pitch, posdir.
roll);
558 SGVec3d eye_position = SGVec3d::fromGeod(posdir.
position);
561 SGQuatd eye_direction = eye_position_direction * eye_local_direction;
567 SGVec3d target_position = SGVec3d::fromGeod(posdir.
target);
574 SGVec3d eye_to_target_direction = normalize(target_position - eye_position);
577 SGVec3d up = eye_direction.backTransform(SGVec3d(0, 0, -1));
583 posdir.
direction2 = SGQuatd::fromRotateTo(-eye_to_target_direction, 2, up, 1);
590 SGQuatd q(-0.5, -0.5, 0.5, 0.5);
598 virtual void stream(std::ostream& out)
const
600 out <<
" <SviewStepFinal>";
628 double _fov_user_deg = 30;
629 double _configFOV_deg = 30;
633 double ground_altitude = 0;
634 const simgear::BVHMaterial* material = NULL;
635 SGGeod target0 = posdir.
target;
636 SGGeod target_plus = posdir.
target;
637 target_plus.setElevationM(target_plus.getElevationM() + 1);
638 bool ok =
globals->get_scenery()->get_elevation_m(target_plus, ground_altitude, &material);
650 double h_distance = SGGeodesy::distanceM(posdir.
position, posdir.
target);
651 if (h_distance == 0) {
657 double relative_height_target = posdir.
target.getElevationM() - posdir.
position.getElevationM();
658 double relative_height_ground = ground_altitude - posdir.
position.getElevationM();
669 relative_height_ground -= 2;
674 double relative_height_target_plus = relative_height_target + aircraft_size_vertical;
675 double relative_height_ground_ = relative_height_ground;
677 if (relative_height_ground > relative_height_target) {
688 double delta = relative_height_target_plus - relative_height_ground;
689 delta *= (_fov_user_deg / _configFOV_deg);
690 relative_height_ground = relative_height_target_plus - delta;
693 double angle_v_target = atan(relative_height_target_plus / h_distance);
694 double angle_v_ground = atan(relative_height_ground / h_distance);
698 double angle_v_mid = (angle_v_target + angle_v_ground) / 2;
699 double posdir_target_old_elevation = posdir.
target.getElevationM();
700 posdir.
target.setElevationM(posdir.
position.getElevationM() + h_distance * tan(angle_v_mid));
705 double fov_v = fabs(angle_v_target - angle_v_ground);
710 double fov_h = 2 * atan(aircraft_size_horizontal / 2 / h_distance);
712 posdir.
fov_v = fov_v * 180 /
pi;
713 posdir.
fov_h = fov_h * 180 /
pi;
715 bool verbose =
false;
717 static time_t t0 = 0;
718 time_t t = time(NULL);
719 if (0 && t - t0 >= 3) {
724 if (verbose) SG_LOG(SG_VIEW, SG_ALERT,
""
725 <<
" target0=" << target0
726 <<
" fov_v=" << fov_v * 180/
pi
727 <<
" ground_altitude=" << ground_altitude
728 <<
" relative_height_target_plus=" << relative_height_target_plus
729 <<
" h_distance=" << h_distance
730 <<
" relative_height_ground=" << relative_height_ground
732 <<
" angle_v_mid=" << angle_v_mid * 180/
pi
733 <<
" posdir_target_old_elevation=" << posdir_target_old_elevation
734 <<
" posdir.target=" << posdir.
target
808 static time_t t0 = 0;
809 time_t t = time(NULL);
810 if (0 && t - t0 > 3) {
822 SG_LOG(SG_VIEW, SG_ALERT,
" posdir =" << posdir);
823 SG_LOG(SG_VIEW, SG_ALERT,
" posdir_local =" << posdir_local);
824 SG_LOG(SG_VIEW, SG_ALERT,
" posdir_remote=" << posdir_remote);
828 SGVec3d local_pos = SGVec3d::fromGeod(posdir_local.
target);
829 SGVec3d remote_pos = SGVec3d::fromGeod(posdir_remote.
target);
830 double lr = sqrt(distSqr(local_pos, remote_pos));
841 double er_root_term = lr*lr - le*le*sin(ler)*sin(ler);
842 if (er_root_term < 0) {
847 double er = le * cos(ler) + sqrt(er_root_term);
852 double cos_rle = (lr*lr + le*le - er*er) / (2*le*lr);
853 if (cos_rle > 1) cos_rle = 1;
854 if (cos_rle < -1) cos_rle = -1;
855 double rle = acos(cos_rle);
856 double rle_deg = rle * 180 /
pi;
861 double lr_vertical = posdir_remote.
target.getElevationM() - posdir_local.
target.getElevationM();
862 double lr_horizontal = SGGeodesy::distanceM(posdir_local.
target, posdir_remote.
target);
863 double hlr = atan2(lr_vertical, lr_horizontal);
864 posdir_local.
heading = SGGeodesy::courseDeg(
868 posdir_local.
pitch = (hlr + rle) * 180 /
pi;
869 posdir_local.
roll = 0;
871 move.evaluate(posdir_local, 0 );
876 double er_vertical = posdir_remote.
target.getElevationM()
877 - posdir_local.
position.getElevationM();
878 double her = asin(er_vertical / er);
879 double hel = (hlr + rle) -
pi;
880 posdir_local.
pitch = (her + hel) / 2 * 180 /
pi;
881 posdir = posdir_local;
888 SG_LOG(SG_VIEW, SG_ALERT,
""
891 <<
" er_root_term=" << er_root_term
893 <<
" cos_rle=" << cos_rle
894 <<
" rle_deg=" << rle_deg
895 <<
" lr_vertical=" << lr_vertical
896 <<
" lr_horizontal=" << lr_horizontal
898 <<
" posdir_local=" << posdir_local
899 <<
" posdir_remote=" << posdir_remote
920 return add_step(std::shared_ptr<SviewStep>(step));
925 if (debug) SG_LOG(SG_VIEW, SG_ALERT,
"evaluating m_name=" <<
m_name);
927 step->evaluate(posdir, dt);
928 if (debug) SG_LOG(SG_VIEW, SG_ALERT,
"posdir=" << posdir);
933 std::vector<std::shared_ptr<SviewStep>>
m_steps;
937 out << viewpos.
m_name <<
" (" << viewpos.
m_steps.size() <<
")";
938 for (
auto step: viewpos.
m_steps) {
961 snprintf(buffer,
sizeof(buffer),
"[%i] ",
s_id);
973 osgViewer::ViewerBase* viewer_base =
m_osg_view->getViewerBase();
974 auto composite_viewer =
dynamic_cast<osgViewer::CompositeViewer*
>(viewer_base);
975 assert(composite_viewer);
976 for (
unsigned i=0;
i<composite_viewer->getNumViews(); ++
i) {
977 osgViewer::View* view = composite_viewer->getView(
i);
978 SG_LOG(SG_VIEW, SG_DEBUG,
"composite_viewer view i=" <<
i <<
" view=" << view);
980 SG_LOG(SG_VIEW, SG_DEBUG,
"removing m_osg_view=" <<
m_osg_view);
981 composite_viewer->stopThreading();
983 composite_viewer->startThreading();
989 virtual void mouse_drag(
double delta_x_deg,
double delta_y_deg) = 0;
995 osg::Vec3d position = toOsg(posdir.
position2);
996 osg::Quat orientation = toOsg(posdir.
direction2);
998 osg::Camera* camera =
m_osg_view->getCamera();
999 osg::Matrix old_m = camera->getViewMatrix();
1001 const osg::Matrix new_m(
1002 osg::Matrix::translate(-position)
1003 * osg::Matrix::rotate(orientation.inverse())
1005 SG_LOG(SG_VIEW, SG_BULK,
"old_m: " << old_m);
1006 SG_LOG(SG_VIEW, SG_BULK,
"new_m: " << new_m);
1007 camera->setViewMatrix(new_m);
1013 double aspect_ratio;
1016 camera->getProjectionMatrixAsPerspective(fovy, aspect_ratio, zNear, zFar);
1018 camera->setProjectionMatrixAsPerspective(
1027 double aspect_ratio;
1028 camera->getProjectionMatrixAsPerspective(
1034 if (fovy * aspect_ratio < posdir.
fov_h) {
1035 camera->setProjectionMatrixAsPerspective(
1036 posdir.
fov_v * posdir.
fov_h / (fovy * aspect_ratio),
1045 camera->setProjectionMatrixAsPerspective(
1046 posdir.
fov_h / aspect_ratio,
1069 if (damping <= 0)
return 0;
1083 if (config->getStringValue(
"type") ==
"legacy")
1086 std::string callsign = config->getStringValue(
"callsign");
1087 std::string callsign_desc = (callsign ==
"") ?
"" :
": " + callsign;
1088 SG_LOG(SG_VIEW, SG_INFO,
"callsign=" << callsign);
1090 if (config->getBoolValue(
"view/config/eye-fixed")) {
1091 SG_LOG(SG_VIEW, SG_INFO,
"eye-fixed");
1092 m_steps.m_name = std::string() +
"legacy tower" + callsign_desc;
1094 if (config->getStringValue(
"view/type") ==
"lookat") {
1099 m_steps.add_step(new SviewStepAircraft(callsign));
1100 m_steps.add_step(new SviewStepMove(
1101 -config->getDoubleValue(
"view/config/target-z-offset-m"),
1102 -config->getDoubleValue(
"view/config/target-y-offset-m"),
1103 -config->getDoubleValue(
"view/config/target-x-offset-m")
1109 m_steps.add_step(new SviewStepDirectionMultiply(
1117 m_steps.add_step(new SviewStepCopyToTarget);
1121 m_steps.add_step(new SviewStepNearestTower(callsign));
1123 if (config->getBoolValue(
"view/config/lookat-agl")) {
1124 double damping = config->getDoubleValue(
"view/config/lookat-agl-damping");
1125 double damping_time = log(10) * legacy_damping_time(damping);
1126 SG_LOG(SG_VIEW, SG_DEBUG,
"lookat-agl");
1127 m_steps.add_step(new SviewStepAGL(callsign, damping_time));
1130 m_steps.add_step(new SviewStepFinal);
1140 m_steps.add_step(new SviewStepNearestTower(callsign));
1143 m_steps.add_step(new SviewStepRotate(
1144 -globals->get_props()->getDoubleValue(
"sim/current-view/heading-offset-deg"),
1145 globals->get_props()->getDoubleValue(
"sim/current-view/pitch-offset-deg"),
1146 globals->get_props()->getDoubleValue(
"sim/current-view/roll-offset-deg")
1154 m_steps.add_step(new SviewStepMove(1, 0, 0));
1156 m_steps.add_step(new SviewStepMouseDrag(
1160 m_steps.add_step(new SviewStepFinal);
1164 SG_LOG(SG_VIEW, SG_INFO,
"not eye-fixed");
1167 SGPropertyNode* global_sim_view = globals->get_props()
1168 ->getNode(
"sim/view", config->getIntValue(
"view-number-raw"));
1170 if (global_sim_view->getStringValue(
"type") ==
"lookat") {
1172 m_steps.m_name = std::string() +
"legacy helicopter/chase" + callsign_desc;
1173 m_steps.add_step(new SviewStepAircraft(callsign));
1179 m_steps.add_step(new SviewStepMove(
1180 -config->getDoubleValue(
"view/config/target-z-offset-m"),
1181 -config->getDoubleValue(
"view/config/target-y-offset-m"),
1182 -config->getDoubleValue(
"view/config/target-x-offset-m")
1190 assert(global_sim_view);
1191 m_steps.add_step(new SviewStepDirectionMultiply(
1192 global_sim_view->getStringValue(
"config/eye-heading-deg-path")[0] ? 1 : 0,
1193 global_sim_view->getStringValue(
"config/eye-pitch-deg-path")[0] ? 1 : 0,
1194 global_sim_view->getStringValue(
"config/eye-roll-deg-path")[0] ? 1 : 0
1202 double damping_heading = legacy_damping_time(config->getDoubleValue(
"view/config/at-model-heading-damping"));
1203 double damping_pitch = legacy_damping_time(config->getDoubleValue(
"view/config/at-model-pitch-damping"));
1204 double damping_roll = legacy_damping_time(config->getDoubleValue(
"view/config/at-model-roll-damping"));
1206 m_steps.add_step(new SviewStepRotate(
1207 -globals->get_props()->getDoubleValue(
"sim/current-view/heading-offset-deg"),
1208 -globals->get_props()->getDoubleValue(
"sim/current-view/pitch-offset-deg"),
1209 globals->get_props()->getDoubleValue(
"sim/current-view/roll-offset-deg"),
1215 m_steps.add_step(new SviewStepMouseDrag(
1226 m_steps.add_step(new SviewStepCopyToTarget);
1231 m_steps.add_step(new SviewStepMove(
1232 config->getDoubleValue(
"view/config/z-offset-m"),
1233 -config->getDoubleValue(
"view/config/y-offset-m"),
1234 config->getDoubleValue(
"view/config/x-offset-m")
1240 m_steps.add_step(new SviewStepFinal);
1250 m_steps.m_name = std::string() +
"legacy pilot" + callsign_desc;
1251 m_steps.add_step(new SviewStepAircraft(callsign));
1252 m_steps.add_step(new SviewStepMove(
1253 -config->getDoubleValue(
"view/config/z-offset-m"),
1254 -config->getDoubleValue(
"view/config/y-offset-m"),
1255 -config->getDoubleValue(
"view/config/x-offset-m")
1258 double current_heading_offset = globals->get_props()->getDoubleValue(
"sim/current-view/heading-offset-deg");
1259 double current_pitch_offset = globals->get_props()->getDoubleValue(
"sim/current-view/pitch-offset-deg");
1260 double current_roll_offset = globals->get_props()->getDoubleValue(
"sim/current-view/roll-offset-deg");
1266 m_steps.add_step(new SviewStepRotate(
1267 current_heading_offset,
1268 current_pitch_offset,
1272 m_steps.add_step(new SviewStepMouseDrag(
1276 m_steps.add_step(new SviewStepFinal);
1277 SG_LOG(SG_VIEW, SG_INFO,
"m_steps=" << m_steps);
1285 simgear::PropertyList steps = config->getChildren(
"step");
1286 if (steps.empty()) {
1287 throw std::runtime_error(std::string() +
"No steps specified");
1289 for (SGPropertyNode* step: steps) {
1290 std::string type = step->getStringValue(
"type");
1292 else if (type ==
"aircraft") {
1293 std::string callsign = step->getStringValue(
"callsign");
1295 if (callsign !=
"") {
1296 m_steps.m_name +=
" callsign=" + callsign;
1299 else if (type ==
"move") {
1301 step->getDoubleValue(
"forward"),
1302 step->getDoubleValue(
"up"),
1303 step->getDoubleValue(
"right")
1306 else if (type ==
"direction-multiply") {
1308 step->getDoubleValue(
"heading"),
1309 step->getDoubleValue(
"pitch"),
1310 step->getDoubleValue(
"roll")
1313 else if (type ==
"copy-to-target") {
1316 else if (type ==
"nearest-tower") {
1317 std::string callsign = step->getStringValue(
"callsign");
1319 m_steps.m_name +=
" tower";
1320 if (callsign !=
"") m_steps.m_name +=
" callsign=" + callsign;
1322 else if (type ==
"rotate") {
1324 step->getDoubleValue(
"heading"),
1325 step->getDoubleValue(
"pitch"),
1326 step->getDoubleValue(
"roll"),
1327 step->getDoubleValue(
"damping-heading"),
1328 step->getDoubleValue(
"damping-pitch"),
1329 step->getDoubleValue(
"damping-roll")
1332 else if (type ==
"rotate-current-view") {
1334 globals->get_props()->getDoubleValue(
"heading"),
1335 globals->get_props()->getDoubleValue(
"pitch"),
1336 globals->get_props()->getDoubleValue(
"roll")
1339 else if (type ==
"mouse-drag")
1342 step->getDoubleValue(
"heading-scale", 1),
1343 step->getDoubleValue(
"pitch-scale", 1)
1346 else if (type ==
"double") {
1348 m_steps.m_name +=
" double";
1350 else if (type ==
"agl") {
1351 std::string callsign = step->getStringValue(
"callsign");
1352 double damping_time = step->getDoubleValue(
"damping-time");
1353 m_steps.add_step(
new SviewStepAGL(callsign, damping_time));
1356 throw std::runtime_error(std::string() +
"Unrecognised step name: '" + type +
"'");
1361 SG_LOG(SG_VIEW, SG_DEBUG,
"m_steps=" << m_steps);
1366 osgViewer::View* view,
1367 SGPropertyNode* config,
1374 std::string type = config->getStringValue(
"type");
1376 throw std::runtime_error(
"double-type not specified");
1378 if (type ==
"last_pair" || type ==
"last_pair_double")
1407 if (type ==
"last_pair_double")
1418 SG_LOG(SG_VIEW, SG_INFO,
" m_steps:" <<
m_steps);
1421 throw std::runtime_error(std::string(
"Unrecognised double view: ") + type);
1426 SG_LOG(SG_VIEW, SG_DEBUG,
"m_steps=" <<
m_steps);
1436 bool valid =
m_osg_view->getCamera()->getGraphicsContext()->valid();
1437 SG_LOG(SG_VIEW, SG_BULK,
"valid=" << valid);
1438 if (!valid)
return false;
1443 time_t t = time(NULL) / 10;
1449 if (debug) SG_LOG(SG_VIEW, SG_INFO,
"evaluating m_steps:");
1450 m_steps.evaluate(posdir, dt, debug);
1459 for (
auto step:
m_steps.m_steps) {
1460 step->mouse_drag(delta_x_deg, delta_y_deg);
1472static std::vector<std::shared_ptr<SviewView>>
s_views;
1482 SGPropertyNode_ptr config =
new SGPropertyNode;
1483 int view_number_raw =
globals->get_props()->getIntValue(
"/sim/current-view/view-number-raw");
1484 config->setIntValue(
"view-number-raw", view_number_raw);
1485 SGPropertyNode* global_view =
globals->get_props()->getNode(
"/sim/view", view_number_raw ,
true );
1486 std::string root_path = global_view->getStringValue(
"config/root");
1487 SGPropertyNode* root =
globals->get_props()->getNode(root_path);
1488 std::string callsign = root->getStringValue(
"callsign");
1490 config->setStringValue(
"type",
"legacy");
1491 config->setStringValue(
"callsign", callsign);
1492 SGPropertyNode* config_view = config->getNode(
"view",
true );
1493 if (callsign ==
"") {
1495 copyProperties(
globals->get_props()->getNode(
"/sim/view", view_number_raw), config_view);
1499 copyProperties(root->getNode(
"set/sim/view", view_number_raw), config_view);
1502 config->setDoubleValue(
1503 "direction-delta/heading",
1504 globals->get_props()->getDoubleValue(
"sim/current-view/heading-offset-deg")
1506 config->setDoubleValue(
1507 "direction-delta/pitch",
1508 globals->get_props()->getDoubleValue(
"sim/current-view/pitch-offset-deg")
1510 config->setDoubleValue(
1511 "direction-delta/roll",
1512 globals->get_props()->getDoubleValue(
"sim/current-view/roll-offset-deg")
1515 config->setDoubleValue(
"zoom-delta", 1);
1517 SG_LOG(SG_VIEW, SG_INFO,
"returning:\n" << writePropertiesInline(config,
true ));
1532 SG_LOG(SG_VIEW, SG_DEBUG,
"Have pushed view: " << v);
1541 SG_LOG(SG_VIEW, SG_INFO,
"updating i=" <<
i
1546 bool valid =
s_views[
i]->update(dt);
1548 const osg::Matrix& view_matrix =
s_views[
i]->m_osg_view->getCamera()->getViewMatrix();
1549 const osg::Matrix& projection_matrix =
s_views[
i]->m_osg_view->getCamera()->getProjectionMatrix();
1550 s_views[
i]->m_compositor->update(view_matrix, projection_matrix);
1561 auto view_it =
s_views.begin() +
i;
1562 SG_LOG(SG_VIEW, SG_INFO,
"deleting SviewView i=" <<
i <<
": " << (*view_it)->description2());
1563 for (
size_t j=0; j<
s_views.size(); ++j) {
1564 SG_LOG(SG_VIEW, SG_INFO,
" " << j
1565 <<
": " <<
s_views[j]->m_osg_view
1566 <<
' ' <<
s_views[j]->m_compositor
1571 for (
size_t j=0; j<
s_views.size(); ++j) {
1572 SG_LOG(SG_VIEW, SG_INFO,
" " << j
1573 <<
": " <<
s_views[j]->m_osg_view
1574 <<
' ' <<
s_views[j]->m_compositor
1595 bool handle(osgGA::Event* event, osg::Object*
object, osg::NodeVisitor* nv)
override
1597 osgGA::GUIEventAdapter* ea =
event->asGUIEventAdapter();
1599 osgGA::GUIEventAdapter::EventType et = ea->getEventType();
1600 if (et != osgGA::GUIEventAdapter::FRAME) {
1601 SG_LOG(SG_GENERAL, SG_BULK,
"sview event handler called. ea->getEventType()=" << ea->getEventType());
1605 SG_LOG(SG_GENERAL, SG_BULK,
"sview event handler called...");
1618 osgViewer::ViewerBase* viewer_base = renderer->
getViewerBase();
1619 osgViewer::CompositeViewer* composite_viewer =
dynamic_cast<osgViewer::CompositeViewer*
>(viewer_base);
1620 if (!composite_viewer) {
1624 osgViewer::View* main_view = renderer->
getView();
1625 osg::Node* scene_data = main_view->getSceneData();
1627 SG_LOG(SG_GENERAL, SG_DEBUG,
"main_view->getNumSlaves()=" << main_view->getNumSlaves());
1629 osgViewer::View* view =
new osgViewer::View();
1631 view->addEventHandler(event_handler);
1633 std::shared_ptr<SviewView> sview_view;
1635 std::string type = config->getStringValue(
"type");
1636 SG_LOG(SG_VIEW, SG_DEBUG,
"type=" << type);
1639 else if (type ==
"current") {
1641 copyProperties(config, config2);
1642 config2->setStringValue(
"type",
"legacy");
1645 else if (type ==
"last_pair") {
1647 SG_LOG(SG_VIEW, SG_ALERT,
"Need two pushed views");
1651 std::shared_ptr<SviewViewEyeTarget> target = *(--it);
1652 std::shared_ptr<SviewViewEyeTarget> eye = *(--it);
1653 sview_view.reset(
new SviewViewEyeTarget(view, config, eye->m_steps, target->m_steps));
1655 else if (type ==
"last_pair_double") {
1657 SG_LOG(SG_VIEW, SG_ALERT,
"Need two pushed views");
1661 std::shared_ptr<SviewViewEyeTarget> remote = *(--it);
1662 std::shared_ptr<SviewViewEyeTarget> local = *(--it);
1663 sview_view.reset(
new SviewViewEyeTarget(view, config, local->m_steps, remote->m_steps));
1666 SG_LOG(SG_VIEW, SG_ALERT,
"config is:\n" << writePropertiesInline(config,
true ));
1670 osg::ref_ptr<osg::GraphicsContext::Traits> traits =
new osg::GraphicsContext::Traits;
1671 osg::ref_ptr<osg::GraphicsContext> gc;
1681 assert(main_window);
1682 osg::ref_ptr<osg::GraphicsContext> main_gc = main_window->
gc;
1683 const osg::GraphicsContext::Traits* main_traits = main_gc->getTraits();
1686 traits->x = config->getIntValue(
"window-x", 100);
1687 traits->y = config->getIntValue(
"window-y", 100);
1694 traits->width = config->getIntValue(
"window-width", main_traits->width / 2);
1695 traits->height = config->getIntValue(
"window-height", main_traits->height / 2);
1696 traits->windowDecoration =
true;
1697 traits->doubleBuffer =
true;
1698 traits->sharedContext = 0;
1700 traits->readDISPLAY();
1701 if (traits->displayNum < 0) traits->displayNum = 0;
1702 if (traits->screenNum < 0) traits->screenNum = 0;
1704 int bpp =
fgGetInt(
"/sim/rendering/bits-per-pixel");
1705 int cbits = (bpp <= 16) ? 5 : 8;
1706 int zbits = (bpp <= 16) ? 16 : 24;
1707 traits->red = traits->green = traits->blue = cbits;
1708 traits->depth = zbits;
1710 traits->mipMapGeneration =
true;
1711 traits->windowName =
"Flightgear " + sview_view->description2();
1712 traits->sampleBuffers =
fgGetInt(
"/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
1713 traits->samples =
fgGetInt(
"/sim/rendering/multi-samples", traits->samples);
1714 traits->vsync =
fgGetBool(
"/sim/rendering/vsync-enable", traits->vsync);
1715 traits->stencil = 8;
1717 gc = osg::GraphicsContext::createGraphicsContext(traits);
1727 view->setSceneData(scene_data);
1732 view->getDatabasePager()->setUnrefImageDataAfterApplyPolicy(
true,
false);
1733 osg::GraphicsContext::createNewContextID();
1735 osg::Camera* main_camera = main_view->getCamera();
1736 osg::Camera* camera = view->getCamera();
1737 camera->setGraphicsContext(gc.get());
1747 auto projection_matrix = main_camera->getProjectionMatrix();
1748 bool ok = projection_matrix.getFrustum(left, right, bottom, top, zNear, zFar);
1749 SG_LOG(SG_GENERAL, SG_ALERT,
"projection_matrix:"
1752 <<
" right=" << right
1753 <<
" bottom=" << bottom
1755 <<
" zNear=" << zNear
1760 camera->setProjectionMatrix(main_camera->getProjectionMatrix());
1761 camera->setViewMatrix(main_camera->getViewMatrix());
1762 camera->setCullMask(0xffffffff);
1763 camera->setCullMaskLeft(0xffffffff);
1764 camera->setCullMaskRight(0xffffffff);
1768 camera->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR);
1788 view->getCamera()->setViewport(0, 0, traits->width, traits->height);
1790 view->setName(
"Cloned view");
1792 view->setFrameStamp(composite_viewer->getFrameStamp());
1794 simgear::compositor::Compositor* compositor = simgear::compositor::Compositor::create(
1797 view->getCamera()->getViewport(),
1802 sview_view->m_compositor = compositor;
1803 s_views.push_back(sview_view);
1808 composite_viewer->stopThreading();
1809 composite_viewer->addView(view);
1810 composite_viewer->startThreading();
1812 SG_LOG(SG_GENERAL, SG_DEBUG,
"main_view->getNumSlaves()=" << main_view->getNumSlaves());
1813 SG_LOG(SG_GENERAL, SG_DEBUG,
"view->getNumSlaves()=" << view->getNumSlaves());
1815 SG_LOG(SG_VIEW, SG_DEBUG,
"have added extra view. views are now:");
1816 for (
unsigned i=0;
i<composite_viewer->getNumViews(); ++
i) {
1817 osgViewer::View* view = composite_viewer->getView(
i);
1818 SG_LOG(SG_VIEW, SG_DEBUG,
"composite_viewer view i=" <<
i <<
" view=" << view);
1826 return SviewCreate(
const_cast<SGPropertyNode*
>(config));
1831 const osg::GraphicsContext* gc = ea.getGraphicsContext();
1832 for (std::shared_ptr<SviewView> sview_view:
s_views) {
1833 if (sview_view->m_compositor->getGraphicsContext() == gc) {
1834 return sview_view->m_compositor;
1841 osg::ref_ptr<simgear::SGReaderWriterOptions>
options,
1842 const std::string& compositor_path
1851 const osg::GraphicsContext* gc = ea.getGraphicsContext();
1852 std::shared_ptr<SviewView> sview_view;
1854 if (v->m_compositor->getGraphicsContext() == gc) {
1868 SG_LOG(SG_GENERAL, SG_DEBUG,
"sview_view=" << sview_view.get() <<
" xx=" << xx <<
" yy=" << yy);
1869 bool button2 =
globals->get_props()->getBoolValue(
"/devices/status/mice/mouse/button[2]");
1870 if (button2 && sview_view->m_mouse_button2) {
1872 double delta_x = xx - sview_view->m_mouse_x;
1873 double delta_y = yy - sview_view->m_mouse_y;
1874 if (delta_x || delta_y) {
1881 osg::Camera* camera = sview_view->m_osg_view->getCamera();
1883 double aspect_ratio;
1886 camera->getProjectionMatrixAsPerspective(fov_y, aspect_ratio, z_near, z_far);
1887 double fov_x = fov_y * aspect_ratio;
1889 simgear::compositor::Compositor* compositor = sview_view->m_compositor;
1890 osg::Viewport* viewport = compositor->getViewport();
1891 double delta_x_deg = delta_x / viewport->width() * fov_x;
1892 double delta_y_deg = delta_y / viewport->height() * fov_y;
1897 delta_x_deg *=
scale;
1898 delta_y_deg *=
scale;
1899 sview_view->mouse_drag(delta_x_deg, delta_y_deg);
1902 sview_view->m_mouse_button2 = button2;
1903 sview_view->m_mouse_x = xx;
1904 sview_view->m_mouse_y = yy;
bool options(int, char **)
osgViewer::View * getView()
osgViewer::ViewerBase * getViewerBase() const
static flightgear::SceneryPager * getPagerSingleton()
A window with a graphics context and an integer ID.
osg::ref_ptr< osg::GraphicsContext > gc
The OSG graphics context for this window.
Adapter from windows system / graphics context management API to functions used by flightgear.
GraphicsWindow * getGUIWindow() const
Get the first window marked as GUI (there should only be one).
static WindowSystemAdapter * getWSA()
Get the global WindowSystemAdapter.
int fgGetInt(const char *name, int defaultValue)
Get an int value for a property.
bool eventToWindowCoords(const osgGA::GUIEventAdapter *ea, double &x, double &y)
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
Callsign(const std::string &callsign)
SGPropertyNode_ptr m_root
double reset(double current)
Damping(double damping_time, double wrap_max=0, double current=0)
double update(double dt, double target)
bool handle(osgGA::Event *event, osg::Object *object, osg::NodeVisitor *nv) override
friend std::ostream & operator<<(std::ostream &out, const SviewPosDir &posdir)
void evaluate(SviewPosDir &posdir, double dt) override
Damping relative_height_ground_damping
SviewStepAGL(const std::string &callsign, double damping_time)
SviewStepAircraft(const std::string &callsign)
virtual void stream(std::ostream &out) const
void evaluate(SviewPosDir &posdir, double dt) override
void evaluate(SviewPosDir &posdir, double dt) override
virtual void stream(std::ostream &out) const
virtual void stream(std::ostream &out) const
void evaluate(SviewPosDir &posdir, double dt) override
SviewStepDirectionMultiply(double heading=0, double pitch=0, double roll=0)
void evaluate(SviewPosDir &posdir, double dt) override
double m_local_chase_distance
SviewStepDouble(SGPropertyNode *config)
void evaluate(SviewPosDir &posdir, double dt) override
virtual void stream(std::ostream &out) const
void evaluate(SviewPosDir &posdir, double dt) override
void mouse_drag(double delta_x_deg, double delta_y_deg) override
SviewStepMouseDrag(double heading_scale, double pitch_scale)
SviewStepMove(double forward, double up, double right)
virtual void stream(std::ostream &out) const
void evaluate(SviewPosDir &posdir, double dt) override
SGPropertyNode_ptr m_longitude
virtual void stream(std::ostream &out) const
SGPropertyNode_ptr m_latitude
void evaluate(SviewPosDir &posdir, double dt) override
SGPropertyNode_ptr m_altitude
SviewStepNearestTower(const std::string &callsign)
virtual void stream(std::ostream &out) const
SviewStepRotate(double heading, double pitch, double roll, double damping_heading=0, double damping_pitch=0, double damping_roll=0)
void evaluate(SviewPosDir &posdir, double dt) override
virtual void mouse_drag(double delta_x_deg, double delta_y_deg)
std::string m_description
friend std::ostream & operator<<(std::ostream &out, const SviewStep &step)
virtual void evaluate(SviewPosDir &posdir, double dt=0)=0
virtual void stream(std::ostream &out) const
void add_step(std::shared_ptr< SviewStep > step)
std::vector< std::shared_ptr< SviewStep > > m_steps
void add_step(SviewStep *step)
friend std::ostream & operator<<(std::ostream &out, const SviewSteps &viewpos)
void evaluate(SviewPosDir &posdir, double dt, bool debug=false)
void mouse_drag(double delta_x_deg, double delta_y_deg) override
SviewViewEyeTarget(osgViewer::View *view, SGPropertyNode *config, SviewSteps &a, SviewSteps &b)
SviewViewEyeTarget(osgViewer::View *view, SGPropertyNode *config)
const std::string description() override
bool update(double dt) override
SviewView(osgViewer::View *osg_view)
void posdir_to_view(SviewPosDir posdir)
const std::string description2()
simgear::compositor::Compositor * m_compositor
osgViewer::View * m_osg_view
virtual bool update(double dt)=0
virtual void mouse_drag(double delta_x_deg, double delta_y_deg)=0
virtual const std::string description()=0
static std::vector< std::shared_ptr< SviewView > > s_views
bool SviewMouseMotion(int x, int y, const osgGA::GUIEventAdapter &ea)
static double legacy_damping_time(double damping)
void SViewSetCompositorParams(osg::ref_ptr< simgear::SGReaderWriterOptions > options, const std::string &compositor_path)
static SGPropertyNode_ptr SviewConfigForCurrentView()
static std::string s_compositor_path
static std::ostream & operator<<(std::ostream &out, const osg::Vec3f &vec)
static std::deque< std::shared_ptr< SviewViewEyeTarget > > s_recent_views
std::shared_ptr< SviewView > SviewCreate(SGPropertyNode *config)
static osg::ref_ptr< simgear::SGReaderWriterOptions > s_compositor_options
void SviewUpdate(double dt)
simgear::compositor::Compositor * SviewGetEventViewport(const osgGA::GUIEventAdapter &ea)