123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- #include "../public/VHACD.h"
- #include <stdlib.h>
- #include <string.h>
- #include <stdarg.h>
- #include <thread>
- #include <atomic>
- #include <mutex>
- #include <string>
- #include <float.h>
- #define ENABLE_ASYNC 1
- #define HACD_ALLOC(x) malloc(x)
- #define HACD_FREE(x) free(x)
- #define HACD_ASSERT(x) assert(x)
- namespace VHACD
- {
- class MyHACD_API : public VHACD::IVHACD, public VHACD::IVHACD::IUserCallback, VHACD::IVHACD::IUserLogger
- {
- public:
- MyHACD_API(void)
- {
- mVHACD = VHACD::CreateVHACD();
- }
- virtual ~MyHACD_API(void)
- {
- releaseHACD();
- Cancel();
- mVHACD->Release();
- }
-
- virtual bool Compute(const double* const _points,
- const uint32_t countPoints,
- const uint32_t* const _triangles,
- const uint32_t countTriangles,
- const Parameters& _desc) final
- {
- #if ENABLE_ASYNC
- Cancel(); // if we previously had a solution running; cancel it.
- releaseHACD();
- // We need to copy the input vertices and triangles into our own buffers so we can operate
- // on them safely from the background thread.
- mVertices = (double *)HACD_ALLOC(sizeof(double)*countPoints * 3);
- mIndices = (uint32_t *)HACD_ALLOC(sizeof(uint32_t)*countTriangles * 3);
- memcpy(mVertices, _points, sizeof(double)*countPoints * 3);
- memcpy(mIndices, _triangles, sizeof(uint32_t)*countTriangles * 3);
- mRunning = true;
- mThread = new std::thread([this, countPoints, countTriangles, _desc]()
- {
- ComputeNow(mVertices, countPoints, mIndices, countTriangles, _desc);
- mRunning = false;
- });
- #else
- releaseHACD();
- ComputeNow(_points, countPoints, _triangles, countTriangles, _desc);
- #endif
- return true;
- }
- bool ComputeNow(const double* const points,
- const uint32_t countPoints,
- const uint32_t* const triangles,
- const uint32_t countTriangles,
- const Parameters& _desc)
- {
- uint32_t ret = 0;
- mHullCount = 0;
- mCallback = _desc.m_callback;
- mLogger = _desc.m_logger;
- IVHACD::Parameters desc = _desc;
- // Set our intercepting callback interfaces if non-null
- desc.m_callback = desc.m_callback ? this : nullptr;
- desc.m_logger = desc.m_logger ? this : nullptr;
- if ( countPoints )
- {
- bool ok = mVHACD->Compute(points, countPoints, triangles, countTriangles, desc);
- if (ok)
- {
- ret = mVHACD->GetNConvexHulls();
- mHulls = new IVHACD::ConvexHull[ret];
- for (uint32_t i = 0; i < ret; i++)
- {
- VHACD::IVHACD::ConvexHull vhull;
- mVHACD->GetConvexHull(i, vhull);
- VHACD::IVHACD::ConvexHull h;
- h.m_nPoints = vhull.m_nPoints;
- h.m_points = (double *)HACD_ALLOC(sizeof(double) * 3 * h.m_nPoints);
- memcpy(h.m_points, vhull.m_points, sizeof(double) * 3 * h.m_nPoints);
- h.m_nTriangles = vhull.m_nTriangles;
- h.m_triangles = (uint32_t *)HACD_ALLOC(sizeof(uint32_t) * 3 * h.m_nTriangles);
- memcpy(h.m_triangles, vhull.m_triangles, sizeof(uint32_t) * 3 * h.m_nTriangles);
- h.m_volume = vhull.m_volume;
- h.m_center[0] = vhull.m_center[0];
- h.m_center[1] = vhull.m_center[1];
- h.m_center[2] = vhull.m_center[2];
- mHulls[i] = h;
- if (mCancel)
- {
- ret = 0;
- break;
- }
- }
- }
- }
- mHullCount = ret;
- return ret ? true : false;
- }
- void releaseHull(VHACD::IVHACD::ConvexHull &h)
- {
- HACD_FREE((void *)h.m_triangles);
- HACD_FREE((void *)h.m_points);
- h.m_triangles = nullptr;
- h.m_points = nullptr;
- }
- virtual void GetConvexHull(const uint32_t index, VHACD::IVHACD::ConvexHull& ch) const final
- {
- if ( index < mHullCount )
- {
- ch = mHulls[index];
- }
- }
- void releaseHACD(void) // release memory associated with the last HACD request
- {
- for (uint32_t i=0; i<mHullCount; i++)
- {
- releaseHull(mHulls[i]);
- }
- delete[]mHulls;
- mHulls = nullptr;
- mHullCount = 0;
- HACD_FREE(mVertices);
- mVertices = nullptr;
- HACD_FREE(mIndices);
- mIndices = nullptr;
- }
- virtual void release(void) // release the HACD_API interface
- {
- delete this;
- }
- virtual uint32_t getHullCount(void)
- {
- return mHullCount;
- }
- virtual void Cancel() final
- {
- if (mRunning)
- {
- mVHACD->Cancel(); // Set the cancel signal to the base VHACD
- }
- if (mThread)
- {
- mThread->join(); // Wait for the thread to fully exit before we delete the instance
- delete mThread;
- mThread = nullptr;
- Log("Convex Decomposition thread canceled\n");
- }
- mCancel = false; // clear the cancel semaphore
- }
- virtual bool Compute(const float* const points,
- const uint32_t countPoints,
- const uint32_t* const triangles,
- const uint32_t countTriangles,
- const Parameters& params) final
- {
- double *vertices = (double *)HACD_ALLOC(sizeof(double)*countPoints * 3);
- const float *source = points;
- double *dest = vertices;
- for (uint32_t i = 0; i < countPoints; i++)
- {
- dest[0] = source[0];
- dest[1] = source[1];
- dest[2] = source[2];
- dest += 3;
- source += 3;
- }
- bool ret = Compute(vertices, countPoints, triangles, countTriangles, params);
- HACD_FREE(vertices);
- return ret;
- }
- virtual uint32_t GetNConvexHulls() const final
- {
- processPendingMessages();
- return mHullCount;
- }
- virtual void Clean(void) final // release internally allocated memory
- {
- Cancel();
- releaseHACD();
- mVHACD->Clean();
- }
- virtual void Release(void) final // release IVHACD
- {
- delete this;
- }
- virtual bool OCLInit(void* const oclDevice,
- IVHACD::IUserLogger* const logger = 0) final
- {
- return mVHACD->OCLInit(oclDevice, logger);
- }
-
- virtual bool OCLRelease(IVHACD::IUserLogger* const logger = 0) final
- {
- return mVHACD->OCLRelease(logger);
- }
- virtual void Update(const double overallProgress,
- const double stageProgress,
- const double operationProgress,
- const char* const stage,
- const char* const operation) final
- {
- mMessageMutex.lock();
- mHaveUpdateMessage = true;
- mOverallProgress = overallProgress;
- mStageProgress = stageProgress;
- mOperationProgress = operationProgress;
- mStage = std::string(stage);
- mOperation = std::string(operation);
- mMessageMutex.unlock();
- }
- virtual void Log(const char* const msg) final
- {
- mMessageMutex.lock();
- mHaveLogMessage = true;
- mMessage = std::string(msg);
- mMessageMutex.unlock();
- }
- virtual bool IsReady(void) const final
- {
- processPendingMessages();
- return !mRunning;
- }
- // As a convenience for the calling application we only send it update and log messages from it's own main
- // thread. This reduces the complexity burden on the caller by making sure it only has to deal with log
- // messages in it's main application thread.
- void processPendingMessages(void) const
- {
- // If we have a new update message and the user has specified a callback we send the message and clear the semaphore
- if (mHaveUpdateMessage && mCallback)
- {
- mMessageMutex.lock();
- mCallback->Update(mOverallProgress, mStageProgress, mOperationProgress, mStage.c_str(), mOperation.c_str());
- mHaveUpdateMessage = false;
- mMessageMutex.unlock();
- }
- // If we have a new log message and the user has specified a callback we send the message and clear the semaphore
- if (mHaveLogMessage && mLogger)
- {
- mMessageMutex.lock();
- mLogger->Log(mMessage.c_str());
- mHaveLogMessage = false;
- mMessageMutex.unlock();
- }
- }
- // Will compute the center of mass of the convex hull decomposition results and return it
- // in 'centerOfMass'. Returns false if the center of mass could not be computed.
- virtual bool ComputeCenterOfMass(double centerOfMass[3]) const
- {
- bool ret = false;
- centerOfMass[0] = 0;
- centerOfMass[1] = 0;
- centerOfMass[2] = 0;
- if (mVHACD && IsReady() )
- {
- ret = mVHACD->ComputeCenterOfMass(centerOfMass);
- }
- return ret;
- }
- private:
- double *mVertices{ nullptr };
- uint32_t *mIndices{ nullptr };
- std::atomic< uint32_t> mHullCount{ 0 };
- VHACD::IVHACD::ConvexHull *mHulls{ nullptr };
- VHACD::IVHACD::IUserCallback *mCallback{ nullptr };
- VHACD::IVHACD::IUserLogger *mLogger{ nullptr };
- VHACD::IVHACD *mVHACD{ nullptr };
- std::thread *mThread{ nullptr };
- std::atomic< bool > mRunning{ false };
- std::atomic<bool> mCancel{ false };
- // Thread safe caching mechanism for messages and update status.
- // This is so that caller always gets messages in his own thread
- // Member variables are marked as 'mutable' since the message dispatch function
- // is called from const query methods.
- mutable std::mutex mMessageMutex;
- mutable std::atomic< bool > mHaveUpdateMessage{ false };
- mutable std::atomic< bool > mHaveLogMessage{ false };
- mutable double mOverallProgress{ 0 };
- mutable double mStageProgress{ 0 };
- mutable double mOperationProgress{ 0 };
- mutable std::string mStage;
- mutable std::string mOperation;
- mutable std::string mMessage;
- };
- IVHACD* CreateVHACD_ASYNC(void)
- {
- MyHACD_API *m = new MyHACD_API;
- return static_cast<IVHACD *>(m);
- }
- }; // end of VHACD namespace
|