diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a4a8d6c01..9af86e2891 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,4 +10,5 @@ add_subdirectory(interface) add_subdirectory(injector) add_subdirectory(pairing-server) add_subdirectory(space-server) -add_subdirectory(voxel-server) \ No newline at end of file +add_subdirectory(voxel-server) +add_subdirectory(voxel-edit) \ No newline at end of file diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 675d4ce1c0..3cf38f1527 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -1556,6 +1556,15 @@ void Avatar::readAvatarDataFromFile() { FILE* avatarFile = fopen(AVATAR_DATA_FILENAME, "r"); if (avatarFile) { - fscanf(avatarFile, "%f,%f,%f %f", &_position.x, &_position.y, &_position.z, &_bodyYaw); + glm::vec3 readPosition; + float readYaw; + fscanf(avatarFile, "%f,%f,%f %f", &readPosition.x, &readPosition.y, &readPosition.z, &readYaw); + + // make sure these values are sane + if (!isnan(readPosition.x) && !isnan(readPosition.y) && !isnan(readPosition.z) && !isnan(readYaw)) { + _position = readPosition; + _bodyYaw = readYaw; + } + fclose(avatarFile); } } diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index 74195a8761..1a417c6fb1 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -6,6 +6,7 @@ //--------------------------------------------------------------------- #include +#include // #include "Log.h" #include "Camera.h" @@ -16,7 +17,7 @@ Camera::Camera() { _tightness = 10.0; // default _fieldOfView = 60.0; // default _nearClip = 0.08; // default - _farClip = 50.0; // default + _farClip = 50.0 * TREE_SCALE; // default _modeShift = 0.0; _yaw = 0.0; _pitch = 0.0; diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 8669ec7130..16bab45e4f 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -12,6 +12,8 @@ #ifndef __hifi_VoxelConstants_h__ #define __hifi_VoxelConstants_h__ +#include + const int MAX_VOXEL_PACKET_SIZE = 1492; const int MAX_TREE_SLICE_BYTES = 26; const int TREE_SCALE = 10; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 23027de420..7352991839 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -69,7 +69,7 @@ void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperati } } -VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode) { +VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode) const { // find the appropriate branch index based on this ancestorNode if (*needleCode > 0) { int branchForNeedle = branchIndexWithDescendant(ancestorNode->octalCode, needleCode); @@ -157,16 +157,6 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, bytesRead += 3; } } - // average node's color based on color of children - bool nodeWasDirty = destinationNode->isDirty(); - destinationNode->setColorFromAverageOfChildren(); - bool nodeIsDirty = destinationNode->isDirty(); - if (nodeIsDirty) { - _isDirty = true; - } - if (!nodeWasDirty && nodeIsDirty) { - _nodesChangedFromBitstream++; - } // give this destination node the child mask from the packet unsigned char childMask = *(nodeData + bytesRead); @@ -205,7 +195,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, return bytesRead; } -void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes) { +void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes) { int bytesRead = 0; unsigned char* bitstreamAt = bitstream; @@ -245,6 +235,13 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt this->voxelsBytesReadStats.updateAverage(bufferSizeBytes); } +void VoxelTree::deleteVoxelAt(float x, float y, float z, float s) { + unsigned char* octalCode = pointToVoxel(x,y,z,s,0,0,0); + deleteVoxelCodeFromTree(octalCode); + delete octalCode; // cleanup memory +} + + // Note: uses the codeColorBuffer format, but the color's are ignored, because // this only finds and deletes the node from the tree. void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) { @@ -255,20 +252,14 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) { int lengthInBytes = bytesRequiredForCodeLength(*codeBuffer); // includes octet count, not color! if (0 == memcmp(nodeToDelete->octalCode,codeBuffer,lengthInBytes)) { - - float* vertices = firstVertexForCode(nodeToDelete->octalCode); - delete[] vertices; - if (parentNode) { - float* vertices = firstVertexForCode(parentNode->octalCode); - delete[] vertices; - int childIndex = branchIndexWithDescendant(parentNode->octalCode, codeBuffer); delete parentNode->children[childIndex]; // delete the child nodes parentNode->children[childIndex] = NULL; // set it to NULL reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode + _isDirty = true; } } } @@ -279,6 +270,7 @@ void VoxelTree::eraseAllVoxels() { rootNode = new VoxelNode(); rootNode->octalCode = new unsigned char[1]; *rootNode->octalCode = 0; + _isDirty = true; } void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { @@ -287,6 +279,7 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { // create the node if it does not exist if (*lastCreatedNode->octalCode != *codeColorBuffer) { lastCreatedNode = createMissingNode(lastCreatedNode, codeColorBuffer); + _isDirty = true; } // give this node its color @@ -296,6 +289,9 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { memcpy(newColor, codeColorBuffer + octalCodeBytes, 3); newColor[3] = 1; lastCreatedNode->setColor(newColor); + if (lastCreatedNode->isDirty()) { + _isDirty = true; + } } void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes) { @@ -438,6 +434,16 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { } } +VoxelNode* VoxelTree::getVoxelAt(float x, float y, float z, float s) const { + unsigned char* octalCode = pointToVoxel(x,y,z,s,0,0,0); + VoxelNode* node = nodeForOctalCode(rootNode, octalCode, NULL); + if (*node->octalCode != *octalCode) { + node = NULL; + } + delete octalCode; // cleanup memory + return node; +} + void VoxelTree::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue) { unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue); this->readCodeColorBufferToTree(voxelData); @@ -664,15 +670,14 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe return maxChildLevel; } -int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag) { +int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, + VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const { // How many bytes have we written so far at this level; int bytesWritten = 0; // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! - if (!node->isInView(viewFrustum)) { + if (viewFrustum && !node->isInView(*viewFrustum)) { return bytesWritten; } @@ -686,8 +691,7 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const Vi int currentEncodeLevel = 0; int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel, - node, viewFrustum, - outputBuffer, availableBytes, bag); + node, outputBuffer, availableBytes, bag, viewFrustum); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); @@ -709,9 +713,8 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const Vi } int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, - VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag) const { + VoxelNode* node, unsigned char* outputBuffer, int availableBytes, + VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -723,21 +726,24 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco return bytesAtThisLevel; } - float distance = node->distanceToCamera(viewFrustum); - float boundaryDistance = boundaryDistanceForRenderLevel(*node->octalCode + 1); + // caller can pass NULL as viewFrustum if they want everything + if (viewFrustum) { + float distance = node->distanceToCamera(*viewFrustum); + float boundaryDistance = boundaryDistanceForRenderLevel(*node->octalCode + 1); - // If we're too far away for our render level, then just return - if (distance >= boundaryDistance) { - return bytesAtThisLevel; - } + // If we're too far away for our render level, then just return + if (distance >= boundaryDistance) { + return bytesAtThisLevel; + } - // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! - // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if - // we're out of view - if (!node->isInView(viewFrustum)) { - return bytesAtThisLevel; + // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! + // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if + // we're out of view + if (!node->isInView(*viewFrustum)) { + return bytesAtThisLevel; + } } - + bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! // At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level @@ -765,11 +771,11 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco for (int i = 0; i < MAX_CHILDREN; i++) { VoxelNode* childNode = node->children[i]; bool childExists = (childNode != NULL); - bool childIsInView = (childExists && childNode->isInView(viewFrustum)); + bool childIsInView = (childExists && (!viewFrustum || childNode->isInView(*viewFrustum))); if (childIsInView) { // Before we determine consider this further, let's see if it's in our LOD scope... - float distance = childNode->distanceToCamera(viewFrustum); - float boundaryDistance = boundaryDistanceForRenderLevel(*childNode->octalCode + 1); + float distance = viewFrustum ? childNode->distanceToCamera(*viewFrustum) : 0; + float boundaryDistance = viewFrustum ? boundaryDistanceForRenderLevel(*childNode->octalCode + 1) : 1; if (distance < boundaryDistance) { inViewCount++; @@ -842,7 +848,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco int thisLevel = currentEncodeLevel; int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode, - viewFrustum, outputBuffer, availableBytes, bag); + outputBuffer, availableBytes, bag, viewFrustum); // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. @@ -882,3 +888,46 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco } // end keepDiggingDeeper return bytesAtThisLevel; } + +bool VoxelTree::readFromFileV2(const char* fileName) { + std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate); + if(file.is_open()) { + printLog("loading file...\n"); + + // get file length.... + unsigned long fileLength = file.tellg(); + file.seekg( 0, std::ios::beg ); + + // read the entire file into a buffer, WHAT!? Why not. + unsigned char* entireFile = new unsigned char[fileLength]; + file.read((char*)entireFile, fileLength); + readBitstreamToTree(entireFile, fileLength); + delete[] entireFile; + + file.close(); + return true; + } + return false; +} + +void VoxelTree::writeToFileV2(const char* fileName) const { + + std::ofstream file(fileName, std::ios::out|std::ios::binary); + + if(file.is_open()) { + VoxelNodeBag nodeBag; + nodeBag.insert(rootNode); + + static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static + int bytesWritten = 0; + + while (!nodeBag.isEmpty()) { + VoxelNode* subTree = nodeBag.extract(); + bytesWritten = encodeTreeBitstream(INT_MAX, subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, NULL); + + file.write((const char*)&outputBuffer[0], bytesWritten); + } + } + file.close(); +} + diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 221a04138b..1f2ec44e48 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -39,22 +39,22 @@ public: void eraseAllVoxels(); void processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes); - void readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes); + void readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes); void readCodeColorBufferToTree(unsigned char *codeColorBuffer); void deleteVoxelCodeFromTree(unsigned char *codeBuffer); void printTreeForDebugging(VoxelNode *startNode); void reaverageVoxelColors(VoxelNode *startNode); - void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); - void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); - void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue); + void deleteVoxelAt(float x, float y, float z, float s); + VoxelNode* getVoxelAt(float x, float y, float z, float s) const; + void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue); void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color); + void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); - int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag); + int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, + VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const; int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); @@ -63,18 +63,24 @@ public: unsigned long int getNodesChangedFromBitstream() const { return _nodesChangedFromBitstream; }; bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, VoxelNode*& node, float& distance); + + // Note: this assumes the fileFormat is the HIO individual voxels code files + void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); + + // these will read/write files that match the wireformat, excluding the 'V' leading + void writeToFileV2(const char* filename) const; + bool readFromFileV2(const char* filename); private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, - VoxelNode* node, const ViewFrustum& viewFrustum, - unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag) const; + VoxelNode* node, unsigned char* outputBuffer, int availableBytes, + VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const; int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); - VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode); + VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes); diff --git a/voxel-edit/CMakeLists.txt b/voxel-edit/CMakeLists.txt new file mode 100644 index 0000000000..f7acb26e92 --- /dev/null +++ b/voxel-edit/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 2.8) + +set(TARGET_NAME voxel-edit) + +set(ROOT_DIR ..) +set(MACRO_DIR ${ROOT_DIR}/cmake/macros) + +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") + +# set up the external glm library +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + +include(${MACRO_DIR}/SetupHifiProject.cmake) + +setup_hifi_project(${TARGET_NAME}) + +# link in the shared library +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) + +# link in the hifi voxels library +link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) + + diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp new file mode 100644 index 0000000000..7592de00f4 --- /dev/null +++ b/voxel-edit/src/main.cpp @@ -0,0 +1,135 @@ +// +// main.cpp +// Voxel Edit +// +// Created by Brad Hefta-Gaub on 05/03/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include +#include + +VoxelTree myTree; + +int _nodeCount=0; +bool countVoxelsOperation(VoxelNode* node, void* extraData) { + if (node->isColored()){ + _nodeCount++; + } + return true; // keep going +} + +void addScene(VoxelTree * tree) { + printf("adding scene...\n"); + + float voxelSize = 1.f/32; + + // Here's an example of how to create a voxel. + printf("creating corner points...\n"); + tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255); + + // Here's an example of how to test if a voxel exists + VoxelNode* node = tree->getVoxelAt(0, 0, 0, voxelSize); + if (node) { + // and how to access it's color + printf("corner point 0,0,0 exists... color is (%d,%d,%d) \n", + node->getColor()[0], node->getColor()[1], node->getColor()[2]); + } + + // here's an example of how to delete a voxel + printf("attempting to delete corner point 0,0,0\n"); + tree->deleteVoxelAt(0, 0, 0, voxelSize); + + // Test to see that the delete worked... it should be FALSE... + if (tree->getVoxelAt(0, 0, 0, voxelSize)) { + printf("corner point 0,0,0 exists...\n"); + } else { + printf("corner point 0,0,0 does not exists...\n"); + } + + // Now some more examples... a little more complex + printf("creating corner points...\n"); + tree->createVoxel(0 , 0 , 0 , voxelSize, 255, 255 ,255); + + + tree->createVoxel(1.0 - voxelSize, 0 , 0 , voxelSize, 255, 0 ,0 ); + tree->createVoxel(0 , 1.0 - voxelSize, 0 , voxelSize, 0 , 255 ,0 ); + tree->createVoxel(0 , 0 , 1.0 - voxelSize, voxelSize, 0 , 0 ,255); + tree->createVoxel(1.0 - voxelSize, 0 , 1.0 - voxelSize, voxelSize, 255, 0 ,255); + tree->createVoxel(0 , 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 0 , 255 ,255); + tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 0 , voxelSize, 255, 255 ,0 ); + tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 255, 255 ,255); + printf("DONE creating corner points...\n"); + + // Now some more examples... creating some lines using the line primitive + printf("creating voxel lines...\n"); + float lineVoxelSize = 0.99f/256; + rgbColor red = {255,0,0}; + rgbColor green = {0,255,0}; + rgbColor blue = {0,0,255}; + tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), lineVoxelSize, blue); + tree->createLine(glm::vec3(0, 0, 0), glm::vec3(1, 0, 0), lineVoxelSize, red); + tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 1, 0), lineVoxelSize, green); + printf("DONE creating lines...\n"); + + // Now some more examples... creating some spheres using the sphere primitive + int sphereBaseSize = 512; + printf("creating spheres...\n"); + tree->createSphere(0.25, 0.5, 0.5, 0.5, (1.0 / sphereBaseSize), true, false); + printf("one sphere added...\n"); + tree->createSphere(0.030625, 0.5, 0.5, (0.25-0.06125), (1.0 / (sphereBaseSize * 2)), true, true); + + + printf("two spheres added...\n"); + tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), (0.75 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true); + printf("three spheres added...\n"); + tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), 0.06125, (1.0 / (sphereBaseSize * 2)), true, true); + printf("four spheres added...\n"); + tree->createSphere(0.030625, (0.75 - 0.030625), 0.06125, (0.75 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true); + printf("five spheres added...\n"); + tree->createSphere(0.06125, 0.125, 0.125, (0.75 - 0.125), (1.0 / (sphereBaseSize * 2)), true, true); + + float radius = 0.0125f; + printf("6 spheres added...\n"); + tree->createSphere(radius, 0.25, radius * 5.0f, 0.25, (1.0 / 4096), true, true); + printf("7 spheres added...\n"); + tree->createSphere(radius, 0.125, radius * 5.0f, 0.25, (1.0 / 4096), true, true); + printf("8 spheres added...\n"); + tree->createSphere(radius, 0.075, radius * 5.0f, 0.25, (1.0 / 4096), true, true); + printf("9 spheres added...\n"); + tree->createSphere(radius, 0.05, radius * 5.0f, 0.25, (1.0 / 4096), true, true); + printf("10 spheres added...\n"); + tree->createSphere(radius, 0.025, radius * 5.0f, 0.25, (1.0 / 4096), true, true); + printf("11 spheres added...\n"); + printf("DONE creating spheres...\n"); + + // Here's an example of how to recurse the tree and do some operation on the nodes as you recurse them. + // This one is really simple, it just couts them... + // Look at the function countVoxelsOperation() for an example of how you could use this function + _nodeCount=0; + tree->recurseTreeWithOperation(countVoxelsOperation); + printf("Nodes after adding scene %d nodes\n", _nodeCount); + + printf("DONE adding scene of spheres...\n"); +} + + +int main(int argc, const char * argv[]) +{ + const char* SAY_HELLO = "--sayHello"; + if (cmdOptionExists(argc, argv, SAY_HELLO)) { + printf("I'm just saying hello...\n"); + } + + const char* DONT_CREATE_FILE = "--dontCreateSceneFile"; + bool dontCreateFile = cmdOptionExists(argc, argv, DONT_CREATE_FILE); + + if (dontCreateFile) { + printf("You asked us not to create a scene file, so we will not.\n"); + } else { + printf("Creating Scene File...\n"); + addScene(&myTree); + myTree.writeToFileV2("voxels.hio2"); + } + return 0; +} \ No newline at end of file diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 17c4915988..eec5bb308a 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -43,6 +43,7 @@ int PACKETS_PER_CLIENT_PER_INTERVAL = 20; const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; VoxelTree randomTree; +bool wantVoxelPersist = true; bool wantColorRandomizer = false; bool debugVoxelSending = false; @@ -83,8 +84,6 @@ void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { tree->createVoxel(1.0 - voxelSize, 0 , 0 , voxelSize, 255, 0 ,0 ); tree->createVoxel(0 , 1.0 - voxelSize, 0 , voxelSize, 0 , 255 ,0 ); tree->createVoxel(0 , 0 , 1.0 - voxelSize, voxelSize, 0 , 0 ,255); - - tree->createVoxel(1.0 - voxelSize, 0 , 1.0 - voxelSize, voxelSize, 255, 0 ,255); tree->createVoxel(0 , 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 0 , 255 ,255); tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 0 , voxelSize, 255, 255 ,0 ); @@ -245,9 +244,9 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL) { if (!agentData->nodeBag.isEmpty()) { VoxelNode* subTree = agentData->nodeBag.extract(); - bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, viewFrustum, + bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, - agentData->nodeBag); + agentData->nodeBag, &viewFrustum); if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); @@ -299,6 +298,16 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge } } +void persistVoxelsWhenDirty() { + // check the dirty bit and persist here... + if (::wantVoxelPersist && ::randomTree.isDirty()) { + printf("saving voxels to file...\n"); + randomTree.writeToFileV2("voxels.hio2"); + randomTree.clearDirtyBit(); // tree is clean after saving + printf("DONE saving voxels to file...\n"); + } +} + void *distributeVoxelsToListeners(void *args) { AgentList* agentList = AgentList::getInstance(); @@ -349,7 +358,6 @@ void attachVoxelAgentDataToAgent(Agent *newAgent) { } } - int main(int argc, const char * argv[]) { AgentList* agentList = AgentList::createInstance(AGENT_TYPE_VOXEL, VOXEL_LISTEN_PORT); @@ -359,9 +367,9 @@ int main(int argc, const char * argv[]) const char* local = "--local"; bool wantLocalDomain = cmdOptionExists(argc, argv,local); if (wantLocalDomain) { - printf("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); + printf("Local Domain MODE!\n"); + int ip = getLocalAddress(); + sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); } agentList->linkedDataCreateCallback = &attachVoxelAgentDataToAgent; @@ -370,56 +378,87 @@ int main(int argc, const char * argv[]) srand((unsigned)time(0)); - const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending"; + const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending"; ::debugVoxelSending = cmdOptionExists(argc, argv, DEBUG_VOXEL_SENDING); - printf("debugVoxelSending=%s\n", (::debugVoxelSending ? "yes" : "no")); - - const char* WANT_COLOR_RANDOMIZER = "--wantColorRandomizer"; + printf("debugVoxelSending=%s\n", (::debugVoxelSending ? "yes" : "no")); + + const char* WANT_COLOR_RANDOMIZER = "--wantColorRandomizer"; ::wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER); - printf("wantColorRandomizer=%s\n", (::wantColorRandomizer ? "yes" : "no")); + printf("wantColorRandomizer=%s\n", (::wantColorRandomizer ? "yes" : "no")); - // Check to see if the user passed in a command line option for loading a local - // Voxel File. If so, load it now. - const char* INPUT_FILE = "-i"; - const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE); - if (voxelsFilename) { - randomTree.loadVoxelsFile(voxelsFilename,wantColorRandomizer); - } + // By default we will voxel persist, if you want to disable this, then pass in this parameter + const char* NO_VOXEL_PERSIST = "--NoVoxelPersist"; + if (cmdOptionExists(argc, argv, NO_VOXEL_PERSIST)) { + ::wantVoxelPersist = false; + } + printf("wantVoxelPersist=%s\n", (::wantVoxelPersist ? "yes" : "no")); - // Check to see if the user passed in a command line option for setting packet send rate - const char* PACKETS_PER_SECOND = "--packetsPerSecond"; - const char* packetsPerSecond = getCmdOption(argc, argv, PACKETS_PER_SECOND); - if (packetsPerSecond) { - PACKETS_PER_CLIENT_PER_INTERVAL = atoi(packetsPerSecond)/10; - if (PACKETS_PER_CLIENT_PER_INTERVAL < 1) { - PACKETS_PER_CLIENT_PER_INTERVAL = 1; - } - printf("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, PACKETS_PER_CLIENT_PER_INTERVAL); - } - - const char* ADD_RANDOM_VOXELS = "--AddRandomVoxels"; - if (cmdOptionExists(argc, argv, ADD_RANDOM_VOXELS)) { - // create an octal code buffer and load it with 0 so that the recursive tree fill can give - // octal codes to the tree nodes that it is creating - randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, randomTree.rootNode); - } - - const char* ADD_SPHERE = "--AddSphere"; - const char* ADD_RANDOM_SPHERE = "--AddRandomSphere"; - if (cmdOptionExists(argc, argv, ADD_SPHERE)) { - addSphere(&randomTree,false,wantColorRandomizer); - } else if (cmdOptionExists(argc, argv, ADD_RANDOM_SPHERE)) { - addSphere(&randomTree,true,wantColorRandomizer); + // if we want Voxel Persistance, load the local file now... + bool persistantFileRead = false; + if (::wantVoxelPersist) { + printf("loading voxels from file...\n"); + persistantFileRead = ::randomTree.readFromFileV2("voxels.hio2"); + ::randomTree.clearDirtyBit(); // the tree is clean since we just loaded it + printf("DONE loading voxels from file...\n"); + _nodeCount=0; + ::randomTree.recurseTreeWithOperation(countVoxelsOperation); + printf("Nodes after loading scene %d nodes\n", _nodeCount); } - const char* NO_ADD_SCENE = "--NoAddScene"; - if (!cmdOptionExists(argc, argv, NO_ADD_SCENE)) { - addSphereScene(&randomTree,wantColorRandomizer); + // Check to see if the user passed in a command line option for loading an old style local + // Voxel File. If so, load it now. This is not the same as a voxel persist file + const char* INPUT_FILE = "-i"; + const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE); + if (voxelsFilename) { + randomTree.loadVoxelsFile(voxelsFilename,wantColorRandomizer); + } + + // Check to see if the user passed in a command line option for setting packet send rate + const char* PACKETS_PER_SECOND = "--packetsPerSecond"; + const char* packetsPerSecond = getCmdOption(argc, argv, PACKETS_PER_SECOND); + if (packetsPerSecond) { + PACKETS_PER_CLIENT_PER_INTERVAL = atoi(packetsPerSecond)/10; + if (PACKETS_PER_CLIENT_PER_INTERVAL < 1) { + PACKETS_PER_CLIENT_PER_INTERVAL = 1; + } + printf("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, PACKETS_PER_CLIENT_PER_INTERVAL); + } + + const char* ADD_RANDOM_VOXELS = "--AddRandomVoxels"; + if (cmdOptionExists(argc, argv, ADD_RANDOM_VOXELS)) { + // create an octal code buffer and load it with 0 so that the recursive tree fill can give + // octal codes to the tree nodes that it is creating + randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, randomTree.rootNode); + } + + const char* ADD_SPHERE = "--AddSphere"; + const char* ADD_RANDOM_SPHERE = "--AddRandomSphere"; + if (cmdOptionExists(argc, argv, ADD_SPHERE)) { + addSphere(&randomTree,false,wantColorRandomizer); + } else if (cmdOptionExists(argc, argv, ADD_RANDOM_SPHERE)) { + addSphere(&randomTree,true,wantColorRandomizer); + } + + const char* ADD_SCENE = "--AddScene"; + bool addScene = cmdOptionExists(argc, argv, ADD_SCENE); + const char* NO_ADD_SCENE = "--NoAddScene"; + bool noAddScene = cmdOptionExists(argc, argv, NO_ADD_SCENE); + if (addScene && noAddScene) { + printf("WARNING! --AddScene and --NoAddScene are mutually exclusive. We will honor --NoAddScene\n"); + } + + // We will add a scene if... + // 1) we attempted to load a persistant file and it wasn't there + // 2) you asked us to add a scene + // HOWEVER -- we will NEVER add a scene if you explicitly tell us not to! + bool actuallyAddScene = !noAddScene && (addScene || (::wantVoxelPersist && !persistantFileRead)); + if (actuallyAddScene) { + addSphereScene(&randomTree,wantColorRandomizer); } pthread_t sendVoxelThread; pthread_create(&sendVoxelThread, NULL, distributeVoxelsToListeners, NULL); - + sockaddr agentPublicAddress; unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE]; @@ -427,6 +466,9 @@ int main(int argc, const char * argv[]) // loop to send to agents requesting data while (true) { + // check to see if we need to persist our voxel state + persistVoxelsWhenDirty(); + if (agentList->getAgentSocket().receive(&agentPublicAddress, packetData, &receivedBytes)) { // XXXBHG: Hacked in support for 'S' SET command if (packetData[0] == PACKET_HEADER_SET_VOXEL) {