Files
WickedEngine/Editor/RigidBodyWindow.cpp
T
2025-11-25 09:43:19 +01:00

827 lines
35 KiB
C++

#include "stdafx.h"
#include "RigidBodyWindow.h"
using namespace wi::ecs;
using namespace wi::scene;
void RigidBodyWindow::Create(EditorComponent* _editor)
{
editor = _editor;
wi::gui::Window::Create(ICON_RIGIDBODY " Rigid Body Physics", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE | wi::gui::Window::WindowControls::FIT_ALL_WIDGETS_VERTICAL);
SetSize(XMFLOAT2(670, 440));
closeButton.SetTooltip("Delete RigidBodyPhysicsComponent");
OnClose([=](wi::gui::EventArgs args) {
wi::Archive& archive = editor->AdvanceHistory();
archive << EditorComponent::HISTORYOP_COMPONENT_DATA;
editor->RecordEntity(archive, entity);
editor->GetCurrentScene().rigidbodies.Remove(entity);
editor->RecordEntity(archive, entity);
editor->componentsWnd.RefreshEntityTree();
});
auto forEachSelectedPhysicsComponent = [this](auto /* void(RigidBodyPhysicsComponent*, wi::gui::EventArgs) */ func) {
return [this, func](wi::gui::EventArgs args) {
wi::scene::Scene& scene = editor->GetCurrentScene();
for (auto& x : editor->translator.selected)
{
RigidBodyPhysicsComponent* physicscomponent = scene.rigidbodies.GetComponent(x.entity);
if (physicscomponent != nullptr)
{
func(physicscomponent, args);
}
}
};
};
auto forEachSelectedPhysicsComponentWithRefresh = [forEachSelectedPhysicsComponent](auto /* void(RigidBodyPhysicsComponent*, wi::gui::EventArgs) */ func) {
return forEachSelectedPhysicsComponent([func](auto physicscomponent, auto args) {
func(physicscomponent, args);
physicscomponent->SetRefreshParametersNeeded();
});
};
collisionShapeComboBox.Create("Collision Shape: ");
collisionShapeComboBox.AddItem("Box", RigidBodyPhysicsComponent::CollisionShape::BOX);
collisionShapeComboBox.AddItem("Sphere", RigidBodyPhysicsComponent::CollisionShape::SPHERE);
collisionShapeComboBox.AddItem("Capsule", RigidBodyPhysicsComponent::CollisionShape::CAPSULE);
collisionShapeComboBox.AddItem("Cylinder", RigidBodyPhysicsComponent::CollisionShape::CYLINDER);
collisionShapeComboBox.AddItem("Convex Hull", RigidBodyPhysicsComponent::CollisionShape::CONVEX_HULL);
collisionShapeComboBox.AddItem("Triangle Mesh", RigidBodyPhysicsComponent::CollisionShape::TRIANGLE_MESH);
collisionShapeComboBox.AddItem("Height Field", RigidBodyPhysicsComponent::CollisionShape::HEIGHTFIELD);
collisionShapeComboBox.OnSelect([=](wi::gui::EventArgs args) {
forEachSelectedPhysicsComponent([](auto physicscomponent, auto args) {
RigidBodyPhysicsComponent::CollisionShape shape = (RigidBodyPhysicsComponent::CollisionShape)args.userdata;
if (physicscomponent->shape != shape)
{
physicscomponent->physicsobject.reset();
physicscomponent->shape = shape;
}
})(args);
RefreshShapeType();
});
collisionShapeComboBox.SetSelected(0);
collisionShapeComboBox.SetEnabled(true);
collisionShapeComboBox.SetTooltip("Set rigid body collision shape.");
AddWidget(&collisionShapeComboBox);
XSlider.Create(0, 10, 1, 100000, "XSlider");
XSlider.OnSlide(forEachSelectedPhysicsComponent([](auto physicscomponent, auto args) {
switch (physicscomponent->shape)
{
default:
case RigidBodyPhysicsComponent::CollisionShape::BOX:
physicscomponent->box.halfextents.x = args.fValue;
break;
case RigidBodyPhysicsComponent::CollisionShape::SPHERE:
physicscomponent->sphere.radius = args.fValue;
break;
case RigidBodyPhysicsComponent::CollisionShape::CAPSULE:
case RigidBodyPhysicsComponent::CollisionShape::CYLINDER:
physicscomponent->capsule.height = args.fValue;
break;
}
physicscomponent->physicsobject.reset();
}));
ZSlider.SetLocalizationEnabled(false);
AddWidget(&XSlider);
YSlider.Create(0, 10, 1, 100000, "YSlider");
YSlider.OnSlide(forEachSelectedPhysicsComponent([](auto physicsComponent, auto args) {
switch (physicsComponent->shape)
{
default:
case RigidBodyPhysicsComponent::CollisionShape::BOX:
physicsComponent->box.halfextents.y = args.fValue;
break;
case RigidBodyPhysicsComponent::CollisionShape::CAPSULE:
case RigidBodyPhysicsComponent::CollisionShape::CYLINDER:
physicsComponent->capsule.radius = args.fValue;
break;
}
physicsComponent->physicsobject.reset();
}));
ZSlider.SetLocalizationEnabled(false);
AddWidget(&YSlider);
ZSlider.Create(0, 10, 1, 100000, "ZSlider");
ZSlider.OnSlide(forEachSelectedPhysicsComponent([](auto physicscomponent, auto args) {
switch (physicscomponent->shape)
{
default:
case RigidBodyPhysicsComponent::CollisionShape::BOX:
case RigidBodyPhysicsComponent::CollisionShape::CYLINDER:
physicscomponent->box.halfextents.z = args.fValue;
break;
}
physicscomponent->physicsobject.reset();
}));
ZSlider.SetLocalizationEnabled(false);
AddWidget(&ZSlider);
massSlider.Create(0, 10, 1, 100000, "Mass: ");
massSlider.SetTooltip("Set the mass amount for the physics engine.");
massSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->mass = args.fValue;
}));
AddWidget(&massSlider);
frictionSlider.Create(0, 1, 0.5f, 100000, "Friction: ");
frictionSlider.SetTooltip("Set the friction amount for the physics engine.");
frictionSlider.OnSlide(forEachSelectedPhysicsComponent([](auto physicscomponent, auto args) {
physicscomponent->friction = args.fValue;
}));
AddWidget(&frictionSlider);
restitutionSlider.Create(0, 1, 0, 100000, "Restitution: ");
restitutionSlider.SetTooltip("Set the restitution amount for the physics engine.");
restitutionSlider.OnSlide(forEachSelectedPhysicsComponent([](auto physicscomponent, auto args) {
physicscomponent->restitution = args.fValue;
}));
AddWidget(&restitutionSlider);
lineardampingSlider.Create(0, 1, 0, 100000, "Linear Damping: ");
lineardampingSlider.SetTooltip("Set the linear damping amount for the physics engine.");
lineardampingSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->damping_linear = args.fValue;
}));
AddWidget(&lineardampingSlider);
angulardampingSlider.Create(0, 1, 0, 100000, "Angular Damping: ");
angulardampingSlider.SetTooltip("Set the angular damping amount for the physics engine.");
angulardampingSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->damping_angular = args.fValue;
}));
AddWidget(&angulardampingSlider);
buoyancySlider.Create(0, 2, 0, 1000, "Buoyancy: ");
buoyancySlider.SetTooltip("Higher buoyancy will make the bodies float up faster in water.");
buoyancySlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->buoyancy = args.fValue;
}));
AddWidget(&buoyancySlider);
physicsMeshLODSlider.Create(0, 6, 0, 6, "Use Mesh LOD: ");
physicsMeshLODSlider.SetTooltip("Specify which LOD to use for triangle mesh physics.");
physicsMeshLODSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
if (physicscomponent->mesh_lod != uint32_t(args.iValue))
{
physicscomponent->physicsobject.reset(); // will be recreated automatically
physicscomponent->mesh_lod = uint32_t(args.iValue);
}
physicscomponent->mesh_lod = uint32_t(args.iValue);
}));
AddWidget(&physicsMeshLODSlider);
kinematicCheckBox.Create("Kinematic: ");
kinematicCheckBox.SetTooltip("Toggle kinematic behaviour.");
kinematicCheckBox.SetCheck(false);
kinematicCheckBox.OnClick(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->SetKinematic(args.bValue);
}));
AddWidget(&kinematicCheckBox);
disabledeactivationCheckBox.Create("Disable Deactivation: ");
disabledeactivationCheckBox.SetTooltip("Toggle kinematic behaviour.");
disabledeactivationCheckBox.SetCheck(false);
disabledeactivationCheckBox.OnClick(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->SetDisableDeactivation(args.bValue);
}));
AddWidget(&disabledeactivationCheckBox);
startDeactivatedCheckBox.Create("Start deactivated: ");
startDeactivatedCheckBox.SetTooltip("If enabled, the rigid body will start in a deactivated state.\nEven if the body is dynamic (non-kinematic, mass > 0), it will not fall unless interacted with.");
startDeactivatedCheckBox.SetCheck(false);
startDeactivatedCheckBox.OnClick(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->SetStartDeactivated(args.bValue);
}));
AddWidget(&startDeactivatedCheckBox);
offsetXSlider.Create(-10, 10, 0, 100000, "Local Offset X: ");
offsetXSlider.SetTooltip("Set a local offset relative to the object transform");
offsetXSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->local_offset.x = args.fValue;
}));
AddWidget(&offsetXSlider);
offsetYSlider.Create(-10, 10, 0, 100000, "Local Offset Y: ");
offsetYSlider.SetTooltip("Set a local offset relative to the object transform");
offsetYSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->local_offset.y = args.fValue;
}));
AddWidget(&offsetYSlider);
offsetZSlider.Create(-10, 10, 0, 100000, "Local Offset Z: ");
offsetZSlider.SetTooltip("Set a local offset relative to the object transform");
offsetZSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->local_offset.z = args.fValue;
}));
AddWidget(&offsetZSlider);
physicsDebugCheckBox.Create(ICON_EYE " Physics visualizer: ");
physicsDebugCheckBox.SetTooltip("Visualize the physics world");
physicsDebugCheckBox.OnClick([=](wi::gui::EventArgs args) {
wi::physics::SetDebugDrawEnabled(args.bValue);
editor->generalWnd.physicsDebugCheckBox.SetCheck(args.bValue);
editor->componentsWnd.constraintWnd.physicsDebugCheckBox.SetCheck(args.bValue);
});
physicsDebugCheckBox.SetCheck(wi::physics::IsDebugDrawEnabled());
AddWidget(&physicsDebugCheckBox);
characterCheckBox.Create(ICON_PHYSICS_CHARACTER " Character physics: ");
characterCheckBox.SetTooltip("Enable physics-driven character");
characterCheckBox.OnClick(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->SetCharacterPhysics(args.bValue);
}));
AddWidget(&characterCheckBox);
characterLabel.Create("CharacterLabel");
characterLabel.SetText("Notes about physics-driven character:\n- The capsule shape is recommended for a physics character.\n- The friction and mass of the physics character are taken from the standard rigid body parameters.\n- This is different from CharacterComponent which uses custom character movement logic.");
characterLabel.SetFitTextEnabled(true);
AddWidget(&characterLabel);
characterSlopeSlider.Create(0, 90, 50, 90, "Max slope angle: ");
characterSlopeSlider.SetTooltip("Specify the slope angle that the character can stand on.");
characterSlopeSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->character.maxSlopeAngle = wi::math::DegreesToRadians(args.fValue);
}));
AddWidget(&characterSlopeSlider);
characterGravitySlider.Create(0, 4, 1, 100, "Gravity factor: ");
characterGravitySlider.SetTooltip("Specify the strength of gravity acting on the character.");
characterGravitySlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->character.gravityFactor = args.fValue;
}));
AddWidget(&characterGravitySlider);
vehicleLabel.Create("VehicleLabel");
std::string tips;
tips += "Vehicle physics tips:\n";
tips += "- The vehicle's base shape can be configured in the standard shape settings above\n";
tips += "- A vehicle is always facing forward in +Z direction by default\n";
tips += "- Check that mass is set higher than the default 1kg, somewhere around ~1000 kg\n";
tips += "- Enable physics visualizer while editing vehicle parameters\n";
tips += "- You can reset vehicles by Ctrl + left click on the physics toggle button\n";
vehicleLabel.SetText(tips);
vehicleLabel.SetFitTextEnabled(true);
AddWidget(&vehicleLabel);
vehicleCombo.Create(ICON_VEHICLE " Vehicle physics: ");
vehicleCombo.AddItem("None", (uint64_t)RigidBodyPhysicsComponent::Vehicle::Type::None);
vehicleCombo.AddItem("Car", (uint64_t)RigidBodyPhysicsComponent::Vehicle::Type::Car);
vehicleCombo.AddItem("Motorcycle", (uint64_t)RigidBodyPhysicsComponent::Vehicle::Type::Motorcycle);
vehicleCombo.OnSelect(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.type = (RigidBodyPhysicsComponent::Vehicle::Type)args.userdata;
}));
AddWidget(&vehicleCombo);
vehicleCollisionCombo.Create("Vehicle collision: ");
vehicleCollisionCombo.AddItem("Ray", (uint64_t)RigidBodyPhysicsComponent::Vehicle::CollisionMode::Ray);
vehicleCollisionCombo.AddItem("Sphere", (uint64_t)RigidBodyPhysicsComponent::Vehicle::CollisionMode::Sphere);
vehicleCollisionCombo.AddItem("Cylinder", (uint64_t)RigidBodyPhysicsComponent::Vehicle::CollisionMode::Cylinder);
vehicleCollisionCombo.OnSelect(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.collision_mode = (RigidBodyPhysicsComponent::Vehicle::CollisionMode)args.userdata;
}));
AddWidget(&vehicleCollisionCombo);
wheelRadiusSlider.Create(0.001f, 10, 1, 1000, "Wheel radius: ");
wheelRadiusSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.wheel_radius = args.fValue;
}));
AddWidget(&wheelRadiusSlider);
wheelWidthSlider.Create(0.001f, 10, 1, 1000, "Wheel width: ");
wheelWidthSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.wheel_width = args.fValue;
}));
AddWidget(&wheelWidthSlider);
chassisHalfWidthSlider.Create(0, 10, 1, 1000, "Chassis width: ");
chassisHalfWidthSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.chassis_half_width = args.fValue;
}));
AddWidget(&chassisHalfWidthSlider);
chassisHalfHeightSlider.Create(-10, 10, 1, 1000, "Chassis height: ");
chassisHalfHeightSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.chassis_half_height = args.fValue;
}));
AddWidget(&chassisHalfHeightSlider);
chassisHalfLengthSlider.Create(0, 10, 1, 1000, "Chassis length: ");
chassisHalfLengthSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.chassis_half_length = args.fValue;
}));
AddWidget(&chassisHalfLengthSlider);
frontWheelOffsetSlider.Create(-10, 10, 0, 1000, "Front wheel offset: ");
frontWheelOffsetSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.front_wheel_offset = args.fValue;
}));
AddWidget(&frontWheelOffsetSlider);
rearWheelOffsetSlider.Create(-10, 10, 0, 1000, "Rear wheel offset: ");
rearWheelOffsetSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.rear_wheel_offset = args.fValue;
}));
AddWidget(&rearWheelOffsetSlider);
maxTorqueSlider.Create(0, 1000, 0, 1000, "Max Torque: ");
maxTorqueSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.max_engine_torque = args.fValue;
}));
AddWidget(&maxTorqueSlider);
clutchStrengthSlider.Create(0, 100, 0, 1000, "Clutch Strength: ");
clutchStrengthSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.clutch_strength = args.fValue;
}));
AddWidget(&clutchStrengthSlider);
maxRollAngleSlider.Create(0, 180, 0, 180, "Max Roll Angle: ");
maxRollAngleSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.max_roll_angle = wi::math::DegreesToRadians(args.fValue);
}));
AddWidget(&maxRollAngleSlider);
maxSteeringAngleSlider.Create(0, 90, 0, 90, "Max Steering Angle: ");
maxSteeringAngleSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.max_steering_angle = wi::math::DegreesToRadians(args.fValue);
}));
AddWidget(&maxSteeringAngleSlider);
fSuspensionMinSlider.Create(0, 2, 0, 200, "F. Susp. Min Length: ");
fSuspensionMinSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.front_suspension.min_length = args.fValue;
}));
AddWidget(&fSuspensionMinSlider);
fSuspensionMaxSlider.Create(0, 2, 0, 200, "F. Susp. Max Length: ");
fSuspensionMaxSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.front_suspension.max_length = args.fValue;
physicscomponent->SetRefreshParametersNeeded();
}));
AddWidget(&fSuspensionMaxSlider);
fSuspensionFrequencySlider.Create(0, 2, 0, 200, "F. Susp. Frequency: ");
fSuspensionFrequencySlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.front_suspension.frequency = args.fValue;
}));
AddWidget(&fSuspensionFrequencySlider);
fSuspensionDampingSlider.Create(0, 2, 0, 200, "F. Susp. Damping: ");
fSuspensionDampingSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.front_suspension.damping = args.fValue;
}));
AddWidget(&fSuspensionDampingSlider);
rSuspensionMinSlider.Create(0, 2, 0, 200, "R. Susp. Min Length: ");
rSuspensionMinSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.rear_suspension.min_length = args.fValue;
}));
AddWidget(&rSuspensionMinSlider);
rSuspensionMaxSlider.Create(0, 2, 0, 200, "R. Susp. Max Length: ");
rSuspensionMaxSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.rear_suspension.max_length = args.fValue;
}));
AddWidget(&rSuspensionMaxSlider);
rSuspensionFrequencySlider.Create(0, 2, 0, 200, "R. Susp. Frequency: ");
rSuspensionFrequencySlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.rear_suspension.frequency = args.fValue;
}));
AddWidget(&rSuspensionFrequencySlider);
rSuspensionDampingSlider.Create(0, 2, 0, 200, "R. Susp. Damping: ");
rSuspensionDampingSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.rear_suspension.damping = args.fValue;
}));
AddWidget(&rSuspensionDampingSlider);
motorcycleFBrakeSuspensionAngleSlider.Create(0, 90, 0, 90, "F. Brake Susp. Angle: ");
motorcycleFBrakeSuspensionAngleSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.motorcycle.front_suspension_angle = wi::math::DegreesToRadians(args.fValue);
}));
AddWidget(&motorcycleFBrakeSuspensionAngleSlider);
motorcycleFBrakeTorqueSlider.Create(0, 2000, 0, 2000, "F. Brake Torque: ");
motorcycleFBrakeTorqueSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.motorcycle.front_brake_torque = args.fValue;
}));
AddWidget(&motorcycleFBrakeTorqueSlider);
motorcycleRBrakeTorqueSlider.Create(0, 2000, 0, 2000, "R. Brake Torque: ");
motorcycleRBrakeTorqueSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.motorcycle.rear_brake_torque = args.fValue;
}));
AddWidget(&motorcycleRBrakeTorqueSlider);
fourwheelCheckbox.Create("4-wheel drive: ");
fourwheelCheckbox.OnClick(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) {
physicscomponent->vehicle.car.four_wheel_drive = args.bValue;
}));
AddWidget(&fourwheelCheckbox);
motorleanCheckbox.Create("Motorcycle lean control: ");
// Here we don't need to recreate physics!!
motorleanCheckbox.OnClick(forEachSelectedPhysicsComponent([](auto physicscomponent, auto args) {
physicscomponent->vehicle.motorcycle.lean_control = args.bValue;
}));
AddWidget(&motorleanCheckbox);
driveCheckbox.Create(ICON_VEHICLE " Drive in Editor: ");
driveCheckbox.SetTooltip("Override editor controls to drive this vehicle.\nControls: WASD for driving, left-right for camera rotation, Left Shift: brake, Space: handbrake\nController: R2: forward, L2: backward, Square/X: handbrake.");
driveCheckbox.OnClick([=](wi::gui::EventArgs args) {
if (args.bValue)
{
driving_entity = entity;
}
else
{
driving_entity = INVALID_ENTITY;
}
});
AddWidget(&driveCheckbox);
wheelEntityFrontLeftCombo.Create("Front Left Wheel: ");
wheelEntityFrontLeftCombo.SetTooltip("Map an entity transform to this wheel, so the wheel graphics can be animated by physics (optional).\nThe entity name must contain the word wheel to be displayed here.");
wheelEntityFrontLeftCombo.OnSelect(forEachSelectedPhysicsComponent([](auto physicscomponent, auto args) {
physicscomponent->vehicle.wheel_entity_front_left = args.userdata;
}));
AddWidget(&wheelEntityFrontLeftCombo);
wheelEntityFrontRightCombo.Create("Front Right Wheel: ");
wheelEntityFrontRightCombo.SetTooltip("Map an entity transform to this wheel, so the wheel graphics can be animated by physics (optional).\nThe entity name must contain the word wheel to be displayed here.");
wheelEntityFrontRightCombo.OnSelect(forEachSelectedPhysicsComponent([](auto physicscomponent, auto args) {
physicscomponent->vehicle.wheel_entity_front_right = args.userdata;
}));
AddWidget(&wheelEntityFrontRightCombo);
wheelEntityRearLeftCombo.Create("Rear Left Wheel: ");
wheelEntityRearLeftCombo.SetTooltip("Map an entity transform to this wheel, so the wheel graphics can be animated by physics (optional).\nThe entity name must contain the word wheel to be displayed here.");
wheelEntityRearLeftCombo.OnSelect(forEachSelectedPhysicsComponent([](auto physicscomponent, auto args) {
physicscomponent->vehicle.wheel_entity_rear_left = args.userdata;
}));
AddWidget(&wheelEntityRearLeftCombo);
wheelEntityRearRightCombo.Create("Rear Right Wheel: ");
wheelEntityRearRightCombo.SetTooltip("Map an entity transform to this wheel, so the wheel graphics can be animated by physics (optional).\nThe entity name must contain the word wheel to be displayed here.");
wheelEntityRearRightCombo.OnSelect(forEachSelectedPhysicsComponent([](auto physicscomponent, auto args) {
physicscomponent->vehicle.wheel_entity_rear_right = args.userdata;
}));
AddWidget(&wheelEntityRearRightCombo);
SetMinimized(true);
SetVisible(false);
SetEntity(INVALID_ENTITY);
}
void RigidBodyWindow::RefreshShapeType()
{
Scene& scene = editor->GetCurrentScene();
const RigidBodyPhysicsComponent* physicscomponent = scene.rigidbodies.GetComponent(entity);
if (physicscomponent == nullptr)
return;
switch (physicscomponent->shape)
{
case RigidBodyPhysicsComponent::CollisionShape::BOX:
XSlider.SetVisible(true);
YSlider.SetVisible(true);
ZSlider.SetVisible(true);
XSlider.SetText("Width: ");
YSlider.SetText("Height: ");
ZSlider.SetText("Depth: ");
XSlider.SetValue(physicscomponent->box.halfextents.x);
YSlider.SetValue(physicscomponent->box.halfextents.y);
ZSlider.SetValue(physicscomponent->box.halfextents.z);
break;
case RigidBodyPhysicsComponent::CollisionShape::SPHERE:
XSlider.SetVisible(true);
YSlider.SetVisible(false);
ZSlider.SetVisible(false);
XSlider.SetText("Radius: ");
XSlider.SetValue(physicscomponent->sphere.radius);
break;
case RigidBodyPhysicsComponent::CollisionShape::CAPSULE:
case RigidBodyPhysicsComponent::CollisionShape::CYLINDER:
XSlider.SetVisible(true);
YSlider.SetVisible(true);
ZSlider.SetVisible(false);
XSlider.SetText("Height: ");
YSlider.SetText("Radius: ");
XSlider.SetValue(physicscomponent->capsule.height);
YSlider.SetValue(physicscomponent->capsule.radius);
break;
case RigidBodyPhysicsComponent::CollisionShape::CONVEX_HULL:
case RigidBodyPhysicsComponent::CollisionShape::TRIANGLE_MESH:
default:
XSlider.SetVisible(false);
YSlider.SetVisible(false);
ZSlider.SetVisible(false);
break;
}
}
void RigidBodyWindow::SetEntity(Entity entity)
{
Scene& scene = editor->GetCurrentScene();
const RigidBodyPhysicsComponent* physicsComponent = scene.rigidbodies.GetComponent(entity);
if (physicsComponent != nullptr)
{
if (this->entity == entity)
return;
this->entity = entity;
massSlider.SetValue(physicsComponent->mass);
frictionSlider.SetValue(physicsComponent->friction);
restitutionSlider.SetValue(physicsComponent->restitution);
lineardampingSlider.SetValue(physicsComponent->damping_linear);
angulardampingSlider.SetValue(physicsComponent->damping_angular);
buoyancySlider.SetValue(physicsComponent->buoyancy);
physicsMeshLODSlider.SetValue(float(physicsComponent->mesh_lod));
offsetXSlider.SetValue(physicsComponent->local_offset.x);
offsetYSlider.SetValue(physicsComponent->local_offset.y);
offsetZSlider.SetValue(physicsComponent->local_offset.z);
kinematicCheckBox.SetCheck(physicsComponent->IsKinematic());
disabledeactivationCheckBox.SetCheck(physicsComponent->IsDisableDeactivation());
startDeactivatedCheckBox.SetCheck(physicsComponent->IsStartDeactivated());
collisionShapeComboBox.SetSelectedByUserdataWithoutCallback((uint64_t)physicsComponent->shape);
characterCheckBox.SetCheck(physicsComponent->IsCharacterPhysics());
characterSlopeSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->character.maxSlopeAngle));
characterGravitySlider.SetValue(physicsComponent->character.gravityFactor);
vehicleCombo.SetSelectedByUserdataWithoutCallback((uint64_t)physicsComponent->vehicle.type);
vehicleCollisionCombo.SetSelectedByUserdataWithoutCallback((uint64_t)physicsComponent->vehicle.collision_mode);
wheelRadiusSlider.SetValue(physicsComponent->vehicle.wheel_radius);
wheelWidthSlider.SetValue(physicsComponent->vehicle.wheel_width);
chassisHalfWidthSlider.SetValue(physicsComponent->vehicle.chassis_half_width);
chassisHalfHeightSlider.SetValue(physicsComponent->vehicle.chassis_half_height);
chassisHalfLengthSlider.SetValue(physicsComponent->vehicle.chassis_half_length);
frontWheelOffsetSlider.SetValue(physicsComponent->vehicle.front_wheel_offset);
rearWheelOffsetSlider.SetValue(physicsComponent->vehicle.rear_wheel_offset);
maxTorqueSlider.SetValue(physicsComponent->vehicle.max_engine_torque);
clutchStrengthSlider.SetValue(physicsComponent->vehicle.clutch_strength);
maxRollAngleSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->vehicle.max_roll_angle));
maxSteeringAngleSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->vehicle.max_steering_angle));
fourwheelCheckbox.SetCheck(physicsComponent->vehicle.car.four_wheel_drive);
motorleanCheckbox.SetCheck(physicsComponent->vehicle.motorcycle.lean_control);
fSuspensionMinSlider.SetValue(physicsComponent->vehicle.front_suspension.min_length);
fSuspensionMaxSlider.SetValue(physicsComponent->vehicle.front_suspension.max_length);
fSuspensionFrequencySlider.SetValue(physicsComponent->vehicle.front_suspension.frequency);
fSuspensionDampingSlider.SetValue(physicsComponent->vehicle.front_suspension.damping);
rSuspensionMinSlider.SetValue(physicsComponent->vehicle.rear_suspension.min_length);
rSuspensionMaxSlider.SetValue(physicsComponent->vehicle.rear_suspension.max_length);
rSuspensionFrequencySlider.SetValue(physicsComponent->vehicle.rear_suspension.frequency);
rSuspensionDampingSlider.SetValue(physicsComponent->vehicle.rear_suspension.damping);
motorcycleFBrakeSuspensionAngleSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->vehicle.motorcycle.front_suspension_angle));
motorcycleFBrakeTorqueSlider.SetValue(physicsComponent->vehicle.motorcycle.front_brake_torque);
motorcycleRBrakeTorqueSlider.SetValue(physicsComponent->vehicle.motorcycle.rear_brake_torque);
wheelEntityFrontLeftCombo.ClearItems();
wheelEntityFrontLeftCombo.AddItem("INVALID_ENTITY", (uint64_t)INVALID_ENTITY);
wheelEntityFrontRightCombo.ClearItems();
wheelEntityFrontRightCombo.AddItem("INVALID_ENTITY", (uint64_t)INVALID_ENTITY);
wheelEntityRearLeftCombo.ClearItems();
wheelEntityRearLeftCombo.AddItem("INVALID_ENTITY", (uint64_t)INVALID_ENTITY);
wheelEntityRearRightCombo.ClearItems();
wheelEntityRearRightCombo.AddItem("INVALID_ENTITY", (uint64_t)INVALID_ENTITY);
for (size_t i = 0; i < scene.transforms.GetCount(); ++i)
{
Entity wheelEntity = scene.transforms.GetEntity(i);
if (!scene.Entity_IsDescendant(wheelEntity, entity))
continue;
const NameComponent* name = scene.names.GetComponent(wheelEntity);
if (name != nullptr && wi::helper::toUpper(name->name).find("WHEEL") != std::string::npos)
{
wheelEntityFrontLeftCombo.AddItem(name->name, (uint64_t)wheelEntity);
wheelEntityFrontRightCombo.AddItem(name->name, (uint64_t)wheelEntity);
wheelEntityRearLeftCombo.AddItem(name->name, (uint64_t)wheelEntity);
wheelEntityRearRightCombo.AddItem(name->name, (uint64_t)wheelEntity);
}
}
wheelEntityFrontLeftCombo.SetSelectedByUserdataWithoutCallback(physicsComponent->vehicle.wheel_entity_front_left);
wheelEntityFrontRightCombo.SetSelectedByUserdataWithoutCallback(physicsComponent->vehicle.wheel_entity_front_right);
wheelEntityRearLeftCombo.SetSelectedByUserdataWithoutCallback(physicsComponent->vehicle.wheel_entity_rear_left);
wheelEntityRearRightCombo.SetSelectedByUserdataWithoutCallback(physicsComponent->vehicle.wheel_entity_rear_right);
RefreshShapeType();
}
else
{
this->entity = INVALID_ENTITY;
}
}
void RigidBodyWindow::ResizeLayout()
{
RefreshShapeType();
wi::gui::Window::ResizeLayout();
layout.margin_left = 145;
layout.add(collisionShapeComboBox);
layout.add(XSlider);
layout.add(YSlider);
layout.add(ZSlider);
layout.add(massSlider);
layout.add(frictionSlider);
layout.add(restitutionSlider);
layout.add(lineardampingSlider);
layout.add(angulardampingSlider);
layout.add(buoyancySlider);
layout.add(physicsMeshLODSlider);
layout.add(offsetXSlider);
layout.add(offsetYSlider);
layout.add(offsetZSlider);
layout.add_right(startDeactivatedCheckBox);
layout.add_right(disabledeactivationCheckBox);
layout.add_right(kinematicCheckBox);
layout.add_right(physicsDebugCheckBox);
layout.jump();
layout.add_right(characterCheckBox);
if (characterCheckBox.GetCheck())
{
characterLabel.SetVisible(true);
characterSlopeSlider.SetVisible(true);
characterGravitySlider.SetVisible(true);
layout.add_fullwidth(characterLabel);
layout.add(characterSlopeSlider);
layout.add(characterGravitySlider);
}
else
{
characterLabel.SetVisible(false);
characterSlopeSlider.SetVisible(false);
characterGravitySlider.SetVisible(false);
}
layout.jump();
layout.add(vehicleCombo);
if (vehicleCombo.GetSelected() > 0)
{
vehicleLabel.SetVisible(true);
vehicleCollisionCombo.SetVisible(true);
wheelRadiusSlider.SetVisible(true);
wheelWidthSlider.SetVisible(true);
chassisHalfWidthSlider.SetVisible(true);
chassisHalfHeightSlider.SetVisible(true);
chassisHalfLengthSlider.SetVisible(true);
frontWheelOffsetSlider.SetVisible(true);
rearWheelOffsetSlider.SetVisible(true);
maxTorqueSlider.SetVisible(true);
clutchStrengthSlider.SetVisible(true);
maxRollAngleSlider.SetVisible(true);
maxSteeringAngleSlider.SetVisible(true);
driveCheckbox.SetVisible(true);
fSuspensionMinSlider.SetVisible(true);
fSuspensionMaxSlider.SetVisible(true);
fSuspensionFrequencySlider.SetVisible(true);
fSuspensionDampingSlider.SetVisible(true);
rSuspensionMinSlider.SetVisible(true);
rSuspensionMaxSlider.SetVisible(true);
rSuspensionFrequencySlider.SetVisible(true);
rSuspensionDampingSlider.SetVisible(true);
layout.add_fullwidth(vehicleLabel);
layout.add_right(driveCheckbox);
layout.add(vehicleCollisionCombo);
layout.add(wheelRadiusSlider);
layout.add(wheelWidthSlider);
layout.add(chassisHalfWidthSlider);
layout.add(chassisHalfHeightSlider);
layout.add(chassisHalfLengthSlider);
layout.add(frontWheelOffsetSlider);
layout.add(rearWheelOffsetSlider);
layout.add(maxTorqueSlider);
layout.add(clutchStrengthSlider);
layout.add(maxRollAngleSlider);
layout.add(maxSteeringAngleSlider);
layout.add(fSuspensionMinSlider);
layout.add(fSuspensionMaxSlider);
layout.add(fSuspensionFrequencySlider);
layout.add(fSuspensionDampingSlider);
layout.add(rSuspensionMinSlider);
layout.add(rSuspensionMaxSlider);
layout.add(rSuspensionFrequencySlider);
layout.add(rSuspensionDampingSlider);
RigidBodyPhysicsComponent::Vehicle::Type type = (RigidBodyPhysicsComponent::Vehicle::Type)vehicleCombo.GetSelectedUserdata();
switch (type)
{
case wi::scene::RigidBodyPhysicsComponent::Vehicle::Type::Car:
motorcycleFBrakeSuspensionAngleSlider.SetVisible(false);
motorcycleFBrakeTorqueSlider.SetVisible(false);
motorcycleRBrakeTorqueSlider.SetVisible(false);
wheelEntityFrontLeftCombo.SetVisible(true);
wheelEntityFrontRightCombo.SetVisible(true);
wheelEntityRearLeftCombo.SetVisible(true);
wheelEntityRearRightCombo.SetVisible(true);
layout.add(wheelEntityFrontLeftCombo);
layout.add(wheelEntityFrontRightCombo);
layout.add(wheelEntityRearLeftCombo);
layout.add(wheelEntityRearRightCombo);
fourwheelCheckbox.SetVisible(true);
motorleanCheckbox.SetVisible(false);
layout.add_right(fourwheelCheckbox);
break;
case wi::scene::RigidBodyPhysicsComponent::Vehicle::Type::Motorcycle:
motorcycleFBrakeSuspensionAngleSlider.SetVisible(true);
motorcycleFBrakeTorqueSlider.SetVisible(true);
motorcycleRBrakeTorqueSlider.SetVisible(true);
layout.add(motorcycleFBrakeSuspensionAngleSlider);
layout.add(motorcycleFBrakeTorqueSlider);
layout.add(motorcycleRBrakeTorqueSlider);
wheelEntityFrontLeftCombo.SetVisible(true);
wheelEntityFrontRightCombo.SetVisible(false);
wheelEntityRearLeftCombo.SetVisible(true);
wheelEntityRearRightCombo.SetVisible(false);
layout.add(wheelEntityFrontLeftCombo);
layout.add(wheelEntityRearLeftCombo);
motorleanCheckbox.SetVisible(true);
fourwheelCheckbox.SetVisible(false);
layout.add_right(motorleanCheckbox);
break;
default:
break;
}
}
else
{
vehicleLabel.SetVisible(false);
vehicleCollisionCombo.SetVisible(false);
wheelRadiusSlider.SetVisible(false);
wheelWidthSlider.SetVisible(false);
chassisHalfWidthSlider.SetVisible(false);
chassisHalfHeightSlider.SetVisible(false);
chassisHalfLengthSlider.SetVisible(false);
frontWheelOffsetSlider.SetVisible(false);
rearWheelOffsetSlider.SetVisible(false);
maxTorqueSlider.SetVisible(false);
clutchStrengthSlider.SetVisible(false);
maxRollAngleSlider.SetVisible(false);
maxSteeringAngleSlider.SetVisible(false);
wheelEntityFrontLeftCombo.SetVisible(false);
wheelEntityFrontRightCombo.SetVisible(false);
wheelEntityRearLeftCombo.SetVisible(false);
wheelEntityRearRightCombo.SetVisible(false);
fourwheelCheckbox.SetVisible(false);
motorleanCheckbox.SetVisible(false);
driveCheckbox.SetVisible(false);
fSuspensionMinSlider.SetVisible(false);
fSuspensionMaxSlider.SetVisible(false);
fSuspensionFrequencySlider.SetVisible(false);
fSuspensionDampingSlider.SetVisible(false);
rSuspensionMinSlider.SetVisible(false);
rSuspensionMaxSlider.SetVisible(false);
rSuspensionFrequencySlider.SetVisible(false);
rSuspensionDampingSlider.SetVisible(false);
motorcycleFBrakeSuspensionAngleSlider.SetVisible(false);
motorcycleFBrakeTorqueSlider.SetVisible(false);
motorcycleRBrakeTorqueSlider.SetVisible(false);
}
}