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

mapTileTreeNode.cpp

#include "mapTileTreeNode.h"
#include <assert.h>
#include <stdio.h>
#include "heightfieldTreeNodeCore.h"
#include "textureTreeNodeCore.h"

MapTileTreeNode::MapTileTreeNode(MapTileTreeNode *parent) {
  this->parent = parent;
  selectedForDrawing = false;
  wasSelectedForDrawing = false;
  depth = 0;

  for(int nr=0; nr<4; nr++) child[nr]=NULL;
  cores[0]=NULL;
  cores[1]=NULL;

  bs.center = Point3D(0,0,0);
  bs.radius = 100;

  childInterpolates = false;
  thisInterpolates = false;
  interpolationcounter = INTERPOLATIONFRAMES;
  interpolationDirectionIn= true;
}

MapTileTreeNode::~MapTileTreeNode() {
  delete(cores[0]);
  delete(cores[1]);

  for(int i=0; i<4; i++) {
    deleteChild(i);
  }
}

MapTileTreeNode *MapTileTreeNode::getChild(int nr) {
  assert(nr>=0 && nr<=3);
  return(child[nr]);
}

00040 bool MapTileTreeNode::hasAnyChild() {
  for(int i=0; i<4; i++) {
    if (getChild(i)) return(true);
  }
  return(false);
}

void MapTileTreeNode::setChild(int nr, MapTileTreeNode *child) {
  this->child[nr]=child;
}

void MapTileTreeNode::deleteChild(int nr) {
  MapTileTreeNode *child = getChild(nr);
  if (child/* && !child->getGenerated() && !child->hasAnyChild()*/) {
    setChild(nr, NULL);
    delete(child);
  }
}

bool MapTileTreeNode::getRequested() {
  return(cores[0]->getRequested() || cores[1]->getRequested());
}

bool MapTileTreeNode::getGenerated() {
  return(cores[0]->getGenerated() || cores[1]->getGenerated());
}

int MapTileTreeNode::getCoreCount() {
  return(2);
}

MapTileTreeNodeCore *MapTileTreeNode::getCore(int nr) {
  return(cores[nr]);
}

void MapTileTreeNode::setCore(int nr, MapTileTreeNodeCore *core) {
  assert(core->magic==45678);

  cores[nr]=core;
}

MapTileTreeNode *MapTileTreeNode::getParent() {
  return(parent);
}

void MapTileTreeNode::setSelectedForDrawing(bool select) {
  selectedForDrawing = select;
}

bool MapTileTreeNode::getSelectedForDrawing() {
  return(selectedForDrawing);  
}

void MapTileTreeNode::setWasSelectedForDrawing(bool select) {
  wasSelectedForDrawing = select;
}

bool MapTileTreeNode::getWasSelectedForDrawing() {
  return(wasSelectedForDrawing);  
}

void MapTileTreeNode::setVisible(bool select) {
  visible = select;
}

bool MapTileTreeNode::getVisible() {
  return(visible);
}

00109 Point2DInt MapTileTreeNode::getSimpleTileCoordinates(int childnr) {
  switch(childnr) {
  case 0:
    return(Point2DInt(1,0));
  case 1:
    return(Point2DInt(1,1));
  case 2:
    return(Point2DInt(0,0));
  case 3:
    return(Point2DInt(0,1));
  default:
    assert(false);
  }
}

00124 Point2DInt MapTileTreeNode::getSimpleTileDirections(int direction) {
  switch(direction) {
  case 0:
    return(Point2DInt(1,0));
  case 1:
    return(Point2DInt(0,1));
  case 2:
    return(Point2DInt(-1,0));
  case 3:
    return(Point2DInt(0,-1));
  default:
    assert(false);
  }
}

00139 int MapTileTreeNode::getChildnr(Point2DInt p) {
  if (p.x==1 && p.y==0) return(0);
  if (p.x==1 && p.y==1) return(1);
  if (p.x==0 && p.y==0) return(2);
  if (p.x==0 && p.y==1) return(3);

  return(-1);
}

