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

heightfieldTreeNodeCore.cpp

#include "heightfieldTreeNodeCore.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "statusObserverQT.h"

#define max(a,b) ((a)>(b) ? (a):(b))
#define min(a,b) ((a)<(b) ? (a):(b))

QMutex heightfieldtreenodecorechanges;

HeightfieldTreeNodeCore::HeightfieldTreeNodeCore()
  : MapTileTreeNodeCore() {
  vertex[0] = Point3D(0,0,0);
  vertex[1] = Point3D(1,0,0);
  vertex[2] = Point3D(1,1,0);
  vertex[3] = Point3D(0,1,0);

  vertexcount = 0;
  vertexarray = NULL;
  vertexarraysize = 0;
  texcoordarray = NULL;
  dirty = true;
  lastDataRow = 0;
  lastDataColumn = 0;
  innerGenerated = false;
  oldBeginx=0;
  oldEndx=32;
  oldBeginy=0;
  oldEndy=32;

  for(int i=0; i<2; i++) heightborder[i]=NULL;
  for(int i=0; i<4; i++) width[i]=0;

  for(int i=0; i<4; i++) fansize[i]=NULL;
  for(int i=0; i<4; i++) fancount[i]=0;
  for(int i=0; i<4; i++) fanvertexarray[i]=NULL;
  for(int i=0; i<4; i++) fantexcoordarray[i]=NULL;

  markedfordebug = false;
  magicdebug = 123456;
  
  geometry=NULL;
  radius=0;

  vertexbackuparray = NULL;
  vertexinterpolationarray = NULL;
  vertexinterpolationarraysize = 0;
  tmpvertexarray = NULL;

  createMapTile();
}

HeightfieldTreeNodeCore::~HeightfieldTreeNodeCore() {
  for(int i=0; i<2; i++) {
    if (heightborder[i]) delete[](heightborder[i]);
  }

  if (vertexarray) {
    free(vertexarray);
    statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, -float(vertexarraysize)*sizeof(Point3D));
  }
  if (texcoordarray) {
    free(texcoordarray);
    statusobserver.changeMemoryOffset(StatusObserver::MEM_TEXCOORD, -float(vertexarraysize)*sizeof(Point2D));
  }

  if (vertexbackuparray) {
    delete[](vertexbackuparray);
    statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, -float(vertexarraysize)*sizeof(Point3D));
  }

  if (vertexinterpolationarray) {
    delete[](vertexinterpolationarray);
    statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, -float(vertexinterpolationarraysize)*sizeof(Point3D));
  }

  if (tmpvertexarray) {
    delete[](tmpvertexarray);
    statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, -float(vertexarraysize)*sizeof(Point3D));
  }

  for(int i=0; i<4; i++) {
    delete[](fansize[i]);
    delete[](fanvertexarray[i]);
    delete[](fantexcoordarray[i]);
  }
}

void HeightfieldTreeNodeCore::createMapTile() {
  if (tile) delete(tile);
  tile = new MapTileUncompressedFloat();
  tile->setBPP(getBPP());
}

void HeightfieldTreeNodeCore::setVertex(int nr, Point3D p) {
  vertex[nr]=p;
}

void HeightfieldTreeNodeCore::setImage(int width, int height, const char *image, int size, const char *type) {
  QMutexLocker qml(&heightfieldtreenodecorechanges);

  assert(width==HEIGHTFIELDWIDTH && height==HEIGHTFIELDHEIGHT);
  if (hasImage()) {
    /* backup old data for inner rectangle to interpolate it with the new data */
    vertexinterpolationarraysize = vertexarraysize;

    /* create vertexinterpolationarray */
    if (vertexinterpolationarray) {
      delete[](vertexinterpolationarray);
      statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, -int(vertexinterpolationarraysize)*sizeof(Point3D));
    }
    vertexinterpolationarray = new Point3D[vertexinterpolationarraysize];
    statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, vertexinterpolationarraysize*sizeof(Point3D));

    /* create vertexbackuparray */
    if (vertexbackuparray) {
      delete[](vertexbackuparray);
      statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, -int(vertexinterpolationarraysize)*sizeof(Point3D));
    }
    vertexbackuparray = new Point3D[vertexinterpolationarraysize];
    statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, vertexinterpolationarraysize*sizeof(Point3D));

    memcpy(vertexbackuparray, vertexarray, vertexinterpolationarraysize*sizeof(Point3D));
    vertexbackuparraydatarect = vertexarraydatarect;
