From 0f4a4c0e2ba0ea10431fa6abc739d0d540324bf4 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 12 Mar 2009 21:48:14 +0000 Subject: [PATCH] Removed setVoxel() function from BlockVolumeIterator and added setVoxelAt() function to BlockVolume.h Improved OpenGL example. --- examples/OpenGL/main.cpp | 160 ++++++++++-------- library/include/PolyVoxCore/BlockVolume.h | 3 + library/include/PolyVoxCore/BlockVolume.inl | 44 +++++ .../include/PolyVoxCore/BlockVolumeIterator.h | 3 +- .../PolyVoxCore/BlockVolumeIterator.inl | 29 ---- library/source/PolyVoxUtil/Serialization.cpp | 10 +- .../PolyVoxUtil/VolumeChangeTracker.cpp | 13 +- 7 files changed, 148 insertions(+), 114 deletions(-) diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index f5efa62b..73432ca5 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -1,5 +1,4 @@ #include "PolyVoxCore/BlockVolume.h" -#include "PolyVoxCore/BlockVolumeIterator.h" #include "PolyVoxCore/IndexedSurfacePatch.h" #include "PolyVoxCore/SurfaceExtractors.h" #include "PolyVoxCore/Utility.h" @@ -15,6 +14,7 @@ using namespace std; //Global variables are easier for demonstration purposes, especially //as I'm not sure how/if I can pass variables to the GLUT functions. +//Global variables are denoted by the 'g_' prefix const uint16 g_uVolumeSideLength = 128; const uint16 g_uRegionSideLength = 16; const uint16 g_uVolumeSideLengthInRegions = g_uVolumeSideLength / g_uRegionSideLength; @@ -27,51 +27,50 @@ IndexedSurfacePatch* g_ispRegionSurfaces[g_uVolumeSideLengthInRegions][g_uVolume void createSphereInVolume(void) { - //Create an iterator to access data in the volume - BlockVolumeIterator volIter(g_volData); + //This vector hold the position of the center of the volume + Vector3DFloat v3dVolCenter(g_volData.getSideLength() / 2, g_volData.getSideLength() / 2, g_volData.getSideLength() / 2); - //A region corresponding to the whole volume - const Region& regWholeVolume = g_volData.getEnclosingRegion(); - - //This iterator will iterate over the whole volume - volIter.setValidRegion(regWholeVolume); - - //Start at the begining - volIter.setPosition(static_cast(regWholeVolume.getLowerCorner())); - do + //This three-level for loop iterates over every voxel in the volume + for (int z = 0; z < g_volData.getSideLength(); z++) { - Vector3DFloat v3dPos(volIter.getPosX(), volIter.getPosY(), volIter.getPosZ()); - Vector3DFloat v3dVolCenter(g_uVolumeSideLength / 2, g_uVolumeSideLength / 2, g_uVolumeSideLength / 2); - - float fDistToCenter = (v3dPos - v3dVolCenter).length(); - - if(fDistToCenter <= 50.0f) + for (int y = 0; y < g_volData.getSideLength(); y++) { - volIter.setVoxel(static_cast(fDistToCenter)); - } - else - { - volIter.setVoxel(0); - } + for (int x = 0; x < g_volData.getSideLength(); x++) + { + //Store our current position as a vector... + Vector3DFloat v3dCurrentPos(x,y,z); + //And compute how far the current position is from the center of the volume + float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length(); - }while (volIter.moveForwardInRegionXYZ()); //In our case this covers the whole volume + //If the current voxel is less than 50 units from the center, + //then we make it solid, otherwise we make it empty space. + if(fDistToCenter <= 50.0f) + { + g_volData.setVoxelAt(x,y,z, static_cast(fDistToCenter)); + } + else + { + g_volData.setVoxelAt(x,y,z, 0); + } + } + } + } } void init ( GLvoid ) // Create Some Everyday Functions { - - glShadeModel(GL_SMOOTH); // Enable Smooth Shading + glShadeModel(GL_SMOOTH); // Enable Smooth Shading glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background glClearDepth(1.0f); // Depth Buffer Setup glEnable(GL_DEPTH_TEST); // Enables Depth Testing glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do - glEnable ( GL_COLOR_MATERIAL ); + glEnable ( GL_COLOR_MATERIAL ); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); } void display ( void ) // Create The Display Function { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer glLoadIdentity(); // Reset The Current Modelview Matrix glTranslatef(-g_uVolumeSideLength/2,-g_uVolumeSideLength/2,-200.0f); @@ -98,80 +97,99 @@ void display ( void ) // Create The Display Function glEnd(); - glutSwapBuffers ( ); - // Swap The Buffers To Not Be Left With A Clear Screen + glutSwapBuffers ( ); + // Swap The Buffers To Not Be Left With A Clear Screen } void reshape ( int w, int h ) // Create The Reshape Function (the viewport) { - glViewport ( 0, 0, w, h ); - glMatrixMode ( GL_PROJECTION ); // Select The Projection Matrix - glLoadIdentity ( ); // Reset The Projection Matrix - if ( h==0 ) // Calculate The Aspect Ratio Of The Window - gluPerspective ( 80, ( float ) w, 1.0, 5000.0 ); - else - gluPerspective ( 80, ( float ) w / ( float ) h, 1.0, 5000.0 ); - glMatrixMode ( GL_MODELVIEW ); // Select The Model View Matrix - glLoadIdentity ( ); // Reset The Model View Matrix + glViewport ( 0, 0, w, h ); + glMatrixMode ( GL_PROJECTION ); // Select The Projection Matrix + glLoadIdentity ( ); // Reset The Projection Matrix + if ( h==0 ) // Calculate The Aspect Ratio Of The Window + gluPerspective ( 80, ( float ) w, 1.0, 5000.0 ); + else + gluPerspective ( 80, ( float ) w / ( float ) h, 1.0, 5000.0 ); + glMatrixMode ( GL_MODELVIEW ); // Select The Model View Matrix + glLoadIdentity ( ); // Reset The Model View Matrix } void keyboard ( unsigned char key, int x, int y ) // Create Keyboard Function { - switch ( key ) { - case 27: // When Escape Is Pressed... - exit ( 0 ); // Exit The Program - break; // Ready For Next Case - default: // Now Wrap It Up - break; - } + switch ( key ) { + case 27: // When Escape Is Pressed... + exit ( 0 ); // Exit The Program + break; // Ready For Next Case + default: // Now Wrap It Up + break; + } } void arrow_keys ( int a_keys, int x, int y ) // Create Special Function (required for arrow keys) { - switch ( a_keys ) { - case GLUT_KEY_UP: // When Up Arrow Is Pressed... - glutFullScreen ( ); // Go Into Full Screen Mode - break; - case GLUT_KEY_DOWN: // When Down Arrow Is Pressed... - glutReshapeWindow ( 500, 500 ); // Go Into A 500 By 500 Window - break; - default: - break; - } + switch ( a_keys ) { + case GLUT_KEY_UP: // When Up Arrow Is Pressed... + glutFullScreen ( ); // Go Into Full Screen Mode + break; + case GLUT_KEY_DOWN: // When Down Arrow Is Pressed... + glutReshapeWindow ( 500, 500 ); // Go Into A 500 By 500 Window + break; + default: + break; + } } void main ( int argc, char** argv ) // Create Main Function For Bringing It All Together { + //Make our volume contain a sphere in the center. createSphereInVolume(); + //Our volume is broken down into cuboid regions, and we create one mesh for each region. + //This three-level for loop iterates over each region. for(uint16 uRegionZ = 0; uRegionZ < g_uVolumeSideLengthInRegions; ++uRegionZ) { for(uint16 uRegionY = 0; uRegionY < g_uVolumeSideLengthInRegions; ++uRegionY) { for(uint16 uRegionX = 0; uRegionX < g_uVolumeSideLengthInRegions; ++uRegionX) { + //Create a new surface patch (which is basiaclly the PolyVox term for a mesh). g_ispRegionSurfaces[uRegionX][uRegionY][uRegionZ] = new IndexedSurfacePatch(); IndexedSurfacePatch* ispCurrent = g_ispRegionSurfaces[uRegionX][uRegionY][uRegionZ]; - Vector3DInt32 regLowerCorner(uRegionX * g_uRegionSideLength, uRegionY * g_uRegionSideLength, uRegionZ * g_uRegionSideLength); - Vector3DInt32 regUpperCorner((uRegionX + 1) * g_uRegionSideLength, (uRegionY + 1) * g_uRegionSideLength, (uRegionZ + 1) * g_uRegionSideLength); + + //Compute the extents of the current region + //FIXME - This is a little coplex? PolyVox could + //provide more functions for dealing with regions? + uint16 regionStartX = uRegionX * g_uRegionSideLength; + uint16 regionStartY = uRegionY * g_uRegionSideLength; + uint16 regionStartZ = uRegionZ * g_uRegionSideLength; + + uint16 regionEndX = regionStartX + g_uRegionSideLength; + uint16 regionEndY = regionStartY + g_uRegionSideLength; + uint16 regionEndZ = regionStartZ + g_uRegionSideLength; + + Vector3DInt32 regLowerCorner(regionStartX, regionStartY, regionStartZ); + Vector3DInt32 regUpperCorner(regionEndX, regionEndY, regionEndZ); + + //Extract the surface for this region extractReferenceSurface(&g_volData, Region(regLowerCorner, regUpperCorner), ispCurrent); } } } - glutInit ( &argc, argv ); // Erm Just Write It =) - init (); - glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE ); // Display Mode - glutInitWindowSize ( 500, 500 ); // If glutFullScreen wasn't called this is the window size - glutCreateWindow ( "PolyVox OpenGL Example" ); // Window Title (argv[0] for current directory as title) - //glutFullScreen ( ); // Put Into Full Screen - glutDisplayFunc ( display ); // Matching Earlier Functions To Their Counterparts - glutReshapeFunc ( reshape ); - glutKeyboardFunc ( keyboard ); - glutSpecialFunc ( arrow_keys ); - glutMainLoop ( ); // Initialize The Main Loop + glutInit ( &argc, argv ); // Erm Just Write It =) + init (); + glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE ); // Display Mode + glutInitWindowSize ( 500, 500 ); // If glutFullScreen wasn't called this is the window size + glutCreateWindow ( "PolyVox OpenGL Example" ); // Window Title (argv[0] for current directory as title) + //glutFullScreen ( ); // Put Into Full Screen + glutDisplayFunc ( display ); // Matching Earlier Functions To Their Counterparts + glutReshapeFunc ( reshape ); + glutKeyboardFunc ( keyboard ); + glutSpecialFunc ( arrow_keys ); + glutMainLoop ( ); // Initialize The Main Loop - for(uint16 uRegionZ = 0; uRegionZ < g_uVolumeSideLengthInRegions; ++uRegionZ) + //Delete all the surface patches we created. + for(uint16 uRegionZ = 0; uRegionZ < g_uVolumeSideLengthInRegions; ++uRegionZ) { for(uint16 uRegionY = 0; uRegionY < g_uVolumeSideLengthInRegions; ++uRegionY) { diff --git a/library/include/PolyVoxCore/BlockVolume.h b/library/include/PolyVoxCore/BlockVolume.h index 3d599920..fa6412a0 100644 --- a/library/include/PolyVoxCore/BlockVolume.h +++ b/library/include/PolyVoxCore/BlockVolume.h @@ -50,6 +50,9 @@ namespace PolyVox VoxelType getVoxelAt(uint16 uXPos, uint16 uYPos, uint16 uZPos) const; VoxelType getVoxelAt(const Vector3DUint16& v3dPos) const; + void setVoxelAt(uint16 uXPos, uint16 uYPos, uint16 uZPos, VoxelType tValue); + void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); + bool containsPoint(const Vector3DFloat& pos, float boundary) const; bool containsPoint(const Vector3DInt32& pos, uint16 boundary) const; BlockVolumeIterator firstVoxel(void); diff --git a/library/include/PolyVoxCore/BlockVolume.inl b/library/include/PolyVoxCore/BlockVolume.inl index f075e5a1..7512b831 100644 --- a/library/include/PolyVoxCore/BlockVolume.inl +++ b/library/include/PolyVoxCore/BlockVolume.inl @@ -169,6 +169,50 @@ namespace PolyVox } #pragma endregion + #pragma region Setters + template + void BlockVolume::setVoxelAt(uint16 uXPos, uint16 uYPos, uint16 uZPos, VoxelType tValue) + { + const uint16 blockX = uXPos >> m_uBlockSideLengthPower; + const uint16 blockY = uYPos >> m_uBlockSideLengthPower; + const uint16 blockZ = uZPos >> m_uBlockSideLengthPower; + + const uint16 xOffset = uXPos - (blockX << m_uBlockSideLengthPower); + const uint16 yOffset = uYPos - (blockY << m_uBlockSideLengthPower); + const uint16 zOffset = uZPos - (blockZ << m_uBlockSideLengthPower); + + const uint32 uBlockIndex = + blockX + + blockY * m_uSideLengthInBlocks + + blockZ * m_uSideLengthInBlocks * m_uSideLengthInBlocks; + + const bool bIsShared = m_pIsShared[uBlockIndex]; + const VoxelType tHomogenousValue = m_pHomogenousValue[uBlockIndex]; + if(bIsShared) + { + if(tHomogenousValue != tValue) + { + m_pBlocks[uBlockIndex] = new Block(m_uBlockSideLengthPower); + m_pIsShared[uBlockIndex] = false; + m_pBlocks[uBlockIndex]->fill(tHomogenousValue); + m_pBlocks[uBlockIndex]->setVoxelAt(xOffset,yOffset,zOffset, tValue); + } + } + else + { + //There is a chance that setting this voxel makes the block homogenous and therefore shareable. + m_pIsPotentiallySharable[uBlockIndex] = true; + m_pBlocks[uBlockIndex]->setVoxelAt(xOffset,yOffset,zOffset, tValue); + } + } + + template + void BlockVolume::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue) + { + setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); + } + #pragma endregion + #pragma region Other template bool BlockVolume::containsPoint(const Vector3DFloat& pos, float boundary) const diff --git a/library/include/PolyVoxCore/BlockVolumeIterator.h b/library/include/PolyVoxCore/BlockVolumeIterator.h index 939ded5e..d3643bcc 100644 --- a/library/include/PolyVoxCore/BlockVolumeIterator.h +++ b/library/include/PolyVoxCore/BlockVolumeIterator.h @@ -53,8 +53,7 @@ namespace PolyVox void setPosition(const Vector3DInt16& v3dNewPos); void setPosition(uint16 xPos, uint16 yPos, uint16 zPos); void setValidRegion(const Region& region); - void setValidRegion(uint16 xFirst, uint16 yFirst, uint16 zFirst, uint16 xLast, uint16 yLast, uint16 zLast); - void setVoxel(VoxelType tValue); + void setValidRegion(uint16 xFirst, uint16 yFirst, uint16 zFirst, uint16 xLast, uint16 yLast, uint16 zLast); bool isValidForRegion(void) const; void moveForwardInRegionFast(void); diff --git a/library/include/PolyVoxCore/BlockVolumeIterator.inl b/library/include/PolyVoxCore/BlockVolumeIterator.inl index f08750ab..61446636 100644 --- a/library/include/PolyVoxCore/BlockVolumeIterator.inl +++ b/library/include/PolyVoxCore/BlockVolumeIterator.inl @@ -235,35 +235,6 @@ namespace PolyVox mYRegionLastBlock = mYRegionLast >> mVolume.m_uBlockSideLengthPower; mZRegionLastBlock = mZRegionLast >> mVolume.m_uBlockSideLengthPower; } - - template - void BlockVolumeIterator::setVoxel(VoxelType tValue) - { - const uint32 uBlockIndex = - mXBlock + - mYBlock * mVolume.m_uSideLengthInBlocks + - mZBlock * mVolume.m_uSideLengthInBlocks * mVolume.m_uSideLengthInBlocks; - - const bool bIsShared = mVolume.m_pIsShared[uBlockIndex]; - const VoxelType tHomogenousValue = mVolume.m_pHomogenousValue[uBlockIndex]; - if(bIsShared) - { - if(tHomogenousValue != tValue) - { - mVolume.m_pBlocks[uBlockIndex] = new Block(mVolume.m_uBlockSideLengthPower); - mVolume.m_pIsShared[uBlockIndex] = false; - mVolume.m_pBlocks[uBlockIndex]->fill(tHomogenousValue); - mCurrentVoxel = mVolume.m_pBlocks[uBlockIndex]->m_tData + mVoxelIndexInBlock; - *mCurrentVoxel = tValue; - } - } - else - { - //There is a chance that setting this voxel makes the block homogenous and therefore shareable. - mVolume.m_pIsPotentiallySharable[uBlockIndex] = true; - *mCurrentVoxel = tValue; - } - } #pragma endregion #pragma region Other diff --git a/library/source/PolyVoxUtil/Serialization.cpp b/library/source/PolyVoxUtil/Serialization.cpp index 68a2e51b..c2bbf6c2 100644 --- a/library/source/PolyVoxUtil/Serialization.cpp +++ b/library/source/PolyVoxUtil/Serialization.cpp @@ -28,7 +28,6 @@ namespace PolyVox uint16 volumeDepth = 0x0001 << volumeDepthPower; //Read data - BlockVolumeIterator volIter(*volume); for(uint16 z = 0; z < volumeDepth; ++z) { for(uint16 y = 0; y < volumeHeight; ++y) @@ -38,8 +37,7 @@ namespace PolyVox uint8 value = 0; stream.read(reinterpret_cast(&value), sizeof(value)); - volIter.setPosition(x,y,z); - volIter.setVoxel(value); + volume->setVoxelAt(x,y,z,value); } } } @@ -98,7 +96,6 @@ namespace PolyVox uint16 volumeDepth = 0x0001 << volumeDepthPower; //Read data - BlockVolumeIterator volIter(*volume); bool firstTime = true; uint32 runLength = 0; uint8 value = 0; @@ -110,10 +107,9 @@ namespace PolyVox { for(uint16 x = 0; x < volumeWidth; ++x) { - volIter.setPosition(x,y,z); if(runLength != 0) { - volIter.setVoxel(value); + volume->setVoxelAt(x,y,z,value); runLength--; } else @@ -121,7 +117,7 @@ namespace PolyVox stream.read(reinterpret_cast(&value), sizeof(value)); stream.read(reinterpret_cast(&runLength), sizeof(runLength)); - volIter.setVoxel(value); + volume->setVoxelAt(x,y,z,value); runLength--; } } diff --git a/library/source/PolyVoxUtil/VolumeChangeTracker.cpp b/library/source/PolyVoxUtil/VolumeChangeTracker.cpp index 6bb699d1..a6625146 100644 --- a/library/source/PolyVoxUtil/VolumeChangeTracker.cpp +++ b/library/source/PolyVoxUtil/VolumeChangeTracker.cpp @@ -117,9 +117,11 @@ namespace PolyVox { ++m_iCurrentTime; //FIXME - rather than creating a iterator each time we should have one stored - BlockVolumeIterator iterVol(*volumeData); - iterVol.setPosition(x,y,z); - iterVol.setVoxel(value); + //BlockVolumeIterator 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 % POLYVOX_REGION_SIDE_LENGTH != 0) && @@ -164,9 +166,10 @@ namespace PolyVox assert(m_bIsLocked); //FIXME - rather than creating a iterator each time we should have one stored - BlockVolumeIterator iterVol(*volumeData); + /*BlockVolumeIterator iterVol(*volumeData); iterVol.setPosition(x,y,z); - iterVol.setVoxel(value); + iterVol.setVoxel(value);*/ + volumeData->setVoxelAt(x,y,z,value); } void VolumeChangeTracker::lockRegion(const Region& regToLock)