00148 int MapTileTreeNode::getThisChildnr() {
  int owndirection = -1;
  for(int childnr=0; childnr<4; childnr++) {
    if (getParent()->getChild(childnr)==this) owndirection=childnr;
  }
  assert(owndirection!=-1);

  return(owndirection);
}

00158 MapPart MapTileTreeNode::getNeighbor(int direction) {
  if (!getParent()) return(MapPart(0, this, Point2DInt(0,0))); // loop the root tile

  /* test which child this tile is */
  Point2DInt ownposition = getSimpleTileCoordinates(getThisChildnr());

  /* if we can reach the neighbor directly using the parent then do so */
  Point2DInt godirection = getSimpleTileDirections(direction);
  Point2DInt newposition = ownposition + godirection;
  if (newposition.x>=0 && newposition.x<=1 &&
      newposition.y>=0 && newposition.y<=1) {
    MapTileTreeNode *result = getParent()->getChild(getChildnr(newposition));
    if (result==NULL) { // child does not exist, use parent and difference level of 1
      return(MapPart(1, getParent(), newposition));
    }
    else { // child does exist, use it with level difference of 0
      return(MapPart(0, getParent()->getChild(getChildnr(newposition)), Point2DInt(0,0)));
    }
  }

  /* otherwise we need to get the right neighbor from the parent tile */
  MapPart parentNeighbor = getParent()->getNeighbor(direction);

  /* from the parentNeighbor we need the child that is in the opposite direction */
  Point2DInt searchposition = ownposition + getSimpleTileDirections((direction + 2) % 4);
  assert(searchposition.x>=0 && searchposition.x<=1 && searchposition.y>=0 && searchposition.y<=1);

//   /* by getting this parent neighbor, we moved two times in that direction
//      and need to correct our search position accordingly */
//   newposition = newposition - godirection*2;

  if (parentNeighbor.node==NULL) { // neighbor does not exist
    return(MapPart(0, NULL, Point2DInt(0,0)));
  }

  if (parentNeighbor.level==0 && !parentNeighbor.node->getSelectedForDrawing()) { // more childs exist
    /* now get this child */
    MapTileTreeNode *result = parentNeighbor.node->getChild(getChildnr(searchposition));
    if (result) { // has a child
      return(MapPart(0, result, Point2DInt(0,0)));
    }
    else { // has no child, use parent
      return(MapPart(1, parentNeighbor.node, searchposition));
    }
  }
  else { // there was already a child missing so the parent was used
    parentNeighbor.offset *= 2;
    parentNeighbor.offset += searchposition;
    return(MapPart(parentNeighbor.level+1, parentNeighbor.node, parentNeighbor.offset));
  }
}