//     for(int i=0; i<vertexinterpolationarraysize; i++) {
//       printf("vertexarray: x: %f y: %f z: %f\n", vertexarray[i].x, vertexarray[i].y, vertexarray[i].z);
//     }
  }

  dirty = true;
  dirtyBorders = true;
  innerGenerated = false;
  informedNeighbors = false;

  /* first set the original image */
  MapTileTreeNodeCore::setImage(width, height, (char *) image, size, type);

  assert(magicdebug == 123456);

  /* move water to 0 */
  float *fimage = (float *) getUncompressedImage();
  
  for(int y=0; y<height; y++) {
    for(int x=0; x<width; x++) {
      if (fimage[y*width+x]==-9999) fimage[y*width+x]=0;
    }
  }

  /* extend to its final size */
  extendImage(width, height, getUncompressedImage());

  char *extendedimage = getUncompressedImage();

  /* copy the borders */
  for(int i=0; i<2; i++) {
    if (heightborder[i]) delete[](heightborder[i]);

    if (i&1) { // top/bottom border
      heightborder[i] = new float[getWidth()];
      int offset = 0;
      for(int x=0; x<getWidth(); x++) {
//    assert(((int *)extendedimage)[x+offset]==0);
      heightborder[i][x]=((float *)extendedimage)[x+offset];
      }
    }
    else { // left/right border
      heightborder[i] = new float[getHeight()];
      int offset = 0;
      for(int y=0; y<getHeight(); y++) {
//    assert(((float *)extendedimage)[y*getWidth()+offset]==0);
      heightborder[i][y]=((float *)extendedimage)[y*getWidth()+offset];
      }
    }
  }

  this->width[0]=getHeight();
  this->width[1]=getWidth();
  this->width[2]=getHeight();
  this->width[3]=getWidth();

  /* create interpolation array */
  generateVertexArray();
}

void HeightfieldTreeNodeCore::extendImage(int width, int height, const char *image) {
  /* extend the tile by one pixel to the right and the bottom */
  int oldwidth, oldheight, size;

  lastDataRow = height-1;
  lastDataColumn = width-1;

  oldwidth = width;
  oldheight = height;

  width++;
  height++;

  float *extended = new float[width*height];

  for(int y=0; y<oldheight; y++) {
    memcpy(extended+y*width, ((float *)image)+y*(oldwidth), (oldwidth)*sizeof(float));
    extended[y*width+width-1]=1000; //DEBUG
  }
  memset(extended+(height-1)*width, 0, sizeof(float)*width); //DEBUG
  size = width*height*sizeof(float);
  
  MapTileTreeNodeCore::setImage(width, height, (char *) extended, size, "RAW");
  
  delete[](extended);
}

void HeightfieldTreeNodeCore::setRect(Rect2D *rect) {
  this->rect = *rect;

#ifdef RELATIVETRANSFORM
  vertexorigin = (vertex[0]+vertex[1]+vertex[2]+vertex[3])/4.;
  vertexscale = (vertex[0]-vertexorigin).length();
#endif 
}

Rect2D *HeightfieldTreeNodeCore::getRect() {
  return(&rect);
}

void HeightfieldTreeNodeCore::setBaseGeometry(Geometry2D3D *geometry, float radius) {
  this->geometry = geometry;
  this->radius = radius;
}

