Logo Search packages:      
Sourcecode: earth3d version File versions  Download package

heightfieldTree.cpp

#include "heightfieldTree.h"
#include "heightfieldTreeNodeCore.h"
#include "heightfieldconfig.h"
#include <qmutex.h>
#include <assert.h>
#include "globaltimer.h"

QMutex heightfieldTreeMutex;

HeightfieldTree::HeightfieldTree(ConnectNetworkService *cns, char *rootRequestID) {
  rootNode = new HeightfieldTreeNode(this, NULL);
  this->cns = cns;
  this->drmt = new DataReceivedMapTile();

  rootNode->setRequestID(rootRequestID);
  requestFromNetwork(rootNode);
}

HeightfieldTree::~HeightfieldTree() {
  delete(rootNode);
  delete(drmt);
}
  
HeightfieldTreeNode *HeightfieldTree::getRootNode() {
  return(rootNode);
}

void HeightfieldTree::request(HeightfieldTreeNodeCore *hcore) {
  /* set child request IDs. In case that we can not fulfil the request yet we have at least
     valid request IDs. */
  char rID[1024];
  strcpy(rID, hcore->getRequestID());
  strcat(rID, "0");
  int rIDlen = strlen(rID);
  for(int nr=0; nr<4; nr++) {
    rID[rIDlen-1]='0'+nr;
    hcore->setChildRequestID(nr, rID);
  }

  /* we need to transform heightfield data from one tree to another */
  
  /* find the node in the source tree. We can use the requestID of hcore
     to determine where in our tree to start:
     It is build as a path through the tree:
     02312322
     Every digit is a subtile. The empty string is the root node. The
     order is 0=right up, 1=right down, 2=left up, 3=left down.
   */
  HeightfieldTreeNode *sourceNode = getRootNode();
  char *requestID = hcore->getRequestID();
  assert(requestID);
  int xoffset=0, yoffset=0, width=SOURCEWIDTH, height=SOURCEHEIGHT;
  if (strlen(requestID)>0) {
    for(int i=0; i<strlen(requestID); i++) {
      int digit = requestID[i]-'0';
      width /= 2;
      height/= 2;
      xoffset += digit<2 ? width:0;
      yoffset += digit&1 ? height:0;
      
      if (width<HEIGHTFIELDWIDTH || height<HEIGHTFIELDHEIGHT) {
      /* its a tile that is deeper in the tree than layer 3 */
      width *= 2;
      height*= 2;
      assert(width==HEIGHTFIELDWIDTH && height==HEIGHTFIELDHEIGHT);
      
      /* get lower HeightfieldTreeNode */
      int targetChild = 0;
      if (xoffset>=SOURCEWIDTH/2) {
        xoffset-=SOURCEWIDTH/2;
      }
      else {
        targetChild+=2;
      }
      if (yoffset>=SOURCEHEIGHT/2) {
        targetChild+=1;
        yoffset-=SOURCEHEIGHT/2;
      }
      xoffset *= 2;
      yoffset *= 2;
      
      HeightfieldTreeNode *newSourceNode = sourceNode->getChild(targetChild);
      
      if (newSourceNode==NULL) {
        /* if we do not have the needed data we have to request it for
           our source tree first and enqueue this request */
        HeightfieldTreeNode *newNode = new HeightfieldTreeNode(this, sourceNode);
        sourceNode->setChild(targetChild, newNode);
        newNode->setRequestID(sourceNode->getChildRequestID(targetChild));
#ifdef EARTH3DDEBUG
        printf("ENQUEUE HEIGHTTILE\n");
#endif

        if (sourceNode->getChildRequestID(targetChild)) {
          newNode->enqueueRequest(hcore); // call HeightfieldTree::request(hcore) when the tile has arrived
          requestFromNetwork(newNode);
        }
        else {
          newNode->setDownloaded(true);
          newNode->setDownloadFailed();
          hcore->setGenerated(false);
          hcore->setDownloaded(true);
          hcore->setDownloadFailed();
        }
        return;
      }
      else {
        if (newSourceNode->getDownloadFailed()) {
          hcore->setGenerated(false);
          hcore->setDownloaded(true);
          hcore->setDownloadFailed();
          return;
        }
        else if (!newSourceNode->hasImage()) {
          // this node must be already requested, just add the new hcore to be informed
#ifdef EARTH3DDEBUG
          printf("ENQUEUE2 HEIGHTTILE\n");
#endif
          newSourceNode->enqueueRequest(hcore);
          return;
        }
      }
      
      sourceNode = newSourceNode;
      }
    }
  }

  /* we have the needed data in the tree. Now extract it and update hcore. */
//   float *subtile = new float[width*height];
  float *subtile = new float[256*256];

  if (sourceNode->getDownloadFailed()) {
    hcore->setGenerated(false);
    hcore->setDownloaded(true);
    hcore->setDownloadFailed();
  }
  else if (!sourceNode->hasImage()) {
    // this node must be already requested, just add the new hcore to be informed
#ifdef EARTH3DDEBUG
    printf("ENQUEUE3 HEIGHTTILE\n");
#endif
    sourceNode->enqueueRequest(hcore);
    delete[](subtile);
    return;
  }
  else {
    sourceNode->getArea(xoffset, yoffset, width, height, subtile);
    if (width>HEIGHTFIELDWIDTH || height>HEIGHTFIELDHEIGHT) {
      /* scale image */
#ifdef EARTH3DDEBUG
      printf("width=%i height=%i xoffset=%i yoffset=%i\n", width, height, xoffset, yoffset);
#endif
      float *subtilenew = new float[HEIGHTFIELDWIDTH*HEIGHTFIELDHEIGHT];
      int sx = width/HEIGHTFIELDWIDTH, sy = height/HEIGHTFIELDHEIGHT;
      for(int ty=0; ty<HEIGHTFIELDHEIGHT; ty++) {
      for(int tx=0; tx<HEIGHTFIELDWIDTH; tx++) {
        subtilenew[ty*HEIGHTFIELDWIDTH+tx]=subtile[(ty*sy)*width+(tx*sx)];
      }
      }
      delete[](subtile);
      subtile = subtilenew;
      width=HEIGHTFIELDWIDTH;
      height=HEIGHTFIELDHEIGHT;
    }
  
    hcore->setImage(width, height, (char *) subtile, width*height*sizeof(float), "RAW");
    hcore->setGenerated(false);
    hcore->setDownloaded(true);
    hcore->generateVertexArray();
    delete[](subtile);
  }
}

void HeightfieldTree::requestFromNetwork(HeightfieldTreeNode *hnode) {
  if (!hnode->getRequested()) {
    hnode->setRequested(true);
    if (hnode->getRequestID()) {
//       hnode->addDownloader(drmt);
      cns->getOne(hnode->getRequestID(), hnode, hnode, 10);
    }
    else {
      hnode->setDownloaded(true);
      hnode->setDownloadFailed();
    }
  }
}

void HeightfieldTree::garbageCollect() {
  garbageCollectNode(getRootNode());  
}

void HeightfieldTree::garbageCollectNode(HeightfieldTreeNode *node) {
  node->garbageCollect();
  for(int i=0; i<4; i++) {
    HeightfieldTreeNode *child = node->getChild(i);
    if (child) garbageCollectNode(child);
  }
}

Generated by  Doxygen 1.6.0   Back to index