MapPart MapTileTreeNode::getCornerNeighbor() {
  if (!getParent()) return(MapPart(0, this, Point2DInt(0,0))); // loop the root tile

  /* test what child this tile is */
  Point2DInt ownposition = getSimpleTileCoordinates(getThisChildnr());

  /* if we can reach the neighbor directly using the parent then do so */
  Point2DInt godirection = Point2DInt(1,1);
  Point2DInt newposition = ownposition + godirection;
  if (newposition.x>=0 && newposition.x<=1 &&
      newposition.y>=0 && newposition.y<=1) {
    MapTileTreeNode *result = getParent()->getChild(getChildnr(newposition));
    if (result==NULL) { // child does not exist, use parent and difference level of 1
      return(MapPart(1, getParent(), newposition));
    }
    else { // child does exist, use it with level difference of 0
      return(MapPart(0, getParent()->getChild(getChildnr(newposition)), Point2DInt(0,0)));
    }
  }

  MapPart parentNeighbor;
  Point2DInt searchposition;

  if (newposition.x>1 && newposition.y>1) {
    /* otherwise we need to get the right neighbor from the parent tile */
    parentNeighbor = getParent()->getCornerNeighbor();
    searchposition = Point2DInt(0,0);
    
  }
  else {
    if (newposition.x>1) {
      parentNeighbor = getSelectedNeighbor(0);
      searchposition = Point2DInt(0,1);
    }
    else {
      if (newposition.y>1) {
      parentNeighbor = getSelectedNeighbor(1);
      searchposition = Point2DInt(1,0);
      }
    }
  }

  /* from the parentNeighbor we need the child that is in the opposite direction */
  assert(searchposition.x>=0 && searchposition.x<=1 && searchposition.y>=0 && searchposition.y<=1);


  if (parentNeighbor.node==NULL) { // neighbor does not exist
    return(MapPart(0, NULL, Point2DInt(0,0)));
  }

  if (parentNeighbor.level==0 && !parentNeighbor.node->getSelectedForDrawing()) { // more childs exist
    /* now get this child */
    MapTileTreeNode *result = parentNeighbor.node->getChild(getChildnr(searchposition));
    if (result) { // has a child
      return(MapPart(0, result, Point2DInt(0,0)));
    }
    else { // has no child, use parent
      return(MapPart(1, parentNeighbor.node, searchposition));
    }
  }
  else { // there was already a child missing so the parent was used
    parentNeighbor.offset *= 2;
    parentNeighbor.offset += searchposition;
    return(MapPart(parentNeighbor.level+1, parentNeighbor.node, parentNeighbor.offset));
  }
}

/* this function is not really in use any more since getNeighbor now only looks at selected nodes */
00278 MapPart MapTileTreeNode::getSelectedNeighbor(int direction) {
  MapPart mp = getNeighbor(direction);
  MapPart orig = mp;

  while(!mp.node->getSelectedForDrawing()) {
    mp.node = mp.node->getParent();
    mp.level++;
    mp.offset /=2;
    if (!mp.node) break;
  }

  if (mp.node) return(mp);
  return(orig);
}

00293 void MapTileTreeNode::informNeighborNodes() {
//   printf("node %li changed\n", this);
  assert(getSelectedForDrawing());
  if (getCore(1)==NULL) return; // needs heightfield

  float cornerValue = 0;
  /* first correct the right down corner */
  MapPart cornerNeighbor = getCornerNeighbor();
  if (cornerNeighbor.node) {
    HeightfieldTreeNodeCore *hcore = (HeightfieldTreeNodeCore *) cornerNeighbor.node->getCore(1);
    if (hcore) {
      cornerValue = hcore->getCorner(0,0);
    }
  }

  HeightfieldTreeNodeCore *thiscore = (HeightfieldTreeNodeCore *) getCore(1);

  for(int direction=0; direction<4; direction++) {

    if (thiscore) {
//       printf("this: %li cornerValue: %f\n", thiscore, cornerValue);
//       thiscore->setCorner(1,1,cornerValue);
    }

    /* regenerate the smaller, deeper node to fit the higher, set the border element distance,
     * restore the higher node and copy the right and bottom values from the neighbor node
     */
    MapPart neighbor = getSelectedNeighbor(direction);
    if (neighbor.node) {
      if (neighbor.node->getCore(1)!=NULL) { // needs heightfield
      if (neighbor.level==0) {
        assert(neighbor.node->getSelectedNeighbor((direction+2) % 4).node==this);
      }
      if (neighbor.level>0) {
        assert(neighbor.node->getSelectedForDrawing());
      }
      assert(neighbor.level>=0);
      
      // if the other tile is larger than this one we have to adjust
      // if the other tile has children, they need to adjust
      if (depth>2 && direction==0 && neighbor.level==1) {
        //  MapPart downneighbor = getSelectedNeighbor(1);
        //  if (downneighbor.level==1 && downneighbor.node->getSelectedForDrawing()) {
        ((HeightfieldTreeNodeCore *)neighbor.node->getCore(1))->markedfordebug=true;
      }
      
      neighbor.node->regenerateHeightfield(this, (direction+2) % 4, -neighbor.level, neighbor.offset);
      //       regenerateHeightfield(neighbor.node, direction, neighbor.level, neighbor.offset);
      }
    }
    else {
      assert(false);
      printf("no neighbor\n");
    }
  }
}