void HeightfieldTreeNodeCore::generateVertexArray() {
  QMutexLocker qml(&vertexarraymutex);
  QMutexLocker qml2(&uncompressedimagemutex);

  if (!dirty) return;
  if (!geometry) return;
  if (markedfordebug) {
//     printf("MARKED GENERATE\n");
  }

  // is the first line drawn normal or in a lower resolution as triangle fan?
  int beginy = width[3]==getWidth() ? 0:1;
  //   int endy = width[1]==getWidth() ? getHeight()-1 : getHeight()-2;
  int endy = width[1]>getWidth()-3 ? getHeight()-1 : getHeight()-2;
  int beginx = width[2]==getHeight() ? 0:1;
  int endx = width[0]>getHeight()-3 ? getWidth() : getWidth()-1;

  vertexarraydatarect = Rect2D(Point2D(beginx, beginy), Point2D(endx-beginx, endy-beginy));

  stripsize = (endx-beginx)*2;

  if (vertexarraysize<stripsize * (getHeight()-1)) {
    vertexarraysize=getWidth() * 2 * (getHeight());
    if (vertexarray) free(vertexarray);
    if (texcoordarray) free(texcoordarray);
    vertexarray = (Point3D *) calloc(vertexarraysize, sizeof(Point3D));
    statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, vertexarraysize*sizeof(Point3D));

    texcoordarray = (Point2D *) calloc(vertexarraysize, sizeof(Point2D));
    statusobserver.changeMemoryOffset(StatusObserver::MEM_TEXCOORD, vertexarraysize*sizeof(Point2D));
  }
  else {
    if (innerGenerated) {
      /* move old data to new positions */
      unsigned int oldstripsize = (oldEndx-oldBeginx)*2;

      int offset = (oldBeginx - beginx)*2;
      int destoffset = offset>0 ? offset:0;
      int sourceoffset = offset<0 ? -offset:0;
      if (oldstripsize>stripsize) {
      for(int row=0; row<oldEndy-oldBeginy; row++) {
        memmove(vertexarray+row*stripsize+destoffset, vertexarray+row*oldstripsize+sourceoffset, stripsize*sizeof(Point3D));
        memmove(texcoordarray+row*stripsize+destoffset, texcoordarray+row*oldstripsize+sourceoffset, stripsize*sizeof(Point2D));
      }
      }
      else {
      for(int row=oldEndy-oldBeginy-1; row>0; row--) {
        memmove(vertexarray+row*stripsize+destoffset, vertexarray+row*oldstripsize+sourceoffset, stripsize*sizeof(Point3D));
        memmove(texcoordarray+row*stripsize+destoffset, texcoordarray+row*oldstripsize+sourceoffset, stripsize*sizeof(Point2D));
      }
      }

      if (oldBeginy>beginy) {
      // insert one row
      memmove(vertexarray+stripsize, vertexarray+0, stripsize*(getHeight()-1)*sizeof(Point3D));
      memmove(texcoordarray+stripsize, texcoordarray+0, stripsize*(getHeight()-1)*sizeof(Point2D));
      }
      if (oldBeginy<beginy) {
      // remove one row
      memmove(vertexarray+0, vertexarray+stripsize, stripsize*(getHeight()-1)*sizeof(Point3D));
      memmove(texcoordarray+0, texcoordarray+stripsize, stripsize*(getHeight()-1)*sizeof(Point2D));
      }
    }
  }

  /* create vertexarray for the inner rectangle */
  int vertexnr=0;
  float *image = (float *) getUncompressedImage();

  DOUBLE minfy=DOUBLE(beginy)/(getHeight()-1), maxfy=0;
  for(int y=beginy; y<endy; y++) {
    vertexnr = (y-beginy)*stripsize;
    
    vertexarray[vertexnr] = geometry->getPoint(rect.p+Point2D((rect.size.x/(getWidth()-1))*beginx, (rect.size.y/(getHeight()-1))*y), 1+(image[beginx+y*getWidth()]/radius));
#ifdef RELATIVETRANSFORM
    vertexarray[vertexnr] -= vertexorigin;
    vertexarray[vertexnr] /= vertexscale;
#endif
    texcoordarray[vertexnr++] = Point2D(DOUBLE(beginx)/(getWidth()-1), DOUBLE(y)/(getHeight()-1));
    vertexarray[vertexnr] = geometry->getPoint(rect.p+Point2D((rect.size.x/(getWidth()-1))*beginx, (rect.size.y/(getHeight()-1))*(y+1)), 1+(image[beginx+(y+1)*getWidth()]/radius));
#ifdef RELATIVETRANSFORM
    vertexarray[vertexnr] -= vertexorigin;
    vertexarray[vertexnr] /= vertexscale;
#endif
    texcoordarray[vertexnr++] = Point2D(DOUBLE(beginx)/(getWidth()-1), DOUBLE(y+1)/(getHeight()-1));
    //     }
    //     else {
    //       vertexnr += 2;
    //     }
    DOUBLE rectxfactor = (rect.size.x/(getWidth()-1));
    DOUBLE rectyfactor = (rect.size.y/(getHeight()-1));

    for(int x=beginx+1; x<endx; x++) {
      if (x<=1 || x>=oldEndx-2 || y<2 || y>=oldEndy-2 || !innerGenerated) {
      if (y>beginy) { // use the vertices of the last row
        vertexarray[vertexnr] = vertexarray[vertexnr-stripsize+1];
      }
      else {
        vertexarray[vertexnr] = geometry->getPoint(rect.p+Point2D(rectxfactor*x, rectyfactor*y), 1+(image[x+y*getWidth()]/radius));
#ifdef RELATIVETRANSFORM
        vertexarray[vertexnr] -= vertexorigin;
        vertexarray[vertexnr] /= vertexscale;
#endif
      }
      DOUBLE fx = DOUBLE(x)/(getWidth()-1);
      DOUBLE fy = DOUBLE(y)/(getHeight()-1);
      texcoordarray[vertexnr++] = Point2D(fx, fy);
      assert(fx>=0 && fx<=1);
//    assert(fy>=0 && fy<=1);
      minfy = min(fy, minfy);
      maxfy = max(fy, maxfy);
      vertexarray[vertexnr] = geometry->getPoint(rect.p+Point2D(rectxfactor*x, rectyfactor*(y+1)), 1+(image[x+(y+1)*getWidth()]/radius));
#ifdef RELATIVETRANSFORM
      vertexarray[vertexnr] -= vertexorigin;
      vertexarray[vertexnr] /= vertexscale;
#endif
      fy = DOUBLE(y+1)/(getHeight()-1);
      minfy = min(fy, minfy);
      maxfy = max(fy, maxfy);
      texcoordarray[vertexnr++] = Point2D(fx, fy);
//    assert(fy>=0 && fy<=1);
       }
      else {
      vertexnr+=2;
      }
    }

//     if (y>=30) {
//       printf("2 generate y(%i)=%f yb=%f\n", y+1, image[endx-1+(y+1)*getWidth()], rect.p.y);
//     }

    assert(vertexnr == (y-beginy+1)*stripsize);
  }
