/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "WhiteBox_precompiled.h" #include "EditorWhiteBoxColliderComponent.h" #include "EditorWhiteBoxComponent.h" #include "WhiteBoxColliderComponent.h" #include #include #include #include #include #include namespace WhiteBox { void EditorWhiteBoxColliderComponent::Reflect(AZ::ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() ->Version(1) ->Field("Configuration", &EditorWhiteBoxColliderComponent::m_physicsColliderConfiguration) ->Field("MeshData", &EditorWhiteBoxColliderComponent::m_meshShapeConfiguration) ->Field("WhiteBoxConfiguration", &EditorWhiteBoxColliderComponent::m_whiteBoxColliderConfiguration); if (auto editContext = serializeContext->GetEditContext()) { editContext ->Class( "White Box Collider", "Physics collider for White Box Component") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "Shape") ->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/WhiteBox_collider.svg") ->Attribute( AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/WhiteBox_collider.png") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "http://docs.aws.amazon.com/console/lumberyard/whitebox-collider") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement( AZ::Edit::UIHandlers::Default, &EditorWhiteBoxColliderComponent::m_physicsColliderConfiguration, "Configuration", "Collider configuration") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement( AZ::Edit::UIHandlers::Default, &EditorWhiteBoxColliderComponent::m_whiteBoxColliderConfiguration, "White Box Collider Configuration", "White Box collider configuration properties") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly); } } } void EditorWhiteBoxColliderComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC("WhiteBoxColliderService", 0x480d5b06)); } void EditorWhiteBoxColliderComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { required.push_back(AZ_CRC("TransformService", 0x8ee22c50)); required.push_back(AZ_CRC("WhiteBoxService", 0x2f2f42b8)); } void EditorWhiteBoxColliderComponent::Activate() { AzToolsFramework::Components::EditorComponentBase::Activate(); EditorWhiteBoxColliderRequestBus::Handler::BusConnect(GetEntityId()); AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId()); // hide collider properties we do not care about for white box m_physicsColliderConfiguration.SetPropertyVisibility(Physics::ColliderConfiguration::Offset, false); m_physicsColliderConfiguration.SetPropertyVisibility(Physics::ColliderConfiguration::IsTrigger, false); // can't use buses here as EditorWhiteBoxComponentBus is addressed using component id. How do get component id? if (auto whiteBoxComponent = GetEntity()->FindComponent()) { if (auto whiteBoxMesh = whiteBoxComponent->GetWhiteBoxMesh()) { GeneratePhysics(*whiteBoxMesh); } } } void EditorWhiteBoxColliderComponent::Deactivate() { AZ::TransformNotificationBus::Handler::BusDisconnect(); EditorWhiteBoxColliderRequestBus::Handler::BusDisconnect(); AzToolsFramework::Components::EditorComponentBase::Deactivate(); if (m_rigidBody) { m_rigidBody.reset(nullptr); Physics::EditorWorldBus::Broadcast(&Physics::EditorWorldRequests::MarkEditorWorldDirty); } } void EditorWhiteBoxColliderComponent::BuildGameEntity(AZ::Entity* gameEntity) { gameEntity->CreateComponent( m_meshShapeConfiguration, m_physicsColliderConfiguration, m_whiteBoxColliderConfiguration); } void EditorWhiteBoxColliderComponent::OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) { if (m_rigidBody) { m_rigidBody->SetTransform(world); Physics::EditorWorldBus::Broadcast(&Physics::EditorWorldRequests::MarkEditorWorldDirty); } } void EditorWhiteBoxColliderComponent::GeneratePhysics(const WhiteBoxMesh& whiteBox) { if (Api::MeshFaceCount(whiteBox) == 0) { return; } ConvertToPhysicsMesh(whiteBox); Physics::WorldBodyConfiguration bodyConfiguration; bodyConfiguration.m_debugName = GetEntity()->GetName().c_str(); bodyConfiguration.m_entityId = GetEntityId(); bodyConfiguration.m_orientation = GetTransform()->GetWorldRotationQuaternion(); bodyConfiguration.m_position = GetTransform()->GetWorldTranslation(); Physics::SystemRequestBus::BroadcastResult( m_rigidBody, &Physics::SystemRequests::CreateStaticRigidBody, bodyConfiguration); AZStd::shared_ptr shape; Physics::SystemRequestBus::BroadcastResult( shape, &Physics::SystemRequests::CreateShape, m_physicsColliderConfiguration, m_meshShapeConfiguration); m_rigidBody->AddShape(shape); Physics::WorldRequestBus::Event(Physics::EditorPhysicsWorldId, &Physics::World::AddBody, *m_rigidBody); Physics::EditorWorldBus::Broadcast(&Physics::EditorWorldRequests::MarkEditorWorldDirty); } static bool ConvertToTriangles( const WhiteBoxMesh& whiteBox, AZStd::vector& vertices, AZStd::vector& indices) { const size_t triangleCount = Api::MeshFaceCount(whiteBox); if (triangleCount == 0) { return false; } const size_t vertexCount = Api::MeshHalfedgeCount(whiteBox); vertices.resize(vertexCount); indices.resize(triangleCount * 3); // fill vertex position array size_t index = 0; const auto faceHandles = Api::MeshFaceHandles(whiteBox); for (const auto faceHandle : faceHandles) { const auto faceHalfedgeHandles = Api::FaceHalfedgeHandles(whiteBox, faceHandle); for (const auto halfEdgeHandle : faceHalfedgeHandles) { const auto vh = Api::HalfedgeVertexHandleAtTip(whiteBox, halfEdgeHandle); vertices[index] = Api::VertexPosition(whiteBox, vh); index++; } } // fill index array - this will have to change at some point probably std::iota(indices.begin(), indices.end(), 0); return true; } void EditorWhiteBoxColliderComponent::ConvertToPhysicsMesh(const WhiteBoxMesh& whiteBox) { AZStd::vector vertices; AZStd::vector indices; // convert white box mesh to vertices if (!ConvertToTriangles(whiteBox, vertices, indices)) { // if there are no valid triangles then do not attempt to create a physics mesh return; } if (auto* physicsSystem = AZ::Interface::Get()) { AZStd::vector bytes; const bool result = physicsSystem->CookTriangleMeshToMemory( vertices.data(), (AZ::u32)vertices.size(), indices.data(), (AZ::u32)indices.size(), bytes); AZ_Warning("EditorWhiteBoxColliderComponent", result, "Failed to cook mesh data"); if (result) { m_meshShapeConfiguration.SetCookedMeshData( bytes.data(), bytes.size(), Physics::CookedMeshShapeConfiguration::MeshType::TriangleMesh); } } else { AZ_Warning( "EditorWhiteBoxColliderComponent", false, "No physics backend enabled - please ensure one is provided"); } } } // namespace WhiteBox