736 if (m_actor->m_buoyance)
747 ImVec2 screen_size = ImGui::GetIO().DisplaySize;
756 Ogre::Vector3 pos_xyz = world2screen.
Convert(m_actor->getPosition());
759 ImVec2 pos(pos_xyz.x, pos_xyz.y);
762 for (
int i = 0; i < m_actor->ar_num_nodes; ++i)
764 radius = std::max(radius, pos_xyz.distance(world2screen.
Convert(m_actor->ar_nodes[i].AbsPosition)));
767 drawlist->AddCircleFilled(pos, radius * 1.05f, 0x22222222, 36);
777 const beam_t* beams = m_actor->ar_beams;
778 const size_t num_beams =
static_cast<size_t>(m_actor->ar_num_beams);
779 for (
size_t i = 0; i < num_beams; ++i)
786 Ogre::Vector3 pos1 = world2screen.
Convert(beams[i].p1->AbsPosition);
787 Ogre::Vector3 pos2 = world2screen.
Convert(beams[i].p2->AbsPosition);
789 if ((pos1.z < 0.f) && (pos2.z < 0.f))
791 ImVec2 pos1xy(pos1.x, pos1.y);
792 ImVec2 pos2xy(pos2.x, pos2.y);
794 if (beams[i].bm_broken)
803 if (!beams[i].bm_disabled)
813 if (beams[i].stress > 0)
815 float stress_ratio = pow(beams[i].stress / beams[i].maxposstress, 2.0f);
816 float s = std::min(stress_ratio, 1.0f);
817 color = Ogre::ColourValue(0.2f * (1 + 2.0f * s), 0.4f * (1.0f - s), 0.33f, 1.0f).getAsABGR();
819 else if (beams[i].stress < 0)
821 float stress_ratio = pow(beams[i].stress / beams[i].maxnegstress, 2.0f);
822 float s = std::min(stress_ratio, 1.0f);
823 color = Ogre::ColourValue(0.2f, 0.4f * (1.0f - s), 0.33f * (1 + 1.0f * s), 1.0f).getAsABGR();
834 const node_t* nodes = m_actor->ar_nodes;
835 const size_t num_nodes =
static_cast<size_t>(m_actor->ar_num_nodes);
836 for (
size_t i = 0; i < num_nodes; ++i)
841 Ogre::Vector3 pos_xyz = world2screen.
Convert(nodes[i].AbsPosition);
845 ImVec2 pos(pos_xyz.x, pos_xyz.y);
846 if (nodes[i].nd_immovable)
860 for (
size_t i = 0; i < num_nodes; ++i)
863 (nodes[i].nd_tyre_node || nodes[i].nd_rim_node))
866 Ogre::Vector3 pos = world2screen.
Convert(nodes[i].AbsPosition);
870 ImVec2 pos_xy(pos.x, pos.y);
872 id_buf << nodes[i].
pos;
878 snprintf(mass_buf, 50,
"|%.1fKg", nodes[i].mass);
879 ImVec2 offset = ImGui::CalcTextSize(id_buf.
ToCStr());
890 for (
size_t i = 0; i < num_beams; ++i)
899 Ogre::Vector3 pos_xyz = world2screen.
Convert(world_pos);
900 if (pos_xyz.z >= 0.f)
904 ImVec2 pos(pos_xyz.x, pos_xyz.y);
907 const size_t BUF_LEN = 50;
909 if (beams[i].strength >= 1000000000000.f)
911 snprintf(buf, BUF_LEN,
"%.1fT", (beams[i].strength / 1000000000000.f));
913 else if (beams[i].strength >= 1000000000.f)
915 snprintf(buf, BUF_LEN,
"%.1fG", (beams[i].strength / 1000000000.f));
917 else if (beams[i].strength >= 1000000.f)
919 snprintf(buf, BUF_LEN,
"%.1fM", (beams[i].strength / 1000000.f));
921 else if (beams[i].strength >= 1000.f)
923 snprintf(buf, BUF_LEN,
"%.1fK", (beams[i].strength / 1000.f));
927 snprintf(buf, BUF_LEN,
"%.1f", beams[i].strength);
929 const ImVec2 stren_text_size = ImGui::CalcTextSize(buf);
933 snprintf(buf, BUF_LEN,
"|%.1f", beams[i].stress);
940 const wheel_t* wheels = m_actor->ar_wheels;
941 const size_t num_wheels =
static_cast<size_t>(m_actor->ar_num_wheels);
942 for (
int i = 0; i < num_wheels; i++)
949 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_axis_node_1->AbsPosition);
950 if (pos1_xyz.z < 0.f)
952 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
955 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_axis_node_0->AbsPosition);
956 if (pos2_xyz.z < 0.f)
958 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
961 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
963 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
964 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
969 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
972 float v = ImGui::GetTextLineHeightWithSpacing();
973 ImVec2 pos(pos_xyz.x, pos_xyz.y);
975 wheel_id_buf <<
"Id: " << (i + 1);
976 float h1 = ImGui::CalcTextSize(wheel_id_buf.
ToCStr()).x / 2.0f;
979 rpm_buf <<
"Speed: " <<
static_cast<int>(
Round(wheels[i].debug_rpm)) <<
" rpm";
980 float h2 = ImGui::CalcTextSize(rpm_buf.
ToCStr()).x / 2.0f;
983 torque_buf <<
"Torque: " <<
static_cast<int>(
Round(wheels[i].debug_torque)) <<
" Nm";
984 float h3 = ImGui::CalcTextSize(torque_buf.
ToCStr()).x / 2.0f;
993 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
994 if (pos1_xyz.z < 0.f)
996 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
999 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
1000 if (pos2_xyz.z < 0.f)
1002 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
1005 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1007 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1008 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1013 Ogre::Vector3 radius = Ogre::Plane(axis, wheels[i].wh_near_attach_node->RelPosition).projectVector(rradius);
1018 Ogre::Vector3 up = axis.crossProduct(radius);
1019 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius - up);
1020 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius + up);
1021 Ogre::Vector3 pos3_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition - radius + up);
1022 Ogre::Vector3 pos4_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition - radius - up);
1023 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1025 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1026 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1027 ImVec2 pos3xy(pos3_xyz.x, pos3_xyz.y);
1028 ImVec2 pos4xy(pos4_xyz.x, pos4_xyz.y);
1029 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, 0x22888888);
1035 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
1036 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius);
1037 Ogre::Vector3 pos3_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
1038 if (pos2_xyz.z < 0.f)
1040 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
1043 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1045 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1046 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1049 if ((pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1051 ImVec2 pos1xy(pos2_xyz.x, pos2_xyz.y);
1052 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1060 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
1061 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition - cforce);
1062 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1064 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1065 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1070 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
1071 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + cforce);
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);
1085 Ogre::Vector3 u = - axis.crossProduct(m_simbuf.simbuf_direction);
1086 if (!wheels[i].debug_force.isZeroLength())
1090 Ogre::Vector3 f = axis.crossProduct(u);
1091 Ogre::Vector3 a = - axis *
w + f * std::max(
w, wheels[i].wh_radius * 0.5f);
1092 Ogre::Vector3 b = + axis *
w + f * std::max(
w, wheels[i].wh_radius * 0.5f);
1093 Ogre::Vector3 c = + axis *
w - f * std::max(
w, wheels[i].wh_radius * 0.5f);
1094 Ogre::Vector3 d = - axis *
w - f * std::max(
w, wheels[i].wh_radius * 0.5f);
1095 Ogre::Quaternion r = Ogre::Quaternion::IDENTITY;
1096 if (wheels[i].debug_vel.length() > 1.0f)
1098 r = Ogre::Quaternion(f.angleBetween(wheels[i].
debug_vel), u);
1100 Ogre::Vector3 pos1_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * a);
1101 Ogre::Vector3 pos2_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * b);
1102 Ogre::Vector3 pos3_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * c);
1103 Ogre::Vector3 pos4_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * d);
1104 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1106 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1107 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1108 ImVec2 pos3xy(pos3_xyz.x, pos3_xyz.y);
1109 ImVec2 pos4xy(pos4_xyz.x, pos4_xyz.y);
1110 if (!wheels[i].debug_force.isZeroLength())
1113 float wheelv = wheels[i].
debug_vel.length();
1114 float slip_ratio = std::min(slipv, wheelv) / std::max(1.0f, wheelv);
1115 float scale = pow(slip_ratio, 2);
1116 ImU32 col = Ogre::ColourValue(scale, 1.0f - scale, 0.0f, 0.2f).getAsABGR();
1117 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, col);
1121 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, 0x55555555);
1127 if (!wheels[i].debug_vel.isZeroLength())
1131 Ogre::Vector3 d = axis.crossProduct(m_simbuf.simbuf_direction) * wheels[i].
wh_radius;
1132 Ogre::Real slipv = wheels[i].
debug_slip.length();
1133 Ogre::Real wheelv = wheels[i].
debug_vel.length();
1134 Ogre::Vector3 s = wheels[i].
debug_slip * (std::min(slipv, wheelv) / std::max(1.0f, wheelv)) / slipv;
1135 Ogre::Vector3 pos1_xyz = world2screen.
Convert(m + d);
1136 Ogre::Vector3 pos2_xyz = world2screen.
Convert(m + d + s * std::max(
w, wheels[i].wh_radius * 0.5f));
1137 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1139 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1140 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1148 Ogre::Real mass = m_actor->getTotalMass(
false) * num_wheels;
1149 Ogre::Vector3 normalised_force = wheels[i].
debug_force.normalisedCopy() * std::min(f / mass, 1.0f);
1151 Ogre::Vector3 pos5_xyz = world2screen.
Convert(m);
1152 Ogre::Vector3 pos6_xyz = world2screen.
Convert(m + normalised_force * wheels[i].wh_radius);
1153 if ((pos5_xyz.z < 0.f) && (pos6_xyz.z < 0.f))
1155 ImVec2 pos1xy(pos5_xyz.x, pos5_xyz.y);
1156 ImVec2 pos2xy(pos6_xyz.x, pos6_xyz.y);
1164 const beam_t* beams = m_actor->ar_beams;
1165 const size_t num_beams =
static_cast<size_t>(m_actor->ar_num_beams);
1166 std::set<int> node_ids;
1167 for (
size_t i = 0; i < num_beams; ++i)
1171 if (!(beams[i].bounded ==
SHOCK1 || beams[i].bounded ==
SHOCK2 || beams[i].bounded ==
SHOCK3))
1174 Ogre::Vector3 pos1_xyz = world2screen.
Convert(beams[i].p1->AbsPosition);
1175 Ogre::Vector3 pos2_xyz = world2screen.
Convert(beams[i].p2->AbsPosition);
1177 if (pos1_xyz.z < 0.f)
1179 node_ids.insert(beams[i].p1->pos);
1181 if (pos2_xyz.z < 0.f)
1183 node_ids.insert(beams[i].p2->pos);
1186 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1188 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1189 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1196 for (
auto id : node_ids)
1198 Ogre::Vector3 pos_xyz = world2screen.
Convert(m_actor->ar_nodes[
id].AbsPosition);
1199 if (pos_xyz.z < 0.f)
1201 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1209 for (
size_t i = 0; i < num_beams; ++i)
1213 if (!(beams[i].bounded ==
SHOCK1 || beams[i].bounded ==
SHOCK2 || beams[i].bounded ==
SHOCK3))
1216 Ogre::Vector3 pos1_xyz = world2screen.
Convert(beams[i].p1->AbsPosition);
1217 Ogre::Vector3 pos2_xyz = world2screen.
Convert(beams[i].p2->AbsPosition);
1218 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
1220 if (pos_xyz.z < 0.f)
1223 float diff = beams[i].
p1->
AbsPosition.distance(beams[i].p2->AbsPosition) - beams[i].
L;
1224 ImU32 text_color = (diff < 0.0f) ? 0xff66ee66 : 0xff8888ff;
1225 float bound = (diff < 0.0f) ? beams[i].shortbound : beams[i].
longbound;
1226 float ratio = Ogre::Math::Clamp(diff / (bound * beams[i].L), -2.0f, +2.0f);
1228 float v = ImGui::GetTextLineHeightWithSpacing();
1229 ImVec2 pos(pos_xyz.x, pos_xyz.y - v - v);
1231 len_buf <<
"L: " <<
static_cast<int>(
Round(std::abs(ratio) * 100.0f)) <<
" %";
1232 float h1 = ImGui::CalcTextSize(len_buf.
ToCStr()).x / 2.0f;
1233 drawlist->AddText(ImVec2(pos.x - h1, pos.y), text_color, len_buf.
ToCStr());
1235 spring_buf <<
"S: " <<
static_cast<int>(
Round(beams[i].debug_k)) <<
" N";
1236 float h2 = ImGui::CalcTextSize(spring_buf.
ToCStr()).x / 2.0f;
1237 drawlist->AddText(ImVec2(pos.x - h2, pos.y + v), text_color, spring_buf.
ToCStr());
1239 damp_buf <<
"D: " <<
static_cast<int>(
Round(beams[i].debug_d)) <<
" N";
1240 float h3 = ImGui::CalcTextSize(damp_buf.
ToCStr()).x / 2.0f;
1241 drawlist->AddText(ImVec2(pos.x - h3, pos.y + v + v), text_color, damp_buf.
ToCStr());
1243 snprintf(vel_buf, 25,
"V: %.2f m/s", beams[i].debug_v);
1244 float h4 = ImGui::CalcTextSize(vel_buf).x / 2.0f;
1245 drawlist->AddText(ImVec2(pos.x - h4, pos.y + v + v + v), text_color, vel_buf);
1251 const node_t* nodes = m_actor->ar_nodes;
1252 const rotator_t* rotators = m_actor->ar_rotators;
1253 const size_t num_rotators =
static_cast<size_t>(m_actor->ar_num_rotators);
1254 for (
int i = 0; i < num_rotators; i++)
1256 Ogre::Vector3 pos1_xyz = world2screen.
Convert(nodes[rotators[i].axis1].AbsPosition);
1257 Ogre::Vector3 pos2_xyz = world2screen.
Convert(nodes[rotators[i].axis2].AbsPosition);
1261 if (pos1_xyz.z < 0.f)
1263 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
1266 id_buf << nodes[rotators[i].
axis1].
pos;
1269 if (pos2_xyz.z < 0.f)
1271 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
1274 id_buf << nodes[rotators[i].
axis2].
pos;
1277 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1279 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1280 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1285 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
1286 if (pos_xyz.z < 0.f)
1288 float v = ImGui::GetTextLineHeightWithSpacing();
1289 ImVec2 pos(pos_xyz.x, pos_xyz.y);
1291 rotator_id_buf <<
"Id: " << (i + 1);
1292 float h1 = ImGui::CalcTextSize(rotator_id_buf.
ToCStr()).x / 2.0f;
1295 snprintf(angle_buf, 25,
"Rate: %.1f rpm", 60.0f * rotators[i].debug_rate / Ogre::Math::TWO_PI);
1296 float h2 = ImGui::CalcTextSize(angle_buf).x / 2.0f;
1297 drawlist->AddText(ImVec2(pos.x - h2, pos.y + v),
NODE_TEXT_COLOR, angle_buf);
1298 char aerror_buf[25];
1299 snprintf(aerror_buf, 25,
"Error: %.1f mrad", 1000.0f * std::abs(rotators[i].debug_aerror));
1300 float h3 = ImGui::CalcTextSize(aerror_buf).x / 2.0f;
1301 drawlist->AddText(ImVec2(pos.x - h3, pos.y + v + v),
NODE_TEXT_COLOR, aerror_buf);
1306 for (
int j = 0; j < 4; j++)
1310 ImU32 node_color = Ogre::ColourValue(0.33f, 0.33f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1311 ImU32 beam_color = Ogre::ColourValue(0.33f, 0.33f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1313 Ogre::Vector3 pos3_xyz = world2screen.
Convert(nodes[rotators[i].nodes1[j]].AbsPosition);
1314 if (pos3_xyz.z < 0.f)
1316 ImVec2 pos(pos3_xyz.x, pos3_xyz.y);
1317 drawlist->AddCircleFilled(pos,
NODE_RADIUS, node_color);
1319 id_buf << nodes[rotators[i].
nodes1[j]].
pos;
1322 if ((pos1_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1324 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1325 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1331 ImU32 node_color = Ogre::ColourValue(1.00f, 0.87f, 0.27f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1332 ImU32 beam_color = Ogre::ColourValue(0.88f, 0.64f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1334 Ogre::Vector3 pos3_xyz = world2screen.
Convert(nodes[rotators[i].nodes2[j]].AbsPosition);
1335 if (pos3_xyz.z < 0.f)
1337 ImVec2 pos(pos3_xyz.x, pos3_xyz.y);
1338 drawlist->AddCircleFilled(pos,
NODE_RADIUS, node_color);
1340 id_buf << nodes[rotators[i].
nodes2[j]].
pos;
1343 if ((pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1345 ImVec2 pos1xy(pos2_xyz.x, pos2_xyz.y);
1346 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1354 Ogre::Vector3 mid = nodes[rotators[i].
axis1].
AbsPosition.midPoint(nodes[rotators[i].axis2].AbsPosition);
1356 Ogre::Vector3 perp = axis.perpendicular();
1359 const int steps = 64;
1360 Ogre::Plane plane = Ogre::Plane(axis, mid);
1362 Ogre::Real radius1 = 0.0f;
1363 Ogre::Real offset1 = 0.0f;
1364 for (
int k = 0; k < 2; k++)
1367 Ogre::Real r = plane.projectVector(r1).length();
1371 offset1 = plane.getDistance(nodes[rotators[i].nodes1[k]].AbsPosition);
1374 std::vector<ImVec2> pos1_xy;
1375 for (
int k = 0; k < steps; k++)
1377 Ogre::Quaternion rotation(Ogre::Radian(((
float)k / steps) * Ogre::Math::TWO_PI), axis);
1378 Ogre::Vector3 pos_xyz = world2screen.
Convert(mid + axis * offset1 + rotation * perp * radius1);
1379 if (pos_xyz.z < 0.f)
1381 pos1_xy.push_back(ImVec2(pos_xyz.x, pos_xyz.y));
1384 if (!pos1_xy.empty())
1386 drawlist->AddConvexPolyFilled(pos1_xy.data(),
static_cast<int>(pos1_xy.size()), 0x33666666);
1389 Ogre::Real radius2 = 0.0f;
1390 Ogre::Real offset2 = 0.0f;
1391 for (
int k = 0; k < 2; k++)
1394 Ogre::Real r = plane.projectVector(r2).length();
1398 offset2 = plane.getDistance(nodes[rotators[i].nodes2[k]].AbsPosition);
1401 std::vector<ImVec2> pos2_xy;
1402 for (
int k = 0; k < steps; k++)
1404 Ogre::Quaternion rotation(Ogre::Radian(((
float)k / steps) * Ogre::Math::TWO_PI), axis);
1405 Ogre::Vector3 pos_xyz = world2screen.
Convert(mid + axis * offset2 + rotation * perp * radius2);
1406 if (pos_xyz.z < 0.f)
1408 pos2_xy.push_back(ImVec2(pos_xyz.x, pos_xyz.y));
1411 if (!pos2_xy.empty())
1413 drawlist->AddConvexPolyFilled(pos2_xy.data(),
static_cast<int>(pos2_xy.size()), 0x1155a3e0);
1416 for (
int k = 0; k < 2; k++)
1419 Ogre::Vector3 ref1 = plane.projectVector(nodes[rotators[i].nodes1[k]].AbsPosition - mid);
1420 Ogre::Vector3 th1 = Ogre::Quaternion(Ogre::Radian(rotators[i].angle), axis) * ref1;
1422 Ogre::Vector3 pos1_xyz = world2screen.
Convert(mid + axis * offset1);
1423 Ogre::Vector3 pos2_xyz = world2screen.
Convert(mid + axis * offset1 + th1);
1424 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1426 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1427 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1432 Ogre::Vector3 ref2 = plane.projectVector(nodes[rotators[i].nodes2[k]].AbsPosition - mid);
1434 Ogre::Vector3 pos1_xyz = world2screen.
Convert(mid + axis * offset2);
1435 Ogre::Vector3 pos2_xyz = world2screen.
Convert(mid + axis * offset2 + ref2);
1436 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1438 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1439 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1445 Ogre::Real radius = std::min(radius1, radius2);
1446 Ogre::Vector3 pos3_xyz = world2screen.
Convert(mid + axis * offset1 + th1 * radius);
1447 Ogre::Vector3 pos4_xyz = world2screen.
Convert(mid + axis * offset2 + th1 * radius);
1448 if ((pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1450 ImVec2 pos1xy(pos3_xyz.x, pos3_xyz.y);
1451 ImVec2 pos2xy(pos4_xyz.x, pos4_xyz.y);
1460 const node_t* nodes = m_actor->ar_nodes;
1461 std::set<int> node_ids;
1462 for (
auto railgroup : m_actor->m_railgroups)
1464 for (
auto railsegment : railgroup->rg_segments)
1466 Ogre::Vector3 pos1 = world2screen.
Convert(railsegment.rs_beam->p1->AbsPosition);
1467 Ogre::Vector3 pos2 = world2screen.
Convert(railsegment.rs_beam->p2->AbsPosition);
1471 node_ids.insert(railsegment.rs_beam->p1->pos);
1475 node_ids.insert(railsegment.rs_beam->p2->pos);
1477 if ((pos1.z < 0.f) && (pos2.z < 0.f))
1479 ImVec2 pos1xy(pos1.x, pos1.y);
1480 ImVec2 pos2xy(pos2.x, pos2.y);
1486 for (
auto id : node_ids)
1488 Ogre::Vector3 pos_xyz = world2screen.
Convert(nodes[
id].AbsPosition);
1489 if (pos_xyz.z < 0.f)
1491 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1499 for (
auto slidenode : m_actor->m_slidenodes)
1501 auto id = slidenode.GetSlideNodeId();
1502 Ogre::Vector3 pos_xyz = world2screen.
Convert(nodes[
id].AbsPosition);
1504 if (pos_xyz.z < 0.f)
1506 ImVec2 pos(pos_xyz.x, pos_xyz.y);
1517 const node_t* nodes = m_actor->ar_nodes;
1518 const auto cabs = m_actor->ar_cabs;
1519 const auto num_cabs = m_actor->ar_num_cabs;
1520 const auto buoycabs = m_actor->ar_buoycabs;
1521 const auto num_buoycabs = m_actor->ar_num_buoycabs;
1522 const auto collcabs = m_actor->ar_collcabs;
1523 const auto num_collcabs = m_actor->ar_num_collcabs;
1525 std::vector<std::pair<float, int>> render_cabs;
1526 for (
int i = 0; i < num_cabs; i++)
1528 Ogre::Vector3 pos1_xyz = world2screen.
Convert(nodes[cabs[i*3+0]].AbsPosition);
1529 Ogre::Vector3 pos2_xyz = world2screen.
Convert(nodes[cabs[i*3+1]].AbsPosition);
1530 Ogre::Vector3 pos3_xyz = world2screen.
Convert(nodes[cabs[i*3+2]].AbsPosition);
1531 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1533 float depth = pos1_xyz.z;
1534 depth = std::max(depth, pos2_xyz.z);
1535 depth = std::max(depth, pos3_xyz.z);
1536 render_cabs.push_back({depth, i});
1539 std::sort(render_cabs.begin(), render_cabs.end());
1542 std::vector<int> node_ids;
1543 for (
auto render_cab : render_cabs)
1545 int i = render_cab.second;
1546 bool coll = std::find(collcabs, collcabs + num_collcabs, i) != (collcabs + num_collcabs);
1547 bool buoy = std::find(buoycabs, buoycabs + num_buoycabs, i) != (buoycabs + num_buoycabs);
1549 ImU32 fill_color = Ogre::ColourValue(0.5f * coll, 0.5f * !buoy, 0.5f * (coll ^ buoy), 0.27f).getAsABGR();
1550 ImU32 beam_color = Ogre::ColourValue(0.5f * coll, 0.5f * !buoy, 0.5f * (coll ^ buoy), 0.53f).getAsABGR();
1552 Ogre::Vector3 pos1_xyz = world2screen.
Convert(nodes[cabs[i*3+0]].AbsPosition);
1553 Ogre::Vector3 pos2_xyz = world2screen.
Convert(nodes[cabs[i*3+1]].AbsPosition);
1554 Ogre::Vector3 pos3_xyz = world2screen.
Convert(nodes[cabs[i*3+2]].AbsPosition);
1555 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1557 ImVec2 pos1_xy(pos1_xyz.x, pos1_xyz.y);
1558 ImVec2 pos2_xy(pos2_xyz.x, pos2_xyz.y);
1559 ImVec2 pos3_xy(pos3_xyz.x, pos3_xyz.y);
1560 drawlist->AddTriangleFilled(pos1_xy, pos2_xy, pos3_xy, fill_color);
1561 drawlist->AddTriangle(pos1_xy, pos2_xy, pos3_xy, beam_color,
BEAM_THICKNESS);
1563 for (
int k = 0; k < 3; k++)
1565 int id = cabs[i*3+k];
1566 if (std::find(node_ids.begin(), node_ids.end(),
id) == node_ids.end())
1568 Ogre::Vector3 pos_xyz = world2screen.
Convert(nodes[
id].AbsPosition);
1569 if (pos_xyz.z < 0.f)
1571 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1572 drawlist->AddCircleFilled(pos_xy,
NODE_RADIUS, nodes[
id].nd_contacter ? 0xbb0033ff : 0x88888888);
1578 node_ids.push_back(
id);
1584 if (m_actor->m_buoyance)
1587 for (
BuoyDebugSubCab& subcab: m_actor->m_buoyance->buoy_debug_subcabs)
1589 ImU32 fill_color = Ogre::ColourValue(0.4f, 0.4f, 0.9f, 0.27f).getAsABGR();
1590 ImU32 beam_color = Ogre::ColourValue(0.2f, 0.3f, 0.8f, 0.53f).getAsABGR();
1592 Ogre::Vector3 pos1_xyz = world2screen.
Convert(subcab.a);
1593 Ogre::Vector3 pos2_xyz = world2screen.
Convert(subcab.b);
1594 Ogre::Vector3 pos3_xyz = world2screen.
Convert(subcab.c);
1595 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1597 ImVec2 pos1_xy(pos1_xyz.x, pos1_xyz.y);
1598 ImVec2 pos2_xy(pos2_xyz.x, pos2_xyz.y);
1599 ImVec2 pos3_xy(pos3_xyz.x, pos3_xyz.y);
1600 drawlist->AddTriangleFilled(pos1_xy, pos2_xy, pos3_xy, fill_color);
1601 drawlist->AddTriangle(pos1_xy, pos2_xy, pos3_xy, beam_color,
BEAM_THICKNESS);
1606 for (
int i = 0; i < m_actor->ar_num_buoycabs; i++)
1608 const ImU32 beam_color = Ogre::ColourValue(0.5f, 0.1f, 0.1f, 0.53f).getAsABGR();
1609 int tmpv = m_actor->ar_buoycabs[i] * 3;
1610 Ogre::Vector3 pos1_xyz = world2screen.
Convert(m_actor->ar_nodes[m_actor->ar_cabs[tmpv]].AbsPosition);
1611 Ogre::Vector3 pos2_xyz = world2screen.
Convert(m_actor->ar_nodes[m_actor->ar_cabs[tmpv + 1]].AbsPosition);
1612 Ogre::Vector3 pos3_xyz = world2screen.
Convert(m_actor->ar_nodes[m_actor->ar_cabs[tmpv + 2]].AbsPosition);
1613 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1615 ImVec2 pos1_xy(pos1_xyz.x, pos1_xyz.y);
1616 ImVec2 pos2_xy(pos2_xyz.x, pos2_xyz.y);
1617 ImVec2 pos3_xy(pos3_xyz.x, pos3_xyz.y);
1618 drawlist->AddTriangle(pos1_xy, pos2_xy, pos3_xy, beam_color,
BEAM_THICKNESS);
1622 for (
BuoyCachedNode& bcn: m_actor->m_buoyance->buoy_cached_nodes)
1624 Ogre::Vector3 pos_xyz = world2screen.
Convert(bcn.AbsPosition);
1625 if (pos_xyz.z < 0.f)
1627 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1628 ImU32 col = 0x88aaaaaa;
1629 drawlist->AddCircleFilled(pos_xy,
NODE_RADIUS, col);
1632 id_buf << bcn.nodenum;
2498 for (spi = 0; spi < m_simbuf.simbuf_screwprops.size(); spi++)
2500 ctmp += m_simbuf.simbuf_screwprops[spi].simbuf_sp_rudder;
2514 for (spi = 0; spi < m_simbuf.simbuf_screwprops.size(); spi++)
2516 ctmp += m_simbuf.simbuf_screwprops[spi].simbuf_sp_throttle;
2528 if (m_actor->m_num_wheel_diffs > 0)
2530 switch (m_simbuf.simbuf_diff_type)
2554 cstate = (m_simbuf.simbuf_rotation * 57.29578f) / 360.0f;
2559 const bool has_engine = (m_actor->ar_engine!=
nullptr);
2562 float torque = m_simbuf.simbuf_engine_crankfactor;
2565 if (torque >= m_prop_anim_crankfactor_prev)
2566 cstate -= torque / 10.0f;
2570 if (cstate <= -1.0f)
2572 m_prop_anim_crankfactor_prev = torque;
2578 bool match =
static_cast<int>(anim.
animOpt3) == m_actor->ar_engine->getGear();
2579 cstate +=
static_cast<int>(match);
2586 float shifterseq_cstate = 0;
2590 int shifter = m_simbuf.simbuf_gear;
2591 if (shifter > m_prop_anim_prev_gear)
2593 shifterseq_cstate = 1.0f;
2594 m_prop_anim_shift_timer = 0.2f;
2596 if (shifter < m_prop_anim_prev_gear)
2598 shifterseq_cstate = -1.0f;
2599 m_prop_anim_shift_timer = -0.2f;
2601 m_prop_anim_prev_gear = shifter;
2603 if (m_prop_anim_shift_timer > 0.0f)
2605 shifterseq_cstate = 1.0f;
2606 m_prop_anim_shift_timer -= dt;
2607 if (m_prop_anim_shift_timer < 0.0f)
2608 m_prop_anim_shift_timer = 0.0f;
2610 if (m_prop_anim_shift_timer < 0.0f)
2612 shifterseq_cstate = -1.0f;
2613 m_prop_anim_shift_timer += dt;
2614 if (m_prop_anim_shift_timer > 0.0f)
2615 m_prop_anim_shift_timer = 0.0f;
2622 if (m_simbuf.simbuf_commandkey[
int(anim.
lower_limit)].simbuf_cmd_value > 0)
2623 shifterseq_cstate = 1.0f;
2626 if (m_simbuf.simbuf_commandkey[
int(anim.
upper_limit)].simbuf_cmd_value > 0)
2627 shifterseq_cstate = -1.0f;
2631 cstate += UpdateSmoothShift(anim, dt, shifterseq_cstate);
2638 float shifterman1_cstate = 0.f;
2639 int shifter = m_simbuf.simbuf_gear;
2642 shifterman1_cstate = -0.5f;
2644 else if (shifter < 0)
2646 shifterman1_cstate = 1.0f;
2650 shifterman1_cstate = -int((shifter - 1.0) / 2.0);
2653 cstate += UpdateSmoothShift(anim, dt, shifterman1_cstate);
2660 float shifterman2_cstate = 0.f;
2661 int shifter = m_simbuf.simbuf_gear;
2662 shifterman2_cstate = 0.5f;
2665 shifterman2_cstate = 1.0f;
2669 shifterman2_cstate = shifter % 2;
2672 cstate += UpdateSmoothShift(anim, dt, shifterman2_cstate);
2679 float shifterlin_cstate = 0.f;
2680 int shifter = m_simbuf.simbuf_gear;
2681 int numgears = m_simbuf.simbuf_num_gears;
2682 shifterlin_cstate -= (shifter + 2.0) / (numgears + 2.0);
2684 cstate += UpdateSmoothShift(anim, dt, shifterlin_cstate);
2691 float shifterlin_cstate = 0.f;
2692 int shifter = std::min(m_simbuf.simbuf_gear, 1);
2694 shifterlin_cstate -= (shifter + 2.0) / (numgears + 2.0);
2696 cstate += UpdateSmoothShift(anim, dt, shifterlin_cstate);
2703 float pbrake =
static_cast<float>(m_simbuf.simbuf_parking_brake);
2711 float speedo = m_simbuf.simbuf_wheel_speed / m_simbuf.simbuf_speedo_highest_kph;
2712 cstate -= speedo * 3.0f;
2719 float tacho = m_simbuf.simbuf_engine_rpm / m_simbuf.simbuf_engine_max_rpm;
2727 float turbo = m_simbuf.simbuf_engine_turbo_psi * 3.34;
2728 cstate -= turbo / 67.0f;
2735 float brakes = m_simbuf.simbuf_brake;
2743 float accel = m_simbuf.simbuf_engine_accel;
2744 cstate -= accel + 0.06f;
2752 float clutch = m_simbuf.simbuf_clutch;
2753 cstate -= fabs(1.0f - clutch);
2760 float signal = 0.0f;
2772 float ignition = m_simbuf.simbuf_engine_ignition;
2779 if (anim.
animOpt3 > 0.f && anim.
animOpt3 <=
float(m_simbuf.simbuf_aeroengines.size()))
2781 const int aenum = int(anim.
animOpt3 - 1.f);
2785 float pcent = m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_rpmpc;
2787 angle = -5.0 + pcent * 1.9167;
2788 else if (pcent < 110.0)
2789 angle = 110.0 + (pcent - 60.0) * 4.075;
2792 cstate -= angle / 314.0f;
2797 float throttle = m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_throttle;
2806 cstate = m_simbuf.simbuf_aeroengines[aenum].simbuf_tp_aetorque / 120.0f;
2812 cstate = m_simbuf.simbuf_aeroengines[aenum].simbuf_tp_aepitch / 120.0f;
2819 if (!m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_ignition)
2823 if (m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_failed)
2829 const Ogre::Vector3 node0_pos = this->GetSimNodeBuffer()[0].AbsPosition;
2830 const Ogre::Vector3 node0_velo = m_simbuf.simbuf_node0_velo;
2835 float ground_speed_kt = node0_velo.length() * 1.9438;
2836 float altitude = node0_pos.y;
2838 float sea_level_pressure = 101325;
2840 float airpressure = sea_level_pressure * pow(1.0 - 0.0065 * altitude / 288.15, 5.24947);
2841 float airdensity = airpressure * 0.0000120896;
2842 float kt = ground_speed_kt * sqrt(airdensity / 1.225);
2843 cstate -= kt / 100.0f;
2850 float vvi = node0_velo.y * 196.85;
2852 cstate -= vvi / 6000.0f;
2855 if (cstate <= -1.0f)
2866 float altimeter = (node0_pos.y * 1.1811) / 360.0f;
2867 int alti_int = int(altimeter);
2868 float alti_mod = (altimeter - alti_int);
2875 float alti = node0_pos.y * 1.1811 / 3600.0f;
2876 int alti_int = int(alti);
2877 float alti_mod = (alti - alti_int);
2879 if (cstate <= -1.0f)
2886 float alti = node0_pos.y * 1.1811 / 36000.0f;
2888 if (cstate <= -1.0f)
2897 float aoa = m_simbuf.simbuf_wing4_aoa / 25.f;
2898 if ((node0_velo.length() * 1.9438) < 10.0f)
2901 if (cstate <= -1.0f)
2908 Ogre::Vector3 cam_pos = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_pos ].AbsPosition;
2909 Ogre::Vector3 cam_roll = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_roll].AbsPosition;
2910 Ogre::Vector3 cam_dir = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_dir ].AbsPosition;
2915 Ogre::Vector3 rollv = (cam_pos - cam_roll).normalisedCopy();
2916 Ogre::Vector3 dirv = (cam_pos - cam_dir).normalisedCopy();
2917 Ogre::Vector3 upv = dirv.crossProduct(-rollv);
2918 float rollangle = asin(rollv.dotProduct(Ogre::Vector3::UNIT_Y));
2920 rollangle = Ogre::Math::RadiansToDegrees(rollangle);
2923 rollangle = 180.0f - rollangle;
2924 cstate = rollangle / 180.0f;
2928 cstate = cstate - 2.0f;
2935 Ogre::Vector3 dirv = (cam_pos - cam_dir).normalisedCopy();
2936 float pitchangle = asin(dirv.dotProduct(Ogre::Vector3::UNIT_Y));
2938 cstate = (Ogre::Math::RadiansToDegrees(pitchangle) / 90.0f);
2945 float airbrake =
static_cast<float>(m_simbuf.simbuf_airbrake_state);
2947 cstate -= airbrake / 5.0f;
2954 float flaps =
FLAP_ANGLES[m_simbuf.simbuf_aero_flap_state];