#ifdef DEBUG
  printf("minfy: %f maxfy: %f\n", minfy, maxfy);
#endif

  vertexcount = vertexnr;
  oldBeginx = beginx;
  oldEndx = endx;
  oldBeginy = beginy;
  oldEndy = endy;
  innerGenerated = true;

  /* create vertexarray for the border triangle fans */
  for(int direction=0; direction<4; direction++) {
    if (width[direction]==getWidth()) { // no fan
      fancount[direction]=0;
    }
    else {
      int borderwidth = direction&1 ? getWidth():getHeight();
      int arraysize = borderwidth*2 + width[direction]*2+20; // FIXME

      // for every point on the outer border one fan
      fancount[direction]=width[direction];

      /* create the necessary arrays */
      if (fansize[direction]) delete[](fansize[direction]);
      fansize[direction]=new int[fancount[direction]];

      int thisfancount = 0;
      if (fanvertexarray[direction]) delete[](fanvertexarray[direction]);
      fanvertexarray[direction]=new Point3D[arraysize];

      if (fantexcoordarray[direction]) delete[](fantexcoordarray[direction]);
      fantexcoordarray[direction]=new Point2D[arraysize];

      /* fill in the values */
      Point3D *nextvertex = fanvertexarray[direction];
      Point2D *nexttexcoord=fantexcoordarray[direction];
      int x=0, y=0, r=0, nextx=0, nexty=0;

      int step;
      if (width[direction]-1>1) {
      step = borderwidth/(width[direction]-1);
      }
      else {
      step = borderwidth-1;
      }
      int trianglecount;
//       printf("width=%i, step=%i\n", width[direction], step);

      for(int outerborder=0; outerborder<width[direction]; outerborder++) {

      trianglecount = 0;
      /* start with the middle of the fan */
      r = step*outerborder;
      switch(direction) {
      case 0:
        y=r;
        x=getWidth()-1;
        nextx = x;
        nexty=y+step;
        break;
      case 1:
        x=r;
        y=getHeight()-1;
        nextx=x+step;
        nexty=y;
        break;
      case 2:
        y=r;
        x=0;
        nextx=x;
        nexty=y+step;
        break;
      case 3:
        x=r;
        y=0;
        nextx=x+step;
        nexty=y;
        break;
      }
      *nextvertex = geometry->getPoint(rect.p+Point2D((rect.size.x/(getWidth()-1))*x, (rect.size.y/(getHeight()-1))*y), 1+(image[x+y*getWidth()]/radius));
#ifdef RELATIVETRANSFORM
      *nextvertex -= vertexorigin;
      *nextvertex /= vertexscale;
#endif
      *nexttexcoord = Point2D(DOUBLE(x)/(getWidth()-1), DOUBLE(y)/(getHeight()-1));

//    if (direction==0) {
//      printf("generate y(%i)=%f yb=%f\n", y, image[x+y*getWidth()], rect.size.y);
//    }

      nextvertex++;
      nexttexcoord++;
      trianglecount++;
      assert(nextvertex-fanvertexarray[direction]<arraysize);

      /* and now the outer points of the fan, the inner points of the tile, ordered clockwise */
      int istart = outerborder*step-(step/2), istop = outerborder*step+(step/2), istep=1;
      if (direction==1 || direction==2) {
        int itmp = istop;
        istop = istart;
        istart = itmp;
        istep = -1;
        /* add next outerborder point here */
        if (nextx<getWidth() && nexty<getHeight()) {
          *nextvertex = geometry->getPoint(rect.p+Point2D((rect.size.x/(getWidth()-1))*nextx, (rect.size.y/(getHeight()-1))*nexty), 1+(image[nextx+nexty*getWidth()]/radius));
#ifdef RELATIVETRANSFORM
          *nextvertex -= vertexorigin;
          *nextvertex /= vertexscale;
#endif
          *nexttexcoord = Point2D(DOUBLE(nextx)/(getWidth()-1), DOUBLE(nexty)/(getHeight()-1));
          nextvertex++;
          nexttexcoord++;
          trianglecount++;
        }
      }

      for(int innerborder=istart; (direction==1 || direction==2) ? innerborder>=istop : innerborder<=istop; innerborder+=istep) {
        if (innerborder>=0 && innerborder<borderwidth) {
          r = innerborder;
          
          switch(direction) {
          case 0:
            y=r;
            x=getWidth()-2;
            break;
          case 1:
            x=r;
            y=getHeight()-2;
            break;
          case 2:
            y=r;
            x=1;
            break;
          case 3:
            x=r;
            y=1;
            break;
          }
          *nextvertex = geometry->getPoint(rect.p+Point2D((rect.size.x/(getWidth()-1))*x, (rect.size.y/(getHeight()-1))*y), 1+(image[x+y*getWidth()]/radius));
#ifdef RELATIVETRANSFORM
          *nextvertex -= vertexorigin;
          *nextvertex /= vertexscale;
#endif
          *nexttexcoord = Point2D(DOUBLE(x)/(getWidth()-1), DOUBLE(y)/(getHeight()-1));
          
          nextvertex++;
          nexttexcoord++;
          trianglecount++;
          assert(nextvertex-fanvertexarray[direction]<=arraysize);
        }
      }

      if (direction==3 || direction==0) {
        /* add next outerborder point here */
        if (nextx<getWidth() && nexty<getHeight()) {
          *nextvertex = geometry->getPoint(rect.p+Point2D((rect.size.x/(getWidth()-1))*nextx, (rect.size.y/(getHeight()-1))*nexty), 1+(image[nextx+nexty*getWidth()]/radius));
#ifdef RELATIVETRANSFORM
          *nextvertex -= vertexorigin;
          *nextvertex /= vertexscale;
#endif
          *nexttexcoord = Point2D(DOUBLE(nextx)/(getWidth()-1), DOUBLE(nexty)/(getHeight()-1));
          nextvertex++;
          nexttexcoord++;
          trianglecount++;
        }
      }

      fansize[direction][thisfancount++]=trianglecount;
      }
      
      fancount[direction]=thisfancount;
    }
  }

  dirty = false;

  /* create interpolation array */
  if (vertexbackuparray) {
    /* the interpolation array contains all points from 1 to width-1 */
    int width = getWidth();
    int height = getHeight();
    int newvertexinterpolationarraysize = (width-1)*(height-1)*2;
    vertexinterpolationarraywidth = (width-1);
    if (vertexinterpolationarray) {
      if (vertexinterpolationarraysize!=newvertexinterpolationarraysize) {
#ifdef DEBUG
      printf("vertexarrayinterpolationsize: %i size: %i\n", vertexinterpolationarraysize, sizeof(Point3D));
#endif
      statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, -float(vertexinterpolationarraysize)*sizeof(Point3D));

      vertexinterpolationarraysize=newvertexinterpolationarraysize;
#ifdef DEBUG
      printf("neu vertexarrayinterpolationsize: %i\n", vertexinterpolationarraysize);
#endif
      delete[](vertexinterpolationarray);
      vertexinterpolationarray = new Point3D[vertexinterpolationarraysize];
      statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, vertexinterpolationarraysize*sizeof(Point3D));
      }
    }
    else {
      vertexinterpolationarraysize=newvertexinterpolationarraysize;
      delete[](vertexinterpolationarray);
      vertexinterpolationarray = new Point3D[vertexinterpolationarraysize];
      statusobserver.changeMemoryOffset(StatusObserver::MEM_VERTEX, vertexinterpolationarraysize*sizeof(Point3D));
    }

    int vpos, bpos , bstripsize = vertexbackuparraydatarect.size.x*2;
    for(int y=1; y<height; y++) {
      for(int x=1; x<width; x++) {
      for(int v=0; v<2; v++) {
        vpos = (y-beginy)*stripsize+(x-beginx)*2+v;
        bpos = (y-vertexbackuparraydatarect.p.y)*bstripsize+(x-vertexbackuparraydatarect.p.x)*2+v;

//      assert(((y-1)*vertexinterpolationarraywidth+x-1)*2+v<vertexinterpolationarraysize);
        vertexinterpolationarray[((y-1)*vertexinterpolationarraywidth+x-1)*2+v] = vertexarray[vpos]-vertexbackuparray[bpos];
      }
      }
    }
  }
}

