27#include "freertos/FreeRTOS.h"
28#include "freertos/task.h"
36#pragma GCC optimize ("O2")
49QuadTree::QuadTree(CollisionDetector * collisionDetector, QuadTree * parent, QuadTreeQuadrant quadrant,
int x,
int y,
int width,
int height)
51 m_collisionDetector = collisionDetector;
53 m_quadrant = quadrant;
60 m_children[TopLeft] =
nullptr;
61 m_children[TopRight] =
nullptr;
62 m_children[BottomLeft] =
nullptr;
63 m_children[BottomRight] =
nullptr;
67bool QuadTree::isEmpty()
69 return m_objectsCount == 0 &&
70 m_children[TopLeft] ==
nullptr &&
71 m_children[TopRight] ==
nullptr &&
72 m_children[BottomLeft] ==
nullptr &&
73 m_children[BottomRight] ==
nullptr;
77void QuadTree::detachFromParent()
80 m_parent->m_children[m_quadrant] =
nullptr;
86void QuadTree::insert(QuadTreeObject *
object)
88 QuadTreeQuadrant quadrant = getQuadrant(
object);
89 if (quadrant != None && m_children[quadrant]) {
90 m_children[quadrant]->insert(
object);
95 object->next = m_objects;
99 if (m_objectsCount < QUADTREE_LEVEL_SPLIT_THRESHOLD)
104 QuadTreeObject * obj = m_objects;
105 QuadTreeObject * prev =
nullptr;
107 QuadTreeObject * next = obj->next;
108 QuadTreeQuadrant quadrant = getQuadrant(obj);
109 if (quadrant != None) {
110 createQuadrant(quadrant);
111 m_children[quadrant]->insert(obj);
125void QuadTree::remove(QuadTreeObject *
object)
128 QuadTreeObject * obj =
object->owner->m_objects;
129 QuadTreeObject * prev =
nullptr;
133 object->owner->m_objects =
object->next;
135 prev->next =
object->next;
141 object->owner->m_objectsCount -= 1;
142 object->owner =
nullptr;
143 object->next =
nullptr;
147void QuadTree::createQuadrant(QuadTreeQuadrant quadrant)
149 if (m_children[quadrant] ==
nullptr) {
150 int halfWidth = m_width >> 1;
151 int halfHeight = m_height >> 1;
154 m_children[TopLeft] = m_collisionDetector->initEmptyQuadTree(
this, TopLeft, m_x, m_y, halfWidth, halfHeight);
157 m_children[TopRight] = m_collisionDetector->initEmptyQuadTree(
this, TopRight, m_x + halfWidth, m_y, halfWidth, halfHeight);
160 m_children[BottomLeft] = m_collisionDetector->initEmptyQuadTree(
this, BottomLeft, m_x, m_y + halfHeight, halfWidth, halfHeight);
163 m_children[BottomRight] = m_collisionDetector->initEmptyQuadTree(
this, BottomRight, m_x + halfWidth, m_y + halfHeight, halfWidth, halfHeight);
173bool QuadTree::objectInRect(QuadTreeObject *
object,
int x,
int y,
int width,
int height)
175 return (object->sprite->x >= x) &&
176 (
object->sprite->y >= y) &&
177 (object->sprite->x + object->sprite->getWidth() <= x +
width) &&
178 (object->sprite->y + object->sprite->getHeight() <= y +
height);
182QuadTreeQuadrant QuadTree::getQuadrant(QuadTreeObject *
object)
184 int hWidth = m_width >> 1;
185 int hHeight = m_height >> 1;
186 if (objectInRect(
object, m_x, m_y, hWidth, hHeight))
188 if (objectInRect(
object, m_x + hWidth, m_y, hWidth, hHeight))
190 if (objectInRect(
object, m_x, m_y + hHeight, hWidth, hHeight))
192 if (objectInRect(
object, m_x + hWidth, m_y + hHeight, hWidth, hHeight))
198void QuadTree::update(QuadTreeObject *
object)
200 QuadTree * qtree =
object->owner;
202 if (qtree->m_parent ==
nullptr || objectInRect(
object, qtree->m_x, qtree->m_y, qtree->m_width, qtree->m_height)) {
204 QuadTreeQuadrant quadrant = qtree->getQuadrant(
object);
205 if (qtree == object->owner && qtree->m_children[quadrant] ==
nullptr)
212 qtree->insert(
object);
215 qtree = qtree->m_parent;
222QuadTreeObject * QuadTree::detectCollision(QuadTreeObject *
object, CollisionDetectionCallback callbackFunc,
void * callbackObj)
224 if (!object->sprite->visible)
228 QuadTreeObject * obj = m_objects;
230 QuadTreeObject * next = obj->next;
232 Point collisionPoint;
233 if (
object != obj && obj->sprite->visible && objectsIntersect(
object, obj) && checkMaskCollision(
object, obj, &collisionPoint)) {
236 callbackFunc(callbackObj, object->sprite, obj->sprite, collisionPoint);
244 QuadTreeQuadrant quadrant = getQuadrant(
object);
245 if (quadrant != None) {
247 if (m_children[quadrant])
248 return m_children[quadrant]->detectCollision(
object, callbackFunc, callbackObj);
251 for (
int i = 0; i < 4; ++i) {
252 QuadTreeObject * obj = m_children[i] && objectIntersectsQuadTree(
object, m_children[i]) ? m_children[i]->detectCollision(
object, callbackFunc, callbackObj) :
nullptr;
253 if (obj && !callbackFunc)
262bool QuadTree::objectsIntersect(QuadTreeObject * objectA, QuadTreeObject * objectB)
264 return objectA->sprite->x + objectA->sprite->getWidth() >= objectB->sprite->x &&
265 objectB->sprite->x + objectB->sprite->getWidth() >= objectA->sprite->x &&
266 objectA->sprite->y + objectA->sprite->getHeight() >= objectB->sprite->y &&
267 objectB->sprite->y + objectB->sprite->getHeight() >= objectA->sprite->y;
272bool QuadTree::objectIntersectsQuadTree(QuadTreeObject *
object, QuadTree * quadTree)
274 return object->sprite->x +
object->sprite->getWidth() >= quadTree->m_x &&
275 quadTree->m_x + quadTree->m_width >=
object->sprite->x &&
276 object->sprite->y +
object->sprite->getHeight() >= quadTree->m_y &&
277 quadTree->m_y + quadTree->m_height >=
object->sprite->y;
281bool QuadTree::checkMaskCollision(QuadTreeObject * objectA, QuadTreeObject * objectB, Point * collisionPoint)
284 int x1 = tmax(objectA->sprite->x, objectB->sprite->x);
285 int y1 = tmax(objectA->sprite->y, objectB->sprite->y);
286 int x2 = tmin(objectA->sprite->x + objectA->sprite->getWidth() - 1, objectB->sprite->x + objectB->sprite->getWidth() - 1);
287 int y2 = tmin(objectA->sprite->y + objectA->sprite->getHeight() - 1, objectB->sprite->y + objectB->sprite->getHeight() - 1);
290 Bitmap * bitmapA = objectA->sprite->getFrame();
291 Bitmap * bitmapB = objectB->sprite->getFrame();
294 for (
int y = y1; y <= y2; ++y) {
295 uint8_t
const * rowA = bitmapA->data + bitmapA->width * (y - objectA->sprite->y);
296 uint8_t
const * rowB = bitmapB->data + bitmapB->width * (y - objectB->sprite->y);
297 for (
int x = x1; x <= x2; ++x) {
298 int alphaA = rowA[x - objectA->sprite->x] >> 6;
299 int alphaB = rowB[x - objectB->sprite->x] >> 6;
300 if (alphaA && alphaB) {
301 *collisionPoint = (Point){(int16_t)x, (int16_t)y};
308 for (
int y = y1; y <= y2; ++y) {
309 for (
int x = x1; x <= x2; ++x) {
310 int alphaA = bitmapA->getAlpha(x - objectA->sprite->x, y - objectA->sprite->y);
311 int alphaB = bitmapB->getAlpha(x - objectB->sprite->x, y - objectB->sprite->y);
312 if (alphaA && alphaB) {
313 *collisionPoint = (Point){(int16_t)x, (int16_t)y};
349 : m_quadTreePool(nullptr), m_objectPool(nullptr)
351 m_objectPoolSize = maxObjectsCount;
352 m_quadTreePoolSize = (5 * maxObjectsCount + 1) / 3;
354 if (maxObjectsCount > 0) {
357 m_quadTreePool = (QuadTree*) malloc(
sizeof(QuadTree) * m_quadTreePoolSize);
360 m_quadTreePool[0] = QuadTree(
this,
nullptr, None, 0, 0,
width,
height);
361 m_rootQuadTree = m_quadTreePool;
364 for (
int i = 1; i < m_quadTreePoolSize; ++i)
365 m_quadTreePool[i] = QuadTree(
this,
nullptr, None, 0, 0, 0, 0);
368 m_objectPool = (QuadTreeObject*) malloc(
sizeof(QuadTreeObject) * m_objectPoolSize);
369 for (
int i = 0; i < m_objectPoolSize; ++i)
370 m_objectPool[i] = QuadTreeObject(
nullptr,
nullptr);
376CollisionDetector::~CollisionDetector()
378 free(m_quadTreePool);
383QuadTree * CollisionDetector::initEmptyQuadTree(QuadTree * parent, QuadTreeQuadrant quadrant,
int x,
int y,
int width,
int height)
386 for (
int i = 1; i < m_quadTreePoolSize; ++i) {
387 if (m_quadTreePool[i].isEmpty()) {
388 m_quadTreePool[i].detachFromParent();
389 m_quadTreePool[i] = QuadTree(
this, parent, quadrant, x, y,
width,
height);
390 return &m_quadTreePool[i];
393 assert(
false &&
"No enough quadtrees");
400 for (
int i = 0; i < m_objectPoolSize; ++i)
401 if (m_objectPool[i].sprite ==
nullptr) {
402 QuadTreeObject * obj = &m_objectPool[i];
403 obj->sprite = sprite;
404 sprite->collisionDetectorObject = obj;
405 m_rootQuadTree->insert(obj);
408 assert(
false &&
"No enough objects");
414 QuadTree::remove(sprite->collisionDetectorObject);
415 sprite->collisionDetectorObject->sprite =
nullptr;
429 QuadTreeObject * obj = m_rootQuadTree->detectCollision(sprite->collisionDetectorObject);
431 Sprite * cSprite = obj->sprite;
442 m_rootQuadTree->detectCollision(sprite->collisionDetectorObject, callbackFunc, callbackObj);
448 m_rootQuadTree->update(sprite->collisionDetectorObject);
void addSprite(Sprite *sprite)
Adds the specified sprite to collision detector.
CollisionDetector(int maxObjectsCount, int width, int height)
Creates an instance of CollisionDetector.
void update(Sprite *sprite)
Updates collision detector.
Sprite * updateAndDetectCollision(Sprite *sprite, bool removeCollidingSprites=true)
Updates collision detector and detect collision with the specified sprite.
void removeSprite(Sprite *sprite)
Removes the specified sprite from collision detector.
Sprite * detectCollision(Sprite *sprite, bool removeCollidingSprites=true)
Detects first collision with the specified sprite.
This file contains fabgl::CollisionDetector class definition.
This file contains some utility classes and functions.