Path: blob/master/modules/godot_physics_2d/godot_step_2d.cpp
10277 views
/**************************************************************************/1/* godot_step_2d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "godot_step_2d.h"3132#include "core/object/worker_thread_pool.h"33#include "core/os/os.h"34#include "godot_constraint_2d.h"3536#define BODY_ISLAND_COUNT_RESERVE 12837#define BODY_ISLAND_SIZE_RESERVE 51238#define ISLAND_COUNT_RESERVE 12839#define ISLAND_SIZE_RESERVE 51240#define CONSTRAINT_COUNT_RESERVE 10244142void GodotStep2D::_populate_island(GodotBody2D *p_body, LocalVector<GodotBody2D *> &p_body_island, LocalVector<GodotConstraint2D *> &p_constraint_island) {43p_body->set_island_step(_step);4445if (p_body->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {46// Only rigid bodies are tested for activation.47p_body_island.push_back(p_body);48}4950for (const Pair<GodotConstraint2D *, int> &E : p_body->get_constraint_list()) {51GodotConstraint2D *constraint = E.first;52if (constraint->get_island_step() == _step) {53continue; // Already processed.54}55constraint->set_island_step(_step);56p_constraint_island.push_back(constraint);57all_constraints.push_back(constraint);5859for (int i = 0; i < constraint->get_body_count(); i++) {60if (i == E.second) {61continue;62}63GodotBody2D *other_body = constraint->get_body_ptr()[i];64if (other_body->get_island_step() == _step) {65continue; // Already processed.66}67if (other_body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC) {68continue; // Static bodies don't connect islands.69}70_populate_island(other_body, p_body_island, p_constraint_island);71}72}73}7475void GodotStep2D::_setup_constraint(uint32_t p_constraint_index, void *p_userdata) {76GodotConstraint2D *constraint = all_constraints[p_constraint_index];77constraint->setup(delta);78}7980void GodotStep2D::_pre_solve_island(LocalVector<GodotConstraint2D *> &p_constraint_island) const {81uint32_t constraint_count = p_constraint_island.size();82uint32_t valid_constraint_count = 0;83for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {84GodotConstraint2D *constraint = p_constraint_island[constraint_index];85if (p_constraint_island[constraint_index]->pre_solve(delta)) {86// Keep this constraint for solving.87p_constraint_island[valid_constraint_count++] = constraint;88}89}90p_constraint_island.resize(valid_constraint_count);91}9293void GodotStep2D::_solve_island(uint32_t p_island_index, void *p_userdata) const {94const LocalVector<GodotConstraint2D *> &constraint_island = constraint_islands[p_island_index];9596for (int i = 0; i < iterations; i++) {97uint32_t constraint_count = constraint_island.size();98for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {99constraint_island[constraint_index]->solve(delta);100}101}102}103104void GodotStep2D::_check_suspend(LocalVector<GodotBody2D *> &p_body_island) const {105bool can_sleep = true;106107uint32_t body_count = p_body_island.size();108for (uint32_t body_index = 0; body_index < body_count; ++body_index) {109GodotBody2D *body = p_body_island[body_index];110111if (!body->sleep_test(delta)) {112can_sleep = false;113}114}115116// Put all to sleep or wake up everyone.117for (uint32_t body_index = 0; body_index < body_count; ++body_index) {118GodotBody2D *body = p_body_island[body_index];119120bool active = body->is_active();121122if (active == can_sleep) {123body->set_active(!can_sleep);124}125}126}127128void GodotStep2D::step(GodotSpace2D *p_space, real_t p_delta) {129p_space->lock(); // can't access space during this130131p_space->setup(); //update inertias, etc132133p_space->set_last_step(p_delta);134135iterations = p_space->get_solver_iterations();136delta = p_delta;137138const SelfList<GodotBody2D>::List *body_list = &p_space->get_active_body_list();139140/* INTEGRATE FORCES */141142uint64_t profile_begtime = OS::get_singleton()->get_ticks_usec();143uint64_t profile_endtime = 0;144145int active_count = 0;146147const SelfList<GodotBody2D> *b = body_list->first();148while (b) {149b->self()->integrate_forces(p_delta);150b = b->next();151active_count++;152}153154p_space->set_active_objects(active_count);155156// Update the broadphase to register collision pairs.157p_space->update();158159{ //profile160profile_endtime = OS::get_singleton()->get_ticks_usec();161p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_INTEGRATE_FORCES, profile_endtime - profile_begtime);162profile_begtime = profile_endtime;163}164165/* GENERATE CONSTRAINT ISLANDS FOR MOVING AREAS */166167uint32_t island_count = 0;168169const SelfList<GodotArea2D>::List &aml = p_space->get_moved_area_list();170171while (aml.first()) {172for (GodotConstraint2D *E : aml.first()->self()->get_constraints()) {173GodotConstraint2D *constraint = E;174if (constraint->get_island_step() == _step) {175continue;176}177constraint->set_island_step(_step);178179// Each constraint can be on a separate island for areas as there's no solving phase.180++island_count;181if (constraint_islands.size() < island_count) {182constraint_islands.resize(island_count);183}184LocalVector<GodotConstraint2D *> &constraint_island = constraint_islands[island_count - 1];185constraint_island.clear();186187all_constraints.push_back(constraint);188constraint_island.push_back(constraint);189}190p_space->area_remove_from_moved_list((SelfList<GodotArea2D> *)aml.first()); //faster to remove here191}192193/* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */194195b = body_list->first();196197uint32_t body_island_count = 0;198199while (b) {200GodotBody2D *body = b->self();201202if (body->get_island_step() != _step) {203++body_island_count;204if (body_islands.size() < body_island_count) {205body_islands.resize(body_island_count);206}207LocalVector<GodotBody2D *> &body_island = body_islands[body_island_count - 1];208body_island.clear();209body_island.reserve(BODY_ISLAND_SIZE_RESERVE);210211++island_count;212if (constraint_islands.size() < island_count) {213constraint_islands.resize(island_count);214}215LocalVector<GodotConstraint2D *> &constraint_island = constraint_islands[island_count - 1];216constraint_island.clear();217constraint_island.reserve(ISLAND_SIZE_RESERVE);218219_populate_island(body, body_island, constraint_island);220221if (body_island.is_empty()) {222--body_island_count;223}224225if (constraint_island.is_empty()) {226--island_count;227}228}229b = b->next();230}231232p_space->set_island_count((int)island_count);233234{ //profile235profile_endtime = OS::get_singleton()->get_ticks_usec();236p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);237profile_begtime = profile_endtime;238}239240/* SETUP CONSTRAINTS / PROCESS COLLISIONS */241242uint32_t total_constraint_count = all_constraints.size();243WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &GodotStep2D::_setup_constraint, nullptr, total_constraint_count, -1, true, SNAME("Physics2DConstraintSetup"));244WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);245246{ //profile247profile_endtime = OS::get_singleton()->get_ticks_usec();248p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_SETUP_CONSTRAINTS, profile_endtime - profile_begtime);249profile_begtime = profile_endtime;250}251252/* PRE-SOLVE CONSTRAINT ISLANDS */253254// WARNING: This doesn't run on threads, because it involves thread-unsafe processing.255for (uint32_t island_index = 0; island_index < island_count; ++island_index) {256_pre_solve_island(constraint_islands[island_index]);257}258259/* SOLVE CONSTRAINT ISLANDS */260261// WARNING: `_solve_island` modifies the constraint islands for optimization purpose,262// their content is not reliable after these calls and shouldn't be used anymore.263group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &GodotStep2D::_solve_island, nullptr, island_count, -1, true, SNAME("Physics2DConstraintSolveIslands"));264WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);265266{ //profile267profile_endtime = OS::get_singleton()->get_ticks_usec();268p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_SOLVE_CONSTRAINTS, profile_endtime - profile_begtime);269profile_begtime = profile_endtime;270}271272/* INTEGRATE VELOCITIES */273274b = body_list->first();275while (b) {276const SelfList<GodotBody2D> *n = b->next();277b->self()->integrate_velocities(p_delta);278b = n; // in case it shuts itself down279}280281/* SLEEP / WAKE UP ISLANDS */282283for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {284_check_suspend(body_islands[island_index]);285}286287{ //profile288profile_endtime = OS::get_singleton()->get_ticks_usec();289p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime);290//profile_begtime=profile_endtime;291}292293all_constraints.clear();294295p_space->unlock();296_step++;297}298299GodotStep2D::GodotStep2D() {300body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);301constraint_islands.reserve(ISLAND_COUNT_RESERVE);302all_constraints.reserve(CONSTRAINT_COUNT_RESERVE);303}304305GodotStep2D::~GodotStep2D() {306}307308309