void HeightfieldTreeNodeCore::generateBorder(int direction, int level, int offset, HeightfieldTreeNodeCore *otherhcore) {
  dirty = true;
  dirtyBorders = false;
  assert(direction==0 || direction==1 || direction==2 || direction==3);
  if (markedfordebug) {
//     printf("MARKED BORDER\n");
  }

  float *image = (float *) getUncompressedImage();

  /* for direction 2 and 3 first restore the border and then only use every pow(2,level)st point. 
     This is only necessary if the neighbor has a lower resolution. */
  if (direction==2) {
    //       restoreBorder(direction);
    if (level>0) {
      width[direction]=int(getHeight()/pow(2,level)+1);
    }
    else {
      width[direction]=getHeight();
    }
  }
  if (direction==3) {
    //       restoreBorder(direction);
    if (level>0) {
      width[direction]=int(getWidth()/pow(2,level)+1);
    }
    else {
      width[direction]=getWidth();
    }
  }

  /* for direction 0 and 1 just copy the data from the neighbor */
  /* when the neighbor has a higher resolution, copy a low resolution from there */
  if (direction==0) {
    int othertileoffset = 0;    
    if (level>0) { // we adapt
      width[direction]=int(getHeight()/pow(2,level)+1);
      othertileoffset = int((float(offset)/pow(2,level))*(getHeight()-1));
    }
    else { // they adapt
      width[direction]=getHeight();
      othertileoffset = int(-float(offset)*(getHeight()-1)); // FIXME should be othertile->getWidth()
    }

    float step = pow(0.5,level);

    for(int y=0; y<getHeight(); y++) {
      int thistiley = y;
      int othertiley = float(y)*step+othertileoffset;
      int nextothertiley = float(y)*step+0.5+othertileoffset;
      
      if (othertiley>=0 && othertiley<getHeight()) { // FIXME should be othertile->getHeight()
      float value1 = ((float *)otherhcore->getUncompressedImage())[(othertiley/*+othertileoffset*/)*otherhcore->getWidth()];
      float thisvalue = value1;
      float oldvalue = image[thistiley*getWidth()+(getWidth()-1)];
      image[thistiley*getWidth()+(getWidth()-1)]=thisvalue;
      if (othertileoffset<0) {
      }
      }
    }
  }
  if (direction==1) {
    int othertileoffset = 0;    
    if (level>0) { // we adapt
      width[direction]=getWidth()/pow(2,level)+1;
      othertileoffset = (float(offset)/pow(2,level))*(getWidth()-1);
    }
    else { // they adapt
      width[direction]=getWidth();
      othertileoffset = -float(offset)*(getWidth()-1); // FIXME should be othertile->getWidth()
    }

    float step = pow(0.5,level);

    for(int x=0; x<getWidth(); x++) {
      int thistilex = x;
      int othertilex = float(x)*step+othertileoffset;
      int nextothertilex = float(x)*step+0.5+othertileoffset;

      if (othertilex>=0 && othertilex<getWidth()/* &&
                                       nextothertilex>=0 && nextothertilex<getWidth()*/) { // FIXME should be othertile->getWidth()
      float value1 = ((float *)otherhcore->getUncompressedImage())[(othertilex)];
      float thisvalue = value1;
      image[thistilex+getWidth()*(getHeight()-1)]=thisvalue;
      }
    }
  }
}

