summaryrefslogtreecommitdiff
path: root/src/samples/firebirds/plugin/CollisionDetector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/samples/firebirds/plugin/CollisionDetector.cpp')
-rw-r--r--src/samples/firebirds/plugin/CollisionDetector.cpp122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/samples/firebirds/plugin/CollisionDetector.cpp b/src/samples/firebirds/plugin/CollisionDetector.cpp
new file mode 100644
index 0000000..1eca5c9
--- /dev/null
+++ b/src/samples/firebirds/plugin/CollisionDetector.cpp
@@ -0,0 +1,122 @@
+#include "CollisionDetector.h"
+
+#include "../../../base/ScopeTimer.h"
+#include "../../../wrapper/WrapHelper.h"
+
+namespace avg {
+
+CollisionDetector::CollisionDetector(const Bitmap& bmpA, const Bitmap& bmpB)
+{
+ m_pBmpA = new Bitmap(bmpA.getSize(), B8G8R8A8);
+ m_pBmpA->copyPixels(bmpA);
+ m_pBmpB = new Bitmap(bmpB.getSize(), B8G8R8A8);
+ m_pBmpB->copyPixels(bmpB);
+}
+
+CollisionDetector::~CollisionDetector()
+{
+ delete m_pBmpA;
+ delete m_pBmpB;
+}
+
+static ProfilingZoneID CollisionDetectorProfilingZone("Detect collisions");
+
+bool CollisionDetector::detect(glm::vec2 posA, glm::vec2 posB)
+{
+ ScopeTimer Timer(CollisionDetectorProfilingZone);
+
+ int widthA = m_pBmpA->getSize().x;
+ int heightA = m_pBmpA->getSize().y;
+ int rightA = posA.x + widthA;
+ int bottomA = posA.y + heightA;
+ int widthB = m_pBmpB->getSize().x;
+ int heightB = m_pBmpB->getSize().y;
+ int rightB = posB.x + widthB;
+ int bottomB = posB.y + heightB;
+
+ // bounding box test
+ if (rightA <= posB.x || posA.x >= rightB || bottomA <= posB.y || posA.y >= bottomB) {
+ return false;
+ }
+
+ // pixel level test
+
+ // calculate x overlap
+ int dX = posB.x - posA.x;
+ if (dX < 0) {
+ posA.x = 0;
+ posB.x = -dX;
+ }
+ else {
+ posA.x = dX;
+ posB.x = 0;
+ }
+ int width;
+ dX = rightB - rightA;
+ if (dX < 0)
+ width = std::min(widthA + dX, widthB);
+ else
+ width = std::min(widthB - dX, widthA);
+ // calculate y overlap
+ int dY = posB.y - posA.y;
+ if (dY < 0) {
+ posA.y = 0;
+ posB.y = -dY;
+ }
+ else {
+ posA.y = dY;
+ posB.y = 0;
+ }
+ int height;
+ dY = bottomB - bottomA;
+ if (dY < 0)
+ height = std::min(heightA + dY, heightB);
+ else
+ height = std::min(heightB - dY, heightA);
+
+ // test alpha channels
+ const unsigned char* pPixStartA = m_pBmpA->getPixels() +
+ (int) posA.y * m_pBmpA->getStride() +
+ (int) posA.x * 4 + 3; // alpha channel of 1st A pixel
+ const unsigned char* pPixStartB = m_pBmpB->getPixels() +
+ (int) posB.y * m_pBmpB->getStride() +
+ (int) posB.x * 4 + 3; // alpha channel of 1st B pixel
+ const unsigned char* pPixA = pPixStartA;
+ const unsigned char* pPixB = pPixStartB;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ if (*pPixA && *pPixB) {
+ return true; // both pixels have alpha > 0 --> collision
+ }
+ pPixA += 4;
+ pPixB += 4;
+ }
+ pPixA = pPixStartA + y * m_pBmpA->getStride();
+ pPixB = pPixStartB + y * m_pBmpB->getStride();
+ }
+
+ return false;
+}
+
+} // namespace avg
+
+
+using namespace boost::python;
+
+BOOST_PYTHON_MODULE(collisiondetector)
+{
+ class_<avg::CollisionDetector, boost::noncopyable>("CollisionDetector", no_init)
+ .def(init<avg::Bitmap&, avg::Bitmap&>())
+ .def("detect", &avg::CollisionDetector::detect)
+ ;
+}
+
+
+AVG_PLUGIN_API void registerPlugin()
+{
+ initcollisiondetector(); // created by BOOST_PYTHON_MODULE
+ object mainModule(handle<>(borrowed(PyImport_AddModule("__main__"))));
+ object collisiondetectorModule(handle<>(PyImport_ImportModule("collisiondetector")));
+ mainModule.attr("collisiondetector") = collisiondetectorModule;
+}
+