Waterflow
Visualize water in terrain
src/voxel.cpp
00001 #include "voxel.h"
00002 #include "GL_utilities.h"
00003 
00004 #include <iostream>
00005 #include "gtc/type_ptr.hpp"
00006 #include "GL_utilities.h"
00007 #include "glm.hpp"
00008 
00009 
00010 void Voxelgrid::rehash(){
00011   hashSize = hashSize*2;
00012   std::vector<voxel*>* tempTable = new std::vector<voxel*>((int)hashSize,nullptr);
00013   numCollisions = 0;
00014   numInTable = 0;
00015 
00016   std::cout << "Rehash Triggered: " << hashSize << std::endl;
00017 
00018   for (std::vector<voxel*>::iterator it = hashTable->begin(); it!=hashTable->end(); ++it){
00019     if(*it != nullptr){
00020 
00021       voxel* temp = *it;
00022       int64_t hashPos = hashFunc(temp->x,temp->y,temp->z,hashSize);
00023       if(tempTable->at(hashPos)  == nullptr){
00024         tempTable->at(hashPos) = *it;
00025         numInTable++;
00026       }else{
00027         numCollisions++;
00028         hashPos++;
00029         int numLinearRepeat = 0;
00030         hashPos = hashPos % hashSize;
00031         while (tempTable->at(hashPos) != nullptr) {
00032             hashPos++;
00033             hashPos = hashPos % hashSize;
00034             numLinearRepeat++;
00035         }
00036         numInTable++;
00037         tempTable->at(hashPos) = *it;
00038       }
00039     }
00040   }
00041 
00042   delete hashTable;
00043   hashTable = tempTable;
00044 
00045   std::cout << "rehash finished" << std::endl;
00046 }
00047 
00048 int64_t Voxelgrid::hashFunc(int64_t x, int64_t y, int64_t z,int64_t inHashSize){
00049   return std::abs((((73856093 * x) + (19349663 * y) + (83492791 * z)) % inHashSize));
00050 }
00051 
00052 void Voxelgrid::hashAdd(int16_t x, int16_t y, int16_t z,bool filled, float a, float b){
00053   voxel* temp = new voxel;
00054   temp->filled = filled;
00055   temp->x = x;
00056   temp->y = y;
00057   temp->z = z;
00058   temp->a = a;
00059   temp->b = b;
00060   int64_t hashPos = hashFunc(x,y,z,hashSize);
00061 
00062   if(hashTable->at(hashPos)  == nullptr){
00063     hashTable->at(hashPos) = temp;
00064     numInTable++;
00065   }else{
00066     numCollisions++;
00067     hashPos++;
00068     int numLinearRepeat = 0;
00069     hashPos = hashPos % hashSize;
00070     while(hashTable->at(hashPos)  != nullptr && numLinearRepeat < 100000){
00071       hashPos++;
00072       hashPos = hashPos % hashSize;
00073       numLinearRepeat++;
00074     }
00075     if (numLinearRepeat > 90000) {
00076         rehash();
00077         hashAdd(x, y, z, filled, a, b);
00078         return;
00079     }
00080     numInTable++;
00081     hashTable->at(hashPos) = temp;
00082   }
00083   if((float)numCollisions/(float)numInTable > rehashTresh){
00084     rehash();
00085   }
00086 }
00087 
00088 voxel* Voxelgrid::hashGet(int16_t x, int16_t y, int16_t z){
00089   int64_t hashPos = hashFunc(x,y,z,hashSize);
00090   if(hashTable->at(hashPos)  != nullptr){
00091     while(hashTable->at(hashPos) != nullptr && !isEqualPoint(hashTable->at(hashPos),x,y,z)){
00092       hashPos++;
00093       hashPos = hashPos % hashSize;
00094     }
00095     return hashTable->at(hashPos);
00096   }else{
00097     return nullptr;
00098   }
00099 
00100 }
00101 
00102 
00103 bool Voxelgrid::isEqualPoint(voxel* vox,short int x, short int y,short int z){
00104   return (vox->x == x && vox->y == y && vox->z == z);
00105 }
00106 
00107 
00108 void Voxelgrid::hashInit() {
00109     this->hashTable = new std::vector<voxel*>((int)hashSize, nullptr);
00110 }
00111 
00112 
00113 neighs* Voxelgrid::getNeighbourhoodHash(int16_t x, int16_t y, int16_t z) {
00114 
00115     neighs* neigh = new neighs();
00116     for (size_t i = 0; i < 27; i++)
00117     {
00118         neigh->voxs[i] = hashGet(x + xoff[i],y+yoff[i],z+zoff[i]);
00119     }
00120 
00121     return neigh;
00122 
00123 }
00124 
00125 
00126 neighs* Voxelgrid::getNeighbourhood(int16_t x, int16_t y, int16_t z) {
00127 
00128     neighs* neigh = new neighs();
00129     for (size_t i = 0; i < 27; i++)
00130     {
00131         neigh->voxs[i] = getVoxel(x + xoff[i], y + yoff[i], z + zoff[i]);
00132     }
00133 
00134     return neigh;
00135 
00136 }
00137 
00138 
00139 
00140 /* -----------------------------------------------------------------
00141 Voxelgrid - Create the initial vector strutcture.
00142 */
00143 
00144 Voxelgrid::Voxelgrid(DataHandler* dataHandler,int64_t hashSize){
00145   this->hashSize = hashSize;
00146   this->rehashTresh = 0.75;
00147   this->numInTable = 0; 
00148   this->numCollisions = 0;
00149   this->voxels  = new std::vector<std::vector<std::vector<voxel*>*>*>;
00150   this->datahandler = dataHandler;
00151   this->width = dataHandler->getDataWidth();
00152   this->height = dataHandler->getDataHeight();
00153   this->waterHeight = new std::vector<GLint>(width*height, -1);
00154 
00155   int i = 0;
00156   for (int x = -1; x < 2; x++)
00157   {
00158       for (int y = -1; y < 2; y++)
00159       {
00160           for (int z = -1; z < 2; z++)
00161           {
00162               xoff[i] = x;
00163               yoff[i] = y;
00164               zoff[i] = z;
00165               i++;
00166           }
00167       }
00168   }
00169 }
00170 
00171 
00172 /* -----------------------------------------------------------------
00173 Voxelgrid - Destructor, ensure destruction of all pointer structures
00174 */
00175 
00176 Voxelgrid::~Voxelgrid(){
00177   for (GLuint x = 0; x < voxels->size(); x++) {
00178     if(voxels->at(x) != nullptr){
00179       for (GLuint y = 0; y < voxels->at(x)->size(); y++)
00180       {
00181         if(voxels->at(x)->at(y) != nullptr){
00182           for (GLuint z = 0; z < voxels->at(x)->at(y)->size(); z++)
00183           {
00184             if( voxels->at(x)->at(y)->at(z) != nullptr){
00185               delete voxels->at(x)->at(y)->at(z);
00186             }
00187           }
00188           delete voxels->at(x)->at(y);
00189         }
00190       }
00191       delete voxels->at(x);
00192     }
00193   }
00194   delete voxels;
00195   delete voxelPositions;
00196 }
00197 
00198 
00199 
00200 /* -----------------------------------------------------------------
00201 setVoxel take a x,y,z coordinate where the voxel will be created (or modified)
00202 with the values ax, bx.
00203 */
00204 
00205 void Voxelgrid::setVoxel(int16_t x, int16_t y, int16_t z, bool filledx, float ax, float bx)
00206 {
00207     GLuint xorig = x;
00208     GLuint yorig = y;
00209     GLuint zorig = z;
00210 
00211     setHeight(xorig, yorig, zorig);
00212 
00213     x += 10;
00214     y += 10;
00215     z += 10;
00216 
00217 
00218 
00219   //if x is not in table. Create y and z tables, resize x, and
00220   //point to children (y,z);
00221   if(voxels->size() < (unsigned int)x+1){
00222     std::vector<voxel*>* tempZ = new std::vector<voxel*>(z+1);
00223     std::vector<std::vector<voxel*>*>* tempY = new std::vector<std::vector<voxel*>*>(y+1);
00224     voxels->resize(x+1,nullptr);
00225     (*voxels)[x] = tempY;
00226     (*(*voxels)[x])[y] = tempZ;
00227 
00228   }
00229   //if y is not in table. Create z table, resize y, and
00230   //point to childtable z; Note that existence of y table is
00231   //managed by the first part of the if-statement
00232   else if((*voxels)[x] != nullptr && (*voxels)[x]->size() < (unsigned int)y+1){
00233 
00234     std::vector<voxel*>* tempZ = new std::vector<voxel*>(z+1);
00235     (*voxels)[x]->resize(y+1,nullptr);
00236     (*(*voxels)[x])[y] = tempZ;
00237 
00238   }
00239   //if z is not large enough resize. Note that existence of z table is
00240   //managed by the first two parts of the if-statement
00241   else if((*voxels)[x] != nullptr &&  (*(*voxels)[x])[y] != nullptr && (*(*voxels)[x])[y]->size() < (unsigned int)z+1){
00242     (*(*voxels)[x])[y]->resize(z+1,nullptr);
00243 
00244   }
00245 
00246   //If x is large enough but does not contain a table at position x
00247   //create and insert relevant tables.
00248   if((*voxels)[x] == nullptr){
00249     std::vector<voxel*>* tempZ = new std::vector<voxel*>(z+1);
00250     std::vector<std::vector<voxel*>*>* tempY = new std::vector<std::vector<voxel*>*>(y+1);
00251     (*voxels)[x] = tempY;
00252     (*(*voxels)[x])[y] = tempZ;
00253   }
00254   //If y is large enough but does not contain a table at position y
00255   //create and insert relevant tables.
00256   else if((*(*voxels)[x])[y] == nullptr){
00257     std::vector<voxel*>* tempZ = new std::vector<voxel*>(z+1);
00258     (*(*voxels)[x])[y] = tempZ;
00259   }
00260   //If there is already a voxel at position x,y,z, delete this in
00261   //preperation for new insertion.
00262   else if((*(*(*voxels)[x])[y])[z]  != nullptr){
00263     delete (*(*(*voxels)[x])[y])[z];
00264   }
00265 
00266   //create and insert the new voxel.
00267   voxel* temp = new voxel;
00268   temp->filled = filledx;
00269   temp->a = ax;
00270   temp->b = bx;
00271   temp->x = xorig;
00272   temp->y = yorig;
00273   temp->z = zorig;
00274   (*(*(*voxels)[x])[y])[z] = temp;
00275 
00276 }
00277 
00278 /* -----------------------------------------------------------------
00279 Get voxel at x,y,z. This function returns a pointer to the struct.
00280 If no voxel is present it returns a nullptr.
00281 */
00282 
00283 voxel* Voxelgrid::getVoxel(int16_t x, int16_t y, int16_t z)
00284 {
00285 
00286     x += 10;
00287     y += 10;
00288     z += 10;
00289 
00290 
00291     //std::cout << "In getVoxel, size of vector voxels is: " << voxels->size() << std::endl;
00292 
00293     //std::cout << "Voxels at x is empty" << std::endl;
00294 
00295     //ensure table existance and table size, if either fails return nullptr.
00296     if (voxels->size() < (unsigned int)x + 1 || (*voxels)[x] == nullptr) {
00297         //std::cout << "In first if in get_Voxel" << std::endl;
00298         return nullptr;
00299     }
00300     //ensure table existance and table size, if either fails return nullptr.
00301     else if ((*voxels)[x]->size() < (unsigned int)y + 1 || (*(*voxels)[x])[y] == nullptr) {
00302         //std::cout << "In second if in get_Voxel" << std::endl;
00303         return nullptr;
00304     }
00305     //ensure table existance and table size, if either fails return nullptr.
00306     else if ((*(*voxels)[x])[y]->size() < (unsigned int)z + 1 || (*(*(*voxels)[x])[y])[z] == nullptr) {
00307         return nullptr;
00308     }
00309 
00310     //Existance is ensured, return pointer at location x,y,z
00311     //std::cout << "Just before returning voxel in get_Voxel" << std::endl;
00312     return (voxel*)(*(*(*voxels)[x])[y])[z];
00313 }
00314 
00315 
00316 /* FloodFill function creates a vector queue. Tests if the first voxel coordinates are above land, if so its coordinates are added to the queue
00317 vector and the struct for the voxel is creatd using setVoxel. While there are still coordinates in the queue, the neighboring voxels'
00318 coordinates relative to the current coordinates (last position in queue) are added to the queue and a corresponding struct is created with setVoxel.
00319 As each element in the queue is processed the voxels beneath the current voxel are filled.
00320 */
00321 
00322 void Voxelgrid::FloodFill(int x, int z, int height, bool fillDown){
00323 
00324   std::vector<std::vector<int>> queue;
00325   std::cout << x << std::endl;
00326 
00327   if (datahandler->giveHeight((GLfloat)x, (GLfloat)z) < (GLfloat)height) {
00328     queue.push_back({x, z});
00329     setVoxel(x, height, z, true, 0, 0);
00330   }
00331 
00332   int temp_x, temp_z;
00333   int height_test;
00334   int terrain_height;
00335 
00336   /* While queue is not empty, keep processing queue from back to front.
00337   */
00338   while(queue.size() > 0){
00339 
00340     temp_x  = queue.back().at(0);
00341     temp_z = queue.back().at(1);
00342 
00343     queue.pop_back();
00344 
00345     /* Fill voxels beneath current voxel
00346     */
00347     height_test = height;
00348     terrain_height = (int)datahandler->giveHeight((GLfloat)temp_x, (GLfloat)temp_z);
00349 
00350     if(fillDown){
00351       while(height_test > terrain_height && height_test >= 0){
00352 
00353         setVoxel(temp_x, height_test, temp_z, true, 0, 0);
00354         height_test--;
00355       }
00356     }
00357 
00358 
00359 
00360 /* Checking voxels adjacent to current voxel and adding their coordinates to the queue if they are inside the terrain,
00361 above land and have not yet been added to the queue. Before coordinates are added the struct is created. Struct existance
00362 (!= nullptr) thus equivalent to voxel added to cue as used in if-statement.
00363 */
00364 // temp_x + 1 < datahandler->getDataWidth() -1 dye to giveHeight not able to give height and edge!!!
00365 if (temp_x + 1 < datahandler->getDataWidth() - 1 && datahandler->giveHeight((GLfloat)(temp_x + 1), (GLfloat)temp_z) < height && getVoxel(temp_x + 1, height, temp_z) == nullptr) {
00366     setVoxel(temp_x + 1, height, temp_z, true, 0, 0);
00367     queue.push_back({ temp_x + 1,temp_z });
00368 }
00369 
00370 
00371 if (temp_x - 1 > 0 && datahandler->giveHeight((GLfloat)(temp_x - 1), (GLfloat)temp_z) < height && getVoxel(temp_x - 1, height, temp_z) == nullptr) {
00372     setVoxel(temp_x - 1, height, temp_z, true, 0, 0);
00373     queue.push_back({ temp_x - 1, temp_z });
00374 }
00375 if (temp_z + 1 < datahandler->getDataHeight() - 1 && datahandler->giveHeight((GLfloat)temp_x, (GLfloat)(temp_z + 1)) < height && getVoxel(temp_x, height, temp_z + 1) == nullptr) {
00376     setVoxel(temp_x, height, temp_z + 1, true, 0, 0);
00377     queue.push_back({ temp_x,temp_z + 1 });
00378 }
00379 
00380 if (temp_z - 1 > 0 && datahandler->giveHeight((GLfloat)temp_x, (GLfloat)(temp_z - 1)) < height && getVoxel(temp_x, height, temp_z - 1) == nullptr) {
00381     setVoxel(temp_x, height, temp_z - 1, true, 0, 0);
00382     queue.push_back({ temp_x, temp_z - 1 });
00383 }
00384   }
00385 
00386 }
00387 
00388 std::vector<GLuint> *Voxelgrid::getVoxelPositions() {
00389     std::vector<GLuint> *positions = new std::vector<GLuint>;
00390     GLint tempH = 0;
00391     for (GLuint x = 0; x < width; x++)
00392     {
00393         for (GLuint z = 0; z < height; z++)
00394         {
00395             tempH = getHeight(x, z);
00396             if (tempH != -1) {
00397                 positions->push_back(x);
00398                 positions->push_back((GLuint)tempH);
00399                 positions->push_back(z);
00400             }
00401 
00402         }
00403     }
00404 
00405     return positions;
00406 }
00407 
00408 void Voxelgrid::initDraw() {
00409     voxelPositions = getVoxelPositions();
00410     numVoxels = (GLuint)voxelPositions->size() / 3;
00411     voxelShader = loadShadersG("src/shaders/simplevoxels.vert", "src/shaders/simplevoxels.frag", "src/shaders/simplevoxels.geom");
00412 
00413     glGenBuffers(1, &voxelBuffer);
00414     glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer);
00415     glBufferData(GL_ARRAY_BUFFER, numVoxels * 3 * sizeof(GLuint), voxelPositions->data(), GL_STATIC_COPY);
00416     glBindBuffer(GL_ARRAY_BUFFER, 0);
00417 
00418     glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer);
00419     glGenVertexArrays(1, &voxelVAO);
00420     glBindVertexArray(voxelVAO);
00421 
00422     GLuint posAttrib = glGetAttribLocation(voxelShader, "posValue");
00423     glEnableVertexAttribArray(posAttrib);
00424     glVertexAttribPointer(posAttrib, 3, GL_UNSIGNED_INT, GL_FALSE, 0, 0);
00425 
00426     glBindVertexArray(0);
00427     glBindBuffer(GL_ARRAY_BUFFER, 0);
00428 }
00429 
00430 void Voxelgrid::updateVoxelrender() {
00431     delete voxelPositions;
00432     voxelPositions = getVoxelPositions();
00433     numVoxels = (GLuint)voxelPositions->size() / 3;
00434 
00435     glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer);
00436     glBufferData(GL_ARRAY_BUFFER, numVoxels * 3 * sizeof(GLuint), voxelPositions->data(), GL_STATIC_COPY);
00437     glBindBuffer(GL_ARRAY_BUFFER, 0);
00438 }
00439 
00440 void Voxelgrid::drawVoxels(glm::mat4 projectionMatrix, glm::mat4 viewMatrix) {
00441     glUseProgram(voxelShader);
00442     glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer);
00443     glBindVertexArray(voxelVAO);
00444     glUniformMatrix4fv(glGetUniformLocation(voxelShader, "VTPMatrix"), 1, GL_FALSE, glm::value_ptr(projectionMatrix));
00445     glUniformMatrix4fv(glGetUniformLocation(voxelShader, "WTVMatrix"), 1, GL_FALSE, glm::value_ptr(viewMatrix));
00446 
00447     if (numVoxels > 0) {
00448         glDrawArrays(GL_POINTS, 0, numVoxels);
00449     }
00450 
00451     glBindVertexArray(0);
00452     glBindBuffer(GL_ARRAY_BUFFER, 0);
00453 
00454     printError("Voxel Draw Billboards");
00455 }
00456 
00457 void Voxelgrid::setHeight(int16_t x, int16_t y, int16_t z) {
00458     GLint curHeight = getHeight(x, z);
00459     if( y > curHeight ){
00460         waterHeight->at(x + z*width) = y;
00461     }
00462 }
00463 
00464 GLint Voxelgrid::getHeight(int16_t x, int16_t z) {
00465 
00466     return waterHeight->at(x + z*width);
00467 
00468 }
00469 
00470 std::vector<GLint>* Voxelgrid::getHeightMap() {
00471     return waterHeight;
00472 }
 All Classes Files Functions Variables Enumerations