void HeightfieldTreeNodeCore::restoreBorder(int direction) {
  dirty = true;
  assert(direction==2 || direction==3);

  direction -=2;

  float *image = (float *) getUncompressedImage();

  if (direction&1) { // top/bottom border
    int offset = 0;
    for(int x=0; x<getWidth(); x++) {
//       assert(heightborder[direction][x]==0);
      ((float *)image)[x+offset] = heightborder[direction][x];
    }
  }
  else { // left/right border
    int offset = 0;
    for(int y=0; y<getHeight(); y++) {
//       assert(heightborder[direction][y]==0);
      ((float *)image)[y*getWidth()+offset] = heightborder[direction][y];
    }
  }
}

float *HeightfieldTreeNodeCore::getBorder(int direction) {
  return(heightborder[direction]);
}

int HeightfieldTreeNodeCore::getLastDataRow() {
  return(lastDataRow);
}

int HeightfieldTreeNodeCore::getLastDataColumn() {
  return(lastDataColumn);
}

Point2DInt HeightfieldTreeNodeCore::getCornerCoordinates(int direction, int maxx, int maxy) {
  int x=0,y=0;

  switch(direction) {
  case 0:
    x=maxx;
    y=maxy;
    break;
  case 1:
    x=0;
    y=maxy;
    break;
  case 2:
    x=0;
    y=0;
    break;
  case 3:
    x=maxx;
    y=0;
    break;
  }

  return(Point2DInt(x,y));
}

