55 #include "imgui_internal.h"
64 m_custom_resource_group(ogre_resource_group),
65 m_renderdash(renderdash)
78 return fmt::format(
"GfxActor::~GfxActor(); instanceID:{}, streamID:{}, filename:{}; {}",
89 while (!m_videocameras.empty())
94 Ogre::TextureManager::getSingleton().remove(vcam.
vcam_render_tex->getHandle());
104 m_videocameras.pop_back();
108 if (m_gfx_beams_parent_scenenode !=
nullptr)
112 for (
BeamGfx& rod: m_gfx_beams)
114 Ogre::MovableObject* ogre_object = rod.rod_scenenode->getAttachedObject(0);
115 rod.rod_scenenode->detachAllObjects();
120 m_gfx_beams_parent_scenenode->removeAndDestroyAllChildren();
122 m_gfx_beams_parent_scenenode =
nullptr;
131 for (
size_t i = 0; i < m_wheels.size(); i++)
135 if (m_wheels[i].wx_flex_mesh !=
nullptr)
137 delete m_wheels[i].wx_flex_mesh;
139 if (m_wheels[i].wx_scenenode !=
nullptr)
141 m_wheels[i].wx_scenenode->removeAndDestroyAllChildren();
158 abx.abx_scenenode->detachAllObjects();
163 Ogre::MeshManager::getSingleton().remove(abx.abx_mesh);
172 m_gfx_airbrakes.clear();
176 for (
Prop & prop: m_props)
180 for (
int k = 0; k < 4; ++k)
182 if (prop.pp_beacon_scene_node[k])
184 Ogre::SceneNode* scene_node = prop.pp_beacon_scene_node[k];
185 scene_node->removeAndDestroyAllChildren();
188 if (prop.pp_beacon_light[k])
201 if (prop.pp_scene_node)
203 prop.pp_scene_node->removeAndDestroyAllChildren();
206 if (prop.pp_wheel_scene_node)
208 prop.pp_wheel_scene_node->removeAndDestroyAllChildren();
219 if (prop.pp_mesh_obj)
221 delete prop.pp_mesh_obj;
223 if (prop.pp_wheel_mesh_obj)
225 delete prop.pp_wheel_mesh_obj;
243 fb->destroyOgreObjects();
254 if (m_cab_mesh !=
nullptr)
258 m_cab_scene_node->detachAllObjects();
259 m_cab_scene_node->getParentSceneNode()->removeAndDestroyChild(m_cab_scene_node);
260 m_cab_scene_node =
nullptr;
262 m_cab_entity->_getManager()->destroyEntity(m_cab_entity);
263 m_cab_entity =
nullptr;
266 m_cab_mesh =
nullptr;
275 if (m_renderdash !=
nullptr)
297 if (entry.flare_index != flare_index)
302 const int num_techniques =
static_cast<int>(entry.mat_instance->getNumTechniques());
303 for (
int i = 0; i < num_techniques; i++)
305 Ogre::Technique* tech = entry.mat_instance->getTechnique(i);
309 if (tech->getSchemeName() ==
"glow")
313 Ogre::Pass* p = tech->getPass(0);
319 p->setSelfIllumination(entry.emissive_color);
320 p->setAmbient(Ogre::ColourValue::White);
321 p->setDiffuse(Ogre::ColourValue::White);
325 p->setSelfIllumination(Ogre::ColourValue::ZERO);
326 p->setAmbient(Ogre::ColourValue::Black);
327 p->setDiffuse(Ogre::ColourValue::Black);
333 Ogre::Pass* p = tech->getPass(0);
337 Ogre::TextureUnitState* tus = p->getTextureUnitState(0);
341 if (tus->getNumFrames() < 2)
344 int frame = state_on ? 1 : 0;
346 tus->setCurrentFrame(frame);
349 p->setSelfIllumination(entry.emissive_color);
351 p->setSelfIllumination(Ogre::ColourValue::ZERO);
360 m_cab_mat_visual = mat;
361 m_cab_mat_visual_trans = mat_trans;
363 if (mat->getTechnique(0)->getNumPasses() == 1)
366 m_cab_mat_template_emissive = mat->clone(
"CabMaterialEmissive-" + mat->getName(),
true, m_custom_resource_group);
368 m_cab_mat_template_plain = mat->clone(
"CabMaterialPlain-" + mat->getName(),
true, m_custom_resource_group);
369 m_cab_mat_template_plain->getTechnique(0)->removePass(1);
370 m_cab_mat_template_plain->compile();
375 if (m_cab_mat_template_emissive.isNull())
381 Ogre::MaterialPtr template_mat = (state_on) ? m_cab_mat_template_emissive : m_cab_mat_template_plain;
382 Ogre::Technique* dest_tech = m_cab_mat_visual->getTechnique(0);
383 Ogre::Technique* templ_tech = template_mat->getTechnique(0);
384 dest_tech->removeAllPasses();
385 for (
unsigned short i = 0; i < templ_tech->getNumPasses(); ++i)
387 Ogre::Pass* templ_pass = templ_tech->getPass(i);
388 Ogre::Pass* dest_pass = dest_tech->createPass();
389 *dest_pass = *templ_pass;
391 m_cab_mat_visual->compile();
396 if (state == m_vidcam_state)
404 if (vidcam.vcam_render_target !=
nullptr)
406 vidcam.vcam_render_target->setActive(enable);
408 vidcam.vcam_material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(vidcam.vcam_render_tex->getName());
410 vidcam.vcam_material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(vidcam.vcam_off_tex_name);
414 if (vidcam.vcam_render_window !=
nullptr)
416 vidcam.vcam_render_window->setActive(enable);
419 m_vidcam_state = state;
434 sky->NotifySkyCameraChanged(vidcam.vcam_ogre_camera);
442 float mirror_angle = 0.f;
443 Ogre::Vector3 offset(Ogre::Vector3::ZERO);
446 mirror_angle = m_actor->ar_left_mirror_angle;
447 offset = Ogre::Vector3(0.07f, -0.22f, 0);
451 mirror_angle = m_actor->ar_right_mirror_angle;
452 offset = Ogre::Vector3(0.07f, +0.22f, 0);
455 Ogre::Vector3 normal = vidcam.vcam_prop_scenenode->getOrientation()
456 * Ogre::Vector3(cos(mirror_angle), sin(mirror_angle), 0.0f);
457 Ogre::Vector3 center = vidcam.vcam_prop_scenenode->getPosition()
458 + vidcam.vcam_prop_scenenode->getOrientation() * offset;
459 Ogre::Radian roll = Ogre::Degree(360)
460 - Ogre::Radian(asin(m_actor->getDirection().dotProduct(Ogre::Vector3::UNIT_Y)));
462 Ogre::Plane plane = Ogre::Plane(normal, center);
463 Ogre::Vector3 project = plane.projectVector(
App::GetCameraManager()->GetCameraNode()->getPosition() - center);
465 vidcam.vcam_ogre_camera->setPosition(center);
466 vidcam.vcam_ogre_camera->lookAt(
App::GetCameraManager()->GetCameraNode()->getPosition() - 2.0f * project);
467 vidcam.vcam_ogre_camera->roll(roll);
468 vidcam.vcam_ogre_camera->setNearClipDistance(1);
474 if (vidcam.vcam_render_target !=
nullptr)
475 vidcam.vcam_render_target->update();
477 if (vidcam.vcam_render_window !=
nullptr)
478 vidcam.vcam_render_window->update();
481 const Ogre::Vector3 abs_pos_center = m_simbuf.simbuf_nodes[vidcam.vcam_node_center].AbsPosition;
482 const Ogre::Vector3 abs_pos_z = m_simbuf.simbuf_nodes[vidcam.vcam_node_dir_z].AbsPosition;
483 const Ogre::Vector3 abs_pos_y = m_simbuf.simbuf_nodes[vidcam.vcam_node_dir_y].AbsPosition;
484 Ogre::Vector3 normal = (-(abs_pos_center - abs_pos_z)).crossProduct(-(abs_pos_center - abs_pos_y));
488 Ogre::Vector3 pos = m_simbuf.simbuf_nodes[vidcam.vcam_node_alt_pos].AbsPosition +
489 (vidcam.vcam_pos_offset.x * normal) +
490 (vidcam.vcam_pos_offset.y * (abs_pos_center - abs_pos_y)) +
491 (vidcam.vcam_pos_offset.z * (abs_pos_center - abs_pos_z));
496 Ogre::Vector3 frustumUP = abs_pos_center - abs_pos_y;
497 frustumUP.normalise();
498 vidcam.vcam_ogre_camera->setFixedYawAxis(
true, frustumUP);
503 normal = vidcam.vcam_rotation * normal;
510 Ogre::Vector3 refx = abs_pos_z - abs_pos_center;
512 Ogre::Vector3 refy = abs_pos_center - abs_pos_y;
514 Ogre::Quaternion rot = Ogre::Quaternion(-refx, -refy, -normal);
515 vidcam.vcam_ogre_camera->setOrientation(rot * vidcam.vcam_rotation);
519 normal = m_simbuf.simbuf_nodes[vidcam.vcam_node_lookat].AbsPosition - pos;
521 Ogre::Vector3 refx = abs_pos_z - abs_pos_center;
525 Ogre::Vector3 refy = refx.crossProduct(normal);
527 Ogre::Quaternion rot = Ogre::Quaternion(-refx, -refy, -normal);
528 vidcam.vcam_ogre_camera->setOrientation(rot * vidcam.vcam_rotation);
531 if (vidcam.vcam_debug_node !=
nullptr)
533 vidcam.vcam_debug_node->setPosition(pos);
534 vidcam.vcam_debug_node->setOrientation(vidcam.vcam_ogre_camera->getOrientation());
538 vidcam.vcam_ogre_camera->setPosition(pos);
544 float water_height = 0.f;
550 for (
NodeGfx& nfx: m_gfx_nodes)
552 const node_t& n = m_actor->ar_nodes[nfx.nx_node_idx];
555 if (nfx.nx_may_get_wet && !nfx.nx_no_particles)
560 nfx.nx_wet_time_sec = 0.f;
564 if (nfx.nx_wet_time_sec != -1)
566 nfx.nx_wet_time_sec += dt_sec;
567 if (nfx.nx_wet_time_sec > 5.f)
569 nfx.nx_wet_time_sec = -1.f;
571 else if (nfx.nx_may_get_wet)
573 if (m_particles_drip !=
nullptr)
577 if (nfx.nx_is_hot && m_particles_dust !=
nullptr)
590 if (m_particles_splash)
594 if (m_particles_ripple)
607 if (m_particles_dust !=
nullptr)
614 if (m_particles_clump !=
nullptr && n.
Velocity.squaredLength() > 1.f)
623 const float SMOKE_THRESHOLD = 8.f;
624 const float SCREECH_THRESHOLD = 5.f;
637 else if (!nfx.nx_no_sparks)
682 ImVec2 screen_size = ImGui::GetIO().DisplaySize;
691 Ogre::Vector3 pos_xyz = world2screen.
Convert(m_actor->getPosition());
694 ImVec2 pos(pos_xyz.x, pos_xyz.y);
697 for (
int i = 0; i < m_actor->ar_num_nodes; ++i)
699 radius = std::max(radius, pos_xyz.distance(world2screen.
Convert(m_actor->ar_nodes[i].AbsPosition)));
702 drawlist->AddCircleFilled(pos, radius * 1.05f, 0x22222222, 36);
712 const beam_t* beams = m_actor->ar_beams;
713 const size_t num_beams =
static_cast<size_t>(m_actor->ar_num_beams);
714 for (
size_t i = 0; i < num_beams; ++i)
721 Ogre::Vector3 pos1 = world2screen.
Convert(beams[i].p1->AbsPosition);
722 Ogre::Vector3 pos2 = world2screen.
Convert(beams[i].p2->AbsPosition);
724 if ((pos1.z < 0.f) && (pos2.z < 0.f))
726 ImVec2 pos1xy(pos1.x, pos1.y);
727 ImVec2 pos2xy(pos2.x, pos2.y);
729 if (beams[i].bm_broken)
738 if (!beams[i].bm_disabled)
748 if (beams[i].stress > 0)
750 float stress_ratio = pow(beams[i].stress / beams[i].maxposstress, 2.0f);
751 float s = std::min(stress_ratio, 1.0f);
752 color = Ogre::ColourValue(0.2f * (1 + 2.0f * s), 0.4f * (1.0f - s), 0.33f, 1.0f).getAsABGR();
754 else if (beams[i].stress < 0)
756 float stress_ratio = pow(beams[i].stress / beams[i].maxnegstress, 2.0f);
757 float s = std::min(stress_ratio, 1.0f);
758 color = Ogre::ColourValue(0.2f, 0.4f * (1.0f - s), 0.33f * (1 + 1.0f * s), 1.0f).getAsABGR();
770 const size_t num_nodes =
static_cast<size_t>(m_actor->ar_num_nodes);
771 for (
size_t i = 0; i < num_nodes; ++i)
776 Ogre::Vector3 pos_xyz = world2screen.
Convert(
nodes[i].AbsPosition);
780 ImVec2 pos(pos_xyz.x, pos_xyz.y);
781 if (
nodes[i].nd_immovable)
795 for (
size_t i = 0; i < num_nodes; ++i)
798 (
nodes[i].nd_tyre_node ||
nodes[i].nd_rim_node))
801 Ogre::Vector3 pos = world2screen.
Convert(
nodes[i].AbsPosition);
805 ImVec2 pos_xy(pos.x, pos.y);
807 id_buf <<
nodes[i].pos;
813 snprintf(mass_buf, 50,
"|%.1fKg",
nodes[i].mass);
814 ImVec2 offset = ImGui::CalcTextSize(id_buf.
ToCStr());
825 for (
size_t i = 0; i < num_beams; ++i)
834 Ogre::Vector3 pos_xyz = world2screen.
Convert(world_pos);
835 if (pos_xyz.z >= 0.f)
839 ImVec2 pos(pos_xyz.x, pos_xyz.y);
842 const size_t BUF_LEN = 50;
844 if (beams[i].strength >= 1000000000000.f)
846 snprintf(buf, BUF_LEN,
"%.1fT", (beams[i].strength / 1000000000000.f));
848 else if (beams[i].strength >= 1000000000.f)
850 snprintf(buf, BUF_LEN,
"%.1fG", (beams[i].strength / 1000000000.f));
852 else if (beams[i].strength >= 1000000.f)
854 snprintf(buf, BUF_LEN,
"%.1fM", (beams[i].strength / 1000000.f));
856 else if (beams[i].strength >= 1000.f)
858 snprintf(buf, BUF_LEN,
"%.1fK", (beams[i].strength / 1000.f));
862 snprintf(buf, BUF_LEN,
"%.1f", beams[i].strength);
864 const ImVec2 stren_text_size = ImGui::CalcTextSize(buf);
868 snprintf(buf, BUF_LEN,
"|%.1f", beams[i].stress);
875 const wheel_t* wheels = m_actor->ar_wheels;
876 const size_t num_wheels =
static_cast<size_t>(m_actor->ar_num_wheels);
877 for (
int i = 0; i < num_wheels; i++)
884 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_axis_node_1->AbsPosition);
885 if (pos1_xyz.z < 0.f)
887 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
890 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_axis_node_0->AbsPosition);
891 if (pos2_xyz.z < 0.f)
893 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
896 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
898 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
899 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
904 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
907 float v = ImGui::GetTextLineHeightWithSpacing();
908 ImVec2 pos(pos_xyz.x, pos_xyz.y);
910 wheel_id_buf <<
"Id: " << (i + 1);
911 float h1 = ImGui::CalcTextSize(wheel_id_buf.
ToCStr()).x / 2.0f;
914 rpm_buf <<
"Speed: " <<
static_cast<int>(
Round(wheels[i].debug_rpm)) <<
" rpm";
915 float h2 = ImGui::CalcTextSize(rpm_buf.
ToCStr()).x / 2.0f;
918 torque_buf <<
"Torque: " <<
static_cast<int>(
Round(wheels[i].debug_torque)) <<
" Nm";
919 float h3 = ImGui::CalcTextSize(torque_buf.
ToCStr()).x / 2.0f;
928 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
929 if (pos1_xyz.z < 0.f)
931 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
934 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
935 if (pos2_xyz.z < 0.f)
937 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
940 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
942 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
943 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
948 Ogre::Vector3 radius = Ogre::Plane(axis, wheels[i].wh_near_attach_node->RelPosition).projectVector(rradius);
953 Ogre::Vector3 up = axis.crossProduct(radius);
954 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius - up);
955 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius + up);
956 Ogre::Vector3 pos3_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition - radius + up);
957 Ogre::Vector3 pos4_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition - radius - up);
958 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
960 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
961 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
962 ImVec2 pos3xy(pos3_xyz.x, pos3_xyz.y);
963 ImVec2 pos4xy(pos4_xyz.x, pos4_xyz.y);
964 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, 0x22888888);
970 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
971 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius);
972 Ogre::Vector3 pos3_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
973 if (pos2_xyz.z < 0.f)
975 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
978 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
980 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
981 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
984 if ((pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
986 ImVec2 pos1xy(pos2_xyz.x, pos2_xyz.y);
987 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
995 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
996 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition - cforce);
997 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
999 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1000 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1005 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
1006 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + cforce);
1007 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1009 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1010 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1020 Ogre::Vector3 u = - axis.crossProduct(m_simbuf.simbuf_direction);
1021 if (!wheels[i].debug_force.isZeroLength())
1025 Ogre::Vector3 f = axis.crossProduct(u);
1026 Ogre::Vector3 a = - axis *
w + f * std::max(
w, wheels[i].wh_radius * 0.5f);
1027 Ogre::Vector3 b = + axis *
w + f * std::max(
w, wheels[i].wh_radius * 0.5f);
1028 Ogre::Vector3 c = + axis *
w - f * std::max(
w, wheels[i].wh_radius * 0.5f);
1029 Ogre::Vector3 d = - axis *
w - f * std::max(
w, wheels[i].wh_radius * 0.5f);
1030 Ogre::Quaternion r = Ogre::Quaternion::IDENTITY;
1031 if (wheels[i].debug_vel.length() > 1.0f)
1033 r = Ogre::Quaternion(f.angleBetween(wheels[i].
debug_vel), u);
1035 Ogre::Vector3 pos1_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * a);
1036 Ogre::Vector3 pos2_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * b);
1037 Ogre::Vector3 pos3_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * c);
1038 Ogre::Vector3 pos4_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * d);
1039 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1041 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1042 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1043 ImVec2 pos3xy(pos3_xyz.x, pos3_xyz.y);
1044 ImVec2 pos4xy(pos4_xyz.x, pos4_xyz.y);
1045 if (!wheels[i].debug_force.isZeroLength())
1048 float wheelv = wheels[i].
debug_vel.length();
1049 float slip_ratio = std::min(slipv, wheelv) / std::max(1.0f, wheelv);
1050 float scale = pow(slip_ratio, 2);
1051 ImU32 col = Ogre::ColourValue(scale, 1.0f - scale, 0.0f, 0.2f).getAsABGR();
1052 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, col);
1056 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, 0x55555555);
1062 if (!wheels[i].debug_vel.isZeroLength())
1066 Ogre::Vector3 d = axis.crossProduct(m_simbuf.simbuf_direction) * wheels[i].
wh_radius;
1067 Ogre::Real slipv = wheels[i].
debug_slip.length();
1068 Ogre::Real wheelv = wheels[i].
debug_vel.length();
1069 Ogre::Vector3 s = wheels[i].
debug_slip * (std::min(slipv, wheelv) / std::max(1.0f, wheelv)) / slipv;
1070 Ogre::Vector3 pos1_xyz = world2screen.
Convert(m + d);
1071 Ogre::Vector3 pos2_xyz = world2screen.
Convert(m + d + s * std::max(
w, wheels[i].wh_radius * 0.5f));
1072 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1074 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1075 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1083 Ogre::Real mass = m_actor->getTotalMass(
false) * num_wheels;
1084 Ogre::Vector3 normalised_force = wheels[i].
debug_force.normalisedCopy() * std::min(f / mass, 1.0f);
1086 Ogre::Vector3 pos5_xyz = world2screen.
Convert(m);
1087 Ogre::Vector3 pos6_xyz = world2screen.
Convert(m + normalised_force * wheels[i].wh_radius);
1088 if ((pos5_xyz.z < 0.f) && (pos6_xyz.z < 0.f))
1090 ImVec2 pos1xy(pos5_xyz.x, pos5_xyz.y);
1091 ImVec2 pos2xy(pos6_xyz.x, pos6_xyz.y);
1099 const beam_t* beams = m_actor->ar_beams;
1100 const size_t num_beams =
static_cast<size_t>(m_actor->ar_num_beams);
1101 std::set<int> node_ids;
1102 for (
size_t i = 0; i < num_beams; ++i)
1106 if (!(beams[i].bounded ==
SHOCK1 || beams[i].bounded ==
SHOCK2 || beams[i].bounded ==
SHOCK3))
1109 Ogre::Vector3 pos1_xyz = world2screen.
Convert(beams[i].p1->AbsPosition);
1110 Ogre::Vector3 pos2_xyz = world2screen.
Convert(beams[i].p2->AbsPosition);
1112 if (pos1_xyz.z < 0.f)
1114 node_ids.insert(beams[i].p1->pos);
1116 if (pos2_xyz.z < 0.f)
1118 node_ids.insert(beams[i].p2->pos);
1121 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1123 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1124 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1131 for (
auto id : node_ids)
1133 Ogre::Vector3 pos_xyz = world2screen.
Convert(m_actor->ar_nodes[
id].AbsPosition);
1134 if (pos_xyz.z < 0.f)
1136 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1144 for (
size_t i = 0; i < num_beams; ++i)
1148 if (!(beams[i].bounded ==
SHOCK1 || beams[i].bounded ==
SHOCK2 || beams[i].bounded ==
SHOCK3))
1151 Ogre::Vector3 pos1_xyz = world2screen.
Convert(beams[i].p1->AbsPosition);
1152 Ogre::Vector3 pos2_xyz = world2screen.
Convert(beams[i].p2->AbsPosition);
1153 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
1155 if (pos_xyz.z < 0.f)
1158 float diff = beams[i].
p1->
AbsPosition.distance(beams[i].p2->AbsPosition) - beams[i].
L;
1159 ImU32 text_color = (diff < 0.0f) ? 0xff66ee66 : 0xff8888ff;
1160 float bound = (diff < 0.0f) ? beams[i].shortbound : beams[i].longbound;
1161 float ratio = Ogre::Math::Clamp(diff / (bound * beams[i].L), -2.0f, +2.0f);
1163 float v = ImGui::GetTextLineHeightWithSpacing();
1164 ImVec2 pos(pos_xyz.x, pos_xyz.y - v - v);
1166 len_buf <<
"L: " <<
static_cast<int>(
Round(std::abs(ratio) * 100.0f)) <<
" %";
1167 float h1 = ImGui::CalcTextSize(len_buf.
ToCStr()).x / 2.0f;
1168 drawlist->AddText(ImVec2(pos.x - h1, pos.y), text_color, len_buf.
ToCStr());
1170 spring_buf <<
"S: " <<
static_cast<int>(
Round(beams[i].debug_k)) <<
" N";
1171 float h2 = ImGui::CalcTextSize(spring_buf.
ToCStr()).x / 2.0f;
1172 drawlist->AddText(ImVec2(pos.x - h2, pos.y + v), text_color, spring_buf.
ToCStr());
1174 damp_buf <<
"D: " <<
static_cast<int>(
Round(beams[i].debug_d)) <<
" N";
1175 float h3 = ImGui::CalcTextSize(damp_buf.
ToCStr()).x / 2.0f;
1176 drawlist->AddText(ImVec2(pos.x - h3, pos.y + v + v), text_color, damp_buf.
ToCStr());
1178 snprintf(vel_buf, 25,
"V: %.2f m/s", beams[i].debug_v);
1179 float h4 = ImGui::CalcTextSize(vel_buf).x / 2.0f;
1180 drawlist->AddText(ImVec2(pos.x - h4, pos.y + v + v + v), text_color, vel_buf);
1187 const rotator_t* rotators = m_actor->ar_rotators;
1188 const size_t num_rotators =
static_cast<size_t>(m_actor->ar_num_rotators);
1189 for (
int i = 0; i < num_rotators; i++)
1191 Ogre::Vector3 pos1_xyz = world2screen.
Convert(
nodes[rotators[i].axis1].AbsPosition);
1192 Ogre::Vector3 pos2_xyz = world2screen.
Convert(
nodes[rotators[i].axis2].AbsPosition);
1196 if (pos1_xyz.z < 0.f)
1198 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
1204 if (pos2_xyz.z < 0.f)
1206 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
1212 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1214 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1215 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1220 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
1221 if (pos_xyz.z < 0.f)
1223 float v = ImGui::GetTextLineHeightWithSpacing();
1224 ImVec2 pos(pos_xyz.x, pos_xyz.y);
1226 rotator_id_buf <<
"Id: " << (i + 1);
1227 float h1 = ImGui::CalcTextSize(rotator_id_buf.
ToCStr()).x / 2.0f;
1230 snprintf(angle_buf, 25,
"Rate: %.1f rpm", 60.0f * rotators[i].debug_rate / Ogre::Math::TWO_PI);
1231 float h2 = ImGui::CalcTextSize(angle_buf).x / 2.0f;
1232 drawlist->AddText(ImVec2(pos.x - h2, pos.y + v),
NODE_TEXT_COLOR, angle_buf);
1233 char aerror_buf[25];
1234 snprintf(aerror_buf, 25,
"Error: %.1f mrad", 1000.0f * std::abs(rotators[i].debug_aerror));
1235 float h3 = ImGui::CalcTextSize(aerror_buf).x / 2.0f;
1236 drawlist->AddText(ImVec2(pos.x - h3, pos.y + v + v),
NODE_TEXT_COLOR, aerror_buf);
1241 for (
int j = 0; j < 4; j++)
1245 ImU32 node_color = Ogre::ColourValue(0.33f, 0.33f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1246 ImU32 beam_color = Ogre::ColourValue(0.33f, 0.33f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1248 Ogre::Vector3 pos3_xyz = world2screen.
Convert(
nodes[rotators[i].nodes1[j]].AbsPosition);
1249 if (pos3_xyz.z < 0.f)
1251 ImVec2 pos(pos3_xyz.x, pos3_xyz.y);
1252 drawlist->AddCircleFilled(pos,
NODE_RADIUS, node_color);
1257 if ((pos1_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1259 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1260 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1266 ImU32 node_color = Ogre::ColourValue(1.00f, 0.87f, 0.27f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1267 ImU32 beam_color = Ogre::ColourValue(0.88f, 0.64f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1269 Ogre::Vector3 pos3_xyz = world2screen.
Convert(
nodes[rotators[i].nodes2[j]].AbsPosition);
1270 if (pos3_xyz.z < 0.f)
1272 ImVec2 pos(pos3_xyz.x, pos3_xyz.y);
1273 drawlist->AddCircleFilled(pos,
NODE_RADIUS, node_color);
1278 if ((pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1280 ImVec2 pos1xy(pos2_xyz.x, pos2_xyz.y);
1281 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1289 Ogre::Vector3 mid =
nodes[rotators[i].
axis1].AbsPosition.midPoint(
nodes[rotators[i].axis2].AbsPosition);
1290 Ogre::Vector3 axis =
nodes[rotators[i].
axis1].RelPosition -
nodes[rotators[i].
axis2].RelPosition;
1291 Ogre::Vector3 perp = axis.perpendicular();
1294 const int steps = 64;
1295 Ogre::Plane plane = Ogre::Plane(axis, mid);
1297 Ogre::Real radius1 = 0.0f;
1298 Ogre::Real offset1 = 0.0f;
1299 for (
int k = 0; k < 2; k++)
1302 Ogre::Real r = plane.projectVector(r1).length();
1306 offset1 = plane.getDistance(
nodes[rotators[i].nodes1[k]].AbsPosition);
1309 std::vector<ImVec2> pos1_xy;
1310 for (
int k = 0; k < steps; k++)
1312 Ogre::Quaternion rotation(Ogre::Radian(((
float)k / steps) * Ogre::Math::TWO_PI), axis);
1313 Ogre::Vector3 pos_xyz = world2screen.
Convert(mid + axis * offset1 + rotation * perp * radius1);
1314 if (pos_xyz.z < 0.f)
1316 pos1_xy.push_back(ImVec2(pos_xyz.x, pos_xyz.y));
1319 if (!pos1_xy.empty())
1321 drawlist->AddConvexPolyFilled(pos1_xy.data(),
static_cast<int>(pos1_xy.size()), 0x33666666);
1324 Ogre::Real radius2 = 0.0f;
1325 Ogre::Real offset2 = 0.0f;
1326 for (
int k = 0; k < 2; k++)
1329 Ogre::Real r = plane.projectVector(r2).length();
1333 offset2 = plane.getDistance(
nodes[rotators[i].nodes2[k]].AbsPosition);
1336 std::vector<ImVec2> pos2_xy;
1337 for (
int k = 0; k < steps; k++)
1339 Ogre::Quaternion rotation(Ogre::Radian(((
float)k / steps) * Ogre::Math::TWO_PI), axis);
1340 Ogre::Vector3 pos_xyz = world2screen.
Convert(mid + axis * offset2 + rotation * perp * radius2);
1341 if (pos_xyz.z < 0.f)
1343 pos2_xy.push_back(ImVec2(pos_xyz.x, pos_xyz.y));
1346 if (!pos2_xy.empty())
1348 drawlist->AddConvexPolyFilled(pos2_xy.data(),
static_cast<int>(pos2_xy.size()), 0x1155a3e0);
1351 for (
int k = 0; k < 2; k++)
1354 Ogre::Vector3 ref1 = plane.projectVector(
nodes[rotators[i].nodes1[k]].AbsPosition - mid);
1355 Ogre::Vector3 th1 = Ogre::Quaternion(Ogre::Radian(rotators[i].angle), axis) * ref1;
1357 Ogre::Vector3 pos1_xyz = world2screen.
Convert(mid + axis * offset1);
1358 Ogre::Vector3 pos2_xyz = world2screen.
Convert(mid + axis * offset1 + th1);
1359 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1361 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1362 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1367 Ogre::Vector3 ref2 = plane.projectVector(
nodes[rotators[i].nodes2[k]].AbsPosition - mid);
1369 Ogre::Vector3 pos1_xyz = world2screen.
Convert(mid + axis * offset2);
1370 Ogre::Vector3 pos2_xyz = world2screen.
Convert(mid + axis * offset2 + ref2);
1371 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1373 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1374 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1380 Ogre::Real radius = std::min(radius1, radius2);
1381 Ogre::Vector3 pos3_xyz = world2screen.
Convert(mid + axis * offset1 + th1 * radius);
1382 Ogre::Vector3 pos4_xyz = world2screen.
Convert(mid + axis * offset2 + th1 * radius);
1383 if ((pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1385 ImVec2 pos1xy(pos3_xyz.x, pos3_xyz.y);
1386 ImVec2 pos2xy(pos4_xyz.x, pos4_xyz.y);
1396 std::set<int> node_ids;
1397 for (
auto railgroup : m_actor->m_railgroups)
1399 for (
auto railsegment : railgroup->rg_segments)
1401 Ogre::Vector3 pos1 = world2screen.
Convert(railsegment.rs_beam->p1->AbsPosition);
1402 Ogre::Vector3 pos2 = world2screen.
Convert(railsegment.rs_beam->p2->AbsPosition);
1406 node_ids.insert(railsegment.rs_beam->p1->pos);
1410 node_ids.insert(railsegment.rs_beam->p2->pos);
1412 if ((pos1.z < 0.f) && (pos2.z < 0.f))
1414 ImVec2 pos1xy(pos1.x, pos1.y);
1415 ImVec2 pos2xy(pos2.x, pos2.y);
1421 for (
auto id : node_ids)
1423 Ogre::Vector3 pos_xyz = world2screen.
Convert(
nodes[
id].AbsPosition);
1424 if (pos_xyz.z < 0.f)
1426 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1434 for (
auto slidenode : m_actor->m_slidenodes)
1436 auto id = slidenode.GetSlideNodeId();
1437 Ogre::Vector3 pos_xyz = world2screen.
Convert(
nodes[
id].AbsPosition);
1439 if (pos_xyz.z < 0.f)
1441 ImVec2 pos(pos_xyz.x, pos_xyz.y);
1453 const auto cabs = m_actor->ar_cabs;
1454 const auto num_cabs = m_actor->ar_num_cabs;
1455 const auto buoycabs = m_actor->ar_buoycabs;
1456 const auto num_buoycabs = m_actor->ar_num_buoycabs;
1457 const auto collcabs = m_actor->ar_collcabs;
1458 const auto num_collcabs = m_actor->ar_num_collcabs;
1460 std::vector<std::pair<float, int>> render_cabs;
1461 for (
int i = 0; i < num_cabs; i++)
1463 Ogre::Vector3 pos1_xyz = world2screen.
Convert(
nodes[cabs[i*3+0]].AbsPosition);
1464 Ogre::Vector3 pos2_xyz = world2screen.
Convert(
nodes[cabs[i*3+1]].AbsPosition);
1465 Ogre::Vector3 pos3_xyz = world2screen.
Convert(
nodes[cabs[i*3+2]].AbsPosition);
1466 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1468 float depth = pos1_xyz.z;
1469 depth = std::max(depth, pos2_xyz.z);
1470 depth = std::max(depth, pos3_xyz.z);
1471 render_cabs.push_back({depth, i});
1474 std::sort(render_cabs.begin(), render_cabs.end());
1477 std::vector<int> node_ids;
1478 for (
auto render_cab : render_cabs)
1480 int i = render_cab.second;
1481 bool coll = std::find(collcabs, collcabs + num_collcabs, i) != (collcabs + num_collcabs);
1482 bool buoy = std::find(buoycabs, buoycabs + num_buoycabs, i) != (buoycabs + num_buoycabs);
1484 ImU32 fill_color = Ogre::ColourValue(0.5f * coll, 0.5f * !buoy, 0.5f * (coll ^ buoy), 0.27f).getAsABGR();
1485 ImU32 beam_color = Ogre::ColourValue(0.5f * coll, 0.5f * !buoy, 0.5f * (coll ^ buoy), 0.53f).getAsABGR();
1487 Ogre::Vector3 pos1_xyz = world2screen.
Convert(
nodes[cabs[i*3+0]].AbsPosition);
1488 Ogre::Vector3 pos2_xyz = world2screen.
Convert(
nodes[cabs[i*3+1]].AbsPosition);
1489 Ogre::Vector3 pos3_xyz = world2screen.
Convert(
nodes[cabs[i*3+2]].AbsPosition);
1490 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1492 ImVec2 pos1_xy(pos1_xyz.x, pos1_xyz.y);
1493 ImVec2 pos2_xy(pos2_xyz.x, pos2_xyz.y);
1494 ImVec2 pos3_xy(pos3_xyz.x, pos3_xyz.y);
1495 drawlist->AddTriangleFilled(pos1_xy, pos2_xy, pos3_xy, fill_color);
1496 drawlist->AddTriangle(pos1_xy, pos2_xy, pos3_xy, beam_color,
BEAM_THICKNESS);
1498 for (
int k = 0; k < 3; k++)
1500 int id = cabs[i*3+k];
1501 if (std::find(node_ids.begin(), node_ids.end(),
id) == node_ids.end())
1503 Ogre::Vector3 pos_xyz = world2screen.
Convert(
nodes[
id].AbsPosition);
1504 if (pos_xyz.z < 0.f)
1506 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1507 drawlist->AddCircleFilled(pos_xy,
NODE_RADIUS,
nodes[
id].nd_contacter ? 0xbb0033ff : 0x88888888);
1513 node_ids.push_back(
id);
1523 m_debug_view = m_last_debug_view;
1542 m_last_debug_view = dv;
1548 switch (m_debug_view)
1600 for (
BeamGfx& rod: m_gfx_beams)
1602 rod.rod_scenenode->setVisible(rod.rod_is_visible);
1603 if (!rod.rod_is_visible)
1606 NodeSB* nodes1 = this->GetSimNodeBuffer();
1607 Ogre::Vector3 pos1 = nodes1[rod.rod_node1].
AbsPosition;
1608 NodeSB* nodes2 = rod.rod_target_actor->GetGfxActor()->GetSimNodeBuffer();
1609 Ogre::Vector3 pos2 = nodes2[rod.rod_node2].
AbsPosition;
1612 float beam_diameter =
static_cast<float>(rod.rod_diameter_mm) * 0.001;
1613 float beam_length = pos1.distance(pos2);
1615 rod.rod_scenenode->setPosition(pos1.midPoint(pos2));
1616 rod.rod_scenenode->setScale(beam_diameter, beam_length, beam_diameter);
1626 Ogre::Vector3 v0 = src;
1627 Ogre::Vector3 v1 = dest;
1633 Ogre::Real d = v0.dotProduct(v1);
1637 return Ogre::Quaternion::IDENTITY;
1639 if (d < (1e-6f - 1.0f))
1642 Ogre::Vector3 axis = Ogre::Vector3::UNIT_X.crossProduct(src);
1643 if (axis.isZeroLength())
1644 axis = Ogre::Vector3::UNIT_Y.crossProduct(src);
1646 q.FromAngleAxis(Ogre::Radian(Ogre::Math::PI), axis);
1652 return Ogre::Quaternion::IDENTITY;
1654 Ogre::Vector3 c = v0.crossProduct(v1);
1655 Ogre::Real invs = 1 / s;
1667 for (
BeamGfx& rod: m_gfx_beams)
1669 float diameter2 =
static_cast<float>(rod.rod_diameter_mm) * (ratio*1000.f);
1670 rod.rod_diameter_mm =
static_cast<uint16_t
>(diameter2);
1675 for (
Prop& prop: m_props)
1677 if (prop.pp_scene_node)
1678 prop.pp_scene_node->scale(ratio, ratio, ratio);
1680 if (prop.pp_wheel_scene_node)
1682 prop.pp_wheel_scene_node->scale(ratio, ratio, ratio);
1683 prop.pp_wheel_pos = relpos + (prop.pp_wheel_pos - relpos) * ratio;
1686 if (prop.pp_beacon_scene_node[0])
1687 prop.pp_beacon_scene_node[0]->scale(ratio, ratio, ratio);
1689 if (prop.pp_beacon_scene_node[1])
1690 prop.pp_beacon_scene_node[1]->scale(ratio, ratio, ratio);
1692 if (prop.pp_beacon_scene_node[2])
1693 prop.pp_beacon_scene_node[2]->scale(ratio, ratio, ratio);
1695 if (prop.pp_beacon_scene_node[3])
1696 prop.pp_beacon_scene_node[3]->scale(ratio, ratio, ratio);
1702 m_cab_mesh->ScaleFlexObj(ratio);
1708 if (m_gfx_beams_parent_scenenode ==
nullptr)
1717 if (visible && !m_gfx_beams_parent_scenenode->isInSceneGraph())
1721 else if (!visible && m_gfx_beams_parent_scenenode->isInSceneGraph())
1732 m_simbuf.simbuf_actor_state = m_actor->ar_state;
1733 m_simbuf.simbuf_physics_paused = m_actor->ar_physics_paused;
1734 m_simbuf.simbuf_cur_cinecam = m_actor->ar_current_cinecam;
1735 m_simbuf.simbuf_net_username = m_actor->m_net_username;
1736 m_simbuf.simbuf_net_colornum = m_actor->m_net_color_num;
1737 m_simbuf.simbuf_driveable = m_actor->ar_driveable;
1740 m_simbuf.simbuf_pos = m_actor->getRotationCenter();
1741 m_simbuf.simbuf_node0_velo = m_actor->ar_nodes[0].Velocity;
1742 m_simbuf.simbuf_rotation = m_actor->getRotation();
1743 m_simbuf.simbuf_direction = m_actor->getDirection();
1744 m_simbuf.simbuf_wheel_speed = m_actor->ar_wheel_speed;
1745 m_simbuf.simbuf_top_speed = m_actor->ar_top_speed;
1746 m_simbuf.simbuf_aabb = m_actor->ar_bounding_box;
1747 if (m_actor->ar_num_cameras > 0)
1749 m_simbuf.simbuf_camera0_pos_node = m_actor->ar_camera_node_pos[0];
1750 m_simbuf.simbuf_camera0_roll_node = m_actor->ar_camera_node_roll[0];
1754 m_simbuf.simbuf_nodes.resize(m_actor->ar_num_nodes);
1755 for (
int i = 0; i < m_actor->ar_num_nodes; ++i)
1757 auto node = m_actor->ar_nodes[i];
1758 m_simbuf.simbuf_nodes[i].AbsPosition = node.AbsPosition;
1759 m_simbuf.simbuf_nodes[i].nd_has_contact = node.nd_has_ground_contact || node.nd_has_mesh_contact;
1762 for (
NodeGfx& nx: m_gfx_nodes)
1764 m_simbuf.simbuf_nodes[nx.nx_node_idx].nd_is_wet = (nx.nx_wet_time_sec != -1.f);
1768 for (
BeamGfx& rod: m_gfx_beams)
1770 const beam_t& beam = m_actor->ar_beams[rod.rod_beam_index];
1771 rod.rod_node1 =
static_cast<uint16_t
>(beam.
p1->
pos);
1772 rod.rod_node2 =
static_cast<uint16_t
>(beam.
p2->
pos);
1781 m_simbuf.simbuf_airbrakes.resize(m_actor->ar_airbrakes.size());
1782 for (
size_t i=0; i< m_actor->ar_airbrakes.size(); ++i)
1784 m_simbuf.simbuf_airbrakes[i].simbuf_ab_ratio = m_actor->ar_airbrakes[i]->getRatio();
1790 m_simbuf.simbuf_commandkey[i].simbuf_cmd_value = m_actor->ar_command_key[i].commandValue;
1794 m_simbuf.simbuf_prop_anim_keys.resize(m_actor->m_prop_anim_key_states.size());
1795 for (
size_t i = 0; i < m_actor->m_prop_anim_key_states.size(); ++i)
1797 m_simbuf.simbuf_prop_anim_keys[i].simbuf_anim_active = m_actor->m_prop_anim_key_states[i].anim_active;
1801 m_simbuf.simbuf_aeroengines.resize(m_actor->ar_num_aeroengines);
1802 for (
int i = 0; i < m_actor->ar_num_aeroengines; ++i)
1804 AeroEngine* src = m_actor->ar_aeroengines[i];
1831 m_simbuf.simbuf_hydro_dir_state = m_actor->ar_hydro_dir_state;
1832 m_simbuf.simbuf_brake = m_actor->ar_brake;
1833 if (m_actor->ar_engine !=
nullptr)
1835 m_simbuf.simbuf_has_engine =
true;
1836 m_simbuf.simbuf_gear = m_actor->ar_engine->GetGear();
1837 m_simbuf.simbuf_autoshift = m_actor->ar_engine->getAutoShift();
1838 m_simbuf.simbuf_engine_rpm = m_actor->ar_engine->GetEngineRpm();
1839 m_simbuf.simbuf_engine_turbo_psi= m_actor->ar_engine->GetTurboPsi();
1840 m_simbuf.simbuf_engine_accel = m_actor->ar_engine->GetAcceleration();
1841 m_simbuf.simbuf_engine_torque = m_actor->ar_engine->GetEngineTorque();
1842 m_simbuf.simbuf_inputshaft_rpm = m_actor->ar_engine->GetInputShaftRpm();
1843 m_simbuf.simbuf_drive_ratio = m_actor->ar_engine->GetDriveRatio();
1844 m_simbuf.simbuf_clutch = m_actor->ar_engine->GetClutch();
1845 m_simbuf.simbuf_num_gears = m_actor->ar_engine->getNumGears();
1846 m_simbuf.simbuf_engine_max_rpm = m_actor->ar_engine->getMaxRPM();
1848 if (m_actor->m_num_wheel_diffs > 0)
1850 m_simbuf.simbuf_diff_type = m_actor->m_wheel_diffs[0]->GetActiveDiffType();
1854 m_simbuf.simbuf_tyre_pressure = m_actor->getTyrePressure().GetCurPressure();
1855 m_simbuf.simbuf_tyre_pressurizing = m_actor->getTyrePressure().IsPressurizing();
1858 m_simbuf.simbuf_lightmask = m_actor->m_lightmask;
1859 m_simbuf.simbuf_smoke_enabled = m_actor->getSmokeEnabled();
1860 m_simbuf.simbuf_parking_brake = m_actor->ar_parking_brake;
1863 m_simbuf.simbuf_hydro_aileron_state = m_actor->ar_hydro_aileron_state;
1864 m_simbuf.simbuf_hydro_elevator_state = m_actor->ar_hydro_elevator_state;
1865 m_simbuf.simbuf_hydro_aero_rudder_state = m_actor->ar_hydro_rudder_state;
1866 m_simbuf.simbuf_aero_flap_state = m_actor->ar_aerial_flap;
1867 m_simbuf.simbuf_airbrake_state = m_actor->ar_airbrake_intensity;
1868 if (m_actor->ar_num_wings > 4)
1870 m_simbuf.simbuf_wing4_aoa = m_actor->ar_wings[4].fa->aoa;
1874 if (m_actor->ar_autopilot !=
nullptr)
1876 m_simbuf.simbuf_has_autopilot =
true;
1877 m_simbuf.simbuf_ap_heading_mode = m_actor->ar_autopilot->GetHeadingMode();
1878 m_simbuf.simbuf_ap_heading_value = m_actor->ar_autopilot->heading;
1879 m_simbuf.simbuf_ap_alt_mode = m_actor->ar_autopilot->GetAltMode();
1880 m_simbuf.simbuf_ap_alt_value = m_actor->ar_autopilot->GetAltValue();
1881 m_simbuf.simbuf_ap_ias_mode = m_actor->ar_autopilot->GetIasMode();
1882 m_simbuf.simbuf_ap_ias_value = m_actor->ar_autopilot->GetIasValue();
1883 m_simbuf.simbuf_ap_gpws_mode = m_actor->ar_autopilot->GetGpwsMode();
1884 m_simbuf.simbuf_ap_ils_available = m_actor->ar_autopilot->IsIlsAvailable();
1885 m_simbuf.simbuf_ap_ils_vdev = m_actor->ar_autopilot->GetVerticalApproachDeviation();
1886 m_simbuf.simbuf_ap_ils_hdev = m_actor->ar_autopilot->GetHorizontalApproachDeviation();
1887 m_simbuf.simbuf_ap_vs_value = m_actor->ar_autopilot->GetVsValue();
1890 m_simbuf.simbuf_speedo_highest_kph = m_actor->ar_guisettings_speedo_max_kph;
1891 m_simbuf.simbuf_speedo_use_engine_max_rpm = m_actor->ar_guisettings_use_engine_max_rpm;
1892 m_simbuf.simbuf_shifter_anim_time = m_actor->ar_guisettings_shifter_anim_time;
1903 if ((m_cab_entity !=
nullptr) && (m_cab_mesh !=
nullptr))
1905 m_cab_scene_node->setPosition(m_cab_mesh->UpdateFlexObj());
1911 m_flexwheel_tasks.clear();
1915 if (
w.wx_flex_mesh !=
nullptr &&
w.wx_flex_mesh->flexitPrepare())
1917 auto func = std::function<void()>([
this,
w]()
1919 w.wx_flex_mesh->flexitCompute();
1922 m_flexwheel_tasks.push_back(task_handle);
1929 for (
auto& task: m_flexwheel_tasks)
1935 if (
w.wx_scenenode !=
nullptr &&
w.wx_flex_mesh !=
nullptr)
1937 w.wx_scenenode->setPosition(
w.wx_flex_mesh->flexitFinal());
1946 if (
w.wx_scenenode !=
nullptr)
1948 w.wx_scenenode->setVisible(value);
1950 if (
w.wx_flex_mesh !=
nullptr)
1952 w.wx_flex_mesh->setVisible(value);
1963 const size_t num_airbrakes = m_gfx_airbrakes.size();
1964 for (
size_t i=0; i<num_airbrakes; ++i)
1967 const float ratio = m_simbuf.simbuf_airbrakes[i].simbuf_ab_ratio;
1968 const float maxangle = m_actor->ar_airbrakes[i]->getMaxAngle();
1969 Ogre::Vector3 ref_node_pos = m_simbuf.simbuf_nodes[m_gfx_airbrakes[i].abx_ref_node].AbsPosition;
1970 Ogre::Vector3 x_node_pos = m_simbuf.simbuf_nodes[m_gfx_airbrakes[i].abx_x_node].AbsPosition;
1971 Ogre::Vector3 y_node_pos = m_simbuf.simbuf_nodes[m_gfx_airbrakes[i].abx_y_node].AbsPosition;
1974 Ogre::Vector3 normal = (y_node_pos - ref_node_pos).crossProduct(x_node_pos - ref_node_pos);
1977 Ogre::Vector3 mposition = ref_node_pos + abx.
abx_offset.x * (x_node_pos - ref_node_pos) + abx.
abx_offset.y * (y_node_pos - ref_node_pos);
1980 Ogre::Vector3 refx = x_node_pos - ref_node_pos;
1982 Ogre::Vector3 refy = refx.crossProduct(normal);
1983 Ogre::Quaternion orientation = Ogre::Quaternion(Ogre::Degree(-ratio * maxangle), (x_node_pos - ref_node_pos).normalisedCopy()) * Ogre::Quaternion(refx, normal, refy);
1993 for (
int i = 0; i < m_actor->ar_num_custom_particles; i++)
1995 Ogre::Vector3 pos = m_simbuf.simbuf_nodes[m_actor->ar_custom_particles[i].emitterNode].AbsPosition;
1996 Ogre::Vector3 dir = pos - m_simbuf.simbuf_nodes[m_actor->ar_custom_particles[i].directionNode].AbsPosition;
1998 m_actor->ar_custom_particles[i].snode->setPosition(pos);
1999 for (
int j = 0; j < m_actor->ar_custom_particles[i].psys->getNumEmitters(); j++)
2001 m_actor->ar_custom_particles[i].psys->getEmitter(j)->setDirection(dir);
2008 for (
int i = 0; i < m_actor->ar_num_aeroengines; i++)
2010 m_actor->ar_aeroengines[i]->updateVisuals(
this);
2016 const bool is_remote =
2027 float y_offset = (m_simbuf.simbuf_aabb.getMaximum().y - m_simbuf.simbuf_pos.y) + (vlen / 100.0);
2028 Ogre::Vector3 scene_pos = m_simbuf.simbuf_pos + Ogre::Vector3::UNIT_Y * y_offset;
2037 Prop* driverseat_prop = &m_props[m_driverseat_prop_index];
2041 const Ogre::Vector3 x_pos =
nodes[driverseat_prop->
pp_node_x].AbsPosition;
2042 const Ogre::Vector3 y_pos =
nodes[driverseat_prop->
pp_node_y].AbsPosition;
2043 const Ogre::Vector3 center_pos =
nodes[driverseat_prop->
pp_node_ref].AbsPosition;
2045 const Ogre::Vector3 x_vec = x_pos - center_pos;
2046 const Ogre::Vector3 y_vec = y_pos - center_pos;
2047 const Ogre::Vector3 normal = (y_vec.crossProduct(x_vec)).normalisedCopy();
2050 Ogre::Vector3 pos = center_pos;
2051 pos += (driverseat_prop->
pp_offset.x * x_vec);
2052 pos += (driverseat_prop->
pp_offset.y * y_vec);
2053 pos += (driverseat_prop->
pp_offset.z * normal);
2057 const Ogre::Vector3 x_vec_norm = x_vec.normalisedCopy();
2058 const Ogre::Vector3 y_vec_norm = x_vec_norm.crossProduct(normal);
2059 Ogre::Quaternion rot(x_vec_norm, normal, y_vec_norm);
2060 rot = rot * driverseat_prop->
pp_rot;
2061 rot = rot * Ogre::Quaternion(Ogre::Degree(180), Ogre::Vector3::UNIT_Y);
2068 using namespace Ogre;
2077 Ogre::Quaternion beacon_orientation = beacon_scene_node->getOrientation();
2083 pp_beacon_light->setPosition(beacon_scene_node->getPosition() + beacon_orientation * Ogre::Vector3(0, 0, 0.12));
2084 beacon_rotation_angle += dt * beacon_rotation_rate;
2085 pp_beacon_light->setDirection(beacon_orientation * Ogre::Vector3(cos(beacon_rotation_angle), sin(beacon_rotation_angle), 0));
2088 float vlen = vdir.length();
2097 float amplitude = pp_beacon_light->getDirection().dotProduct(vdir);
2101 prop.
pp_beacon_bbs[0]->setDefaultDimensions(amplitude * amplitude * amplitude, amplitude * amplitude * amplitude);
2107 pp_beacon_light->setVisible(enableAll);
2115 for (
int k = 0; k < 4; k++)
2118 Quaternion orientation = prop.
pp_scene_node->getOrientation();
2134 float vlen = vdir.length();
2143 float amplitude = prop.
pp_beacon_light[k]->getDirection().dotProduct(vdir);
2147 prop.
pp_beacon_bbs[k]->setDefaultDimensions(amplitude * amplitude * amplitude, amplitude * amplitude * amplitude);
2159 Quaternion orientation = prop.
pp_scene_node->getOrientation();
2164 float vlen = vdir.length();
2173 bool visible =
false;
2179 visible = visible && enableAll;
2188 float vlen = vdir.length();
2205 float vlen = vdir.length();
2214 bool visible =
false;
2220 visible = visible && enableAll;
2228 using namespace Ogre;
2233 for (
Prop& prop: m_props)
2235 if (prop.pp_scene_node ==
nullptr)
2239 if (prop.pp_aero_propeller_blade || prop.pp_aero_propeller_spin)
2241 const float SPINNER_THRESHOLD = 200.f;
2242 const bool show_spinner = m_simbuf.simbuf_aeroengines[prop.pp_aero_engine_idx].simbuf_ae_rpm > SPINNER_THRESHOLD;
2243 if (prop.pp_aero_propeller_blade)
2244 prop.pp_scene_node->setVisible(!show_spinner);
2245 else if (prop.pp_aero_propeller_spin)
2246 prop.pp_scene_node->setVisible(show_spinner);
2250 const bool mo_visible = (prop.pp_camera_mode_active ==
CAMERA_MODE_ALWAYS_VISIBLE || prop.pp_camera_mode_active == m_simbuf.simbuf_cur_cinecam);
2251 prop.pp_mesh_obj->setVisible(mo_visible);
2260 Vector3 diffX =
nodes[prop.pp_node_x].AbsPosition -
nodes[prop.pp_node_ref].AbsPosition;
2261 Vector3 diffY =
nodes[prop.pp_node_y].AbsPosition -
nodes[prop.pp_node_ref].AbsPosition;
2263 Vector3 normal = (diffY.crossProduct(diffX)).normalisedCopy();
2265 Vector3 mposition =
nodes[prop.pp_node_ref].AbsPosition + prop.pp_offset.x * diffX + prop.pp_offset.y * diffY;
2266 prop.pp_scene_node->setPosition(mposition + normal * prop.pp_offset.z);
2268 Vector3 refx = diffX.normalisedCopy();
2269 Vector3 refy = refx.crossProduct(normal);
2270 Quaternion orientation = Quaternion(refx, normal, refy) * prop.pp_rot;
2271 prop.pp_scene_node->setOrientation(orientation);
2273 if (prop.pp_wheel_scene_node)
2275 Quaternion brot = Quaternion(Degree(-59.0), Vector3::UNIT_X);
2276 brot = brot * Quaternion(Degree(m_simbuf.simbuf_hydro_dir_state * prop.pp_wheel_rot_degree), Vector3::UNIT_Y);
2277 prop.pp_wheel_scene_node->setPosition(mposition + normal * prop.pp_offset.z + orientation * prop.pp_wheel_pos);
2278 prop.pp_wheel_scene_node->setOrientation(orientation * brot);
2286 this->SetBeaconsEnabled(m_beaconlight_active);
2290 && m_beaconlight_active)
2292 for (
Prop& prop: m_props)
2294 if (prop.pp_beacon_type != 0)
2296 this->UpdateBeaconFlare(prop, dt, is_player_actor);
2304 for (
Prop& prop: m_props)
2306 prop.setPropMeshesVisible(visible);
2315 for (
int i = 0; i < m_actor->ar_num_aeroengines; i++)
2317 m_actor->ar_aeroengines[i]->setVisible(visible);
2323 if (m_renderdash !=
nullptr)
2325 m_renderdash->setEnable(active);
2331 if (m_renderdash !=
nullptr)
2333 m_renderdash->getRenderTarget()->update();
2341 for (
Prop& prop: m_props)
2343 char beacon_type = prop.pp_beacon_type;
2344 if (beacon_type ==
'b')
2346 prop.pp_beacon_light[0]->setVisible(beacon_light_is_active && enableLight);
2347 prop.pp_beacon_scene_node[0]->setVisible(beacon_light_is_active);
2348 if (prop.pp_beacon_bbs[0] && beacon_light_is_active && !prop.pp_beacon_scene_node[0]->numAttachedObjects())
2350 prop.pp_beacon_bbs[0]->setVisible(
true);
2351 prop.pp_beacon_scene_node[0]->attachObject(prop.pp_beacon_bbs[0]);
2353 else if (prop.pp_beacon_bbs[0] && !beacon_light_is_active)
2355 prop.pp_beacon_scene_node[0]->detachAllObjects();
2356 prop.pp_beacon_bbs[0]->setVisible(
false);
2359 else if (beacon_type ==
'R' || beacon_type ==
'L')
2361 prop.pp_beacon_scene_node[0]->setVisible(beacon_light_is_active);
2362 if (prop.pp_beacon_bbs[0] && beacon_light_is_active && !prop.pp_beacon_scene_node[0]->numAttachedObjects())
2363 prop.pp_beacon_scene_node[0]->attachObject(prop.pp_beacon_bbs[0]);
2364 else if (prop.pp_beacon_bbs[0] && !beacon_light_is_active)
2365 prop.pp_beacon_scene_node[0]->detachAllObjects();
2367 else if (beacon_type ==
'p')
2369 for (
int k = 0; k < 4; k++)
2371 prop.pp_beacon_light[k]->setVisible(beacon_light_is_active && enableLight);
2372 prop.pp_beacon_scene_node[k]->setVisible(beacon_light_is_active);
2373 if (prop.pp_beacon_bbs[k] && beacon_light_is_active && !prop.pp_beacon_scene_node[k]->numAttachedObjects())
2374 prop.pp_beacon_scene_node[k]->attachObject(prop.pp_beacon_bbs[k]);
2375 else if (prop.pp_beacon_bbs[k] && !beacon_light_is_active)
2376 prop.pp_beacon_scene_node[k]->detachAllObjects();
2381 for (
int k = 0; k < 4; k++)
2383 if (prop.pp_beacon_light[k])
2385 prop.pp_beacon_light[k]->setVisible(beacon_light_is_active && enableLight);
2387 if (prop.pp_beacon_scene_node[k])
2389 prop.pp_beacon_scene_node[k]->setVisible(beacon_light_is_active);
2391 if (prop.pp_beacon_bbs[k] && beacon_light_is_active && !prop.pp_beacon_scene_node[k]->numAttachedObjects())
2393 prop.pp_beacon_scene_node[k]->attachObject(prop.pp_beacon_bbs[k]);
2395 else if (prop.pp_beacon_bbs[k] && !beacon_light_is_active)
2397 prop.pp_beacon_scene_node[k]->detachAllObjects();
2408 const float delta_cstate = new_target_cstate - anim.
shifterTarget;
2409 if (delta_cstate != 0)
2417 const float cstate_step = (dt / m_simbuf.simbuf_shifter_anim_time) * anim.
shifterStep;
2440 for (spi = 0; spi < m_simbuf.simbuf_screwprops.size(); spi++)
2442 ctmp += m_simbuf.simbuf_screwprops[spi].simbuf_sp_rudder;
2456 for (spi = 0; spi < m_simbuf.simbuf_screwprops.size(); spi++)
2458 ctmp += m_simbuf.simbuf_screwprops[spi].simbuf_sp_throttle;
2470 if (m_actor->m_num_wheel_diffs > 0)
2472 switch (m_simbuf.simbuf_diff_type)
2496 cstate = (m_simbuf.simbuf_rotation * 57.29578f) / 360.0f;
2501 const bool has_engine = (m_actor->ar_engine!=
nullptr);
2504 float torque = m_simbuf.simbuf_engine_crankfactor;
2507 if (torque >= m_prop_anim_crankfactor_prev)
2508 cstate -= torque / 10.0f;
2512 if (cstate <= -1.0f)
2514 m_prop_anim_crankfactor_prev = torque;
2521 float shifterseq_cstate = 0;
2525 int shifter = m_simbuf.simbuf_gear;
2526 if (shifter > m_prop_anim_prev_gear)
2528 shifterseq_cstate = 1.0f;
2529 m_prop_anim_shift_timer = 0.2f;
2531 if (shifter < m_prop_anim_prev_gear)
2533 shifterseq_cstate = -1.0f;
2534 m_prop_anim_shift_timer = -0.2f;
2536 m_prop_anim_prev_gear = shifter;
2538 if (m_prop_anim_shift_timer > 0.0f)
2540 shifterseq_cstate = 1.0f;
2541 m_prop_anim_shift_timer -= dt;
2542 if (m_prop_anim_shift_timer < 0.0f)
2543 m_prop_anim_shift_timer = 0.0f;
2545 if (m_prop_anim_shift_timer < 0.0f)
2547 shifterseq_cstate = -1.0f;
2548 m_prop_anim_shift_timer += dt;
2549 if (m_prop_anim_shift_timer > 0.0f)
2550 m_prop_anim_shift_timer = 0.0f;
2557 if (m_simbuf.simbuf_commandkey[
int(anim.
lower_limit)].simbuf_cmd_value > 0)
2558 shifterseq_cstate = 1.0f;
2561 if (m_simbuf.simbuf_commandkey[
int(anim.
upper_limit)].simbuf_cmd_value > 0)
2562 shifterseq_cstate = -1.0f;
2566 cstate += UpdateSmoothShift(anim, dt, shifterseq_cstate);
2573 float shifterman1_cstate = 0.f;
2574 int shifter = m_simbuf.simbuf_gear;
2577 shifterman1_cstate = -0.5f;
2579 else if (shifter < 0)
2581 shifterman1_cstate = 1.0f;
2585 shifterman1_cstate = -int((shifter - 1.0) / 2.0);
2588 cstate += UpdateSmoothShift(anim, dt, shifterman1_cstate);
2595 float shifterman2_cstate = 0.f;
2596 int shifter = m_simbuf.simbuf_gear;
2597 shifterman2_cstate = 0.5f;
2600 shifterman2_cstate = 1.0f;
2604 shifterman2_cstate = shifter % 2;
2607 cstate += UpdateSmoothShift(anim, dt, shifterman2_cstate);
2614 float shifterlin_cstate = 0.f;
2615 int shifter = m_simbuf.simbuf_gear;
2616 int numgears = m_simbuf.simbuf_num_gears;
2617 shifterlin_cstate -= (shifter + 2.0) / (numgears + 2.0);
2619 cstate += UpdateSmoothShift(anim, dt, shifterlin_cstate);
2626 float pbrake =
static_cast<float>(m_simbuf.simbuf_parking_brake);
2634 float speedo = m_simbuf.simbuf_wheel_speed / m_simbuf.simbuf_speedo_highest_kph;
2635 cstate -= speedo * 3.0f;
2642 float tacho = m_simbuf.simbuf_engine_rpm / m_simbuf.simbuf_engine_max_rpm;
2650 float turbo = m_simbuf.simbuf_engine_turbo_psi * 3.34;
2651 cstate -= turbo / 67.0f;
2658 float brakes = m_simbuf.simbuf_brake;
2666 float accel = m_simbuf.simbuf_engine_accel;
2667 cstate -= accel + 0.06f;
2675 float clutch = m_simbuf.simbuf_clutch;
2676 cstate -= fabs(1.0f - clutch);
2683 float signal = 0.0f;
2694 if (anim.
animOpt3 > 0.f && anim.
animOpt3 <=
float(m_simbuf.simbuf_aeroengines.size()))
2696 const int aenum = int(anim.
animOpt3 - 1.f);
2700 float pcent = m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_rpmpc;
2702 angle = -5.0 + pcent * 1.9167;
2703 else if (pcent < 110.0)
2704 angle = 110.0 + (pcent - 60.0) * 4.075;
2707 cstate -= angle / 314.0f;
2712 float throttle = m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_throttle;
2721 cstate = m_simbuf.simbuf_aeroengines[aenum].simbuf_tp_aetorque / 120.0f;
2727 cstate = m_simbuf.simbuf_aeroengines[aenum].simbuf_tp_aepitch / 120.0f;
2734 if (!m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_ignition)
2738 if (m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_failed)
2744 const Ogre::Vector3 node0_pos = this->GetSimNodeBuffer()[0].AbsPosition;
2745 const Ogre::Vector3 node0_velo = m_simbuf.simbuf_node0_velo;
2750 float ground_speed_kt = node0_velo.length() * 1.9438;
2751 float altitude = node0_pos.y;
2753 float sea_level_pressure = 101325;
2755 float airpressure = sea_level_pressure * pow(1.0 - 0.0065 * altitude / 288.15, 5.24947);
2756 float airdensity = airpressure * 0.0000120896;
2757 float kt = ground_speed_kt * sqrt(airdensity / 1.225);
2758 cstate -= kt / 100.0f;
2765 float vvi = node0_velo.y * 196.85;
2767 cstate -= vvi / 6000.0f;
2770 if (cstate <= -1.0f)
2781 float altimeter = (node0_pos.y * 1.1811) / 360.0f;
2782 int alti_int = int(altimeter);
2783 float alti_mod = (altimeter - alti_int);
2790 float alti = node0_pos.y * 1.1811 / 3600.0f;
2791 int alti_int = int(alti);
2792 float alti_mod = (alti - alti_int);
2794 if (cstate <= -1.0f)
2801 float alti = node0_pos.y * 1.1811 / 36000.0f;
2803 if (cstate <= -1.0f)
2812 float aoa = m_simbuf.simbuf_wing4_aoa / 25.f;
2813 if ((node0_velo.length() * 1.9438) < 10.0f)
2816 if (cstate <= -1.0f)
2823 Ogre::Vector3 cam_pos = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_pos ].AbsPosition;
2824 Ogre::Vector3 cam_roll = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_roll].AbsPosition;
2825 Ogre::Vector3 cam_dir = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_dir ].AbsPosition;
2830 Ogre::Vector3 rollv = (cam_pos - cam_roll).normalisedCopy();
2831 Ogre::Vector3 dirv = (cam_pos - cam_dir).normalisedCopy();
2832 Ogre::Vector3 upv = dirv.crossProduct(-rollv);
2833 float rollangle = asin(rollv.dotProduct(Ogre::Vector3::UNIT_Y));
2835 rollangle = Ogre::Math::RadiansToDegrees(rollangle);
2838 rollangle = 180.0f - rollangle;
2839 cstate = rollangle / 180.0f;
2843 cstate = cstate - 2.0f;
2850 Ogre::Vector3 dirv = (cam_pos - cam_dir).normalisedCopy();
2851 float pitchangle = asin(dirv.dotProduct(Ogre::Vector3::UNIT_Y));
2853 cstate = (Ogre::Math::RadiansToDegrees(pitchangle) / 90.0f);
2860 float airbrake =
static_cast<float>(m_simbuf.simbuf_airbrake_state);
2862 cstate -= airbrake / 5.0f;
2869 float flaps =
FLAP_ANGLES[m_simbuf.simbuf_aero_flap_state];
2878 int prop_anim_key_index = 0;
2880 for (
Prop& prop: m_props)
2887 for (
PropAnim& anim: prop.pp_animations)
2889 float cstate = 0.0f;
2892 this->CalcPropAnimation(anim, cstate, div, dt);
2897 ROR_ASSERT(prop_anim_key_index < (
int)m_simbuf.simbuf_prop_anim_keys.size());
2898 const bool anim_active = m_simbuf.simbuf_prop_anim_keys[prop_anim_key_index++].simbuf_anim_active;
2899 cstate += (float)anim_active;
2907 cstate += m_actor->ar_dashboard->getNumeric(link_id);
2913 cstate += m_simbuf.simbuf_hydro_dir_state;
2916 cstate += m_simbuf.simbuf_hydro_aileron_state;
2919 cstate += m_simbuf.simbuf_hydro_elevator_state;
2922 cstate += m_simbuf.simbuf_hydro_aero_rudder_state;
2936 float limiter = 0.0f;
2939 float const dt_frac = dt * 2000.f;
2944 prop.pp_rota.x += cstate * dt_frac;
2945 limiter = prop.pp_rota.x;
2949 prop.pp_rota.y += cstate * dt_frac;
2950 limiter = prop.pp_rota.y;
2954 prop.pp_rota.z += cstate * dt_frac;
2955 limiter = prop.pp_rota.z;
2968 bool limiterchanged =
false;
2982 limiterchanged =
true;
2996 limiterchanged =
true;
3002 prop.pp_rota.x = limiter;
3004 prop.pp_rota.y = limiter;
3006 prop.pp_rota.z = limiter;
3014 float offset = 0.0f;
3015 float autooffset = 0.0f;
3018 offset = prop.pp_offset_orig.x;
3020 offset = prop.pp_offset_orig.y;
3022 offset = prop.pp_offset_orig.z;
3028 float const dt_frac = dt * 2000.f;
3029 autooffset = offset + cstate * dt_frac;
3061 prop.pp_offset.x = offset;
3063 prop.pp_offset_orig.x = autooffset;
3067 prop.pp_offset.y = offset;
3069 prop.pp_offset_orig.y = autooffset;
3073 prop.pp_offset.z = offset;
3075 prop.pp_offset_orig.z = autooffset;
3081 rx += prop.pp_rota.x;
3082 ry += prop.pp_rota.y;
3083 rz += prop.pp_rota.z;
3085 prop.pp_rot = Ogre::Quaternion(Ogre::Degree(rz), Ogre::Vector3::UNIT_Z) *
3086 Ogre::Quaternion(Ogre::Degree(ry), Ogre::Vector3::UNIT_Y) *
3087 Ogre::Quaternion(Ogre::Degree(rx), Ogre::Vector3::UNIT_X);
3093 std::sort(m_flexbodies.begin(), m_flexbodies.end(), [](
FlexBody* a,
FlexBody* b) { return a->getVertexCount() > b->getVertexCount(); });
3098 m_flexbody_tasks.clear();
3103 const bool visible = (fb->fb_camera_mode_active ==
CAMERA_MODE_ALWAYS_VISIBLE || fb->fb_camera_mode_active == m_simbuf.simbuf_cur_cinecam);
3104 fb->setVisible(visible);
3107 if (fb->isVisible())
3109 auto func = std::function<void()>([fb]()
3111 fb->computeFlexbody();
3114 m_flexbody_tasks.push_back(task_handle);
3131 fb->setVisible(visible);
3137 for (
auto& task: m_flexbody_tasks)
3143 if (fb->isVisible())
3145 fb->updateFlexbodyVertexBuffers();
3173 int num_flares =
static_cast<int>(m_actor->ar_flares.size());
3174 for (
int i=0; i<num_flares; ++i)
3176 flare_t& flare = m_actor->ar_flares[i];
3184 this->SetMaterialFlareOn(i, flare.
intensity > 0.3);
3199 float vlen = vdir.length();
3203 flare.
snode->setVisible(
false);
3208 float amplitude = normal.dotProduct(vdir);
3209 flare.
snode->setPosition(mposition - 0.1 * amplitude * normal * flare.
offsetz);
3210 flare.
snode->setDirection(normal);
3219 flare.
light->setPosition(mposition - 0.2 * amplitude * normal);
3221 flare.
light->setDirection(-normal - Ogre::Vector3(0, 0.2, 0));
3227 flare.
bbs->setDefaultDimensions(amplitude * fsize, amplitude * fsize);
3228 flare.
snode->setVisible(
true);
3232 flare.
snode->setVisible(
false);
3241 if (m_cab_scene_node !=
nullptr)
3243 static_cast<Ogre::Entity*
>(m_cab_scene_node->getAttachedObject(0))->setCastShadows(value);
3247 for (
Prop& prop: m_props)
3249 if (prop.pp_mesh_obj !=
nullptr && prop.pp_mesh_obj->getEntity())
3250 prop.pp_mesh_obj->getEntity()->setCastShadows(value);
3251 if (prop.pp_wheel_mesh_obj !=
nullptr && prop.pp_wheel_mesh_obj->getEntity())
3252 prop.pp_wheel_mesh_obj->getEntity()->setCastShadows(value);
3258 static_cast<Ogre::Entity*
>(wheel.wx_scenenode->getAttachedObject(0))->setCastShadows(value);
3262 for (
BeamGfx& rod: m_gfx_beams)
3264 static_cast<Ogre::Entity*
>(rod.rod_scenenode->getAttachedObject(0))->setCastShadows(value);
3270 fb->setFlexbodyCastShadow(value);
3276 m_cab_mesh = flexobj;
3278 m_cab_scene_node = snode;
3283 if (m_cab_entity !=
nullptr)
3285 m_cab_entity->setVisible(visible);
3287 this->SetWheelsVisible(visible);
3288 this->SetPropsVisible(visible);
3289 this->SetFlexbodyVisible(visible);
3290 this->SetWingsVisible(visible);
3291 this->SetRodsVisible(visible);
3292 this->SetAeroEnginesVisible(visible);
3297 for (
int i = 0; i < m_actor->ar_num_wings; ++i)
3299 m_actor->ar_wings[i].cnode->setVisible(visible);
3302 for (
size_t i=0; i< m_actor->ar_airbrakes.size(); ++i)
3304 m_gfx_airbrakes[i].abx_scenenode->setVisible(visible);
3310 for (
int i = 0; i < m_actor->ar_num_wings; ++i)
3312 wing_t& wing = m_actor->ar_wings[i];
3324 for (
NodeGfx& nfx : m_gfx_nodes)
3326 if (nfx.nx_node_idx == nodenum)
3328 nfx.nx_is_hot = value;
3335 auto itor = m_gfx_beams.begin();
3336 auto endi = m_gfx_beams.end();
3337 while (itor != endi)
3339 if (itor->rod_beam_index == beam_index)
3342 if (itor->rod_scenenode)
3344 if (itor->rod_scenenode->getAttachedObject(0))
3346 Ogre::Entity* ent =
static_cast<Ogre::Entity*
>(itor->rod_scenenode->getAttachedObject(0));
3349 ent->detachFromParent();
3355 itor->rod_scenenode =
nullptr;
3359 m_gfx_beams.erase(itor);