random_racer/src/VRSTerrainLoader.cpp

Go to the documentation of this file.
00001 #include <assert.h>
00002 #include <stdio.h>
00003 
00004 #include <iostream>
00005 
00006 #include <vrs/box.h>
00007 #include <vrs/container/dataiterator.h>
00008 #include <vrs/mesh.h>
00009 #include <vrs/sg/scenething.h>
00010 #include <vrs/translation.h>
00011 
00012 #include "MeshBeautifier.h"
00013 #include "TerrainGenerator.h"
00014 #include "ControlPointContainer.h"
00015 
00016 #include "VRSTerrainLoader.h"
00017 
00018 using namespace VRS;
00019 
00020 // #define RR_DEBUG_LOADER_THREADING
00021 
00022 
00023 namespace random_racer
00024 {
00025 
00026 VRSTerrainLoader::VRSTerrainLoader(
00027     SO<SceneThing> p_thing,
00028     SO<ControlPointContainer> p_container,
00029     double p_boxSize,
00030     double p_viewSize) :  TerrainLoader(p_thing, p_boxSize, p_viewSize)
00031 {
00032     assert(sizeof(m_terrainCache) == 4*sizeof(TerrainPart));
00033 
00034     const unsigned int levelOfDetail = 64;
00035 
00036 
00037     m_thing->clear();
00038 
00039     m_translation = new Translation((m_viewSize/-2.0), 0.0, (m_viewSize/-2.0));
00040 
00041     m_vertexIter    = new DataIterator<Vector>();
00042     m_textureIter   = new DataIterator<Vector>();
00043     m_colorIter     = new DataIterator<Color>();
00044 
00045     m_generator = new TerrainGenerator(
00046         p_container, m_viewSize, 32.0, levelOfDetail);
00047 
00048     m_generator->generate(0.0, 0.0, &(m_vertexIter->data));
00049 
00050     m_beautifier = new MeshBeautifier(
00051                         this,
00052                         p_container->minHeight(),
00053                         p_container->maxHeight());
00054 
00055     m_mesh = new Mesh(levelOfDetail, levelOfDetail, m_vertexIter);
00056 
00057     m_thing->append(m_translation);
00058 
00059     m_beautifier->initializeSceneThing(m_thing);
00060 
00061     beautifyMesh();
00062 
00063     m_mesh->setColorIterator(m_colorIter);
00064     m_mesh->setTextureIterator(m_textureIter);
00065 
00066 
00067     m_thing->append(m_mesh);    
00068 
00069 
00070     m_terminateWorker   = false;
00071 
00072     m_signalWhenDoneWith= -2;
00073     m_workerIsWaiting   = false;
00074 
00075     m_vertexMutex       = SDL_CreateMutex();
00076     m_controlMutex      = SDL_CreateMutex();
00077     m_generateWakeMutex = SDL_CreateMutex();
00078 
00079     m_replaceWakeCond   = SDL_CreateCond();
00080     m_generateWakeCond  = SDL_CreateCond();
00081 
00082     assert(m_vertexMutex != NULL);
00083     assert(m_controlMutex != NULL && m_generateWakeMutex != NULL);
00084     assert(m_replaceWakeCond != NULL && m_generateWakeCond != NULL);
00085 
00086 
00087     m_worker = SDL_CreateThread(&VRSTerrainLoader::workerWrapper, this);
00088     assert(m_worker != NULL);
00089 
00090 
00091     for(;;)
00092     {
00093         SDL_LockMutex(m_generateWakeMutex);
00094 
00095         if(m_workerIsWaiting)
00096             break;
00097 
00098         SDL_UnlockMutex(m_generateWakeMutex);
00099 
00100 #ifdef RR_DEBUG_LOADER_THREADING
00101         std::cout << "worker not yet waiting (postCtor)" << std::endl;
00102 #endif
00103     }
00104 
00105 #ifdef RR_DEBUG_LOADER_THREADING
00106     std::cout << "SIGNALING worker (postCtor)" << std::endl;
00107 #endif
00108 
00109     SDL_UnlockMutex(m_generateWakeMutex);
00110     SDL_CondSignal(m_generateWakeCond);
00111 }
00112 
00113 
00114 
00115 void
00116 VRSTerrainLoader::replaceTerrain(
00117     const Vector& p_position, const Vector& p_center)
00118 {
00119 #ifdef RR_DEBUG_LOADER_THREADING
00120     std::cout << "replaceTerrain()" << std::endl
00121               << "  p_position: " << p_position << std::endl
00122               << "  diff: " << (p_position - m_position) << std::endl;
00123 #endif
00124 
00125 
00126     unsigned int nearest;
00127     bool indexIsDone;
00128 
00129 
00130     SDL_LockMutex(m_controlMutex);
00131 #ifdef RR_DEBUG_LOADER_THREADING
00132     std::cout << "locked m_controlMutex" << std::endl;
00133 #endif
00134 
00135 
00136     nearest = nearestIndex(
00137                      p_position[0], p_position[2], m_terrainCache, 4);
00138 
00139     indexIsDone = m_terrainCache[nearest].isDone;
00140 
00141 
00142 #ifdef RR_DEBUG_LOADER_THREADING
00143     std::cout << "nearest is " << nearest << " and it is ";
00144 #endif
00145 
00146 
00147     if(!indexIsDone)
00148     {
00149 #ifdef RR_DEBUG_LOADER_THREADING
00150         std::cout << "NOT done" << std::endl
00151                   << "waiting..." << std::endl;
00152 #endif
00153         m_signalWhenDoneWith = nearest; // WAKE ME IF WHAT I NEED IS DONE
00154 
00155         SDL_CondWait(m_replaceWakeCond, m_controlMutex);
00156 
00157 #ifdef RR_DEBUG_LOADER_THREADING
00158         std::cout << "ok, i'm back" << std::endl;
00159 #endif
00160     }
00161     else
00162     {
00163 #ifdef RR_DEBUG_LOADER_THREADING
00164         std::cout << "DONE" << std::endl
00165                   << "continuing" << std::endl;
00166 #endif
00167         m_signalWhenDoneWith = -1; // YOU CAN STOP NOW. GENERATE AGAIN
00168     }
00169 
00170 
00171     Vector translate;
00172 
00173     translate[0] = m_terrainCache[nearest].x - (m_viewSize/2.0);
00174     translate[1] = 0.0;
00175     translate[2] = m_terrainCache[nearest].y - (m_viewSize/2.0);
00176 
00177 
00178     lock();
00179 
00180     m_translation->setTranslate(translate);
00181 
00182     // replace the old vertices with the new ones (COPY)
00183     m_vertexIter->data = m_terrainCache[nearest].points;
00184 
00185     unlock();
00186 
00187 
00188 #ifdef RR_DEBUG_LOADER_THREADING
00189     std::cout << "COPIED the points" << std::endl;
00190 #endif
00191 
00192 
00193     // recalculate the cached terrains with the new position
00194     m_position = p_center;
00195 
00196     
00197     if(!indexIsDone || m_workerIsWaiting)
00198     {
00199         SDL_UnlockMutex(m_controlMutex);
00200 #ifdef RR_DEBUG_LOADER_THREADING
00201         std::cout << "UNlocked m_controlMutex" << std::endl
00202                   << "waking the worker" << std::endl;
00203 #endif
00204 
00205         for(;;)
00206         {
00207             SDL_LockMutex(m_generateWakeMutex);
00208 
00209             if(m_workerIsWaiting)
00210                 break;
00211 
00212             SDL_UnlockMutex(m_generateWakeMutex);
00213 
00214 #ifdef RR_DEBUG_LOADER_THREADING
00215             std::cout << "worker not yet waiting (replaceTerrain)" << std::endl;
00216 #endif
00217         }
00218 
00219         m_signalWhenDoneWith = -2; // WORK NORMALY NOW PLZ
00220 
00221 #ifdef RR_DEBUG_LOADER_THREADING
00222         std::cout << "SIGNALING worker (replaceTerrain)" << std::endl;
00223 #endif
00224 
00225         SDL_UnlockMutex(m_generateWakeMutex);
00226         SDL_CondSignal(m_generateWakeCond);
00227     }
00228     else
00229     {
00230         SDL_UnlockMutex(m_controlMutex);
00231 
00232 #ifdef RR_DEBUG_LOADER_THREADING
00233         std::cout << "BEST CASE" << std::endl
00234                   << "UNlocked m_controlMutex" << std::endl;
00235 #endif
00236     }    
00237 
00238 
00239     beautifyMesh();
00240 
00241 #ifdef RR_DEBUG_LOADER_THREADING
00242     std::cout << "DONE" << std::endl;
00243 #endif
00244 
00245 }
00246 
00247 int
00248 VRSTerrainLoader::workerWrapper(void* p_self)
00249 {
00250     return ((VRSTerrainLoader*)p_self)->generate();
00251 }
00252 
00253 int
00254 VRSTerrainLoader::generate()
00255 {
00256 #ifdef RR_DEBUG_LOADER_THREADING
00257     std::cout << "\tworker started" << std::endl;
00258 #endif
00259 
00260     // used to remember if we have to wake replaceTerrain()
00261     // or if we did so already
00262     enum {SIGNAL, GOTO, CONTINUE} loopResult = CONTINUE;
00263 
00264     // half boxsize
00265     double h = m_boxSize*0.5;
00266 
00267 
00268     SDL_LockMutex(m_generateWakeMutex);
00269 #ifdef RR_DEBUG_LOADER_THREADING
00270     std::cout << "\tlocked m_generateWakeMutex" << std::endl;
00271 #endif
00272 
00273 
00274     // the thread loop
00275     for(;;)
00276     {
00277         if(loopResult != GOTO)
00278         {
00279             SDL_LockMutex(m_controlMutex);
00280 #ifdef RR_DEBUG_LOADER_THREADING
00281             std::cout << "\tlocked m_controlMutex for waiting = true"
00282                       << std::endl;
00283 #endif
00284 
00285             m_workerIsWaiting = true;
00286 
00287             SDL_UnlockMutex(m_controlMutex);
00288 #ifdef RR_DEBUG_LOADER_THREADING
00289             std::cout << "\tUNlocked m_controlMutex" << std::endl;
00290 #endif
00291 
00292 
00293 #ifdef RR_DEBUG_LOADER_THREADING
00294             std::cout << "\twaiting..." << std::endl;
00295 #endif
00296             SDL_CondWait(m_generateWakeCond, m_generateWakeMutex);
00297         }
00298         else
00299             m_signalWhenDoneWith = -2;
00300 
00301 
00302         SDL_LockMutex(m_controlMutex);
00303 #ifdef RR_DEBUG_LOADER_THREADING
00304         std::cout << "\tlocked m_controlMutex for waiting = false" << std::endl;
00305 #endif
00306 
00307         // stop the thread if somebody whishes this
00308         if(m_terminateWorker)
00309         {
00310             SDL_UnlockMutex(m_controlMutex);
00311             return 1;
00312         }
00313 
00314         m_workerIsWaiting = false;
00315 
00316 #ifdef RR_DEBUG_LOADER_THREADING
00317         std::cout << "\ti am awake" << std::endl;
00318 #endif
00319 
00320         // precalculate the terrains positions
00321         for(unsigned int i = 0; i < 4; i++)
00322         {
00323             // FIXME: do this more clever so that the...
00324             // terrains which are highly propable that we need them
00325             // will be generated first and then the other ones.
00326 
00327             switch(i)
00328             {
00329             // left top
00330             case 0:
00331                 m_terrainCache[i].x = m_position[0]-h;
00332                 m_terrainCache[i].y = m_position[2]+h;
00333                 break;
00334             // left bottom
00335             case 1:
00336                 m_terrainCache[i].x = m_position[0]-h;
00337                 m_terrainCache[i].y = m_position[2]-h;
00338                 break;
00339             // right bottom
00340             case 2:
00341                 m_terrainCache[i].x = m_position[0]+h;
00342                 m_terrainCache[i].y = m_position[2]-h;
00343                 break;
00344             // right top
00345             case 3:
00346                 m_terrainCache[i].x = m_position[0]+h;
00347                 m_terrainCache[i].y = m_position[2]+h;
00348                 break;
00349             }
00350 
00351             m_terrainCache[i].isDone = false;
00352         }
00353 
00354         SDL_UnlockMutex(m_controlMutex);
00355 #ifdef RR_DEBUG_LOADER_THREADING
00356         std::cout << "\tUNlocked m_controlMutex" << std::endl;
00357 #endif
00358 
00359         loopResult = CONTINUE;
00360 
00361         // now calculate the real terrain data and check after
00362         // each generation if we can stop now.
00363         for(unsigned int i = 0; i < 4; i++)
00364         {
00365             m_terrainCache[i].points.clear();
00366 
00367             m_generator->generate(
00368                 m_terrainCache[i].x,
00369                 m_terrainCache[i].y,
00370                 &(m_terrainCache[i].points));
00371 
00372 
00373             SDL_LockMutex(m_controlMutex);
00374 #ifdef RR_DEBUG_LOADER_THREADING
00375             std::cout << "\tlocked m_controlMutex" << std::endl;
00376 #endif
00377 
00378             m_terrainCache[i].isDone = true;
00379 
00380 
00381 #ifdef RR_DEBUG_LOADER_THREADING
00382             std::cout << '\t' << i << " is done" << std::endl;
00383 #endif
00384 
00385             if(m_signalWhenDoneWith == -1)
00386             {
00387 #ifdef RR_DEBUG_LOADER_THREADING
00388                 std::cout << "\tm_signalWhenDoneWith == -1" << std::endl;
00389 #endif
00390                 loopResult = GOTO;
00391 
00392                 SDL_UnlockMutex(m_controlMutex);
00393 #ifdef RR_DEBUG_LOADER_THREADING
00394                 std::cout << "\tUNlocked m_controlMutex" << std::endl;
00395 #endif
00396                 break;
00397             }
00398             else if(m_signalWhenDoneWith >= 0 && m_signalWhenDoneWith <= int(i))
00399             {
00400 #ifdef RR_DEBUG_LOADER_THREADING
00401                 std::cout << "\tm_signalWhenDoneWith <= i" << std::endl;
00402 #endif
00403                 loopResult = SIGNAL;
00404 
00405                 SDL_UnlockMutex(m_controlMutex);
00406 #ifdef RR_DEBUG_LOADER_THREADING
00407                 std::cout << "\tUNlocked m_controlMutex" << std::endl;
00408 #endif
00409                 break;
00410             }
00411             else
00412             {
00413                 SDL_UnlockMutex(m_controlMutex);
00414 
00415 #ifdef RR_DEBUG_LOADER_THREADING
00416                 std::cout << "\tm_signalWhenDoneWith ELSE" << std::endl
00417                           << "\tUNlocked m_controlMutex" << std::endl;
00418 #endif
00419             }
00420         }
00421 
00422 #ifdef RR_DEBUG_LOADER_THREADING
00423         std::cout << "\tDONE" << std::endl;
00424 #endif
00425 
00426         if(loopResult == SIGNAL)
00427         {
00428 #ifdef RR_DEBUG_LOADER_THREADING
00429             std::cout << "\ti have to SIGNAL replaceTerrain()" << std::endl;
00430 #endif
00431             SDL_CondSignal(m_replaceWakeCond);
00432         }
00433 
00434     }  // for(;;)
00435 
00436     return 0;
00437 }
00438 
00439 VRSTerrainLoader::~VRSTerrainLoader()
00440 {
00441     m_thing->clear();
00442     // terminate();
00443 }
00444 
00445 void
00446 VRSTerrainLoader::beautifyMesh()
00447 {
00448     m_mesh->setNormalIterator(m_mesh->constructNormalIterator(false, false));
00449 
00450     m_textureIter->data.clear();
00451     m_colorIter->data.clear();
00452 
00453     m_beautifier->generateColorsAndTexCoords(
00454         m_vertexIter->data.begin(),
00455         m_vertexIter->data.end(),
00456         &(m_textureIter->data),
00457         &(m_colorIter->data),
00458         m_translation->getTranslate());
00459 }
00460 
00461 void
00462 VRSTerrainLoader::terminate()
00463 {
00464     for(;;)
00465     {
00466         SDL_LockMutex(m_generateWakeMutex);
00467 
00468         if(m_workerIsWaiting)
00469             break;
00470 
00471         SDL_UnlockMutex(m_generateWakeMutex);
00472 
00473 #ifdef RR_DEBUG_LOADER_THREADING
00474         std::cout << "worker not yet waiting (terminate)" << std::endl;
00475 #endif
00476     }
00477 
00478 #ifdef RR_DEBUG_LOADER_THREADING
00479     std::cout << "SIGNALING worker (terminate)" << std::endl;
00480 #endif
00481 
00482     SDL_LockMutex(m_controlMutex);
00483     m_terminateWorker = true;
00484     SDL_UnlockMutex(m_controlMutex);
00485 
00486     SDL_UnlockMutex(m_generateWakeMutex);
00487     SDL_CondSignal(m_generateWakeCond);
00488 
00489 
00490     // this has to be done for freeing the resources of the thread
00491     SDL_WaitThread(m_worker, NULL);
00492 
00493 #ifdef RR_DEBUG_LOADER_THREADING
00494     std::cout << "WORKER TERMINATED" << std::endl;
00495 #endif
00496 }
00497 
00498 VRS::SO<VRS::Mesh>
00499 VRSTerrainLoader::mesh()
00500 {
00501     return m_mesh;
00502 }
00503 
00504 VRS::Vector
00505 VRSTerrainLoader::heightAt(double p_x, double p_z)
00506 {
00507     double lodSpacing = 8.0;
00508 
00509     VRS::Vector position    = VRS::Vector(p_x, 0, p_z);
00510     VRS::Vector translation = m_vertexIter->data[0] +
00511             m_translation->getTranslate();
00512 
00513     position -= translation;
00514 
00515     position[0] = round(position[0] / lodSpacing);
00516     position[2] = round(position[2] / lodSpacing);
00517 
00518 
00519     VRS::Vector result = m_vertexIter->data[(position[2] * 64) + position[0]];
00520     result += m_translation->getTranslate();
00521 
00522     return result;
00523 }
00524 
00525 } // namespace random_racer

Generated on Fri May 11 21:01:58 2007 for Random Racer by  doxygen 1.5.1