void HeightfieldTreeNodeCore::generateCorner(int direction, int level, Point2DInt offset, int othertiledirection, HeightfieldTreeNodeCore *otherhcore, int matchingborder) {
//   return;
  Point2DInt thisCorner, otherCorner;

  /* calculate offset */
  if (level<0) {
    Point2DInt poffset = Point2DInt(0,0);

    if (matchingborder&1) {
      poffset.x = offset.x*((getWidth()-1)/pow(2,-level));
      thisCorner = getCornerCoordinates(direction, int((getWidth()-1)/pow(2,-level)), (getHeight()-1));
    }
    else {
      poffset.y = offset.y*((getHeight()-1)/pow(2,-level));
      thisCorner = getCornerCoordinates(direction, (getWidth()-1), int((getHeight()-1)/pow(2,-level)));
    }
//     if (othertiledirection==0 && matchingborder==2) {
//       poffset.y+=(getHeight()-1)/pow(2,-level);
//     }

    thisCorner += poffset;
  }
  else {
    thisCorner = getCornerCoordinates(direction, getWidth()-1, getHeight()-1);
  }

  if (thisCorner.x==0 && thisCorner.y==0) return;
  if (markedfordebug) {
//     printf("MARKED CORNER\n");
  }

  if (level<0) {
    if ((thisCorner.x>0 && thisCorner.x<getWidth()-1) || (thisCorner.y>0 && thisCorner.y<getHeight()-1)) {
      return;
    }
  }

  otherCorner = getCornerCoordinates(othertiledirection, otherhcore->getWidth()-1, otherhcore->getHeight()-1);

  float *image = (float *) getUncompressedImage();
  float newvalue, oldvalue;
//   printf("corner: x: %i y: %i\n", thisCorner.x, thisCorner.y);
  if (thisCorner.x==0 &&  thisCorner.y==0) return;
  assert(!(thisCorner.x==16 &&  thisCorner.y==16));
  assert(thisCorner.x+thisCorner.y*getWidth()<getUncompressedImageSize()/sizeof(float));
  oldvalue = image[thisCorner.x+thisCorner.y*getWidth()];
  assert(otherCorner.x+otherCorner.y*otherhcore->getWidth()<getUncompressedImageSize()/sizeof(float));
  newvalue = ((float *)otherhcore->getUncompressedImage())[otherCorner.x+otherCorner.y*otherhcore->getWidth()];
//   printf("oldvalue: %f newvalue: %f\n", oldvalue, newvalue);
//   newvalue = 0;
  if (oldvalue!=newvalue) {
//     printf("this: %li new value: %f thisCorner: %i, %i otherCorner: %i, %i direction: %i level: %i othertiledirection: %i matchingborder: %i offset: %i, %i\n", this, newvalue, thisCorner.x, thisCorner.y, otherCorner.x, otherCorner.y, direction, level, othertiledirection, matchingborder, offset.x, offset.y);
    image[thisCorner.x+thisCorner.y*getWidth()]=newvalue;
    dirty = true;
  }
}

