726 if (m_actor->m_buoyance)
737 ImVec2 screen_size = ImGui::GetIO().DisplaySize;
746 Ogre::Vector3 pos_xyz = world2screen.
Convert(m_actor->getPosition());
749 ImVec2 pos(pos_xyz.x, pos_xyz.y);
752 for (
int i = 0; i < m_actor->ar_num_nodes; ++i)
754 radius = std::max(radius, pos_xyz.distance(world2screen.
Convert(m_actor->ar_nodes[i].AbsPosition)));
757 drawlist->AddCircleFilled(pos, radius * 1.05f, 0x22222222, 36);
767 const beam_t* beams = m_actor->ar_beams;
768 const size_t num_beams =
static_cast<size_t>(m_actor->ar_num_beams);
769 for (
size_t i = 0; i < num_beams; ++i)
776 Ogre::Vector3 pos1 = world2screen.
Convert(beams[i].p1->AbsPosition);
777 Ogre::Vector3 pos2 = world2screen.
Convert(beams[i].p2->AbsPosition);
779 if ((pos1.z < 0.f) && (pos2.z < 0.f))
781 ImVec2 pos1xy(pos1.x, pos1.y);
782 ImVec2 pos2xy(pos2.x, pos2.y);
784 if (beams[i].bm_broken)
793 if (!beams[i].bm_disabled)
803 if (beams[i].stress > 0)
805 float stress_ratio = pow(beams[i].stress / beams[i].maxposstress, 2.0f);
806 float s = std::min(stress_ratio, 1.0f);
807 color = Ogre::ColourValue(0.2f * (1 + 2.0f * s), 0.4f * (1.0f - s), 0.33f, 1.0f).getAsABGR();
809 else if (beams[i].stress < 0)
811 float stress_ratio = pow(beams[i].stress / beams[i].maxnegstress, 2.0f);
812 float s = std::min(stress_ratio, 1.0f);
813 color = Ogre::ColourValue(0.2f, 0.4f * (1.0f - s), 0.33f * (1 + 1.0f * s), 1.0f).getAsABGR();
824 const node_t* nodes = m_actor->ar_nodes;
825 const size_t num_nodes =
static_cast<size_t>(m_actor->ar_num_nodes);
826 for (
size_t i = 0; i < num_nodes; ++i)
831 Ogre::Vector3 pos_xyz = world2screen.
Convert(nodes[i].AbsPosition);
835 ImVec2 pos(pos_xyz.x, pos_xyz.y);
836 if (nodes[i].nd_immovable)
850 for (
size_t i = 0; i < num_nodes; ++i)
853 (nodes[i].nd_tyre_node || nodes[i].nd_rim_node))
856 Ogre::Vector3 pos = world2screen.
Convert(nodes[i].AbsPosition);
860 ImVec2 pos_xy(pos.x, pos.y);
862 id_buf << nodes[i].
pos;
868 snprintf(mass_buf, 50,
"|%.1fKg", nodes[i].mass);
869 ImVec2 offset = ImGui::CalcTextSize(id_buf.
ToCStr());
880 for (
size_t i = 0; i < num_beams; ++i)
889 Ogre::Vector3 pos_xyz = world2screen.
Convert(world_pos);
890 if (pos_xyz.z >= 0.f)
894 ImVec2 pos(pos_xyz.x, pos_xyz.y);
897 const size_t BUF_LEN = 50;
899 if (beams[i].strength >= 1000000000000.f)
901 snprintf(buf, BUF_LEN,
"%.1fT", (beams[i].strength / 1000000000000.f));
903 else if (beams[i].strength >= 1000000000.f)
905 snprintf(buf, BUF_LEN,
"%.1fG", (beams[i].strength / 1000000000.f));
907 else if (beams[i].strength >= 1000000.f)
909 snprintf(buf, BUF_LEN,
"%.1fM", (beams[i].strength / 1000000.f));
911 else if (beams[i].strength >= 1000.f)
913 snprintf(buf, BUF_LEN,
"%.1fK", (beams[i].strength / 1000.f));
917 snprintf(buf, BUF_LEN,
"%.1f", beams[i].strength);
919 const ImVec2 stren_text_size = ImGui::CalcTextSize(buf);
923 snprintf(buf, BUF_LEN,
"|%.1f", beams[i].stress);
930 const wheel_t* wheels = m_actor->ar_wheels;
931 const size_t num_wheels =
static_cast<size_t>(m_actor->ar_num_wheels);
932 for (
int i = 0; i < num_wheels; i++)
939 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_axis_node_1->AbsPosition);
940 if (pos1_xyz.z < 0.f)
942 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
945 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_axis_node_0->AbsPosition);
946 if (pos2_xyz.z < 0.f)
948 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
951 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
953 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
954 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
959 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
962 float v = ImGui::GetTextLineHeightWithSpacing();
963 ImVec2 pos(pos_xyz.x, pos_xyz.y);
965 wheel_id_buf <<
"Id: " << (i + 1);
966 float h1 = ImGui::CalcTextSize(wheel_id_buf.
ToCStr()).x / 2.0f;
969 rpm_buf <<
"Speed: " <<
static_cast<int>(
Round(wheels[i].debug_rpm)) <<
" rpm";
970 float h2 = ImGui::CalcTextSize(rpm_buf.
ToCStr()).x / 2.0f;
973 torque_buf <<
"Torque: " <<
static_cast<int>(
Round(wheels[i].debug_torque)) <<
" Nm";
974 float h3 = ImGui::CalcTextSize(torque_buf.
ToCStr()).x / 2.0f;
983 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
984 if (pos1_xyz.z < 0.f)
986 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
989 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
990 if (pos2_xyz.z < 0.f)
992 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
995 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
997 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
998 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1003 Ogre::Vector3 radius = Ogre::Plane(axis, wheels[i].wh_near_attach_node->RelPosition).projectVector(rradius);
1008 Ogre::Vector3 up = axis.crossProduct(radius);
1009 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius - up);
1010 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius + up);
1011 Ogre::Vector3 pos3_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition - radius + up);
1012 Ogre::Vector3 pos4_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition - radius - up);
1013 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1015 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1016 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1017 ImVec2 pos3xy(pos3_xyz.x, pos3_xyz.y);
1018 ImVec2 pos4xy(pos4_xyz.x, pos4_xyz.y);
1019 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, 0x22888888);
1025 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
1026 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition + radius);
1027 Ogre::Vector3 pos3_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
1028 if (pos2_xyz.z < 0.f)
1030 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
1033 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1035 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1036 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1039 if ((pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1041 ImVec2 pos1xy(pos2_xyz.x, pos2_xyz.y);
1042 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1050 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition);
1051 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_arm_node->AbsPosition - cforce);
1052 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1054 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1055 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1060 Ogre::Vector3 pos1_xyz = world2screen.
Convert(wheels[i].wh_near_attach_node->AbsPosition);
1061 Ogre::Vector3 pos2_xyz = world2screen.
Convert(wheels[i].wh_near_attach_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);
1075 Ogre::Vector3 u = - axis.crossProduct(m_simbuf.simbuf_direction);
1076 if (!wheels[i].debug_force.isZeroLength())
1080 Ogre::Vector3 f = axis.crossProduct(u);
1081 Ogre::Vector3 a = - axis *
w + f * std::max(
w, wheels[i].wh_radius * 0.5f);
1082 Ogre::Vector3 b = + axis *
w + f * std::max(
w, wheels[i].wh_radius * 0.5f);
1083 Ogre::Vector3 c = + axis *
w - f * std::max(
w, wheels[i].wh_radius * 0.5f);
1084 Ogre::Vector3 d = - axis *
w - f * std::max(
w, wheels[i].wh_radius * 0.5f);
1085 Ogre::Quaternion r = Ogre::Quaternion::IDENTITY;
1086 if (wheels[i].debug_vel.length() > 1.0f)
1088 r = Ogre::Quaternion(f.angleBetween(wheels[i].
debug_vel), u);
1090 Ogre::Vector3 pos1_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * a);
1091 Ogre::Vector3 pos2_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * b);
1092 Ogre::Vector3 pos3_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * c);
1093 Ogre::Vector3 pos4_xyz = world2screen.
Convert(m - u * wheels[i].wh_radius + r * d);
1094 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1096 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1097 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1098 ImVec2 pos3xy(pos3_xyz.x, pos3_xyz.y);
1099 ImVec2 pos4xy(pos4_xyz.x, pos4_xyz.y);
1100 if (!wheels[i].debug_force.isZeroLength())
1103 float wheelv = wheels[i].
debug_vel.length();
1104 float slip_ratio = std::min(slipv, wheelv) / std::max(1.0f, wheelv);
1105 float scale = pow(slip_ratio, 2);
1106 ImU32 col = Ogre::ColourValue(scale, 1.0f - scale, 0.0f, 0.2f).getAsABGR();
1107 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, col);
1111 drawlist->AddQuadFilled(pos1xy, pos2xy, pos3xy, pos4xy, 0x55555555);
1117 if (!wheels[i].debug_vel.isZeroLength())
1121 Ogre::Vector3 d = axis.crossProduct(m_simbuf.simbuf_direction) * wheels[i].
wh_radius;
1122 Ogre::Real slipv = wheels[i].
debug_slip.length();
1123 Ogre::Real wheelv = wheels[i].
debug_vel.length();
1124 Ogre::Vector3 s = wheels[i].
debug_slip * (std::min(slipv, wheelv) / std::max(1.0f, wheelv)) / slipv;
1125 Ogre::Vector3 pos1_xyz = world2screen.
Convert(m + d);
1126 Ogre::Vector3 pos2_xyz = world2screen.
Convert(m + d + s * std::max(
w, wheels[i].wh_radius * 0.5f));
1127 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1129 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1130 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1138 Ogre::Real mass = m_actor->getTotalMass(
false) * num_wheels;
1139 Ogre::Vector3 normalised_force = wheels[i].
debug_force.normalisedCopy() * std::min(f / mass, 1.0f);
1141 Ogre::Vector3 pos5_xyz = world2screen.
Convert(m);
1142 Ogre::Vector3 pos6_xyz = world2screen.
Convert(m + normalised_force * wheels[i].wh_radius);
1143 if ((pos5_xyz.z < 0.f) && (pos6_xyz.z < 0.f))
1145 ImVec2 pos1xy(pos5_xyz.x, pos5_xyz.y);
1146 ImVec2 pos2xy(pos6_xyz.x, pos6_xyz.y);
1154 const beam_t* beams = m_actor->ar_beams;
1155 const size_t num_beams =
static_cast<size_t>(m_actor->ar_num_beams);
1156 std::set<int> node_ids;
1157 for (
size_t i = 0; i < num_beams; ++i)
1161 if (!(beams[i].bounded ==
SHOCK1 || beams[i].bounded ==
SHOCK2 || beams[i].bounded ==
SHOCK3))
1164 Ogre::Vector3 pos1_xyz = world2screen.
Convert(beams[i].p1->AbsPosition);
1165 Ogre::Vector3 pos2_xyz = world2screen.
Convert(beams[i].p2->AbsPosition);
1167 if (pos1_xyz.z < 0.f)
1169 node_ids.insert(beams[i].p1->pos);
1171 if (pos2_xyz.z < 0.f)
1173 node_ids.insert(beams[i].p2->pos);
1176 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1178 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1179 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1186 for (
auto id : node_ids)
1188 Ogre::Vector3 pos_xyz = world2screen.
Convert(m_actor->ar_nodes[
id].AbsPosition);
1189 if (pos_xyz.z < 0.f)
1191 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1199 for (
size_t i = 0; i < num_beams; ++i)
1203 if (!(beams[i].bounded ==
SHOCK1 || beams[i].bounded ==
SHOCK2 || beams[i].bounded ==
SHOCK3))
1206 Ogre::Vector3 pos1_xyz = world2screen.
Convert(beams[i].p1->AbsPosition);
1207 Ogre::Vector3 pos2_xyz = world2screen.
Convert(beams[i].p2->AbsPosition);
1208 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
1210 if (pos_xyz.z < 0.f)
1213 float diff = beams[i].
p1->
AbsPosition.distance(beams[i].p2->AbsPosition) - beams[i].
L;
1214 ImU32 text_color = (diff < 0.0f) ? 0xff66ee66 : 0xff8888ff;
1215 float bound = (diff < 0.0f) ? beams[i].shortbound : beams[i].
longbound;
1216 float ratio = Ogre::Math::Clamp(diff / (bound * beams[i].L), -2.0f, +2.0f);
1218 float v = ImGui::GetTextLineHeightWithSpacing();
1219 ImVec2 pos(pos_xyz.x, pos_xyz.y - v - v);
1221 len_buf <<
"L: " <<
static_cast<int>(
Round(std::abs(ratio) * 100.0f)) <<
" %";
1222 float h1 = ImGui::CalcTextSize(len_buf.
ToCStr()).x / 2.0f;
1223 drawlist->AddText(ImVec2(pos.x - h1, pos.y), text_color, len_buf.
ToCStr());
1225 spring_buf <<
"S: " <<
static_cast<int>(
Round(beams[i].debug_k)) <<
" N";
1226 float h2 = ImGui::CalcTextSize(spring_buf.
ToCStr()).x / 2.0f;
1227 drawlist->AddText(ImVec2(pos.x - h2, pos.y + v), text_color, spring_buf.
ToCStr());
1229 damp_buf <<
"D: " <<
static_cast<int>(
Round(beams[i].debug_d)) <<
" N";
1230 float h3 = ImGui::CalcTextSize(damp_buf.
ToCStr()).x / 2.0f;
1231 drawlist->AddText(ImVec2(pos.x - h3, pos.y + v + v), text_color, damp_buf.
ToCStr());
1233 snprintf(vel_buf, 25,
"V: %.2f m/s", beams[i].debug_v);
1234 float h4 = ImGui::CalcTextSize(vel_buf).x / 2.0f;
1235 drawlist->AddText(ImVec2(pos.x - h4, pos.y + v + v + v), text_color, vel_buf);
1241 const node_t* nodes = m_actor->ar_nodes;
1242 const rotator_t* rotators = m_actor->ar_rotators;
1243 const size_t num_rotators =
static_cast<size_t>(m_actor->ar_num_rotators);
1244 for (
int i = 0; i < num_rotators; i++)
1246 Ogre::Vector3 pos1_xyz = world2screen.
Convert(nodes[rotators[i].axis1].AbsPosition);
1247 Ogre::Vector3 pos2_xyz = world2screen.
Convert(nodes[rotators[i].axis2].AbsPosition);
1251 if (pos1_xyz.z < 0.f)
1253 ImVec2 pos(pos1_xyz.x, pos1_xyz.y);
1256 id_buf << nodes[rotators[i].
axis1].
pos;
1259 if (pos2_xyz.z < 0.f)
1261 ImVec2 pos(pos2_xyz.x, pos2_xyz.y);
1264 id_buf << nodes[rotators[i].
axis2].
pos;
1267 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1269 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1270 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1275 Ogre::Vector3 pos_xyz = pos1_xyz.midPoint(pos2_xyz);
1276 if (pos_xyz.z < 0.f)
1278 float v = ImGui::GetTextLineHeightWithSpacing();
1279 ImVec2 pos(pos_xyz.x, pos_xyz.y);
1281 rotator_id_buf <<
"Id: " << (i + 1);
1282 float h1 = ImGui::CalcTextSize(rotator_id_buf.
ToCStr()).x / 2.0f;
1285 snprintf(angle_buf, 25,
"Rate: %.1f rpm", 60.0f * rotators[i].debug_rate / Ogre::Math::TWO_PI);
1286 float h2 = ImGui::CalcTextSize(angle_buf).x / 2.0f;
1287 drawlist->AddText(ImVec2(pos.x - h2, pos.y + v),
NODE_TEXT_COLOR, angle_buf);
1288 char aerror_buf[25];
1289 snprintf(aerror_buf, 25,
"Error: %.1f mrad", 1000.0f * std::abs(rotators[i].debug_aerror));
1290 float h3 = ImGui::CalcTextSize(aerror_buf).x / 2.0f;
1291 drawlist->AddText(ImVec2(pos.x - h3, pos.y + v + v),
NODE_TEXT_COLOR, aerror_buf);
1296 for (
int j = 0; j < 4; j++)
1300 ImU32 node_color = Ogre::ColourValue(0.33f, 0.33f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1301 ImU32 beam_color = Ogre::ColourValue(0.33f, 0.33f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1303 Ogre::Vector3 pos3_xyz = world2screen.
Convert(nodes[rotators[i].nodes1[j]].AbsPosition);
1304 if (pos3_xyz.z < 0.f)
1306 ImVec2 pos(pos3_xyz.x, pos3_xyz.y);
1307 drawlist->AddCircleFilled(pos,
NODE_RADIUS, node_color);
1309 id_buf << nodes[rotators[i].
nodes1[j]].
pos;
1312 if ((pos1_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1314 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1315 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1321 ImU32 node_color = Ogre::ColourValue(1.00f, 0.87f, 0.27f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1322 ImU32 beam_color = Ogre::ColourValue(0.88f, 0.64f, 0.33f, j < 2 ? 1.0f : 0.5f).getAsABGR();
1324 Ogre::Vector3 pos3_xyz = world2screen.
Convert(nodes[rotators[i].nodes2[j]].AbsPosition);
1325 if (pos3_xyz.z < 0.f)
1327 ImVec2 pos(pos3_xyz.x, pos3_xyz.y);
1328 drawlist->AddCircleFilled(pos,
NODE_RADIUS, node_color);
1330 id_buf << nodes[rotators[i].
nodes2[j]].
pos;
1333 if ((pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1335 ImVec2 pos1xy(pos2_xyz.x, pos2_xyz.y);
1336 ImVec2 pos2xy(pos3_xyz.x, pos3_xyz.y);
1344 Ogre::Vector3 mid = nodes[rotators[i].
axis1].
AbsPosition.midPoint(nodes[rotators[i].axis2].AbsPosition);
1346 Ogre::Vector3 perp = axis.perpendicular();
1349 const int steps = 64;
1350 Ogre::Plane plane = Ogre::Plane(axis, mid);
1352 Ogre::Real radius1 = 0.0f;
1353 Ogre::Real offset1 = 0.0f;
1354 for (
int k = 0; k < 2; k++)
1357 Ogre::Real r = plane.projectVector(r1).length();
1361 offset1 = plane.getDistance(nodes[rotators[i].nodes1[k]].AbsPosition);
1364 std::vector<ImVec2> pos1_xy;
1365 for (
int k = 0; k < steps; k++)
1367 Ogre::Quaternion rotation(Ogre::Radian(((
float)k / steps) * Ogre::Math::TWO_PI), axis);
1368 Ogre::Vector3 pos_xyz = world2screen.
Convert(mid + axis * offset1 + rotation * perp * radius1);
1369 if (pos_xyz.z < 0.f)
1371 pos1_xy.push_back(ImVec2(pos_xyz.x, pos_xyz.y));
1374 if (!pos1_xy.empty())
1376 drawlist->AddConvexPolyFilled(pos1_xy.data(),
static_cast<int>(pos1_xy.size()), 0x33666666);
1379 Ogre::Real radius2 = 0.0f;
1380 Ogre::Real offset2 = 0.0f;
1381 for (
int k = 0; k < 2; k++)
1384 Ogre::Real r = plane.projectVector(r2).length();
1388 offset2 = plane.getDistance(nodes[rotators[i].nodes2[k]].AbsPosition);
1391 std::vector<ImVec2> pos2_xy;
1392 for (
int k = 0; k < steps; k++)
1394 Ogre::Quaternion rotation(Ogre::Radian(((
float)k / steps) * Ogre::Math::TWO_PI), axis);
1395 Ogre::Vector3 pos_xyz = world2screen.
Convert(mid + axis * offset2 + rotation * perp * radius2);
1396 if (pos_xyz.z < 0.f)
1398 pos2_xy.push_back(ImVec2(pos_xyz.x, pos_xyz.y));
1401 if (!pos2_xy.empty())
1403 drawlist->AddConvexPolyFilled(pos2_xy.data(),
static_cast<int>(pos2_xy.size()), 0x1155a3e0);
1406 for (
int k = 0; k < 2; k++)
1409 Ogre::Vector3 ref1 = plane.projectVector(nodes[rotators[i].nodes1[k]].AbsPosition - mid);
1410 Ogre::Vector3 th1 = Ogre::Quaternion(Ogre::Radian(rotators[i].angle), axis) * ref1;
1412 Ogre::Vector3 pos1_xyz = world2screen.
Convert(mid + axis * offset1);
1413 Ogre::Vector3 pos2_xyz = world2screen.
Convert(mid + axis * offset1 + th1);
1414 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1416 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1417 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1422 Ogre::Vector3 ref2 = plane.projectVector(nodes[rotators[i].nodes2[k]].AbsPosition - mid);
1424 Ogre::Vector3 pos1_xyz = world2screen.
Convert(mid + axis * offset2);
1425 Ogre::Vector3 pos2_xyz = world2screen.
Convert(mid + axis * offset2 + ref2);
1426 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f))
1428 ImVec2 pos1xy(pos1_xyz.x, pos1_xyz.y);
1429 ImVec2 pos2xy(pos2_xyz.x, pos2_xyz.y);
1435 Ogre::Real radius = std::min(radius1, radius2);
1436 Ogre::Vector3 pos3_xyz = world2screen.
Convert(mid + axis * offset1 + th1 * radius);
1437 Ogre::Vector3 pos4_xyz = world2screen.
Convert(mid + axis * offset2 + th1 * radius);
1438 if ((pos3_xyz.z < 0.f) && (pos4_xyz.z < 0.f))
1440 ImVec2 pos1xy(pos3_xyz.x, pos3_xyz.y);
1441 ImVec2 pos2xy(pos4_xyz.x, pos4_xyz.y);
1450 const node_t* nodes = m_actor->ar_nodes;
1451 std::set<int> node_ids;
1452 for (
auto railgroup : m_actor->m_railgroups)
1454 for (
auto railsegment : railgroup->rg_segments)
1456 Ogre::Vector3 pos1 = world2screen.
Convert(railsegment.rs_beam->p1->AbsPosition);
1457 Ogre::Vector3 pos2 = world2screen.
Convert(railsegment.rs_beam->p2->AbsPosition);
1461 node_ids.insert(railsegment.rs_beam->p1->pos);
1465 node_ids.insert(railsegment.rs_beam->p2->pos);
1467 if ((pos1.z < 0.f) && (pos2.z < 0.f))
1469 ImVec2 pos1xy(pos1.x, pos1.y);
1470 ImVec2 pos2xy(pos2.x, pos2.y);
1476 for (
auto id : node_ids)
1478 Ogre::Vector3 pos_xyz = world2screen.
Convert(nodes[
id].AbsPosition);
1479 if (pos_xyz.z < 0.f)
1481 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1489 for (
auto slidenode : m_actor->m_slidenodes)
1491 auto id = slidenode.GetSlideNodeId();
1492 Ogre::Vector3 pos_xyz = world2screen.
Convert(nodes[
id].AbsPosition);
1494 if (pos_xyz.z < 0.f)
1496 ImVec2 pos(pos_xyz.x, pos_xyz.y);
1507 const node_t* nodes = m_actor->ar_nodes;
1508 const auto cabs = m_actor->ar_cabs;
1509 const auto num_cabs = m_actor->ar_num_cabs;
1510 const auto buoycabs = m_actor->ar_buoycabs;
1511 const auto num_buoycabs = m_actor->ar_num_buoycabs;
1512 const auto collcabs = m_actor->ar_collcabs;
1513 const auto num_collcabs = m_actor->ar_num_collcabs;
1515 std::vector<std::pair<float, int>> render_cabs;
1516 for (
int i = 0; i < num_cabs; i++)
1518 Ogre::Vector3 pos1_xyz = world2screen.
Convert(nodes[cabs[i*3+0]].AbsPosition);
1519 Ogre::Vector3 pos2_xyz = world2screen.
Convert(nodes[cabs[i*3+1]].AbsPosition);
1520 Ogre::Vector3 pos3_xyz = world2screen.
Convert(nodes[cabs[i*3+2]].AbsPosition);
1521 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1523 float depth = pos1_xyz.z;
1524 depth = std::max(depth, pos2_xyz.z);
1525 depth = std::max(depth, pos3_xyz.z);
1526 render_cabs.push_back({depth, i});
1529 std::sort(render_cabs.begin(), render_cabs.end());
1532 std::vector<int> node_ids;
1533 for (
auto render_cab : render_cabs)
1535 int i = render_cab.second;
1536 bool coll = std::find(collcabs, collcabs + num_collcabs, i) != (collcabs + num_collcabs);
1537 bool buoy = std::find(buoycabs, buoycabs + num_buoycabs, i) != (buoycabs + num_buoycabs);
1539 ImU32 fill_color = Ogre::ColourValue(0.5f * coll, 0.5f * !buoy, 0.5f * (coll ^ buoy), 0.27f).getAsABGR();
1540 ImU32 beam_color = Ogre::ColourValue(0.5f * coll, 0.5f * !buoy, 0.5f * (coll ^ buoy), 0.53f).getAsABGR();
1542 Ogre::Vector3 pos1_xyz = world2screen.
Convert(nodes[cabs[i*3+0]].AbsPosition);
1543 Ogre::Vector3 pos2_xyz = world2screen.
Convert(nodes[cabs[i*3+1]].AbsPosition);
1544 Ogre::Vector3 pos3_xyz = world2screen.
Convert(nodes[cabs[i*3+2]].AbsPosition);
1545 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1547 ImVec2 pos1_xy(pos1_xyz.x, pos1_xyz.y);
1548 ImVec2 pos2_xy(pos2_xyz.x, pos2_xyz.y);
1549 ImVec2 pos3_xy(pos3_xyz.x, pos3_xyz.y);
1550 drawlist->AddTriangleFilled(pos1_xy, pos2_xy, pos3_xy, fill_color);
1551 drawlist->AddTriangle(pos1_xy, pos2_xy, pos3_xy, beam_color,
BEAM_THICKNESS);
1553 for (
int k = 0; k < 3; k++)
1555 int id = cabs[i*3+k];
1556 if (std::find(node_ids.begin(), node_ids.end(),
id) == node_ids.end())
1558 Ogre::Vector3 pos_xyz = world2screen.
Convert(nodes[
id].AbsPosition);
1559 if (pos_xyz.z < 0.f)
1561 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1562 drawlist->AddCircleFilled(pos_xy,
NODE_RADIUS, nodes[
id].nd_contacter ? 0xbb0033ff : 0x88888888);
1568 node_ids.push_back(
id);
1574 if (m_actor->m_buoyance)
1577 for (
BuoyDebugSubCab& subcab: m_actor->m_buoyance->buoy_debug_subcabs)
1579 ImU32 fill_color = Ogre::ColourValue(0.4f, 0.4f, 0.9f, 0.27f).getAsABGR();
1580 ImU32 beam_color = Ogre::ColourValue(0.2f, 0.3f, 0.8f, 0.53f).getAsABGR();
1582 Ogre::Vector3 pos1_xyz = world2screen.
Convert(subcab.a);
1583 Ogre::Vector3 pos2_xyz = world2screen.
Convert(subcab.b);
1584 Ogre::Vector3 pos3_xyz = world2screen.
Convert(subcab.c);
1585 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1587 ImVec2 pos1_xy(pos1_xyz.x, pos1_xyz.y);
1588 ImVec2 pos2_xy(pos2_xyz.x, pos2_xyz.y);
1589 ImVec2 pos3_xy(pos3_xyz.x, pos3_xyz.y);
1590 drawlist->AddTriangleFilled(pos1_xy, pos2_xy, pos3_xy, fill_color);
1591 drawlist->AddTriangle(pos1_xy, pos2_xy, pos3_xy, beam_color,
BEAM_THICKNESS);
1596 for (
int i = 0; i < m_actor->ar_num_buoycabs; i++)
1598 const ImU32 beam_color = Ogre::ColourValue(0.5f, 0.1f, 0.1f, 0.53f).getAsABGR();
1599 int tmpv = m_actor->ar_buoycabs[i] * 3;
1600 Ogre::Vector3 pos1_xyz = world2screen.
Convert(m_actor->ar_nodes[m_actor->ar_cabs[tmpv]].AbsPosition);
1601 Ogre::Vector3 pos2_xyz = world2screen.
Convert(m_actor->ar_nodes[m_actor->ar_cabs[tmpv + 1]].AbsPosition);
1602 Ogre::Vector3 pos3_xyz = world2screen.
Convert(m_actor->ar_nodes[m_actor->ar_cabs[tmpv + 2]].AbsPosition);
1603 if ((pos1_xyz.z < 0.f) && (pos2_xyz.z < 0.f) && (pos3_xyz.z < 0.f))
1605 ImVec2 pos1_xy(pos1_xyz.x, pos1_xyz.y);
1606 ImVec2 pos2_xy(pos2_xyz.x, pos2_xyz.y);
1607 ImVec2 pos3_xy(pos3_xyz.x, pos3_xyz.y);
1608 drawlist->AddTriangle(pos1_xy, pos2_xy, pos3_xy, beam_color,
BEAM_THICKNESS);
1612 for (
BuoyCachedNode& bcn: m_actor->m_buoyance->buoy_cached_nodes)
1614 Ogre::Vector3 pos_xyz = world2screen.
Convert(bcn.AbsPosition);
1615 if (pos_xyz.z < 0.f)
1617 ImVec2 pos_xy(pos_xyz.x, pos_xyz.y);
1618 ImU32 col = 0x88aaaaaa;
1619 drawlist->AddCircleFilled(pos_xy,
NODE_RADIUS, col);
1622 id_buf << bcn.nodenum;
2503 for (spi = 0; spi < m_simbuf.simbuf_screwprops.size(); spi++)
2505 ctmp += m_simbuf.simbuf_screwprops[spi].simbuf_sp_rudder;
2519 for (spi = 0; spi < m_simbuf.simbuf_screwprops.size(); spi++)
2521 ctmp += m_simbuf.simbuf_screwprops[spi].simbuf_sp_throttle;
2533 if (m_actor->m_num_wheel_diffs > 0)
2535 switch (m_simbuf.simbuf_diff_type)
2559 cstate = (m_simbuf.simbuf_rotation * 57.29578f) / 360.0f;
2564 const bool has_engine = (m_actor->ar_engine!=
nullptr);
2567 float torque = m_simbuf.simbuf_engine_crankfactor;
2570 if (torque >= m_prop_anim_crankfactor_prev)
2571 cstate -= torque / 10.0f;
2575 if (cstate <= -1.0f)
2577 m_prop_anim_crankfactor_prev = torque;
2583 bool match =
static_cast<int>(anim.
animOpt3) == m_actor->ar_engine->getGear();
2584 cstate +=
static_cast<int>(match);
2591 float shifterseq_cstate = 0;
2595 int shifter = m_simbuf.simbuf_gear;
2596 if (shifter > m_prop_anim_prev_gear)
2598 shifterseq_cstate = 1.0f;
2599 m_prop_anim_shift_timer = 0.2f;
2601 if (shifter < m_prop_anim_prev_gear)
2603 shifterseq_cstate = -1.0f;
2604 m_prop_anim_shift_timer = -0.2f;
2606 m_prop_anim_prev_gear = shifter;
2608 if (m_prop_anim_shift_timer > 0.0f)
2610 shifterseq_cstate = 1.0f;
2611 m_prop_anim_shift_timer -= dt;
2612 if (m_prop_anim_shift_timer < 0.0f)
2613 m_prop_anim_shift_timer = 0.0f;
2615 if (m_prop_anim_shift_timer < 0.0f)
2617 shifterseq_cstate = -1.0f;
2618 m_prop_anim_shift_timer += dt;
2619 if (m_prop_anim_shift_timer > 0.0f)
2620 m_prop_anim_shift_timer = 0.0f;
2627 if (m_simbuf.simbuf_commandkey[
int(anim.
lower_limit)].simbuf_cmd_value > 0)
2628 shifterseq_cstate = 1.0f;
2631 if (m_simbuf.simbuf_commandkey[
int(anim.
upper_limit)].simbuf_cmd_value > 0)
2632 shifterseq_cstate = -1.0f;
2636 cstate += UpdateSmoothShift(anim, dt, shifterseq_cstate);
2643 float shifterman1_cstate = 0.f;
2644 int shifter = m_simbuf.simbuf_gear;
2647 shifterman1_cstate = -0.5f;
2649 else if (shifter < 0)
2651 shifterman1_cstate = 1.0f;
2655 shifterman1_cstate = -int((shifter - 1.0) / 2.0);
2658 cstate += UpdateSmoothShift(anim, dt, shifterman1_cstate);
2665 float shifterman2_cstate = 0.f;
2666 int shifter = m_simbuf.simbuf_gear;
2667 shifterman2_cstate = 0.5f;
2670 shifterman2_cstate = 1.0f;
2674 shifterman2_cstate = shifter % 2;
2677 cstate += UpdateSmoothShift(anim, dt, shifterman2_cstate);
2684 float shifterlin_cstate = 0.f;
2685 int shifter = m_simbuf.simbuf_gear;
2686 int numgears = m_simbuf.simbuf_num_gears;
2687 shifterlin_cstate -= (shifter + 2.0) / (numgears + 2.0);
2689 cstate += UpdateSmoothShift(anim, dt, shifterlin_cstate);
2696 float shifterlin_cstate = 0.f;
2697 int shifter = std::min(m_simbuf.simbuf_gear, 1);
2699 shifterlin_cstate -= (shifter + 2.0) / (numgears + 2.0);
2701 cstate += UpdateSmoothShift(anim, dt, shifterlin_cstate);
2708 float pbrake =
static_cast<float>(m_simbuf.simbuf_parking_brake);
2716 float speedo = m_simbuf.simbuf_wheel_speed / m_simbuf.simbuf_speedo_highest_kph;
2717 cstate -= speedo * 3.0f;
2724 float tacho = m_simbuf.simbuf_engine_rpm / m_simbuf.simbuf_engine_max_rpm;
2732 float turbo = m_simbuf.simbuf_engine_turbo_psi * 3.34;
2733 cstate -= turbo / 67.0f;
2740 float brakes = m_simbuf.simbuf_brake;
2748 float accel = m_simbuf.simbuf_engine_accel;
2749 cstate -= accel + 0.06f;
2757 float clutch = m_simbuf.simbuf_clutch;
2758 cstate -= fabs(1.0f - clutch);
2765 float signal = 0.0f;
2776 if (anim.
animOpt3 > 0.f && anim.
animOpt3 <=
float(m_simbuf.simbuf_aeroengines.size()))
2778 const int aenum = int(anim.
animOpt3 - 1.f);
2782 float pcent = m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_rpmpc;
2784 angle = -5.0 + pcent * 1.9167;
2785 else if (pcent < 110.0)
2786 angle = 110.0 + (pcent - 60.0) * 4.075;
2789 cstate -= angle / 314.0f;
2794 float throttle = m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_throttle;
2803 cstate = m_simbuf.simbuf_aeroengines[aenum].simbuf_tp_aetorque / 120.0f;
2809 cstate = m_simbuf.simbuf_aeroengines[aenum].simbuf_tp_aepitch / 120.0f;
2816 if (!m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_ignition)
2820 if (m_simbuf.simbuf_aeroengines[aenum].simbuf_ae_failed)
2826 const Ogre::Vector3 node0_pos = this->GetSimNodeBuffer()[0].AbsPosition;
2827 const Ogre::Vector3 node0_velo = m_simbuf.simbuf_node0_velo;
2832 float ground_speed_kt = node0_velo.length() * 1.9438;
2833 float altitude = node0_pos.y;
2835 float sea_level_pressure = 101325;
2837 float airpressure = sea_level_pressure * pow(1.0 - 0.0065 * altitude / 288.15, 5.24947);
2838 float airdensity = airpressure * 0.0000120896;
2839 float kt = ground_speed_kt * sqrt(airdensity / 1.225);
2840 cstate -= kt / 100.0f;
2847 float vvi = node0_velo.y * 196.85;
2849 cstate -= vvi / 6000.0f;
2852 if (cstate <= -1.0f)
2863 float altimeter = (node0_pos.y * 1.1811) / 360.0f;
2864 int alti_int = int(altimeter);
2865 float alti_mod = (altimeter - alti_int);
2872 float alti = node0_pos.y * 1.1811 / 3600.0f;
2873 int alti_int = int(alti);
2874 float alti_mod = (alti - alti_int);
2876 if (cstate <= -1.0f)
2883 float alti = node0_pos.y * 1.1811 / 36000.0f;
2885 if (cstate <= -1.0f)
2894 float aoa = m_simbuf.simbuf_wing4_aoa / 25.f;
2895 if ((node0_velo.length() * 1.9438) < 10.0f)
2898 if (cstate <= -1.0f)
2905 Ogre::Vector3 cam_pos = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_pos ].AbsPosition;
2906 Ogre::Vector3 cam_roll = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_roll].AbsPosition;
2907 Ogre::Vector3 cam_dir = this->GetSimNodeBuffer()[m_actor->ar_main_camera_node_dir ].AbsPosition;
2912 Ogre::Vector3 rollv = (cam_pos - cam_roll).normalisedCopy();
2913 Ogre::Vector3 dirv = (cam_pos - cam_dir).normalisedCopy();
2914 Ogre::Vector3 upv = dirv.crossProduct(-rollv);
2915 float rollangle = asin(rollv.dotProduct(Ogre::Vector3::UNIT_Y));
2917 rollangle = Ogre::Math::RadiansToDegrees(rollangle);
2920 rollangle = 180.0f - rollangle;
2921 cstate = rollangle / 180.0f;
2925 cstate = cstate - 2.0f;
2932 Ogre::Vector3 dirv = (cam_pos - cam_dir).normalisedCopy();
2933 float pitchangle = asin(dirv.dotProduct(Ogre::Vector3::UNIT_Y));
2935 cstate = (Ogre::Math::RadiansToDegrees(pitchangle) / 90.0f);
2942 float airbrake =
static_cast<float>(m_simbuf.simbuf_airbrake_state);
2944 cstate -= airbrake / 5.0f;
2951 float flaps =
FLAP_ANGLES[m_simbuf.simbuf_aero_flap_state];