00350 void MapTileTreeNode::regenerateHeightfield(MapTileTreeNode *node, int direction, int level, Point2DInt offset) {
  /* get the layer that is selected for drawing */
  if (getSelectedForDrawing()) {
    /* regenerate this node 
     * the deeper node has to adapt to the other nodes heightfield, but the higher node has to restore
     * its border at this point
     */

    assert(node->getSelectedForDrawing());

    /* get heightfieldcore */
    HeightfieldTreeNodeCore *hcore = (HeightfieldTreeNodeCore *) getCore(1);
    HeightfieldTreeNodeCore *otherhcore = (HeightfieldTreeNodeCore *) node->getCore(1);

//     if (hcore) {
//       hcore->generateBorder(direction, level, direction&1 ? offset.x:offset.y, otherhcore);
//     }

    if (hcore) { // because the rootnode has none yet
      hcore->generateBorder(direction, level, direction&1 ? offset.x:offset.y, otherhcore);
    }
    if (otherhcore) {
      otherhcore->generateBorder((direction+2) % 4, -level, direction&1 ? offset.x:offset.y, hcore);
    }

    /* generate the corner of the neighbor of the neighbor */
    
    /* begin with the left side */
    int ndir = direction;
    MapPart neighbor2 = getSelectedNeighbor((ndir+3)%4);

    if (neighbor2.node) {
      /* now go to the correct selected child, we need the deepest child that is selected and has a common border */
      Point2DInt childpos = HeightfieldTreeNodeCore::getCornerCoordinates(ndir, 1, 1);
      int childposnr = getChildnr(childpos);
      while(!neighbor2.node->getSelectedForDrawing()) {
      neighbor2.node = neighbor2.node->getChild(childposnr);
      neighbor2.offset *= 2;
      neighbor2.offset += getSimpleTileCoordinates(childposnr);
      neighbor2.level--;
      }
      
      /* now generate the corner at the common border between hcore and getCore(1). The common border
       is (seen from the other tile, hcore) (ndir+1)%4
      */
      hcore = (HeightfieldTreeNodeCore *) neighbor2.node->getCore(1);
      if (hcore && getCore(1)) {
      hcore->generateCorner(ndir, -neighbor2.level, neighbor2.offset, (ndir+3)%4, (HeightfieldTreeNodeCore *) getCore(1), (ndir+1)%4);
      }
    }

    /* now the right side */
    neighbor2 = getSelectedNeighbor((ndir+1)%4);

    if (neighbor2.node) {
      Point2DInt childpos = HeightfieldTreeNodeCore::getCornerCoordinates((ndir+3)%4, 1, 1);
      int childposnr = getChildnr(childpos);
      while(!neighbor2.node->getSelectedForDrawing()) {
      neighbor2.node = neighbor2.node->getChild(childposnr);
      neighbor2.offset *= 2;
      neighbor2.offset += getSimpleTileCoordinates(childposnr);
      neighbor2.level--;
      }
      
      hcore = (HeightfieldTreeNodeCore *) neighbor2.node->getCore(1);
      if (hcore && getCore(1)) {
      hcore->generateCorner((ndir+3)%4, -neighbor2.level, neighbor2.offset, ndir, (HeightfieldTreeNodeCore *) getCore(1), (ndir+3)%4);
      }
    }
  }
  else {
    /* regenerate all children in the given direction */
    if (direction==3 || direction==0) if (getChild(0)) 
      getChild(0)->regenerateHeightfield(node, direction, level+1, offset*2+getSimpleTileCoordinates(0));
    if (direction==0 || direction==1) if (getChild(1)) 
      getChild(1)->regenerateHeightfield(node, direction, level+1, offset*2+getSimpleTileCoordinates(1));
    if (direction==2 || direction==3) if (getChild(2)) 
      getChild(2)->regenerateHeightfield(node, direction, level+1, offset*2+getSimpleTileCoordinates(2));
    if (direction==2 || direction==1) if (getChild(3)) 
      getChild(3)->regenerateHeightfield(node, direction, level+1, offset*2+getSimpleTileCoordinates(3));
  }
}