float HeightfieldTreeNodeCore::getCorner(int x, int y) {
  assert(x==0 || x==1);
  assert(y==0 || y==1);

  return(((float *)getUncompressedImage())[x*(getWidth()-1)+y*getWidth()*(getHeight()-1)]);
}

void HeightfieldTreeNodeCore::setCorner(int x, int y, float value) {
  assert(x==0 || x==1);
  assert(y==0 || y==1);

  ((float *)getUncompressedImage())[x*(getWidth()-1)+y*getWidth()*(getHeight()-1)]=value;
}

int HeightfieldTreeNodeCore::getBPP() {
  return(sizeof(float));
}

bool HeightfieldTreeNodeCore::isDirtyBorders() {
  return(dirtyBorders);
}

void HeightfieldTreeNodeCore::resetInformedNeighbors() {
  informedNeighbors = true;
}

bool HeightfieldTreeNodeCore::getInformedNeighbors() {
  return(informedNeighbors);
}

bool HeightfieldTreeNodeCore::getThisInterpolates() {
  return(vertexinterpolationarray!=NULL);
}

void HeightfieldTreeNodeCore::finishInterpolation() {
}

Point3D *HeightfieldTreeNodeCore::getInterpolationVertexArray(float interpolationpos) {
  QMutexLocker qml(&heightfieldtreenodecorechanges);
  QMutexLocker qml2(&vertexarraymutex);

//   printf("interpolationpos: %f\n", interpolationpos);
  if (interpolationpos>1) interpolationpos=1;
  if (interpolationpos<0) interpolationpos=0;

  if (vertexbackuparray) {
    /* allocate memory for the array */
    if (tmpvertexarray) {
      if (tmpvertexarraysize!=vertexarraysize) {
      delete[](tmpvertexarray);
      tmpvertexarraysize = vertexarraysize;
      tmpvertexarray = new Point3D[tmpvertexarraysize];
      }
    }
    else {
      tmpvertexarraysize = vertexarraysize;
      tmpvertexarray = new Point3D[tmpvertexarraysize];
    }
    
    /* create the array. we need to take the border from vertexarray and to interpolate the inner rectangle */
//     assert(vertexinterpolationarraysize==vertexarraysize);
    int width=getWidth(), height=getHeight(), vpos, ipos;
    int by=vertexarraydatarect.p.y, ey=vertexarraydatarect.size.y+vertexarraydatarect.p.y;
    int bx=vertexarraydatarect.p.x, ex=vertexarraydatarect.size.x+vertexarraydatarect.p.x;
    int stripsize = (ex-bx)*2;
    int istripsize = vertexinterpolationarraywidth*2;
    int i=0;
    for(int y=by; y<ey; y++) {
      for(int x=bx; x<ex; x++) {
      for(int v=0; v<2; v++) {
//      assert(vertexarray[(y-by)*stripsize+(x-bx)*2+v]==vertexarray[(y-by+v)*stripsize+(x-bx)*2]);
        if (y<1 && v==1) {
          ipos = y*istripsize+(x-1)*2+v;
          vpos = (y-by+v)*stripsize+(x-bx)*2;
        }
        else {
          ipos = (y-1)*istripsize+(x-1)*2+v;
          vpos = (y-by)*stripsize+(x-bx)*2+v;
        }

        if (x<=bx+1 || (y+v)<=by+1 || x>=ex-1 || (y+v)>=ey-1) {
          /* get border from vertexarray */
          tmpvertexarray[i++] = vertexarray[vpos];
        }
        else {
          /* get inner area from interpolation */
          tmpvertexarray[i++] = vertexarray[vpos]-vertexinterpolationarray[ipos]*interpolationpos;
        }
      }
      }
    }
    assert(i==vertexcount);
  }
  else {
    return(vertexarray);
  }

  /* return the array */
  return(tmpvertexarray);
}

void HeightfieldTreeNodeCore::garbageCollect() {
  MapTileTreeNodeCore::garbageCollect();


}


Generated by  Doxygen 1.6.0   Back to index