Path: blob/master/modules/godot_physics_2d/godot_shape_2d.cpp
10277 views
/**************************************************************************/1/* godot_shape_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_shape_2d.h"3132#include "core/math/geometry_2d.h"33#include "core/templates/sort_array.h"3435void GodotShape2D::configure(const Rect2 &p_aabb) {36aabb = p_aabb;37configured = true;38for (const KeyValue<GodotShapeOwner2D *, int> &E : owners) {39E.key->_shape_changed();40}41}4243Vector2 GodotShape2D::get_support(const Vector2 &p_normal) const {44Vector2 res[2];45int amnt;46get_supports(p_normal, res, amnt);47return res[0];48}4950void GodotShape2D::add_owner(GodotShapeOwner2D *p_owner) {51HashMap<GodotShapeOwner2D *, int>::Iterator E = owners.find(p_owner);52if (E) {53E->value++;54} else {55owners[p_owner] = 1;56}57}5859void GodotShape2D::remove_owner(GodotShapeOwner2D *p_owner) {60HashMap<GodotShapeOwner2D *, int>::Iterator E = owners.find(p_owner);61ERR_FAIL_COND(!E);62E->value--;63if (E->value == 0) {64owners.remove(E);65}66}6768bool GodotShape2D::is_owner(GodotShapeOwner2D *p_owner) const {69return owners.has(p_owner);70}7172const HashMap<GodotShapeOwner2D *, int> &GodotShape2D::get_owners() const {73return owners;74}7576GodotShape2D::~GodotShape2D() {77ERR_FAIL_COND(owners.size());78}7980/*********************************************************/81/*********************************************************/82/*********************************************************/8384void GodotWorldBoundaryShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {85r_amount = 0;86}8788bool GodotWorldBoundaryShape2D::contains_point(const Vector2 &p_point) const {89return normal.dot(p_point) < d;90}9192bool GodotWorldBoundaryShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {93Vector2 segment = p_begin - p_end;94real_t den = normal.dot(segment);9596//printf("den is %i\n",den);97if (Math::abs(den) <= CMP_EPSILON) {98return false;99}100101real_t dist = (normal.dot(p_begin) - d) / den;102//printf("dist is %i\n",dist);103104if (dist < -CMP_EPSILON || dist > (1.0 + CMP_EPSILON)) {105return false;106}107108r_point = p_begin + segment * -dist;109r_normal = normal;110111return true;112}113114real_t GodotWorldBoundaryShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {115return 0;116}117118void GodotWorldBoundaryShape2D::set_data(const Variant &p_data) {119ERR_FAIL_COND(p_data.get_type() != Variant::ARRAY);120Array arr = p_data;121ERR_FAIL_COND(arr.size() != 2);122normal = arr[0];123d = arr[1];124configure(Rect2(Vector2(-1e15, -1e15), Vector2(1e15 * 2, 1e15 * 2)));125}126127Variant GodotWorldBoundaryShape2D::get_data() const {128Array arr;129arr.resize(2);130arr[0] = normal;131arr[1] = d;132return arr;133}134135/*********************************************************/136/*********************************************************/137/*********************************************************/138139void GodotSeparationRayShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {140r_amount = 1;141142if (p_normal.y > 0) {143*r_supports = Vector2(0, length);144} else {145*r_supports = Vector2();146}147}148149bool GodotSeparationRayShape2D::contains_point(const Vector2 &p_point) const {150return false;151}152153bool GodotSeparationRayShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {154return false; //rays can't be intersected155}156157real_t GodotSeparationRayShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {158return 0; //rays are mass-less159}160161void GodotSeparationRayShape2D::set_data(const Variant &p_data) {162Dictionary d = p_data;163length = d["length"];164slide_on_slope = d["slide_on_slope"];165configure(Rect2(0, 0, 0.001, length));166}167168Variant GodotSeparationRayShape2D::get_data() const {169Dictionary d;170d["length"] = length;171d["slide_on_slope"] = slide_on_slope;172return d;173}174175/*********************************************************/176/*********************************************************/177/*********************************************************/178179void GodotSegmentShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {180if (Math::abs(p_normal.dot(n)) > segment_is_valid_support_threshold) {181r_supports[0] = a;182r_supports[1] = b;183r_amount = 2;184return;185}186187real_t dp = p_normal.dot(b - a);188if (dp > 0) {189*r_supports = b;190} else {191*r_supports = a;192}193r_amount = 1;194}195196bool GodotSegmentShape2D::contains_point(const Vector2 &p_point) const {197return false;198}199200bool GodotSegmentShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {201if (!Geometry2D::segment_intersects_segment(p_begin, p_end, a, b, &r_point)) {202return false;203}204205if (n.dot(p_begin) > n.dot(a)) {206r_normal = n;207} else {208r_normal = -n;209}210211return true;212}213214real_t GodotSegmentShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {215return p_mass * ((a * p_scale).distance_squared_to(b * p_scale)) / 12;216}217218void GodotSegmentShape2D::set_data(const Variant &p_data) {219ERR_FAIL_COND(p_data.get_type() != Variant::RECT2);220221Rect2 r = p_data;222a = r.position;223b = r.size;224n = (b - a).orthogonal();225226Rect2 aabb_new;227aabb_new.position = a;228aabb_new.expand_to(b);229if (aabb_new.size.x == 0) {230aabb_new.size.x = 0.001;231}232if (aabb_new.size.y == 0) {233aabb_new.size.y = 0.001;234}235configure(aabb_new);236}237238Variant GodotSegmentShape2D::get_data() const {239Rect2 r;240r.position = a;241r.size = b;242return r;243}244245/*********************************************************/246/*********************************************************/247/*********************************************************/248249void GodotCircleShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {250r_amount = 1;251*r_supports = p_normal * radius;252}253254bool GodotCircleShape2D::contains_point(const Vector2 &p_point) const {255return p_point.length_squared() < radius * radius;256}257258bool GodotCircleShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {259Vector2 line_vec = p_end - p_begin;260261real_t a, b, c;262263a = line_vec.dot(line_vec);264b = 2 * p_begin.dot(line_vec);265c = p_begin.dot(p_begin) - radius * radius;266267real_t sqrtterm = b * b - 4 * a * c;268269if (sqrtterm < 0) {270return false;271}272sqrtterm = Math::sqrt(sqrtterm);273real_t res = (-b - sqrtterm) / (2 * a);274275if (res < 0 || res > 1 + CMP_EPSILON) {276return false;277}278279r_point = p_begin + line_vec * res;280r_normal = r_point.normalized();281return true;282}283284real_t GodotCircleShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {285real_t a = radius * p_scale.x;286real_t b = radius * p_scale.y;287return p_mass * (a * a + b * b) / 4;288}289290void GodotCircleShape2D::set_data(const Variant &p_data) {291ERR_FAIL_COND(!p_data.is_num());292radius = p_data;293configure(Rect2(-radius, -radius, radius * 2, radius * 2));294}295296Variant GodotCircleShape2D::get_data() const {297return radius;298}299300/*********************************************************/301/*********************************************************/302/*********************************************************/303304void GodotRectangleShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {305for (int i = 0; i < 2; i++) {306Vector2 ag;307ag[i] = 1.0;308real_t dp = ag.dot(p_normal);309if (Math::abs(dp) <= segment_is_valid_support_threshold) {310continue;311}312313real_t sgn = dp > 0 ? 1.0 : -1.0;314315r_amount = 2;316317r_supports[0][i] = half_extents[i] * sgn;318r_supports[0][i ^ 1] = half_extents[i ^ 1];319320r_supports[1][i] = half_extents[i] * sgn;321r_supports[1][i ^ 1] = -half_extents[i ^ 1];322323return;324}325326/* USE POINT */327328r_amount = 1;329r_supports[0] = Vector2(330(p_normal.x < 0) ? -half_extents.x : half_extents.x,331(p_normal.y < 0) ? -half_extents.y : half_extents.y);332}333334bool GodotRectangleShape2D::contains_point(const Vector2 &p_point) const {335real_t x = p_point.x;336real_t y = p_point.y;337real_t edge_x = half_extents.x;338real_t edge_y = half_extents.y;339return (x >= -edge_x) && (x < edge_x) && (y >= -edge_y) && (y < edge_y);340}341342bool GodotRectangleShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {343return get_aabb().intersects_segment(p_begin, p_end, &r_point, &r_normal);344}345346real_t GodotRectangleShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {347Vector2 he2 = half_extents * 2 * p_scale;348return p_mass * he2.dot(he2) / 12.0;349}350351void GodotRectangleShape2D::set_data(const Variant &p_data) {352ERR_FAIL_COND(p_data.get_type() != Variant::VECTOR2);353354half_extents = p_data;355configure(Rect2(-half_extents, half_extents * 2.0));356}357358Variant GodotRectangleShape2D::get_data() const {359return half_extents;360}361362/*********************************************************/363/*********************************************************/364/*********************************************************/365366void GodotCapsuleShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {367Vector2 n = p_normal;368369real_t h = height * 0.5 - radius; // half-height of the rectangle part370371if (h > 0 && Math::abs(n.x) > segment_is_valid_support_threshold) {372// make it flat373n.y = 0.0;374n.x = SIGN(n.x) * radius;375376r_amount = 2;377r_supports[0] = n;378r_supports[0].y += h;379r_supports[1] = n;380r_supports[1].y -= h;381} else {382n *= radius;383n.y += (n.y > 0) ? h : -h;384r_amount = 1;385*r_supports = n;386}387}388389bool GodotCapsuleShape2D::contains_point(const Vector2 &p_point) const {390Vector2 p = p_point;391p.y = Math::abs(p.y);392p.y -= height * 0.5 - radius;393if (p.y < 0) {394p.y = 0;395}396397return p.length_squared() < radius * radius;398}399400bool GodotCapsuleShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {401real_t d = 1e10;402Vector2 n = (p_end - p_begin).normalized();403bool collided = false;404405//try spheres406for (int i = 0; i < 2; i++) {407Vector2 begin = p_begin;408Vector2 end = p_end;409real_t ofs = (i == 0) ? -height * 0.5 + radius : height * 0.5 - radius;410begin.y += ofs;411end.y += ofs;412413Vector2 line_vec = end - begin;414415real_t a, b, c;416417a = line_vec.dot(line_vec);418b = 2 * begin.dot(line_vec);419c = begin.dot(begin) - radius * radius;420421real_t sqrtterm = b * b - 4 * a * c;422423if (sqrtterm < 0) {424continue;425}426427sqrtterm = Math::sqrt(sqrtterm);428real_t res = (-b - sqrtterm) / (2 * a);429430if (res < 0 || res > 1 + CMP_EPSILON) {431continue;432}433434Vector2 point = begin + line_vec * res;435Vector2 pointf(point.x, point.y - ofs);436real_t pd = n.dot(pointf);437if (pd < d) {438r_point = pointf;439r_normal = point.normalized();440d = pd;441collided = true;442}443}444445Vector2 rpos, rnorm;446if (Rect2(Point2(-radius, -height * 0.5 + radius), Size2(radius * 2.0, height - radius * 2)).intersects_segment(p_begin, p_end, &rpos, &rnorm)) {447real_t pd = n.dot(rpos);448if (pd < d) {449r_point = rpos;450r_normal = rnorm;451d = pd;452collided = true;453}454}455456//return get_aabb().intersects_segment(p_begin,p_end,&r_point,&r_normal);457return collided; //todo458}459460real_t GodotCapsuleShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {461Vector2 he2 = Vector2(radius * 2, height) * p_scale;462return p_mass * he2.dot(he2) / 12.0;463}464465void GodotCapsuleShape2D::set_data(const Variant &p_data) {466ERR_FAIL_COND(p_data.get_type() != Variant::ARRAY && p_data.get_type() != Variant::VECTOR2);467468if (p_data.get_type() == Variant::ARRAY) {469Array arr = p_data;470ERR_FAIL_COND(arr.size() != 2);471height = arr[0];472radius = arr[1];473} else {474Point2 p = p_data;475radius = p.x;476height = p.y;477}478479Point2 he(radius, height * 0.5);480configure(Rect2(-he, he * 2));481}482483Variant GodotCapsuleShape2D::get_data() const {484return Point2(height, radius);485}486487/*********************************************************/488/*********************************************************/489/*********************************************************/490491void GodotConvexPolygonShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {492int support_idx = -1;493real_t d = -1e10;494r_amount = 0;495496for (int i = 0; i < point_count; i++) {497//test point498real_t ld = p_normal.dot(points[i].pos);499if (ld > d) {500support_idx = i;501d = ld;502}503504//test segment505if (points[i].normal.dot(p_normal) > segment_is_valid_support_threshold) {506r_amount = 2;507r_supports[0] = points[i].pos;508r_supports[1] = points[(i + 1) % point_count].pos;509return;510}511}512513ERR_FAIL_COND_MSG(support_idx == -1, "Convex polygon shape support not found.");514515r_amount = 1;516r_supports[0] = points[support_idx].pos;517}518519bool GodotConvexPolygonShape2D::contains_point(const Vector2 &p_point) const {520bool out = false;521bool in = false;522523for (int i = 0; i < point_count; i++) {524real_t d = points[i].normal.dot(p_point) - points[i].normal.dot(points[i].pos);525if (d > 0) {526out = true;527} else {528in = true;529}530}531532return in != out;533}534535bool GodotConvexPolygonShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {536Vector2 n = (p_end - p_begin).normalized();537real_t d = 1e10;538bool inters = false;539540for (int i = 0; i < point_count; i++) {541Vector2 res;542543if (!Geometry2D::segment_intersects_segment(p_begin, p_end, points[i].pos, points[(i + 1) % point_count].pos, &res)) {544continue;545}546547real_t nd = n.dot(res);548if (nd < d) {549d = nd;550r_point = res;551r_normal = points[i].normal;552inters = true;553}554}555556return inters;557}558559real_t GodotConvexPolygonShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {560ERR_FAIL_COND_V_MSG(point_count == 0, 0, "Convex polygon shape has no points.");561Rect2 aabb_new;562aabb_new.position = points[0].pos * p_scale;563for (int i = 0; i < point_count; i++) {564aabb_new.expand_to(points[i].pos * p_scale);565}566567return p_mass * aabb_new.size.dot(aabb_new.size) / 12.0;568}569570void GodotConvexPolygonShape2D::set_data(const Variant &p_data) {571#ifdef REAL_T_IS_DOUBLE572ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT64_ARRAY);573#else574ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT32_ARRAY);575#endif576577if (points) {578memdelete_arr(points);579}580points = nullptr;581point_count = 0;582583if (p_data.get_type() == Variant::PACKED_VECTOR2_ARRAY) {584Vector<Vector2> arr = p_data;585ERR_FAIL_COND(arr.is_empty());586point_count = arr.size();587points = memnew_arr(Point, point_count);588const Vector2 *r = arr.ptr();589590for (int i = 0; i < point_count; i++) {591points[i].pos = r[i];592}593594for (int i = 0; i < point_count; i++) {595Vector2 p = points[i].pos;596Vector2 pn = points[(i + 1) % point_count].pos;597points[i].normal = (pn - p).orthogonal().normalized();598}599} else {600Vector<real_t> dvr = p_data;601point_count = dvr.size() / 4;602ERR_FAIL_COND(point_count == 0);603604points = memnew_arr(Point, point_count);605const real_t *r = dvr.ptr();606607for (int i = 0; i < point_count; i++) {608int idx = i << 2;609points[i].pos.x = r[idx + 0];610points[i].pos.y = r[idx + 1];611points[i].normal.x = r[idx + 2];612points[i].normal.y = r[idx + 3];613}614}615616ERR_FAIL_COND(point_count == 0);617Rect2 aabb_new;618aabb_new.position = points[0].pos;619for (int i = 1; i < point_count; i++) {620aabb_new.expand_to(points[i].pos);621}622623configure(aabb_new);624}625626Variant GodotConvexPolygonShape2D::get_data() const {627Vector<Vector2> dvr;628629dvr.resize(point_count);630631for (int i = 0; i < point_count; i++) {632dvr.set(i, points[i].pos);633}634635return dvr;636}637638GodotConvexPolygonShape2D::~GodotConvexPolygonShape2D() {639if (points) {640memdelete_arr(points);641}642}643644//////////////////////////////////////////////////645646void GodotConcavePolygonShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {647real_t d = -1e10;648int idx = -1;649for (int i = 0; i < points.size(); i++) {650real_t ld = p_normal.dot(points[i]);651if (ld > d) {652d = ld;653idx = i;654}655}656657r_amount = 1;658ERR_FAIL_COND(idx == -1);659*r_supports = points[idx];660}661662bool GodotConcavePolygonShape2D::contains_point(const Vector2 &p_point) const {663return false; //sorry664}665666bool GodotConcavePolygonShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {667if (segments.is_empty() || points.is_empty()) {668return false;669}670671uint32_t *stack = (uint32_t *)alloca(sizeof(int) * bvh_depth);672673enum {674TEST_AABB_BIT = 0,675VISIT_LEFT_BIT = 1,676VISIT_RIGHT_BIT = 2,677VISIT_DONE_BIT = 3,678VISITED_BIT_SHIFT = 29,679NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1,680VISITED_BIT_MASK = ~NODE_IDX_MASK,681682};683684Vector2 n = (p_end - p_begin).normalized();685real_t d = 1e10;686bool inters = false;687688/*689for(int i=0;i<bvh_depth;i++)690stack[i]=0;691*/692693int level = 0;694695const Segment *segmentptr = &segments[0];696const Vector2 *pointptr = &points[0];697const BVH *bvhptr = &bvh[0];698699stack[0] = 0;700while (true) {701uint32_t node = stack[level] & NODE_IDX_MASK;702const BVH &bvh2 = bvhptr[node];703bool done = false;704705switch (stack[level] >> VISITED_BIT_SHIFT) {706case TEST_AABB_BIT: {707bool valid = bvh2.aabb.intersects_segment(p_begin, p_end);708if (!valid) {709stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;710711} else {712if (bvh2.left < 0) {713const Segment &s = segmentptr[bvh2.right];714Vector2 a = pointptr[s.points[0]];715Vector2 b = pointptr[s.points[1]];716717Vector2 res;718719if (Geometry2D::segment_intersects_segment(p_begin, p_end, a, b, &res)) {720real_t nd = n.dot(res);721if (nd < d) {722d = nd;723r_point = res;724r_normal = (b - a).orthogonal().normalized();725inters = true;726}727}728729stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;730731} else {732stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node;733}734}735}736continue;737case VISIT_LEFT_BIT: {738stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;739stack[level + 1] = bvh2.left | TEST_AABB_BIT;740level++;741}742continue;743case VISIT_RIGHT_BIT: {744stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;745stack[level + 1] = bvh2.right | TEST_AABB_BIT;746level++;747}748continue;749case VISIT_DONE_BIT: {750if (level == 0) {751done = true;752break;753} else {754level--;755}756}757continue;758}759760if (done) {761break;762}763}764765if (inters) {766if (n.dot(r_normal) > 0) {767r_normal = -r_normal;768}769}770771return inters;772}773774int GodotConcavePolygonShape2D::_generate_bvh(BVH *p_bvh, int p_len, int p_depth) {775if (p_len == 1) {776bvh_depth = MAX(p_depth, bvh_depth);777bvh.push_back(*p_bvh);778return bvh.size() - 1;779}780781//else sort best782783Rect2 global_aabb = p_bvh[0].aabb;784for (int i = 1; i < p_len; i++) {785global_aabb = global_aabb.merge(p_bvh[i].aabb);786}787788if (global_aabb.size.x > global_aabb.size.y) {789SortArray<BVH, BVH_CompareX> sort;790sort.sort(p_bvh, p_len);791792} else {793SortArray<BVH, BVH_CompareY> sort;794sort.sort(p_bvh, p_len);795}796797int median = p_len / 2;798799BVH node;800node.aabb = global_aabb;801int node_idx = bvh.size();802bvh.push_back(node);803804int l = _generate_bvh(p_bvh, median, p_depth + 1);805int r = _generate_bvh(&p_bvh[median], p_len - median, p_depth + 1);806bvh.write[node_idx].left = l;807bvh.write[node_idx].right = r;808809return node_idx;810}811812void GodotConcavePolygonShape2D::set_data(const Variant &p_data) {813#ifdef REAL_T_IS_DOUBLE814ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT64_ARRAY);815#else816ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT32_ARRAY);817#endif818819Rect2 aabb_new;820821if (p_data.get_type() == Variant::PACKED_VECTOR2_ARRAY) {822Vector<Vector2> p2arr = p_data;823int len = p2arr.size();824ERR_FAIL_COND(len % 2);825826segments.clear();827points.clear();828bvh.clear();829bvh_depth = 1;830831if (len == 0) {832configure(aabb_new);833return;834}835836const Vector2 *arr = p2arr.ptr();837838HashMap<Point2, int> pointmap;839for (int i = 0; i < len; i += 2) {840Point2 p1 = arr[i];841Point2 p2 = arr[i + 1];842int idx_p1, idx_p2;843844if (pointmap.has(p1)) {845idx_p1 = pointmap[p1];846} else {847idx_p1 = pointmap.size();848pointmap[p1] = idx_p1;849}850851if (pointmap.has(p2)) {852idx_p2 = pointmap[p2];853} else {854idx_p2 = pointmap.size();855pointmap[p2] = idx_p2;856}857858Segment s;859s.points[0] = idx_p1;860s.points[1] = idx_p2;861segments.push_back(s);862}863864points.resize(pointmap.size());865aabb_new.position = pointmap.begin()->key;866for (const KeyValue<Point2, int> &E : pointmap) {867aabb_new.expand_to(E.key);868points.write[E.value] = E.key;869}870871Vector<BVH> main_vbh;872main_vbh.resize(segments.size());873for (int i = 0; i < main_vbh.size(); i++) {874main_vbh.write[i].aabb.position = points[segments[i].points[0]];875main_vbh.write[i].aabb.expand_to(points[segments[i].points[1]]);876main_vbh.write[i].left = -1;877main_vbh.write[i].right = i;878}879880_generate_bvh(main_vbh.ptrw(), main_vbh.size(), 1);881882} else {883//dictionary with arrays884}885886configure(aabb_new);887}888889Variant GodotConcavePolygonShape2D::get_data() const {890Vector<Vector2> rsegments;891int len = segments.size();892rsegments.resize(len * 2);893Vector2 *w = rsegments.ptrw();894for (int i = 0; i < len; i++) {895w[(i << 1) + 0] = points[segments[i].points[0]];896w[(i << 1) + 1] = points[segments[i].points[1]];897}898899return rsegments;900}901902void GodotConcavePolygonShape2D::cull(const Rect2 &p_local_aabb, QueryCallback p_callback, void *p_userdata) const {903uint32_t *stack = (uint32_t *)alloca(sizeof(int) * bvh_depth);904905enum {906TEST_AABB_BIT = 0,907VISIT_LEFT_BIT = 1,908VISIT_RIGHT_BIT = 2,909VISIT_DONE_BIT = 3,910VISITED_BIT_SHIFT = 29,911NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1,912VISITED_BIT_MASK = ~NODE_IDX_MASK,913914};915916/*917for(int i=0;i<bvh_depth;i++)918stack[i]=0;919*/920921if (segments.is_empty() || points.is_empty() || bvh.is_empty()) {922return;923}924925int level = 0;926927const Segment *segmentptr = &segments[0];928const Vector2 *pointptr = &points[0];929const BVH *bvhptr = &bvh[0];930931stack[0] = 0;932while (true) {933uint32_t node = stack[level] & NODE_IDX_MASK;934const BVH &bvh2 = bvhptr[node];935936switch (stack[level] >> VISITED_BIT_SHIFT) {937case TEST_AABB_BIT: {938bool valid = p_local_aabb.intersects(bvh2.aabb);939if (!valid) {940stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;941942} else {943if (bvh2.left < 0) {944const Segment &s = segmentptr[bvh2.right];945Vector2 a = pointptr[s.points[0]];946Vector2 b = pointptr[s.points[1]];947948GodotSegmentShape2D ss(a, b, (b - a).orthogonal().normalized());949950if (p_callback(p_userdata, &ss)) {951return;952}953stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;954955} else {956stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node;957}958}959}960continue;961case VISIT_LEFT_BIT: {962stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;963stack[level + 1] = bvh2.left | TEST_AABB_BIT;964level++;965}966continue;967case VISIT_RIGHT_BIT: {968stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;969stack[level + 1] = bvh2.right | TEST_AABB_BIT;970level++;971}972continue;973case VISIT_DONE_BIT: {974if (level == 0) {975return;976} else {977level--;978}979}980continue;981}982}983}984985986