#pragma region License /****************************************************************************** This file is part of the PolyVox library Copyright (C) 2006 David Williams This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ******************************************************************************/ #pragma endregion #include "PolyVoxUtil/VolumeChangeTracker.h" #include "PolyVoxCore/GradientEstimators.h" #include "PolyVoxCore/IndexedSurfacePatch.h" #include "PolyVoxCore/MarchingCubesTables.h" #include "PolyVoxCore/SurfaceExtractors.h" #include "PolyVoxCore/SurfaceVertex.h" #include "PolyVoxCore/Utility.h" #include "PolyVoxCore/Vector.h" #include "PolyVoxCore/Volume.h" #include "PolyVoxCore/VolumeIterator.h" using namespace std; namespace PolyVox { int32_t VolumeChangeTracker::m_iCurrentTime = 0; ////////////////////////////////////////////////////////////////////////// // VolumeChangeTracker ////////////////////////////////////////////////////////////////////////// VolumeChangeTracker::VolumeChangeTracker(Volume* volumeDataToSet, uint16_t regionSideLength) :m_bIsLocked(false) ,volumeData(0) ,m_uRegionSideLength(regionSideLength) { volumeData = volumeDataToSet; m_uVolumeSideLengthInRegions = volumeData->getSideLength() / m_uRegionSideLength; m_uRegionSideLengthPower = PolyVox::logBase2(m_uRegionSideLength); volRegionLastModified = new BlockData(m_uRegionSideLength); } VolumeChangeTracker::~VolumeChangeTracker() { } void VolumeChangeTracker::setAllRegionsModified(void) { for(uint16_t blockZ = 0; blockZ < m_uVolumeSideLengthInRegions; ++blockZ) { for(uint16_t blockY = 0; blockY < m_uVolumeSideLengthInRegions; ++blockY) { for(uint16_t blockX = 0; blockX < m_uVolumeSideLengthInRegions; ++blockX) { volRegionLastModified->setVoxelAt(blockX, blockY, blockZ, m_iCurrentTime); ++m_iCurrentTime; } } } } int32_t VolumeChangeTracker::getCurrentTime(void) const { return m_iCurrentTime; } uint16_t VolumeChangeTracker::getSideLength(void) { return volumeData->getSideLength(); } Region VolumeChangeTracker::getEnclosingRegion(void) const { return volumeData->getEnclosingRegion(); } int32_t VolumeChangeTracker::getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ) { return volRegionLastModified->getVoxelAt(uX, uY, uZ); } uint8_t VolumeChangeTracker::getVoxelAt(const Vector3DUint16& pos) { return getVoxelAt(pos.getX(), pos.getY(), pos.getZ()); } uint8_t VolumeChangeTracker::getVoxelAt(uint16_t uX, uint16_t uY, uint16_t uZ) { assert(uX < volumeData->getSideLength()); assert(uY < volumeData->getSideLength()); assert(uZ < volumeData->getSideLength()); VolumeIterator volIter(*volumeData); volIter.setPosition(uX,uY,uZ); return volIter.getVoxel(); } Volume* VolumeChangeTracker::getVolumeData(void) const { return volumeData; } //NOTE - Document the fact that the time stamp is incremented at the start, not the end. void VolumeChangeTracker::setVoxelAt(uint16_t x, uint16_t y, uint16_t z, uint8_t value) { ++m_iCurrentTime; //FIXME - rather than creating a iterator each time we should have one stored //VolumeIterator iterVol(*volumeData); /*iterVol.setPosition(x,y,z); iterVol.setVoxel(value);*/ volumeData->setVoxelAt(x,y,z,value); //If we are not on a boundary, just mark one region. if((x % m_uRegionSideLength != 0) && (x % m_uRegionSideLength != m_uRegionSideLength-1) && (y % m_uRegionSideLength != 0) && (y % m_uRegionSideLength != m_uRegionSideLength-1) && (z % m_uRegionSideLength != 0) && (z % m_uRegionSideLength != m_uRegionSideLength-1)) { volRegionLastModified->setVoxelAt(x >> m_uRegionSideLengthPower, y >> m_uRegionSideLengthPower, z >> m_uRegionSideLengthPower, m_iCurrentTime); } else //Mark surrounding regions as well { const uint16_t regionX = x >> m_uRegionSideLengthPower; const uint16_t regionY = y >> m_uRegionSideLengthPower; const uint16_t regionZ = z >> m_uRegionSideLengthPower; const uint16_t minRegionX = (std::max)(uint16_t(0),uint16_t(regionX-1)); const uint16_t minRegionY = (std::max)(uint16_t(0),uint16_t(regionY-1)); const uint16_t minRegionZ = (std::max)(uint16_t(0),uint16_t(regionZ-1)); const uint16_t maxRegionX = (std::min)(uint16_t(m_uVolumeSideLengthInRegions-1),uint16_t(regionX+1)); const uint16_t maxRegionY = (std::min)(uint16_t(m_uVolumeSideLengthInRegions-1),uint16_t(regionY+1)); const uint16_t maxRegionZ = (std::min)(uint16_t(m_uVolumeSideLengthInRegions-1),uint16_t(regionZ+1)); for(uint16_t zCt = minRegionZ; zCt <= maxRegionZ; zCt++) { for(uint16_t yCt = minRegionY; yCt <= maxRegionY; yCt++) { for(uint16_t xCt = minRegionX; xCt <= maxRegionX; xCt++) { volRegionLastModified->setVoxelAt(xCt,yCt,zCt,m_iCurrentTime); } } } } //++m_iCurrentTime; } void VolumeChangeTracker::setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, uint8_t value) { assert(m_bIsLocked); //FIXME - rather than creating a iterator each time we should have one stored /*VolumeIterator iterVol(*volumeData); iterVol.setPosition(x,y,z); iterVol.setVoxel(value);*/ volumeData->setVoxelAt(x,y,z,value); } void VolumeChangeTracker::lockRegion(const Region& regToLock) { if(m_bIsLocked) { throw std::logic_error("A region is already locked. Please unlock it before locking another."); } m_regLastLocked = regToLock; m_bIsLocked = true; } void VolumeChangeTracker::unlockRegion(void) { ++m_iCurrentTime; if(!m_bIsLocked) { throw std::logic_error("No region is locked. You must lock a region before you can unlock it."); } const uint16_t firstRegionX = m_regLastLocked.getLowerCorner().getX() >> m_uRegionSideLengthPower; const uint16_t firstRegionY = m_regLastLocked.getLowerCorner().getY() >> m_uRegionSideLengthPower; const uint16_t firstRegionZ = m_regLastLocked.getLowerCorner().getZ() >> m_uRegionSideLengthPower; const uint16_t lastRegionX = m_regLastLocked.getUpperCorner().getX() >> m_uRegionSideLengthPower; const uint16_t lastRegionY = m_regLastLocked.getUpperCorner().getY() >> m_uRegionSideLengthPower; const uint16_t lastRegionZ = m_regLastLocked.getUpperCorner().getZ() >> m_uRegionSideLengthPower; for(uint16_t zCt = firstRegionZ; zCt <= lastRegionZ; zCt++) { for(uint16_t yCt = firstRegionY; yCt <= lastRegionY; yCt++) { for(uint16_t xCt = firstRegionX; xCt <= lastRegionX; xCt++) { volRegionLastModified->setVoxelAt(xCt,yCt,zCt,m_iCurrentTime); } } } //++m_iCurrentTime; m_bIsLocked = false; } }