/* * File: ThreadedMeshGenerator.hpp * Author: oliver * * Created on April 7, 2011, 4:04 PM */ #ifndef THREADEDMESHGENERATOR_HPP # define THREADEDMESHGENERATOR_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include template class ThreadedVolume; template class VoxelAccessor { public: VoxelAccessor(ThreadedVolume& vol); void setVoxel(int32_t x, int32_t y, int32_t z, VoxelType voxel); void setVoxel(PolyVox::Vector3DInt32 pos, VoxelType voxel); VoxelType getVoxel(int32_t x, int32_t y, int32_t z) const; VoxelType getVoxel(PolyVox::Vector3DInt32 pos) const; private: ThreadedVolume& m_TV; boost::lock_guard m_Lock; }; struct MeshCommand { MeshCommand(PolyVox::Vector3DInt32 p) : pos(p) {} PolyVox::SurfaceMesh mesh; PolyVox::Vector3DInt32 pos; }; template class ThreadedVolume { friend class VoxelAccessor; typedef PolyVox::Volume Volume; public: ThreadedVolume(uint32_t uChunkSideLengthPower); ~ThreadedVolume(); void stop(); void start(); std::unique_ptr next(); void resize(uint32_t uChunkSideLengthPower); PolyVox::RaycastResult raycast(PolyVox::Vector3DFloat start, PolyVox::Vector3DFloat end); void add(PolyVox::Vector3DInt32 pos); private: std::set m_Blocks; std::queue m_vecMeshesToRender; std::queue m_vecMeshesRendered; Volume m_Volume, m_Volume2; void thread_loop(); bool m_bStopThread; uint32_t m_uChunkSideLengthPower; boost::scoped_ptr m_Thread; boost::mutex m_mutexVolume; boost::mutex m_mutexMeshesToRender; boost::mutex m_mutexMeshesRendered; std::set m_ModifiedChunks; std::set m_LoadedChunks; }; template inline void VoxelAccessor::setVoxel(int32_t x, int32_t y, int32_t z, VoxelType voxel) { m_TV.m_Volume.setVoxelAt(x, y, z, voxel); } template inline void VoxelAccessor::setVoxel(PolyVox::Vector3DInt32 pos, VoxelType voxel) { setVoxel(pos.getX(), pos.getY(), pos.getZ(), voxel); } template inline VoxelType VoxelAccessor::getVoxel(int32_t x, int32_t y, int32_t z) const { return m_TV.m_Volume.getVoxelAt(x, y, z); } template inline VoxelType VoxelAccessor::getVoxel(PolyVox::Vector3DInt32 pos) const { return getVoxel(pos.getX(), pos.getY(), pos.getZ()); } template inline ThreadedVolume::~ThreadedVolume() { if(m_Thread) { m_Thread->join(); } } template inline VoxelAccessor::VoxelAccessor(ThreadedVolume& tv) :m_TV(tv), m_Lock(tv.m_mutexVolume) { } template inline PolyVox::RaycastResult ThreadedVolume::raycast(PolyVox::Vector3DFloat start, PolyVox::Vector3DFloat direction) { boost::lock_guard lock(m_mutexVolume); PolyVox::RaycastResult raycastResult; PolyVox::Raycast raycast(&m_Volume, start, direction, raycastResult); raycast.execute(); return raycastResult; } template inline std::unique_ptr ThreadedVolume::next() { std::unique_ptr ret; boost::lock_guard lock(m_mutexMeshesRendered); if(m_vecMeshesRendered.empty()) { return ret; } // get one ret.reset(m_vecMeshesRendered.front()); m_vecMeshesRendered.pop(); return std::move(ret); } template inline void ThreadedVolume::add(PolyVox::Vector3DInt32 pos) { boost::lock_guard lock(m_mutexMeshesToRender); if(m_ModifiedChunks.count(pos) == 0) { m_vecMeshesToRender.push(new MeshCommand(pos)); m_LoadedChunks.insert(pos); m_ModifiedChunks.insert(pos); } } template inline void ThreadedVolume::start() { if(!m_bStopThread && m_Thread) { stop(); m_Thread->join(); } m_bStopThread = false; m_Thread.reset(new boost::thread(boost::bind(&ThreadedVolume::thread_loop, this))); } template inline void ThreadedVolume::stop() { m_bStopThread = true; } template inline ThreadedVolume::ThreadedVolume(uint32_t uChunkSideLengthPower) :m_Volume(NULL, NULL), m_Volume2(NULL, NULL), m_bStopThread(true) { resize(uChunkSideLengthPower); } template inline void ThreadedVolume::resize(uint32_t uChunkSideLengthPower) { boost::lock_guard lock1(m_mutexMeshesToRender); boost::lock_guard lock2(m_mutexMeshesRendered); boost::lock_guard lock3(m_mutexVolume); m_uChunkSideLengthPower = uChunkSideLengthPower; m_Volume.resize(PolyVox::Region::MaxRegion, 0x01< inline void ThreadedVolume::thread_loop() { while(!m_bStopThread) { boost::this_thread::sleep(boost::posix_time::milliseconds(10)); MeshCommand* mcCurrent; { boost::lock_guard lock(m_mutexMeshesToRender); if(m_vecMeshesToRender.empty()) { continue; } mcCurrent = m_vecMeshesToRender.front(); m_vecMeshesToRender.pop(); m_ModifiedChunks.erase(mcCurrent->pos); } { boost::lock_guard lock(m_mutexVolume); int32_t x = mcCurrent->pos.getX(); int32_t y = mcCurrent->pos.getY(); int32_t z = mcCurrent->pos.getZ(); bool bCanRender = true; for(int x1 = x-1; x1 <= x+1 && bCanRender; x1++) { for(int y1 = y-1; y1 <= y+1 && bCanRender; y1++) { for(int z1 = z-1; z1 <= z+1; z1++) { if(m_ModifiedChunks.count(PolyVox::Vector3DInt32(x1, y1, z1)) == 1) { m_Volume.copyBlockTo(m_Volume2, x1, y1, z1); } else if(m_LoadedChunks.count(PolyVox::Vector3DInt32(x1, y1, z1)) == 0) { bCanRender = false; break; } } } } if(!bCanRender) { continue; } } PolyVox::Region reg( (mcCurrent->pos) << static_cast(m_uChunkSideLengthPower), ((mcCurrent->pos) + PolyVox::Vector3DInt32(1,1,1)) << static_cast(m_uChunkSideLengthPower) ); PolyVox::SurfaceExtractor extractor(&m_Volume2, reg, &(mcCurrent->mesh)); extractor.execute(); { boost::lock_guard lock(m_mutexMeshesRendered); m_vecMeshesRendered.push(mcCurrent); } } } #endif /* THREADEDMESHGENERATOR_HPP */