#pragma once #include "base_vehicle.hpp" #include "controller.hpp" #include "btMatrix4x4.hpp" using namespace ace::simulation; namespace ace { namespace vehicledamage { base_vehicle::base_vehicle(uint32_t id, ace::simulation::object_p object_, ace::vector3 position_) : id(id), object(object_) { bt_mesh = std::make_shared(); fire_lod = -1; // Find the fire LOD for (int x = 0; x < object_->lods.size(); x++) { if (object_->lods[x]->type == LOD_TYPE_GEOMETRY_FIRE) { fire_lod = x; break; } } if (fire_lod == -1) // @TODO: fallback on geo LOD fire_lod = 11; assert(fire_lod != -1); // Build the mesh from object faces // TODO: LOD!? // P3d store in x,z,y format for (auto & face : object_->lods[fire_lod]->faces) { bt_mesh->addTriangle( btVector3(face->vertices[0]->x(), face->vertices[0]->y(), face->vertices[0]->z()), btVector3(face->vertices[1]->x(), face->vertices[1]->y(), face->vertices[1]->z()), btVector3(face->vertices[2]->x(), face->vertices[2]->y(), face->vertices[2]->z()) ); } bt_shape = std::make_shared(bt_mesh.get(), true, true); bt_object = std::make_shared(); bt_object->setCollisionShape(bt_shape.get()); bt_object->setUserIndex(id); bt_object->setUserPointer((void *)this); // @TODO: This is moving it in the bullet world for handling multiple collisions, instead our raytests need to ignore ALL but this type. How do we do that? // For now this only works for single-object collisions then //btTransform transform = bt_object->getWorldTransform(); //transform.setOrigin(btVector3(position_.x(), position_.y(), position_.z())); //bt_object->setWorldTransform(transform); controller::get().bt_world->addCollisionObject(bt_object.get()); } base_vehicle::~base_vehicle() { controller::get().bt_world->removeCollisionObject(bt_object.get()); } bool base_vehicle::simulate() { std::vector lods; lods.push_back(fire_lod); object->animate(animation_state, lods); return true; } void base_vehicle::transform() { btTransform transform = bt_object->getWorldTransform(); transform.getBasis().setEulerZYX(direction.x(), direction.y(), direction.z()); transform.setOrigin(btVector3(up.x(),up.y(),up.z())); bt_object->setWorldTransform(transform); } float base_vehicle::thickness(const ace::vector3 & position, const ace::vector3 & direction) { float result = -1.0f; btVector3 bt_from(position.x(), position.y(), position.z()); btVector3 bt_dir(direction.x(), direction.y(), direction.z()); btVector3 bt_to(bt_from + (bt_dir * 100)); btCollisionWorld::AllHitsRayResultCallback allResults(bt_from, bt_to); controller::get().bt_world->rayTest(bt_from, bt_to, allResults); // get the first and last result on the target object, give results assert(allResults.m_hitPointWorld.size() > 2); if (allResults.m_hitPointWorld.size() == 2) { // @TODO: This just gets the thickness of hte first 2 hit surfaces result = allResults.m_hitPointWorld[0].distance(allResults.m_hitPointWorld[1]); } else { // @TODO: // We dont support multi-surface hits yet } return result; } float base_vehicle::surface_raycast(const ace::vector3 & position, const ace::vector3 & direction, std::vector> & results) { float result = -1.0f; btVector3 bt_from(position.x(), position.y(), position.z()); btVector3 bt_dir(direction.x(), direction.y(), direction.z()); btVector3 bt_to(bt_from + (bt_dir * 100)); btCollisionWorld::AllHitsRayResultCallback allResults(bt_from, bt_to); controller::get().bt_world->rayTest(bt_from, bt_to, allResults); if (allResults.m_hitNormalWorld.size() > 0) { for (int x = 0; x < allResults.m_hitNormalWorld.size(); x++) { results.push_back(ace::vector3(allResults.m_hitNormalWorld[x].x(), allResults.m_hitNormalWorld[x].y(), allResults.m_hitNormalWorld[x].z())); } result = allResults.m_hitNormalWorld[0].distance(allResults.m_hitNormalWorld[allResults.m_hitNormalWorld.size() - 1]); } return result; } std::vector> base_vehicle::selection_position(const uint32_t lod, const std::string &name, const SELECTION_SEARCH_TYPE searchType) { named_selection_p selection; std::vector> result; if ((selection = selection_by_name(lod, name)) == nullptr) return result; switch (searchType) { case SELECTION_SEARCH_TYPE::AVERAGE_CENTER: { ace::vector3 average; std::vector> results; for (auto & a : selection->vertices) { for (auto & b : selection->vertices) { if (a != b) { average = average + ace::vector3::lerp(static_cast>(*a), static_cast>(*b), 0.5f); } } } average = average / results.size(); result.push_back(average); break; } } return result; } std::vector> base_vehicle::selection_by_name_vertices(const uint32_t lod, const std::string &name) { std::vector> result; ace::simulation::named_selection_p selection = selection_by_name(lod, name); for (auto & vertex : selection->vertices) { result.push_back( static_cast>(*vertex) ); } return result; } ace::simulation::named_selection_p base_vehicle::selection_by_name(const uint32_t lod, const std::string &name) { named_selection_p result; if (lod != -1) { auto iter = object->lods[lod]->selections.find(name); if (iter == object->lods[lod]->selections.end()) { return nullptr; } result = iter->second; } else { for (auto & lod : object->lods) { auto iter = lod->selections.find(name); if (iter == lod->selections.end()) { continue; } else { result = iter->second; } } } return result; } } };