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)
288 for (std::vector<Exhaust>::iterator it = m_exhausts.begin(); it != m_exhausts.end(); it++)
294 it->smokeNode->removeAndDestroyAllChildren();
299 it->smoker->removeAllAffectors();
300 it->smoker->removeAllEmitters();
307 m_actor->ar_instance_id, m_actor->ar_net_stream_id, m_actor->ar_filename, std::distance(m_exhausts.begin(), it), m_exhausts.size()),
HANDLEGENERICEXCEPTION_LOGFILE);
312 for (
int i = 0; i < (int)m_cparticles.size(); i++)
316 if (m_cparticles[i].snode)
318 m_cparticles[i].snode->removeAndDestroyAllChildren();
321 if (m_cparticles[i].psys)
323 m_cparticles[i].psys->removeAllAffectors();
324 m_cparticles[i].psys->removeAllEmitters();
345 if (entry.flare_index != flare_index)
350 const int num_techniques =
static_cast<int>(entry.mat_instance->getNumTechniques());
351 for (
int i = 0; i < num_techniques; i++)
353 Ogre::Technique* tech = entry.mat_instance->getTechnique(i);
357 if (tech->getSchemeName() ==
"glow")
361 Ogre::Pass* p = tech->getPass(0);
367 p->setSelfIllumination(entry.emissive_color);
368 p->setAmbient(Ogre::ColourValue::White);
369 p->setDiffuse(Ogre::ColourValue::White);
373 p->setSelfIllumination(Ogre::ColourValue::ZERO);
374 p->setAmbient(Ogre::ColourValue::Black);
375 p->setDiffuse(Ogre::ColourValue::Black);
381 Ogre::Pass* p = tech->getPass(0);
385 Ogre::TextureUnitState* tus = p->getTextureUnitState(0);
389 if (tus->getNumFrames() < 2)
392 int frame = state_on ? 1 : 0;
394 tus->setCurrentFrame(frame);
397 p->setSelfIllumination(entry.emissive_color);
399 p->setSelfIllumination(Ogre::ColourValue::ZERO);
408 m_cab_mat_visual = mat;
409 m_cab_mat_visual_trans = mat_trans;
411 if (mat->getTechnique(0)->getNumPasses() == 1)
414 m_cab_mat_template_emissive = mat->clone(
"CabMaterialEmissive-" + mat->getName(),
true, m_custom_resource_group);
416 m_cab_mat_template_plain = mat->clone(
"CabMaterialPlain-" + mat->getName(),
true, m_custom_resource_group);
417 m_cab_mat_template_plain->getTechnique(0)->removePass(1);
418 m_cab_mat_template_plain->compile();
423 if (!m_cab_mat_template_emissive)
429 Ogre::MaterialPtr template_mat = (state_on) ? m_cab_mat_template_emissive : m_cab_mat_template_plain;
430 Ogre::Technique* dest_tech = m_cab_mat_visual->getTechnique(0);
431 Ogre::Technique* templ_tech = template_mat->getTechnique(0);
432 dest_tech->removeAllPasses();
433 for (
unsigned short i = 0; i < templ_tech->getNumPasses(); ++i)
435 Ogre::Pass* templ_pass = templ_tech->getPass(i);
436 Ogre::Pass* dest_pass = dest_tech->createPass();
437 *dest_pass = *templ_pass;
439 m_cab_mat_visual->compile();
444 if (state == m_vidcam_state)
452 if (vidcam.vcam_render_target !=
nullptr)
454 vidcam.vcam_render_target->setActive(enable);
456 vidcam.vcam_material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(vidcam.vcam_render_tex->getName());
458 vidcam.vcam_material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(vidcam.vcam_off_tex_name);
462 if (vidcam.vcam_render_window !=
nullptr)
464 vidcam.vcam_render_window->setActive(enable);
467 m_vidcam_state = state;
482 sky->NotifySkyCameraChanged(vidcam.vcam_ogre_camera);
490 float mirror_angle = 0.f;
491 Ogre::Vector3 offset(Ogre::Vector3::ZERO);
494 mirror_angle = m_actor->ar_left_mirror_angle;
495 offset = Ogre::Vector3(0.07f, -0.22f, 0);
499 mirror_angle = m_actor->ar_right_mirror_angle;
500 offset = Ogre::Vector3(0.07f, +0.22f, 0);
503 Ogre::Vector3 normal = vidcam.vcam_prop_scenenode->getOrientation()
504 * Ogre::Vector3(cos(mirror_angle), sin(mirror_angle), 0.0f);
505 Ogre::Vector3 center = vidcam.vcam_prop_scenenode->getPosition()
506 + vidcam.vcam_prop_scenenode->getOrientation() * offset;
507 Ogre::Radian roll = Ogre::Degree(360)
508 - Ogre::Radian(asin(m_actor->getDirection().dotProduct(Ogre::Vector3::UNIT_Y)));
510 Ogre::Plane plane = Ogre::Plane(normal, center);
511 Ogre::Vector3 project = plane.projectVector(
App::GetCameraManager()->GetCameraNode()->getPosition() - center);
513 vidcam.vcam_ogre_camera->getParentSceneNode()->setPosition(center);
514 vidcam.vcam_ogre_camera->getParentSceneNode()->lookAt(
App::GetCameraManager()->GetCameraNode()->getPosition() - 2.0f * project, Ogre::Node::TS_WORLD);
516 vidcam.vcam_ogre_camera->setNearClipDistance(1);
522 if (vidcam.vcam_render_target !=
nullptr)
523 vidcam.vcam_render_target->update();
525 if (vidcam.vcam_render_window !=
nullptr)
526 vidcam.vcam_render_window->update();
529 const Ogre::Vector3 abs_pos_center = m_simbuf.simbuf_nodes[vidcam.vcam_node_center].AbsPosition;
530 const Ogre::Vector3 abs_pos_z = m_simbuf.simbuf_nodes[vidcam.vcam_node_dir_z].AbsPosition;
531 const Ogre::Vector3 abs_pos_y = m_simbuf.simbuf_nodes[vidcam.vcam_node_dir_y].AbsPosition;
532 Ogre::Vector3 normal = (-(abs_pos_center - abs_pos_z)).crossProduct(-(abs_pos_center - abs_pos_y));
536 Ogre::Vector3 pos = m_simbuf.simbuf_nodes[vidcam.vcam_node_alt_pos].AbsPosition +
537 (vidcam.vcam_pos_offset.x * normal) +
538 (vidcam.vcam_pos_offset.y * (abs_pos_center - abs_pos_y)) +
539 (vidcam.vcam_pos_offset.z * (abs_pos_center - abs_pos_z));
544 Ogre::Vector3 frustumUP = abs_pos_center - abs_pos_y;
545 frustumUP.normalise();
546 vidcam.vcam_ogre_camera->getParentSceneNode()->setFixedYawAxis(
true, frustumUP);
551 normal = vidcam.vcam_rotation * normal;
558 Ogre::Vector3 refx = abs_pos_z - abs_pos_center;
560 Ogre::Vector3 refy = abs_pos_center - abs_pos_y;
562 Ogre::Quaternion rot = Ogre::Quaternion(-refx, -refy, -normal);
563 vidcam.vcam_ogre_camera->getParentSceneNode()->setOrientation(rot * vidcam.vcam_rotation);
568 normal = m_simbuf.simbuf_nodes[vidcam.vcam_node_lookat].AbsPosition - pos;
570 Ogre::Vector3 refx = abs_pos_z - abs_pos_center;
574 Ogre::Vector3 refy = refx.crossProduct(normal);
576 Ogre::Quaternion rot = Ogre::Quaternion(-refx, -refy, -normal);
577 vidcam.vcam_ogre_camera->getParentSceneNode()->setOrientation(rot * vidcam.vcam_rotation);
580 if (vidcam.vcam_debug_node !=
nullptr)
582 vidcam.vcam_debug_node->setPosition(pos);
583 vidcam.vcam_debug_node->setOrientation(vidcam.vcam_ogre_camera->getParentSceneNode()->getOrientation());
587 vidcam.vcam_ogre_camera->getParentSceneNode()->setPosition(pos);
593 float water_height = 0.f;
599 for (
NodeGfx& nfx: m_gfx_nodes)
601 const node_t& n = m_actor->ar_nodes[nfx.nx_node_idx];
604 if (nfx.nx_may_get_wet && !nfx.nx_no_particles)
609 nfx.nx_wet_time_sec = 0.f;
613 if (nfx.nx_wet_time_sec != -1)
615 nfx.nx_wet_time_sec += dt;
616 if (nfx.nx_wet_time_sec > 5.f)
618 nfx.nx_wet_time_sec = -1.f;
620 else if (nfx.nx_may_get_wet)
622 if (m_particles_drip !=
nullptr)
626 if (nfx.nx_is_hot && m_particles_dust !=
nullptr)
639 if (m_particles_splash)
643 if (m_particles_ripple)
656 if (m_particles_dust !=
nullptr)
663 if (m_particles_clump !=
nullptr && n.
Velocity.squaredLength() > 1.f)
672 const float SMOKE_THRESHOLD = 8.f;
673 const float SCREECH_THRESHOLD = 5.f;
686 else if (!nfx.nx_no_sparks)
731 ImVec2 screen_size = ImGui::GetIO().DisplaySize;
740 Ogre::Vector3 pos_xyz = world2screen.
Convert(m_actor->getPosition());
743 ImVec2 pos(pos_xyz.x, pos_xyz.y);
746 for (
int i = 0; i < m_actor->ar_num_nodes; ++i)
748 radius = std::max(radius, pos_xyz.distance(world2screen.
Convert(m_actor->ar_nodes[i].AbsPosition)));
751 drawlist->AddCircleFilled(pos, radius * 1.05f, 0x22222222, 36);
761 const beam_t* beams = m_actor->ar_beams;
762 const size_t num_beams =
static_cast<size_t>(m_actor->ar_num_beams);
763 for (
size_t i = 0; i < num_beams; ++i)
770 Ogre::Vector3 pos1 = world2screen.
Convert(beams[i].p1->AbsPosition);
771 Ogre::Vector3 pos2 = world2screen.
Convert(beams[i].p2->AbsPosition);
773 if ((pos1.z < 0.f) && (pos2.z < 0.f))
775 ImVec2 pos1xy(pos1.x, pos1.y);
776 ImVec2 pos2xy(pos2.x, pos2.y);
778 if (beams[i].bm_broken)
787 if (!beams[i].bm_disabled)
797 if (beams[i].stress > 0)
799 float stress_ratio = pow(beams[i].stress / beams[i].maxposstress, 2.0f);
800 float s = std::min(stress_ratio, 1.0f);
801 color = Ogre::ColourValue(0.2f * (1 + 2.0f * s), 0.4f * (1.0f - s), 0.33f, 1.0f).getAsABGR();
803 else if (beams[i].stress < 0)
805 float stress_ratio = pow(beams[i].stress / beams[i].maxnegstress, 2.0f);
806 float s = std::min(stress_ratio, 1.0f);
807 color = Ogre::ColourValue(0.2f, 0.4f * (1.0f - s), 0.33f * (1 + 1.0f * s), 1.0f).getAsABGR();
819 const size_t num_nodes =
static_cast<size_t>(m_actor->ar_num_nodes);
820 for (
size_t i = 0; i < num_nodes; ++i)
825 Ogre::Vector3 pos_xyz = world2screen.
Convert(
nodes[i].AbsPosition);
829 ImVec2 pos(pos_xyz.x, pos_xyz.y);
830 if (
nodes[i].nd_immovable)
844 for (
size_t i = 0; i < num_nodes; ++i)
847 (
nodes[i].nd_tyre_node ||
nodes[i].nd_rim_node))
850 Ogre::Vector3 pos = world2screen.
Convert(
nodes[i].AbsPosition);
854 ImVec2 pos_xy(pos.x, pos.y);
856 id_buf <<
nodes[i].pos;
862 snprintf(mass_buf, 50,
"|%.1fKg",
nodes[i].mass);
863 ImVec2 offset = ImGui::CalcTextSize(id_buf.
ToCStr());
874 for (
size_t i = 0; i < num_beams; ++i)
883 Ogre::Vector3 pos_xyz = world2screen.
Convert(world_pos);
884 if (pos_xyz.z >= 0.f)
888 ImVec2 pos(pos_xyz.x, pos_xyz.y);
891 const size_t BUF_LEN = 50;
893 if (beams[i].strength >= 1000000000000.f)
895 snprintf(buf, BUF_LEN,
"%.1fT", (beams[i].strength / 1000000000000.f));
897 else if (beams[i].strength >= 1000000000.f)
899 snprintf(buf, BUF_LEN,
"%.1fG", (beams[i].strength / 1000000000.f));
901 else if (beams[i].strength >= 1000000.f)
903 snprintf(buf, BUF_LEN,
"%.1fM", (beams[i].strength / 1000000.f));
905 else if (beams[i].strength >= 1000.f)
907 snprintf(buf, BUF_LEN,
"%.1fK", (beams[i].strength / 1000.f));
911 snprintf(buf, BUF_LEN,
"%.1f", beams[i].strength);
913 const ImVec2 stren_text_size = ImGui::CalcTextSize(buf);
917 snprintf(buf, BUF_LEN,
"|%.1f", beams[i].stress);
924 const wheel_t* wheels = m_actor->ar_wheels;
925 const size_t num_wheels =
static_cast<size_t>(m_actor->ar_num_wheels);
926 for (
int i = 0; i < num_wheels; i++)
933 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_axis_node_1->AbsPosition);
934 if (pos1_xyz.z < 0.f)
936 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
939 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_axis_node_0->AbsPosition);
940 if (pos2_xyz.z < 0.f)
942 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
945 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
947 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
948 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
953 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
956 float v = ImGui::GetTextLineHeightWithSpacing();
957 ImVec2 pos(pos_xyz.x, pos_xyz.y);
959 wheel_id_buf <<
"Id: " << (i + 1);
960 float h1 = ImGui::CalcTextSize(wheel_id_buf.
ToCStr()).x / 2.0f;
963 rpm_buf <<
"Speed: " <<
static_cast<int>(
Round(wheels[i].debug_rpm)) <<
" rpm";
964 float h2 = ImGui::CalcTextSize(rpm_buf.
ToCStr()).x / 2.0f;
967 torque_buf <<
"Torque: " <<
static_cast<int>(
Round(wheels[i].debug_torque)) <<
" Nm";
968 float h3 = ImGui::CalcTextSize(torque_buf.
ToCStr()).x / 2.0f;
977 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
978 if (pos1_xyz.z < 0.f)
980 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
983 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
984 if (pos2_xyz.z < 0.f)
986 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
989 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
991 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
992 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
997 Ogre::Vector3 radius = Ogre::Plane(axis, wheels[i].wh_near_attach_node->RelPosition).projectVector(rradius);
1002 Ogre::Vector3 up = axis.crossProduct(radius);
1003 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius - up);
1004 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius + up);
1005 Ogre::Vector3 pos3_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition - radius + up);
1006 Ogre::Vector3 pos4_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition - radius - up);
1007 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1009 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1010 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1011 ImVec2 pos3xy(pos3_xyz.x, pos3_xyz.y);
1012 ImVec2 pos4xy(pos4_xyz.x, pos4_xyz.y);
1013 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, 0x22888888);
1019 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
1020 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius);
1021 Ogre::Vector3 pos3_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
1022 if (pos2_xyz.z < 0.f)
1024 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
1027 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1029 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1030 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1033 if ((pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1035 ImVec2 pos1xy(pos2_xyz.x, pos2_xyz.y);
1036 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1044 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
1045 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition - cforce);
1046 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1048 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1049 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1054 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
1055 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + cforce);
1056 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1058 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1059 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1069 Ogre::Vector3 u = - axis.crossProduct(m_simbuf.simbuf_direction);
1070 if (!wheels[i].debug_force.isZeroLength())
1074 Ogre::Vector3 f = axis.crossProduct(u);
1075 Ogre::Vector3 a = - axis *
w + f * std::max(
w, wheels[i].wh_radius * 0.5f);
1076 Ogre::Vector3 b = + axis *
w + f * std::max(
w, wheels[i].wh_radius * 0.5f);
1077 Ogre::Vector3 c = + axis *
w - f * std::max(
w, wheels[i].wh_radius * 0.5f);
1078 Ogre::Vector3 d = - axis *
w - f * std::max(
w, wheels[i].wh_radius * 0.5f);
1079 Ogre::Quaternion r = Ogre::Quaternion::IDENTITY;
1080 if (wheels[i].debug_vel.length() > 1.0f)
1082 r = Ogre::Quaternion(f.angleBetween(wheels[i].
debug_vel), u);
1084 Ogre::Vector3 pos1_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * a);
1085 Ogre::Vector3 pos2_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * b);
1086 Ogre::Vector3 pos3_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * c);
1087 Ogre::Vector3 pos4_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * d);
1088 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1090 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1091 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1092 ImVec2 pos3xy(pos3_xyz.x, pos3_xyz.y);
1093 ImVec2 pos4xy(pos4_xyz.x, pos4_xyz.y);
1094 if (!wheels[i].debug_force.isZeroLength())
1097 float wheelv = wheels[i].
debug_vel.length();
1098 float slip_ratio = std::min(slipv, wheelv) / std::max(1.0f, wheelv);
1099 float scale = pow(slip_ratio, 2);
1100 ImU32 col = Ogre::ColourValue(scale, 1.0f - scale, 0.0f, 0.2f).getAsABGR();
1101 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, col);
1105 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, 0x55555555);
1111 if (!wheels[i].debug_vel.isZeroLength())
1115 Ogre::Vector3 d = axis.crossProduct(m_simbuf.simbuf_direction) * wheels[i].
wh_radius;
1116 Ogre::Real slipv = wheels[i].
debug_slip.length();
1117 Ogre::Real wheelv = wheels[i].
debug_vel.length();
1118 Ogre::Vector3 s = wheels[i].
debug_slip * (std::min(slipv, wheelv) / std::max(1.0f, wheelv)) / slipv;
1119 Ogre::Vector3 pos1_xyz = world2screen.
Convert(m + d);
1120 Ogre::Vector3 pos2_xyz = world2screen.
Convert(m + d + s * std::max(
w, wheels[i].wh_radius * 0.5f));
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);
1132 Ogre::Real mass = m_actor->getTotalMass(
false) * num_wheels;
1133 Ogre::Vector3 normalised_force = wheels[i].
debug_force.normalisedCopy() * std::min(f / mass, 1.0f);
1135 Ogre::Vector3 pos5_xyz = world2screen.
Convert(m);
1136 Ogre::Vector3 pos6_xyz = world2screen.
Convert(m + normalised_force * wheels[i].wh_radius);
1137 if ((pos5_xyz.z < 0.f) && (pos6_xyz.z < 0.f))
1139 ImVec2 pos1xy(pos5_xyz.x, pos5_xyz.y);
1140 ImVec2 pos2xy(pos6_xyz.x, pos6_xyz.y);
1148 const beam_t* beams = m_actor->ar_beams;
1149 const size_t num_beams =
static_cast<size_t>(m_actor->ar_num_beams);
1150 std::set<int> node_ids;
1151 for (
size_t i = 0; i < num_beams; ++i)
1155 if (!(beams[i].bounded ==
SHOCK1 || beams[i].bounded ==
SHOCK2 || beams[i].bounded ==
SHOCK3))
1158 Ogre::Vector3 pos1_xyz = world2screen.
Convert(beams[i].p1->AbsPosition);
1159 Ogre::Vector3 pos2_xyz = world2screen.
Convert(beams[i].p2->AbsPosition);
1161 if (pos1_xyz.z < 0.f)
1163 node_ids.insert(beams[i].p1->pos);
1165 if (pos2_xyz.z < 0.f)
1167 node_ids.insert(beams[i].p2->pos);
1170 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1172 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1173 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1180 for (
auto id : node_ids)
1182 Ogre::Vector3 pos_xyz = world2screen.
Convert(m_actor->ar_nodes[
id].AbsPosition);
1183 if (pos_xyz.z < 0.f)
1185 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1193 for (
size_t i = 0; i < num_beams; ++i)
1197 if (!(beams[i].bounded ==
SHOCK1 || beams[i].bounded ==
SHOCK2 || beams[i].bounded ==
SHOCK3))
1200 Ogre::Vector3 pos1_xyz = world2screen.
Convert(beams[i].p1->AbsPosition);
1201 Ogre::Vector3 pos2_xyz = world2screen.
Convert(beams[i].p2->AbsPosition);
1202 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
1204 if (pos_xyz.z < 0.f)
1207 float diff = beams[i].
p1->
AbsPosition.distance(beams[i].p2->AbsPosition) - beams[i].
L;
1208 ImU32 text_color = (diff < 0.0f) ? 0xff66ee66 : 0xff8888ff;
1209 float bound = (diff < 0.0f) ? beams[i].shortbound : beams[i].longbound;
1210 float ratio = Ogre::Math::Clamp(diff / (bound * beams[i].L), -2.0f, +2.0f);
1212 float v = ImGui::GetTextLineHeightWithSpacing();
1213 ImVec2 pos(pos_xyz.x, pos_xyz.y - v - v);
1215 len_buf <<
"L: " <<
static_cast<int>(
Round(std::abs(ratio) * 100.0f)) <<
" %";
1216 float h1 = ImGui::CalcTextSize(len_buf.
ToCStr()).x / 2.0f;
1217 drawlist->AddText(ImVec2(pos.x - h1, pos.y), text_color, len_buf.
ToCStr());
1219 spring_buf <<
"S: " <<
static_cast<int>(
Round(beams[i].debug_k)) <<
" N";
1220 float h2 = ImGui::CalcTextSize(spring_buf.
ToCStr()).x / 2.0f;
1221 drawlist->AddText(ImVec2(pos.x - h2, pos.y + v), text_color, spring_buf.
ToCStr());
1223 damp_buf <<
"D: " <<
static_cast<int>(
Round(beams[i].debug_d)) <<
" N";
1224 float h3 = ImGui::CalcTextSize(damp_buf.
ToCStr()).x / 2.0f;
1225 drawlist->AddText(ImVec2(pos.x - h3, pos.y + v + v), text_color, damp_buf.
ToCStr());
1227 snprintf(vel_buf, 25,
"V: %.2f m/s", beams[i].debug_v);
1228 float h4 = ImGui::CalcTextSize(vel_buf).x / 2.0f;
1229 drawlist->AddText(ImVec2(pos.x - h4, pos.y + v + v + v), text_color, vel_buf);
1236 const rotator_t* rotators = m_actor->ar_rotators;
1237 const size_t num_rotators =
static_cast<size_t>(m_actor->ar_num_rotators);
1238 for (
int i = 0; i < num_rotators; i++)
1240 Ogre::Vector3 pos1_xyz = world2screen.
Convert(
nodes[rotators[i].axis1].AbsPosition);
1241 Ogre::Vector3 pos2_xyz = world2screen.
Convert(
nodes[rotators[i].axis2].AbsPosition);
1245 if (pos1_xyz.z < 0.f)
1247 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
1253 if (pos2_xyz.z < 0.f)
1255 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
1261 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1263 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1264 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1269 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
1270 if (pos_xyz.z < 0.f)
1272 float v = ImGui::GetTextLineHeightWithSpacing();
1273 ImVec2 pos(pos_xyz.x, pos_xyz.y);
1275 rotator_id_buf <<
"Id: " << (i + 1);
1276 float h1 = ImGui::CalcTextSize(rotator_id_buf.
ToCStr()).x / 2.0f;
1279 snprintf(angle_buf, 25,
"Rate: %.1f rpm", 60.0f * rotators[i].debug_rate / Ogre::Math::TWO_PI);
1280 float h2 = ImGui::CalcTextSize(angle_buf).x / 2.0f;
1281 drawlist->AddText(ImVec2(pos.x - h2, pos.y + v),
NODE_TEXT_COLOR, angle_buf);
1282 char aerror_buf[25];
1283 snprintf(aerror_buf, 25,
"Error: %.1f mrad", 1000.0f * std::abs(rotators[i].debug_aerror));
1284 float h3 = ImGui::CalcTextSize(aerror_buf).x / 2.0f;
1285 drawlist->AddText(ImVec2(pos.x - h3, pos.y + v + v),
NODE_TEXT_COLOR, aerror_buf);
1290 for (
int j = 0; j < 4; j++)
1294 ImU32 node_color = Ogre::ColourValue(0.33f, 0.33f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1295 ImU32 beam_color = Ogre::ColourValue(0.33f, 0.33f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1297 Ogre::Vector3 pos3_xyz = world2screen.
Convert(
nodes[rotators[i].nodes1[j]].AbsPosition);
1298 if (pos3_xyz.z < 0.f)
1300 ImVec2 pos(pos3_xyz.x, pos3_xyz.y);
1301 drawlist->AddCircleFilled(pos,
NODE_RADIUS, node_color);
1306 if ((pos1_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1308 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1309 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1315 ImU32 node_color = Ogre::ColourValue(1.00f, 0.87f, 0.27f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1316 ImU32 beam_color = Ogre::ColourValue(0.88f, 0.64f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1318 Ogre::Vector3 pos3_xyz = world2screen.
Convert(
nodes[rotators[i].nodes2[j]].AbsPosition);
1319 if (pos3_xyz.z < 0.f)
1321 ImVec2 pos(pos3_xyz.x, pos3_xyz.y);
1322 drawlist->AddCircleFilled(pos,
NODE_RADIUS, node_color);
1327 if ((pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1329 ImVec2 pos1xy(pos2_xyz.x, pos2_xyz.y);
1330 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1338 Ogre::Vector3 mid =
nodes[rotators[i].
axis1].AbsPosition.midPoint(
nodes[rotators[i].axis2].AbsPosition);
1339 Ogre::Vector3 axis =
nodes[rotators[i].
axis1].RelPosition -
nodes[rotators[i].
axis2].RelPosition;
1340 Ogre::Vector3 perp = axis.perpendicular();
1343 const int steps = 64;
1344 Ogre::Plane plane = Ogre::Plane(axis, mid);
1346 Ogre::Real radius1 = 0.0f;
1347 Ogre::Real offset1 = 0.0f;
1348 for (
int k = 0; k < 2; k++)
1351 Ogre::Real r = plane.projectVector(r1).length();
1355 offset1 = plane.getDistance(
nodes[rotators[i].nodes1[k]].AbsPosition);
1358 std::vector<ImVec2> pos1_xy;
1359 for (
int k = 0; k < steps; k++)
1361 Ogre::Quaternion rotation(Ogre::Radian(((
float)k / steps) * Ogre::Math::TWO_PI), axis);
1362 Ogre::Vector3 pos_xyz = world2screen.
Convert(mid + axis * offset1 + rotation * perp * radius1);
1363 if (pos_xyz.z < 0.f)
1365 pos1_xy.push_back(ImVec2(pos_xyz.x, pos_xyz.y));
1368 if (!pos1_xy.empty())
1370 drawlist->AddConvexPolyFilled(pos1_xy.data(),
static_cast<int>(pos1_xy.size()), 0x33666666);
1373 Ogre::Real radius2 = 0.0f;
1374 Ogre::Real offset2 = 0.0f;
1375 for (
int k = 0; k < 2; k++)
1378 Ogre::Real r = plane.projectVector(r2).length();
1382 offset2 = plane.getDistance(
nodes[rotators[i].nodes2[k]].AbsPosition);
1385 std::vector<ImVec2> pos2_xy;
1386 for (
int k = 0; k < steps; k++)
1388 Ogre::Quaternion rotation(Ogre::Radian(((
float)k / steps) * Ogre::Math::TWO_PI), axis);
1389 Ogre::Vector3 pos_xyz = world2screen.
Convert(mid + axis * offset2 + rotation * perp * radius2);
1390 if (pos_xyz.z < 0.f)
1392 pos2_xy.push_back(ImVec2(pos_xyz.x, pos_xyz.y));
1395 if (!pos2_xy.empty())
1397 drawlist->AddConvexPolyFilled(pos2_xy.data(),
static_cast<int>(pos2_xy.size()), 0x1155a3e0);
1400 for (
int k = 0; k < 2; k++)
1403 Ogre::Vector3 ref1 = plane.projectVector(
nodes[rotators[i].nodes1[k]].AbsPosition - mid);
1404 Ogre::Vector3 th1 = Ogre::Quaternion(Ogre::Radian(rotators[i].angle), axis) * ref1;
1406 Ogre::Vector3 pos1_xyz = world2screen.
Convert(mid + axis * offset1);
1407 Ogre::Vector3 pos2_xyz = world2screen.
Convert(mid + axis * offset1 + th1);
1408 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1410 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1411 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1416 Ogre::Vector3 ref2 = plane.projectVector(
nodes[rotators[i].nodes2[k]].AbsPosition - mid);
1418 Ogre::Vector3 pos1_xyz = world2screen.
Convert(mid + axis * offset2);
1419 Ogre::Vector3 pos2_xyz = world2screen.
Convert(mid + axis * offset2 + ref2);
1420 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1422 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1423 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1429 Ogre::Real radius = std::min(radius1, radius2);
1430 Ogre::Vector3 pos3_xyz = world2screen.
Convert(mid + axis * offset1 + th1 * radius);
1431 Ogre::Vector3 pos4_xyz = world2screen.
Convert(mid + axis * offset2 + th1 * radius);
1432 if ((pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1434 ImVec2 pos1xy(pos3_xyz.x, pos3_xyz.y);
1435 ImVec2 pos2xy(pos4_xyz.x, pos4_xyz.y);
1445 std::set<int> node_ids;
1446 for (
auto railgroup : m_actor->m_railgroups)
1448 for (
auto railsegment : railgroup->rg_segments)
1450 Ogre::Vector3 pos1 = world2screen.
Convert(railsegment.rs_beam->p1->AbsPosition);
1451 Ogre::Vector3 pos2 = world2screen.
Convert(railsegment.rs_beam->p2->AbsPosition);
1455 node_ids.insert(railsegment.rs_beam->p1->pos);
1459 node_ids.insert(railsegment.rs_beam->p2->pos);
1461 if ((pos1.z < 0.f) && (pos2.z < 0.f))
1463 ImVec2 pos1xy(pos1.x, pos1.y);
1464 ImVec2 pos2xy(pos2.x, pos2.y);
1470 for (
auto id : node_ids)
1472 Ogre::Vector3 pos_xyz = world2screen.
Convert(
nodes[
id].AbsPosition);
1473 if (pos_xyz.z < 0.f)
1475 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1483 for (
auto slidenode : m_actor->m_slidenodes)
1485 auto id = slidenode.GetSlideNodeId();
1486 Ogre::Vector3 pos_xyz = world2screen.
Convert(
nodes[
id].AbsPosition);
1488 if (pos_xyz.z < 0.f)
1490 ImVec2 pos(pos_xyz.x, pos_xyz.y);
1502 const auto cabs = m_actor->ar_cabs;
1503 const auto num_cabs = m_actor->ar_num_cabs;
1504 const auto buoycabs = m_actor->ar_buoycabs;
1505 const auto num_buoycabs = m_actor->ar_num_buoycabs;
1506 const auto collcabs = m_actor->ar_collcabs;
1507 const auto num_collcabs = m_actor->ar_num_collcabs;
1509 std::vector<std::pair<float, int>> render_cabs;
1510 for (
int i = 0; i < num_cabs; i++)
1512 Ogre::Vector3 pos1_xyz = world2screen.
Convert(
nodes[cabs[i*3+0]].AbsPosition);
1513 Ogre::Vector3 pos2_xyz = world2screen.
Convert(
nodes[cabs[i*3+1]].AbsPosition);
1514 Ogre::Vector3 pos3_xyz = world2screen.
Convert(
nodes[cabs[i*3+2]].AbsPosition);
1515 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1517 float depth = pos1_xyz.z;
1518 depth = std::max(depth, pos2_xyz.z);
1519 depth = std::max(depth, pos3_xyz.z);
1520 render_cabs.push_back({depth, i});
1523 std::sort(render_cabs.begin(), render_cabs.end());
1526 std::vector<int> node_ids;
1527 for (
auto render_cab : render_cabs)
1529 int i = render_cab.second;
1530 bool coll = std::find(collcabs, collcabs + num_collcabs, i) != (collcabs + num_collcabs);
1531 bool buoy = std::find(buoycabs, buoycabs + num_buoycabs, i) != (buoycabs + num_buoycabs);
1533 ImU32 fill_color = Ogre::ColourValue(0.5f * coll, 0.5f * !buoy, 0.5f * (coll ^ buoy), 0.27f).getAsABGR();
1534 ImU32 beam_color = Ogre::ColourValue(0.5f * coll, 0.5f * !buoy, 0.5f * (coll ^ buoy), 0.53f).getAsABGR();
1536 Ogre::Vector3 pos1_xyz = world2screen.
Convert(
nodes[cabs[i*3+0]].AbsPosition);
1537 Ogre::Vector3 pos2_xyz = world2screen.
Convert(
nodes[cabs[i*3+1]].AbsPosition);
1538 Ogre::Vector3 pos3_xyz = world2screen.
Convert(
nodes[cabs[i*3+2]].AbsPosition);
1539 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1541 ImVec2 pos1_xy(pos1_xyz.x, pos1_xyz.y);
1542 ImVec2 pos2_xy(pos2_xyz.x, pos2_xyz.y);
1543 ImVec2 pos3_xy(pos3_xyz.x, pos3_xyz.y);
1544 drawlist->AddTriangleFilled(pos1_xy, pos2_xy, pos3_xy, fill_color);
1545 drawlist->AddTriangle(pos1_xy, pos2_xy, pos3_xy, beam_color,
BEAM_THICKNESS);
1547 for (
int k = 0; k < 3; k++)
1549 int id = cabs[i*3+k];
1550 if (std::find(node_ids.begin(), node_ids.end(),
id) == node_ids.end())
1552 Ogre::Vector3 pos_xyz = world2screen.
Convert(
nodes[
id].AbsPosition);
1553 if (pos_xyz.z < 0.f)
1555 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1556 drawlist->AddCircleFilled(pos_xy,
NODE_RADIUS,
nodes[
id].nd_contacter ? 0xbb0033ff : 0x88888888);
1562 node_ids.push_back(
id);
1572 m_debug_view = m_last_debug_view;
1591 m_last_debug_view = dv;
1597 switch (m_debug_view)
1649 for (
BeamGfx& rod: m_gfx_beams)
1651 rod.rod_scenenode->setVisible(rod.rod_is_visible);
1652 if (!rod.rod_is_visible)
1655 NodeSB* nodes1 = this->GetSimNodeBuffer();
1656 Ogre::Vector3 pos1 = nodes1[rod.rod_node1].
AbsPosition;
1657 NodeSB* nodes2 = rod.rod_target_actor->GetGfxActor()->GetSimNodeBuffer();
1658 Ogre::Vector3 pos2 = nodes2[rod.rod_node2].
AbsPosition;
1661 float beam_diameter =
static_cast<float>(rod.rod_diameter_mm) * 0.001;
1662 float beam_length = pos1.distance(pos2);
1664 rod.rod_scenenode->setPosition(pos1.midPoint(pos2));
1665 rod.rod_scenenode->setScale(beam_diameter, beam_length, beam_diameter);
1675 Ogre::Vector3 v0 = src;
1676 Ogre::Vector3 v1 = dest;
1682 Ogre::Real d = v0.dotProduct(v1);
1686 return Ogre::Quaternion::IDENTITY;
1688 if (d < (1e-6f - 1.0f))
1691 Ogre::Vector3 axis = Ogre::Vector3::UNIT_X.crossProduct(src);
1692 if (axis.isZeroLength())
1693 axis = Ogre::Vector3::UNIT_Y.crossProduct(src);
1695 q.FromAngleAxis(Ogre::Radian(Ogre::Math::PI), axis);
1701 return Ogre::Quaternion::IDENTITY;
1703 Ogre::Vector3 c = v0.crossProduct(v1);
1704 Ogre::Real invs = 1 / s;
1716 for (
BeamGfx& rod: m_gfx_beams)
1718 float diameter2 =
static_cast<float>(rod.rod_diameter_mm) * (ratio*1000.f);
1719 rod.rod_diameter_mm =
static_cast<uint16_t
>(diameter2);
1724 for (
Prop& prop: m_props)
1726 if (prop.pp_scene_node)
1727 prop.pp_scene_node->scale(ratio, ratio, ratio);
1729 if (prop.pp_wheel_scene_node)
1731 prop.pp_wheel_scene_node->scale(ratio, ratio, ratio);
1732 prop.pp_wheel_pos = relpos + (prop.pp_wheel_pos - relpos) * ratio;
1735 if (prop.pp_beacon_scene_node[0])
1736 prop.pp_beacon_scene_node[0]->scale(ratio, ratio, ratio);
1738 if (prop.pp_beacon_scene_node[1])
1739 prop.pp_beacon_scene_node[1]->scale(ratio, ratio, ratio);
1741 if (prop.pp_beacon_scene_node[2])
1742 prop.pp_beacon_scene_node[2]->scale(ratio, ratio, ratio);
1744 if (prop.pp_beacon_scene_node[3])
1745 prop.pp_beacon_scene_node[3]->scale(ratio, ratio, ratio);
1751 m_cab_mesh->ScaleFlexObj(ratio);
1757 if (m_gfx_beams_parent_scenenode ==
nullptr)
1766 if (visible && !m_gfx_beams_parent_scenenode->isInSceneGraph())
1770 else if (!visible && m_gfx_beams_parent_scenenode->isInSceneGraph())
1781 m_simbuf.simbuf_actor_state = m_actor->ar_state;
1782 m_simbuf.simbuf_physics_paused = m_actor->ar_physics_paused;
1783 m_simbuf.simbuf_cur_cinecam = m_actor->ar_current_cinecam;
1784 m_simbuf.simbuf_net_username = m_actor->m_net_username;
1785 m_simbuf.simbuf_net_colornum = m_actor->m_net_color_num;
1786 m_simbuf.simbuf_driveable = m_actor->ar_driveable;
1789 m_simbuf.simbuf_pos = m_actor->getRotationCenter();
1790 m_simbuf.simbuf_node0_velo = m_actor->ar_nodes[0].Velocity;
1791 m_simbuf.simbuf_rotation = m_actor->getRotation();
1792 m_simbuf.simbuf_direction = m_actor->getDirection();
1793 m_simbuf.simbuf_wheel_speed = m_actor->ar_wheel_speed;
1794 m_simbuf.simbuf_top_speed = m_actor->ar_top_speed;
1795 m_simbuf.simbuf_aabb = m_actor->ar_bounding_box;
1796 if (m_actor->ar_num_cameras > 0)
1798 m_simbuf.simbuf_camera0_pos_node = m_actor->ar_camera_node_pos[0];
1799 m_simbuf.simbuf_camera0_roll_node = m_actor->ar_camera_node_roll[0];
1803 m_simbuf.simbuf_nodes.resize(m_actor->ar_num_nodes);
1804 for (
int i = 0; i < m_actor->ar_num_nodes; ++i)
1806 auto node = m_actor->ar_nodes[i];
1807 m_simbuf.simbuf_nodes[i].AbsPosition = node.AbsPosition;
1808 m_simbuf.simbuf_nodes[i].nd_has_contact = node.nd_has_ground_contact || node.nd_has_mesh_contact;
1811 for (
NodeGfx& nx: m_gfx_nodes)
1813 m_simbuf.simbuf_nodes[nx.nx_node_idx].nd_is_wet = (nx.nx_wet_time_sec != -1.f);
1817 for (
BeamGfx& rod: m_gfx_beams)
1819 const beam_t& beam = m_actor->ar_beams[rod.rod_beam_index];
1820 rod.rod_node1 =
static_cast<uint16_t
>(beam.
p1->
pos);
1821 rod.rod_node2 =
static_cast<uint16_t
>(beam.
p2->
pos);
1830 m_simbuf.simbuf_airbrakes.resize(m_actor->ar_airbrakes.size());
1831 for (
size_t i=0; i< m_actor->ar_airbrakes.size(); ++i)
1833 m_simbuf.simbuf_airbrakes[i].simbuf_ab_ratio = m_actor->ar_airbrakes[i]->getRatio();
1839 m_simbuf.simbuf_commandkey[i].simbuf_cmd_value = m_actor->ar_command_key[i].commandValue;
1843 m_simbuf.simbuf_prop_anim_keys.resize(m_actor->m_prop_anim_key_states.size());
1844 for (
size_t i = 0; i < m_actor->m_prop_anim_key_states.size(); ++i)
1846 m_simbuf.simbuf_prop_anim_keys[i].simbuf_anim_active = m_actor->m_prop_anim_key_states[i].anim_active;
1850 m_simbuf.simbuf_aeroengines.resize(m_actor->ar_num_aeroengines);
1851 for (
int i = 0; i < m_actor->ar_num_aeroengines; ++i)
1853 AeroEngine* src = m_actor->ar_aeroengines[i];
1880 m_simbuf.simbuf_hydro_dir_state = m_actor->ar_hydro_dir_state;
1881 m_simbuf.simbuf_brake = m_actor->ar_brake;
1882 if (m_actor->ar_engine !=
nullptr)
1884 m_simbuf.simbuf_has_engine =
true;
1885 m_simbuf.simbuf_gear = m_actor->ar_engine->getGear();
1886 m_simbuf.simbuf_autoshift = m_actor->ar_engine->getAutoShift();
1887 m_simbuf.simbuf_engine_rpm = m_actor->ar_engine->getRPM();
1888 m_simbuf.simbuf_engine_turbo_psi= m_actor->ar_engine->getTurboPSI();
1889 m_simbuf.simbuf_engine_accel = m_actor->ar_engine->getAcc();
1890 m_simbuf.simbuf_engine_torque = m_actor->ar_engine->getCurEngineTorque();
1891 m_simbuf.simbuf_inputshaft_rpm = m_actor->ar_engine->getInputShaftRPM();
1892 m_simbuf.simbuf_drive_ratio = m_actor->ar_engine->getDriveRatio();
1893 m_simbuf.simbuf_clutch = m_actor->ar_engine->getClutch();
1894 m_simbuf.simbuf_num_gears = m_actor->ar_engine->getNumGears();
1895 m_simbuf.simbuf_engine_max_rpm = m_actor->ar_engine->getShiftUpRPM();
1896 m_simbuf.simbuf_engine_smoke = m_actor->ar_engine->getSmoke();
1898 if (m_actor->m_num_wheel_diffs > 0)
1900 m_simbuf.simbuf_diff_type = m_actor->m_wheel_diffs[0]->GetActiveDiffType();
1904 m_simbuf.simbuf_tyre_pressure = m_actor->getTyrePressure().GetCurPressure();
1905 m_simbuf.simbuf_tyre_pressurizing = m_actor->getTyrePressure().IsPressurizing();
1908 m_simbuf.simbuf_lightmask = m_actor->m_lightmask;
1909 m_simbuf.simbuf_smoke_enabled = m_actor->getSmokeEnabled();
1910 m_simbuf.simbuf_parking_brake = m_actor->ar_parking_brake;
1911 m_simbuf.simbuf_cparticles_active = m_actor->ar_cparticles_active;
1914 m_simbuf.simbuf_hydro_aileron_state = m_actor->ar_hydro_aileron_state;
1915 m_simbuf.simbuf_hydro_elevator_state = m_actor->ar_hydro_elevator_state;
1916 m_simbuf.simbuf_hydro_aero_rudder_state = m_actor->ar_hydro_rudder_state;
1917 m_simbuf.simbuf_aero_flap_state = m_actor->ar_aerial_flap;
1918 m_simbuf.simbuf_airbrake_state = m_actor->ar_airbrake_intensity;
1919 if (m_actor->ar_num_wings > 4)
1921 m_simbuf.simbuf_wing4_aoa = m_actor->ar_wings[4].fa->aoa;
1925 if (m_actor->ar_autopilot !=
nullptr)
1927 m_simbuf.simbuf_has_autopilot =
true;
1928 m_simbuf.simbuf_ap_heading_mode = m_actor->ar_autopilot->GetHeadingMode();
1929 m_simbuf.simbuf_ap_heading_value = m_actor->ar_autopilot->heading;
1930 m_simbuf.simbuf_ap_alt_mode = m_actor->ar_autopilot->GetAltMode();
1931 m_simbuf.simbuf_ap_alt_value = m_actor->ar_autopilot->GetAltValue();
1932 m_simbuf.simbuf_ap_ias_mode = m_actor->ar_autopilot->GetIasMode();
1933 m_simbuf.simbuf_ap_ias_value = m_actor->ar_autopilot->GetIasValue();
1934 m_simbuf.simbuf_ap_gpws_mode = m_actor->ar_autopilot->GetGpwsMode();
1935 m_simbuf.simbuf_ap_ils_available = m_actor->ar_autopilot->IsIlsAvailable();
1936 m_simbuf.simbuf_ap_ils_vdev = m_actor->ar_autopilot->GetVerticalApproachDeviation();
1937 m_simbuf.simbuf_ap_ils_hdev = m_actor->ar_autopilot->GetHorizontalApproachDeviation();
1938 m_simbuf.simbuf_ap_vs_value = m_actor->ar_autopilot->GetVsValue();
1941 m_simbuf.simbuf_speedo_highest_kph = m_actor->ar_guisettings_speedo_max_kph;
1942 m_simbuf.simbuf_speedo_use_engine_max_rpm = m_actor->ar_guisettings_use_engine_max_rpm;
1943 m_simbuf.simbuf_shifter_anim_time = m_actor->ar_guisettings_shifter_anim_time;
1954 if ((m_cab_entity !=
nullptr) && (m_cab_mesh !=
nullptr))
1956 m_cab_scene_node->setPosition(m_cab_mesh->UpdateFlexObj());
1962 m_flexwheel_tasks.clear();
1966 if (
w.wx_flex_mesh !=
nullptr &&
w.wx_flex_mesh->flexitPrepare())
1968 auto func = std::function<void()>([
this,
w]()
1970 w.wx_flex_mesh->flexitCompute();
1973 m_flexwheel_tasks.push_back(task_handle);
1980 for (
auto& task: m_flexwheel_tasks)
1986 if (
w.wx_scenenode !=
nullptr &&
w.wx_flex_mesh !=
nullptr)
1988 w.wx_scenenode->setPosition(
w.wx_flex_mesh->flexitFinal());
1997 if (
w.wx_scenenode !=
nullptr)
1999 w.wx_scenenode->setVisible(value);
2001 if (
w.wx_flex_mesh !=
nullptr)
2003 w.wx_flex_mesh->setVisible(value);
2014 const size_t num_airbrakes = m_gfx_airbrakes.size();
2015 for (
size_t i=0; i<num_airbrakes; ++i)
2018 const float ratio = m_simbuf.simbuf_airbrakes[i].simbuf_ab_ratio;
2019 const float maxangle = m_actor->ar_airbrakes[i]->getMaxAngle();
2020 Ogre::Vector3 ref_node_pos = m_simbuf.simbuf_nodes[m_gfx_airbrakes[i].abx_ref_node].AbsPosition;
2021 Ogre::Vector3 x_node_pos = m_simbuf.simbuf_nodes[m_gfx_airbrakes[i].abx_x_node].AbsPosition;
2022 Ogre::Vector3 y_node_pos = m_simbuf.simbuf_nodes[m_gfx_airbrakes[i].abx_y_node].AbsPosition;
2025 Ogre::Vector3 normal = (y_node_pos - ref_node_pos).crossProduct(x_node_pos - ref_node_pos);
2028 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);
2031 Ogre::Vector3 refx = x_node_pos - ref_node_pos;
2033 Ogre::Vector3 refy = refx.crossProduct(normal);
2034 Ogre::Quaternion orientation = Ogre::Quaternion(Ogre::Degree(-ratio * maxangle), (x_node_pos - ref_node_pos).normalisedCopy()) * Ogre::Quaternion(refx, normal, refy);
2042 for (
CParticle& cparticle: m_cparticles)
2045 const Ogre::Vector3 pos = m_simbuf.simbuf_nodes[cparticle.emitterNode].AbsPosition;
2046 const Ogre::Vector3 dir =
fast_normalise(pos - m_simbuf.simbuf_nodes[cparticle.directionNode].AbsPosition);
2047 cparticle.snode->setPosition(pos);
2049 for (
unsigned short j = 0; j < cparticle.psys->getNumEmitters(); j++)
2051 cparticle.psys->getEmitter(j)->setEnabled(m_simbuf.simbuf_cparticles_active);
2052 cparticle.psys->getEmitter(j)->setDirection(dir);
2059 if (!m_simbuf.simbuf_has_engine)
2062 for (
Exhaust& exhaust: m_exhausts)
2064 if (!exhaust.smoker)
2068 const Ogre::Vector3 pos = m_simbuf.simbuf_nodes[exhaust.emitterNode].AbsPosition;
2069 const Ogre::Vector3 dir = pos - m_simbuf.simbuf_nodes[exhaust.directionNode].AbsPosition;
2070 exhaust.smokeNode->setPosition(pos);
2072 const bool active = m_simbuf.simbuf_smoke_enabled && m_simbuf.simbuf_engine_smoke != -1.f;
2073 exhaust.smoker->getEmitter(0)->setEnabled(active);
2076 exhaust.smoker->getEmitter(0)->setColour(Ogre::ColourValue(0.0, 0.0, 0.0, 0.02 + m_simbuf.simbuf_engine_smoke * 0.06));
2077 exhaust.smoker->getEmitter(0)->setTimeToLive((0.02 + m_simbuf.simbuf_engine_smoke * 0.06) / 0.04);
2078 exhaust.smoker->getEmitter(0)->setParticleVelocity(1.0 + m_simbuf.simbuf_engine_smoke * 2.0, 2.0 + m_simbuf.simbuf_engine_smoke * 3.0);
2085 for (
int i = 0; i < m_actor->ar_num_aeroengines; i++)
2087 m_actor->ar_aeroengines[i]->updateVisuals(
this);
2093 const bool is_remote =
2104 float y_offset = (m_simbuf.simbuf_aabb.getMaximum().y - m_simbuf.simbuf_pos.y) + (vlen / 100.0);
2105 Ogre::Vector3 scene_pos = m_simbuf.simbuf_pos + Ogre::Vector3::UNIT_Y * y_offset;
2114 Prop* driverseat_prop = &m_props[m_driverseat_prop_index];
2118 const Ogre::Vector3 x_pos =
nodes[driverseat_prop->
pp_node_x].AbsPosition;
2119 const Ogre::Vector3 y_pos =
nodes[driverseat_prop->
pp_node_y].AbsPosition;
2120 const Ogre::Vector3 center_pos =
nodes[driverseat_prop->
pp_node_ref].AbsPosition;
2122 const Ogre::Vector3 x_vec = x_pos - center_pos;
2123 const Ogre::Vector3 y_vec = y_pos - center_pos;
2124 const Ogre::Vector3 normal = (y_vec.crossProduct(x_vec)).normalisedCopy();
2127 Ogre::Vector3 pos = center_pos;
2128 pos += (driverseat_prop->
pp_offset.x * x_vec);
2129 pos += (driverseat_prop->
pp_offset.y * y_vec);
2130 pos += (driverseat_prop->
pp_offset.z * normal);
2134 const Ogre::Vector3 x_vec_norm = x_vec.normalisedCopy();
2135 const Ogre::Vector3 y_vec_norm = x_vec_norm.crossProduct(normal);
2136 Ogre::Quaternion rot(x_vec_norm, normal, y_vec_norm);
2137 rot = rot * driverseat_prop->
pp_rot;
2138 rot = rot * Ogre::Quaternion(Ogre::Degree(180), Ogre::Vector3::UNIT_Y);
2145 using namespace Ogre;
2154 Ogre::Quaternion beacon_orientation = beacon_scene_node->getOrientation();
2160 pp_beacon_light->getParentSceneNode()->setPosition(beacon_scene_node->getPosition() + beacon_orientation * Ogre::Vector3(0, 0, 0.12));
2161 beacon_rotation_angle += dt * beacon_rotation_rate;
2162 pp_beacon_light->getParentSceneNode()->setDirection(beacon_orientation * Ogre::Vector3(cos(beacon_rotation_angle), sin(beacon_rotation_angle), 0));
2165 float vlen = vdir.length();
2173 prop.
pp_beacon_scene_node[0]->setPosition(pp_beacon_light->getParentSceneNode()->getPosition() - vdir * 0.1);
2174 float amplitude = pp_beacon_light->getDerivedDirection().dotProduct(vdir);
2178 prop.
pp_beacon_bbs[0]->setDefaultDimensions(amplitude * amplitude * amplitude, amplitude * amplitude * amplitude);
2184 pp_beacon_light->setVisible(enableAll);
2192 for (
int k = 0; k < 4; k++)
2195 Quaternion orientation = prop.
pp_scene_node->getOrientation();
2198 case 0: prop.
pp_beacon_light[k]->getParentSceneNode()->setPosition(prop.
pp_scene_node->getPosition() + orientation * Vector3(-0.64, 0, 0.14));
2200 case 1: prop.
pp_beacon_light[k]->getParentSceneNode()->setPosition(prop.
pp_scene_node->getPosition() + orientation * Vector3(-0.32, 0, 0.14));
2202 case 2: prop.
pp_beacon_light[k]->getParentSceneNode()->setPosition(prop.
pp_scene_node->getPosition() + orientation * Vector3(+0.32, 0, 0.14));
2204 case 3: prop.
pp_beacon_light[k]->getParentSceneNode()->setPosition(prop.
pp_scene_node->getPosition() + orientation * Vector3(+0.64, 0, 0.14));
2211 float vlen = vdir.length();
2220 float amplitude = prop.
pp_beacon_light[k]->getDerivedDirection().dotProduct(vdir);
2224 prop.
pp_beacon_bbs[k]->setDefaultDimensions(amplitude * amplitude * amplitude, amplitude * amplitude * amplitude);
2236 Quaternion orientation = prop.
pp_scene_node->getOrientation();
2241 float vlen = vdir.length();
2250 bool visible =
false;
2256 visible = visible && enableAll;
2265 float vlen = vdir.length();
2278 prop.
pp_beacon_light[0]->getParentSceneNode()->setPosition(mposition);
2282 float vlen = vdir.length();
2291 bool visible =
false;
2297 visible = visible && enableAll;
2305 using namespace Ogre;
2310 for (
Prop& prop: m_props)
2312 if (prop.pp_scene_node ==
nullptr)
2316 if (prop.pp_aero_propeller_blade || prop.pp_aero_propeller_spin)
2318 const float SPINNER_THRESHOLD = 200.f;
2319 const bool show_spinner = m_simbuf.simbuf_aeroengines[prop.pp_aero_engine_idx].simbuf_ae_rpm > SPINNER_THRESHOLD;
2320 if (prop.pp_aero_propeller_blade)
2321 prop.pp_scene_node->setVisible(!show_spinner);
2322 else if (prop.pp_aero_propeller_spin)
2323 prop.pp_scene_node->setVisible(show_spinner);
2327 const bool mo_visible = (prop.pp_camera_mode_active ==
CAMERA_MODE_ALWAYS_VISIBLE || prop.pp_camera_mode_active == m_simbuf.simbuf_cur_cinecam);
2328 prop.pp_mesh_obj->setVisible(mo_visible);
2337 Vector3 diffX =
nodes[prop.pp_node_x].AbsPosition -
nodes[prop.pp_node_ref].AbsPosition;
2338 Vector3 diffY =
nodes[prop.pp_node_y].AbsPosition -
nodes[prop.pp_node_ref].AbsPosition;
2340 Vector3 normal = (diffY.crossProduct(diffX)).normalisedCopy();
2342 Vector3 mposition =
nodes[prop.pp_node_ref].AbsPosition + prop.pp_offset.x * diffX + prop.pp_offset.y * diffY;
2343 prop.pp_scene_node->setPosition(mposition + normal * prop.pp_offset.z);
2345 Vector3 refx = diffX.normalisedCopy();
2346 Vector3 refy = refx.crossProduct(normal);
2347 Quaternion orientation = Quaternion(refx, normal, refy) * prop.pp_rot;
2348 prop.pp_scene_node->setOrientation(orientation);
2350 if (prop.pp_wheel_scene_node)
2352 Quaternion brot = Quaternion(Degree(-59.0), Vector3::UNIT_X);
2353 brot = brot * Quaternion(Degree(m_simbuf.simbuf_hydro_dir_state * prop.pp_wheel_rot_degree), Vector3::UNIT_Y);
2354 prop.pp_wheel_scene_node->setPosition(mposition + normal * prop.pp_offset.z + orientation * prop.pp_wheel_pos);
2355 prop.pp_wheel_scene_node->setOrientation(orientation * brot);
2363 this->SetBeaconsEnabled(m_beaconlight_active);
2367 && m_beaconlight_active)
2369 for (
Prop& prop: m_props)
2371 if (prop.pp_beacon_type != 0)
2373 this->UpdateBeaconFlare(prop, dt, is_player_actor);
2381 for (
Prop& prop: m_props)
2383 prop.setPropMeshesVisible(visible);
2392 for (
int i = 0; i < m_actor->ar_num_aeroengines; i++)
2394 m_actor->ar_aeroengines[i]->setVisible(visible);
2400 if (m_renderdash !=
nullptr)
2402 m_renderdash->setEnable(active);
2408 if (m_renderdash !=
nullptr)
2410 m_renderdash->getRenderTarget()->update();
2418 for (
Prop& prop: m_props)
2420 char beacon_type = prop.pp_beacon_type;
2421 if (beacon_type ==
'b')
2423 prop.pp_beacon_light[0]->setVisible(beacon_light_is_active && enableLight);
2424 prop.pp_beacon_scene_node[0]->setVisible(beacon_light_is_active);
2425 if (prop.pp_beacon_bbs[0] && beacon_light_is_active && !prop.pp_beacon_scene_node[0]->numAttachedObjects())
2427 prop.pp_beacon_bbs[0]->setVisible(
true);
2428 prop.pp_beacon_scene_node[0]->attachObject(prop.pp_beacon_bbs[0]);
2430 else if (prop.pp_beacon_bbs[0] && !beacon_light_is_active)
2432 prop.pp_beacon_scene_node[0]->detachAllObjects();
2433 prop.pp_beacon_bbs[0]->setVisible(
false);
2436 else if (beacon_type ==
'R' || beacon_type ==
'L')
2438 prop.pp_beacon_scene_node[0]->setVisible(beacon_light_is_active);
2439 if (prop.pp_beacon_bbs[0] && beacon_light_is_active && !prop.pp_beacon_scene_node[0]->numAttachedObjects())
2440 prop.pp_beacon_scene_node[0]->attachObject(prop.pp_beacon_bbs[0]);
2441 else if (prop.pp_beacon_bbs[0] && !beacon_light_is_active)
2442 prop.pp_beacon_scene_node[0]->detachAllObjects();
2444 else if (beacon_type ==
'p')
2446 for (
int k = 0; k < 4; k++)
2448 prop.pp_beacon_light[k]->setVisible(beacon_light_is_active && enableLight);
2449 prop.pp_beacon_scene_node[k]->setVisible(beacon_light_is_active);
2450 if (prop.pp_beacon_bbs[k] && beacon_light_is_active && !prop.pp_beacon_scene_node[k]->numAttachedObjects())
2451 prop.pp_beacon_scene_node[k]->attachObject(prop.pp_beacon_bbs[k]);
2452 else if (prop.pp_beacon_bbs[k] && !beacon_light_is_active)
2453 prop.pp_beacon_scene_node[k]->detachAllObjects();
2458 for (
int k = 0; k < 4; k++)
2460 if (prop.pp_beacon_light[k])
2462 prop.pp_beacon_light[k]->setVisible(beacon_light_is_active && enableLight);
2464 if (prop.pp_beacon_scene_node[k])
2466 prop.pp_beacon_scene_node[k]->setVisible(beacon_light_is_active);
2468 if (prop.pp_beacon_bbs[k] && beacon_light_is_active && !prop.pp_beacon_scene_node[k]->numAttachedObjects())
2470 prop.pp_beacon_scene_node[k]->attachObject(prop.pp_beacon_bbs[k]);
2472 else if (prop.pp_beacon_bbs[k] && !beacon_light_is_active)
2474 prop.pp_beacon_scene_node[k]->detachAllObjects();
2485 const float delta_cstate = new_target_cstate - anim.
shifterTarget;
2486 if (delta_cstate != 0)
2494 const float cstate_step = (dt / m_simbuf.simbuf_shifter_anim_time) * anim.
shifterStep;
2517 for (spi = 0; spi < m_simbuf.simbuf_screwprops.size(); spi++)
2519 ctmp += m_simbuf.simbuf_screwprops[spi].simbuf_sp_rudder;
2533 for (spi = 0; spi < m_simbuf.simbuf_screwprops.size(); spi++)
2535 ctmp += m_simbuf.simbuf_screwprops[spi].simbuf_sp_throttle;
2547 if (m_actor->m_num_wheel_diffs > 0)
2549 switch (m_simbuf.simbuf_diff_type)
2573 cstate = (m_simbuf.simbuf_rotation * 57.29578f) / 360.0f;
2578 const bool has_engine = (m_actor->ar_engine!=
nullptr);
2581 float torque = m_simbuf.simbuf_engine_crankfactor;
2584 if (torque >= m_prop_anim_crankfactor_prev)
2585 cstate -= torque / 10.0f;
2589 if (cstate <= -1.0f)
2591 m_prop_anim_crankfactor_prev = torque;
2597 bool match =
static_cast<int>(anim.
animOpt3) == m_actor->ar_engine->getGear();
2598 cstate +=
static_cast<int>(match);
2605 float shifterseq_cstate = 0;
2609 int shifter = m_simbuf.simbuf_gear;
2610 if (shifter > m_prop_anim_prev_gear)
2612 shifterseq_cstate = 1.0f;
2613 m_prop_anim_shift_timer = 0.2f;
2615 if (shifter < m_prop_anim_prev_gear)
2617 shifterseq_cstate = -1.0f;
2618 m_prop_anim_shift_timer = -0.2f;
2620 m_prop_anim_prev_gear = shifter;
2622 if (m_prop_anim_shift_timer > 0.0f)
2624 shifterseq_cstate = 1.0f;
2625 m_prop_anim_shift_timer -= dt;
2626 if (m_prop_anim_shift_timer < 0.0f)
2627 m_prop_anim_shift_timer = 0.0f;
2629 if (m_prop_anim_shift_timer < 0.0f)
2631 shifterseq_cstate = -1.0f;
2632 m_prop_anim_shift_timer += dt;
2633 if (m_prop_anim_shift_timer > 0.0f)
2634 m_prop_anim_shift_timer = 0.0f;
2641 if (m_simbuf.simbuf_commandkey[
int(anim.
lower_limit)].simbuf_cmd_value > 0)
2642 shifterseq_cstate = 1.0f;
2645 if (m_simbuf.simbuf_commandkey[
int(anim.
upper_limit)].simbuf_cmd_value > 0)
2646 shifterseq_cstate = -1.0f;
2650 cstate += UpdateSmoothShift(anim, dt, shifterseq_cstate);
2657 float shifterman1_cstate = 0.f;
2658 int shifter = m_simbuf.simbuf_gear;
2661 shifterman1_cstate = -0.5f;
2663 else if (shifter < 0)
2665 shifterman1_cstate = 1.0f;
2669 shifterman1_cstate = -int((shifter - 1.0) / 2.0);
2672 cstate += UpdateSmoothShift(anim, dt, shifterman1_cstate);
2679 float shifterman2_cstate = 0.f;
2680 int shifter = m_simbuf.simbuf_gear;
2681 shifterman2_cstate = 0.5f;
2684 shifterman2_cstate = 1.0f;
2688 shifterman2_cstate = shifter % 2;
2691 cstate += UpdateSmoothShift(anim, dt, shifterman2_cstate);
2698 float shifterlin_cstate = 0.f;
2699 int shifter = m_simbuf.simbuf_gear;
2700 int numgears = m_simbuf.simbuf_num_gears;
2701 shifterlin_cstate -= (shifter + 2.0) / (numgears + 2.0);
2703 cstate += UpdateSmoothShift(anim, dt, shifterlin_cstate);
2710 float shifterlin_cstate = 0.f;
2711 int shifter = std::min(m_simbuf.simbuf_gear, 1);
2713 shifterlin_cstate -= (shifter + 2.0) / (numgears + 2.0);
2715 cstate += UpdateSmoothShift(anim, dt, shifterlin_cstate);
2722 float pbrake =
static_cast<float>(m_simbuf.simbuf_parking_brake);
2730 float speedo = m_simbuf.simbuf_wheel_speed / m_simbuf.simbuf_speedo_highest_kph;
2731 cstate -= speedo * 3.0f;
2738 float tacho = m_simbuf.simbuf_engine_rpm / m_simbuf.simbuf_engine_max_rpm;
2746 float turbo = m_simbuf.simbuf_engine_turbo_psi * 3.34;
2747 cstate -= turbo / 67.0f;
2754 float brakes = m_simbuf.simbuf_brake;
2762 float accel = m_simbuf.simbuf_engine_accel;
2763 cstate -= accel + 0.06f;
2771 float clutch = m_simbuf.simbuf_clutch;
2772 cstate -= fabs(1.0f - clutch);
2779 float signal = 0.0f;
2790 if (anim.
animOpt3 > 0.f && anim.
animOpt3 <=
float(m_simbuf.simbuf_aeroengines.size()))
2792 const int aenum = int(anim.
animOpt3 - 1.f);
2796 float pcent = m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_rpmpc;
2798 angle = -5.0 + pcent * 1.9167;
2799 else if (pcent < 110.0)
2800 angle = 110.0 + (pcent - 60.0) * 4.075;
2803 cstate -= angle / 314.0f;
2808 float throttle = m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_throttle;
2817 cstate = m_simbuf.simbuf_aeroengines[aenum].simbuf_tp_aetorque / 120.0f;
2823 cstate = m_simbuf.simbuf_aeroengines[aenum].simbuf_tp_aepitch / 120.0f;
2830 if (!m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_ignition)
2834 if (m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_failed)
2840 const Ogre::Vector3 node0_pos = this->GetSimNodeBuffer()[0].AbsPosition;
2841 const Ogre::Vector3 node0_velo = m_simbuf.simbuf_node0_velo;
2846 float ground_speed_kt = node0_velo.length() * 1.9438;
2847 float altitude = node0_pos.y;
2849 float sea_level_pressure = 101325;
2851 float airpressure = sea_level_pressure * pow(1.0 - 0.0065 * altitude / 288.15, 5.24947);
2852 float airdensity = airpressure * 0.0000120896;
2853 float kt = ground_speed_kt * sqrt(airdensity / 1.225);
2854 cstate -= kt / 100.0f;
2861 float vvi = node0_velo.y * 196.85;
2863 cstate -= vvi / 6000.0f;
2866 if (cstate <= -1.0f)
2877 float altimeter = (node0_pos.y * 1.1811) / 360.0f;
2878 int alti_int = int(altimeter);
2879 float alti_mod = (altimeter - alti_int);
2886 float alti = node0_pos.y * 1.1811 / 3600.0f;
2887 int alti_int = int(alti);
2888 float alti_mod = (alti - alti_int);
2890 if (cstate <= -1.0f)
2897 float alti = node0_pos.y * 1.1811 / 36000.0f;
2899 if (cstate <= -1.0f)
2908 float aoa = m_simbuf.simbuf_wing4_aoa / 25.f;
2909 if ((node0_velo.length() * 1.9438) < 10.0f)
2912 if (cstate <= -1.0f)
2919 Ogre::Vector3 cam_pos = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_pos ].AbsPosition;
2920 Ogre::Vector3 cam_roll = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_roll].AbsPosition;
2921 Ogre::Vector3 cam_dir = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_dir ].AbsPosition;
2926 Ogre::Vector3 rollv = (cam_pos - cam_roll).normalisedCopy();
2927 Ogre::Vector3 dirv = (cam_pos - cam_dir).normalisedCopy();
2928 Ogre::Vector3 upv = dirv.crossProduct(-rollv);
2929 float rollangle = asin(rollv.dotProduct(Ogre::Vector3::UNIT_Y));
2931 rollangle = Ogre::Math::RadiansToDegrees(rollangle);
2934 rollangle = 180.0f - rollangle;
2935 cstate = rollangle / 180.0f;
2939 cstate = cstate - 2.0f;
2946 Ogre::Vector3 dirv = (cam_pos - cam_dir).normalisedCopy();
2947 float pitchangle = asin(dirv.dotProduct(Ogre::Vector3::UNIT_Y));
2949 cstate = (Ogre::Math::RadiansToDegrees(pitchangle) / 90.0f);
2956 float airbrake =
static_cast<float>(m_simbuf.simbuf_airbrake_state);
2958 cstate -= airbrake / 5.0f;
2965 float flaps =
FLAP_ANGLES[m_simbuf.simbuf_aero_flap_state];
2974 int prop_anim_key_index = 0;
2976 for (
Prop& prop: m_props)
2983 for (
PropAnim& anim: prop.pp_animations)
2985 float cstate = 0.0f;
2988 this->CalcPropAnimation(anim, cstate, div, dt);
2993 ROR_ASSERT(prop_anim_key_index < (
int)m_simbuf.simbuf_prop_anim_keys.size());
2994 const bool anim_active = m_simbuf.simbuf_prop_anim_keys[prop_anim_key_index++].simbuf_anim_active;
2995 cstate += (float)anim_active;
3003 cstate += m_actor->ar_dashboard->getNumeric(link_id);
3009 cstate += m_simbuf.simbuf_hydro_dir_state;
3012 cstate += m_simbuf.simbuf_hydro_aileron_state;
3015 cstate += m_simbuf.simbuf_hydro_elevator_state;
3018 cstate += m_simbuf.simbuf_hydro_aero_rudder_state;
3032 float limiter = 0.0f;
3035 float const dt_frac = dt * 2000.f;
3040 prop.pp_rota.x += cstate * dt_frac;
3041 limiter = prop.pp_rota.x;
3045 prop.pp_rota.y += cstate * dt_frac;
3046 limiter = prop.pp_rota.y;
3050 prop.pp_rota.z += cstate * dt_frac;
3051 limiter = prop.pp_rota.z;
3064 bool limiterchanged =
false;
3078 limiterchanged =
true;
3092 limiterchanged =
true;
3098 prop.pp_rota.x = limiter;
3100 prop.pp_rota.y = limiter;
3102 prop.pp_rota.z = limiter;
3110 float offset = 0.0f;
3111 float autooffset = 0.0f;
3114 offset = prop.pp_offset_orig.x;
3116 offset = prop.pp_offset_orig.y;
3118 offset = prop.pp_offset_orig.z;
3124 float const dt_frac = dt * 2000.f;
3125 autooffset = offset + cstate * dt_frac;
3157 prop.pp_offset.x = offset;
3159 prop.pp_offset_orig.x = autooffset;
3163 prop.pp_offset.y = offset;
3165 prop.pp_offset_orig.y = autooffset;
3169 prop.pp_offset.z = offset;
3171 prop.pp_offset_orig.z = autooffset;
3177 rx += prop.pp_rota.x;
3178 ry += prop.pp_rota.y;
3179 rz += prop.pp_rota.z;
3181 prop.pp_rot = Ogre::Quaternion(Ogre::Degree(rz), Ogre::Vector3::UNIT_Z) *
3182 Ogre::Quaternion(Ogre::Degree(ry), Ogre::Vector3::UNIT_Y) *
3183 Ogre::Quaternion(Ogre::Degree(rx), Ogre::Vector3::UNIT_X);
3189 std::sort(m_flexbodies.begin(), m_flexbodies.end(), [](
FlexBody* a,
FlexBody* b) { return a->getVertexCount() > b->getVertexCount(); });
3194 m_flexbody_tasks.clear();
3199 const bool visible = (fb->fb_camera_mode_active ==
CAMERA_MODE_ALWAYS_VISIBLE || fb->fb_camera_mode_active == m_simbuf.simbuf_cur_cinecam);
3200 fb->setVisible(visible);
3203 if (fb->isVisible())
3205 auto func = std::function<void()>([fb]()
3207 fb->computeFlexbody();
3210 m_flexbody_tasks.push_back(task_handle);
3227 fb->setVisible(visible);
3233 for (
auto& task: m_flexbody_tasks)
3239 if (fb->isVisible())
3241 fb->updateFlexbodyVertexBuffers();
3269 int num_flares =
static_cast<int>(m_actor->ar_flares.size());
3270 for (
int i=0; i<num_flares; ++i)
3272 flare_t& flare = m_actor->ar_flares[i];
3280 this->SetMaterialFlareOn(i, flare.
intensity > 0.3);
3295 float vlen = vdir.length();
3299 flare.
snode->setVisible(
false);
3304 float amplitude = normal.dotProduct(vdir);
3305 flare.
snode->setPosition(mposition - 0.1 * amplitude * normal * flare.
offsetz);
3306 flare.
snode->setDirection(normal);
3315 flare.
light->getParentSceneNode()->setPosition(mposition - 0.2 * amplitude * normal);
3317 flare.
light->getParentSceneNode()->setDirection(-normal - Ogre::Vector3(0, 0.2, 0));
3323 flare.
bbs->setDefaultDimensions(amplitude * fsize, amplitude * fsize);
3324 flare.
snode->setVisible(
true);
3328 flare.
snode->setVisible(
false);
3337 if (m_cab_scene_node !=
nullptr)
3339 static_cast<Ogre::Entity*
>(m_cab_scene_node->getAttachedObject(0))->setCastShadows(value);
3343 for (
Prop& prop: m_props)
3345 if (prop.pp_mesh_obj !=
nullptr && prop.pp_mesh_obj->getEntity())
3346 prop.pp_mesh_obj->getEntity()->setCastShadows(value);
3347 if (prop.pp_wheel_mesh_obj !=
nullptr && prop.pp_wheel_mesh_obj->getEntity())
3348 prop.pp_wheel_mesh_obj->getEntity()->setCastShadows(value);
3354 static_cast<Ogre::Entity*
>(wheel.wx_scenenode->getAttachedObject(0))->setCastShadows(value);
3358 for (
BeamGfx& rod: m_gfx_beams)
3360 static_cast<Ogre::Entity*
>(rod.rod_scenenode->getAttachedObject(0))->setCastShadows(value);
3366 fb->setFlexbodyCastShadow(value);
3372 m_cab_mesh = flexobj;
3374 m_cab_scene_node = snode;
3379 if (m_cab_entity !=
nullptr)
3381 m_cab_entity->setVisible(visible);
3383 this->SetWheelsVisible(visible);
3384 this->SetPropsVisible(visible);
3385 this->SetFlexbodyVisible(visible);
3386 this->SetWingsVisible(visible);
3387 this->SetRodsVisible(visible);
3388 this->SetAeroEnginesVisible(visible);
3393 for (
int i = 0; i < m_actor->ar_num_wings; ++i)
3395 m_actor->ar_wings[i].cnode->setVisible(visible);
3398 for (
size_t i=0; i< m_actor->ar_airbrakes.size(); ++i)
3400 m_gfx_airbrakes[i].abx_scenenode->setVisible(visible);
3406 for (
int i = 0; i < m_actor->ar_num_wings; ++i)
3408 wing_t& wing = m_actor->ar_wings[i];
3417 for (
const Prop& prop : m_props)
3419 if (prop.pp_beacon_type != 0)
3429 for (
NodeGfx& nfx : m_gfx_nodes)
3431 if (nfx.nx_node_idx == nodenum)
3433 nfx.nx_is_hot = value;
3440 auto itor = m_gfx_beams.begin();
3441 auto endi = m_gfx_beams.end();
3442 while (itor != endi)
3444 if (itor->rod_beam_index == beam_index)
3447 if (itor->rod_scenenode)
3449 if (itor->rod_scenenode->getAttachedObject(0))
3451 Ogre::Entity* ent =
static_cast<Ogre::Entity*
>(itor->rod_scenenode->getAttachedObject(0));
3454 ent->detachFromParent();
3460 itor->rod_scenenode =
nullptr;
3464 m_gfx_beams.erase(itor);