BoundingSphere *MapTileTreeNode::getBoundingSphere() {
  return(&bs);
}

void MapTileTreeNode::setBoundingSphere(BoundingSphere bs) {
  this->bs = bs;
}

00441 void MapTileTreeNode::generateBoundingSphere() {
  if (getCore(0)) {
    TextureTreeNodeCore *texcore = (TextureTreeNodeCore *) getCore(0);
    Point3D center;
    for(int i=0; i<4; i++) {
      center += *(texcore->getVertex(i));
    }
    center/=4;

    float radius=0, newradius;
    for(int i=0; i<4; i++) {
      newradius = (*(texcore->getVertex(i)) - center).length();
      if (newradius>radius) radius = newradius;
    }

    if (getCore(1)) {
      HeightfieldTreeNodeCore *hcore = (HeightfieldTreeNodeCore *) getCore(1);
      Point3D *vertexarray = hcore->vertexarray;
      for(int i=0; i<hcore->vertexcount; i++) {
      newradius = (vertexarray[i] - center).length();
      if (newradius>radius) radius = newradius;
      }
    }

    bs.center = center;
    bs.radius = radius;
  }
}

void MapTileTreeNode::garbageCollect() {
  if (getSelectedForDrawing()) {
    /* remove deeper nodes */
    for(int i=0; i<4; i++) {
      deleteChild(i);
    }
  }

  if (!getSelectedForDrawing()) {
    getCore(0)->garbageCollect();
//     getCore(1)->garbageCollect();

//     for(int i=0; i<4; i++) {
//       delete(child[i]);
//       child[i]=NULL;
//     }
  }
}

void MapTileTreeNode::setLastNeeded(unsigned long timenr) {
  lastNeeded = timenr;
}

00493 bool MapTileTreeNode::getChildInterpolates() {
  return(childInterpolates);
}

00497 bool MapTileTreeNode::getThisInterpolates() {
  return(thisInterpolates);
}

00501 void MapTileTreeNode::checkThisInterpolates() {
  bool core0i = false;
  bool core1i = false;
  if (cores[0]) if (cores[0]->getThisInterpolates()) core0i = true;
  if (cores[1]) if (cores[1]->getThisInterpolates()) core1i = true;

  /* Start interpolation of this node if texture and heightfield have the new data completed */
  if (core0i && core1i) {
    if (thisInterpolates==false) {
      thisInterpolates = true;
//       interpolationcounter = INTERPOLATIONFRAMES;
    }
    else { // see if we have to finish interpolation now
      if (interpolationcounter<=0) {
//    cores[0]->finishInterpolation();
//    cores[1]->finishInterpolation();
//    thisInterpolates = false;
      }
    }
  }
  else {
    thisInterpolates = false;
  }
}

00526 float MapTileTreeNode::getInterpolationCounter() {
  if (interpolationDirectionIn) {
    return((float(interpolationcounter)/float(INTERPOLATIONFRAMES)));
  }
  else {
    return(1-(float(interpolationcounter)/float(INTERPOLATIONFRAMES)));
  }
}

00535 void MapTileTreeNode::decreaseInterpolationCounter() {
  if (interpolationcounter>0) interpolationcounter--;
}

00539 void MapTileTreeNode::resetInterpolation() {
  interpolationcounter = INTERPOLATIONFRAMES;
}

00543 void MapTileTreeNode::setInterpolationDirection(bool in) {
  interpolationDirectionIn = in;
}

00547 void MapTileTreeNode::setInterpolationCounter(float pos) {
  if (pos>1) pos=1;
  if (pos<0) pos=0;

  interpolationcounter = pos*INTERPOLATIONFRAMES;
}


Generated by  Doxygen 1.6.0   Back to index