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

treeDrawSphere.cpp

#ifdef WIN32
#include "wingl.h"
#else
#define GL_GLEXT_PROTOTYPES
#endif

#include "winconf.h"
#include "treeDrawSphere.h"
#include "heightfieldTreeNodeCore.h"
#include <stdio.h>
#include <qgl.h>
#include <qimage.h>
#include <math.h>
#include <assert.h>
#include "matrix.h"
#include "point4d.h"
#include "heightfieldTree.h"
#include "rect2d.h"
#include "mutex.h"
#include "globaltimer.h"
#include "earth.h"
#include "globalsettings.h"
#include "geometry2d3dFactory.h"

#ifdef FORWARD_VIEW_DRAW
#include <GL/glut.h>
#endif

#include "resources.h"

#include <GL/glext.h>

#define DRAWRADIUS 1

#ifdef STATISTIC_NODECOUNT
#include <fstream>
ofstream statistic_nodecount_stream("statistic_nodecount.txt");
int drawnNodes;
#endif

TreeDrawSphere::TreeDrawSphere(MapTileTree *mtt, ConnectNetworkService *cns, const char *geoType, bool viewatmosphere) 
  : TreeDraw(mtt) {
  this->cns = cns;
  this->gSphere = Geometry2D3DFactory::getFactory()->getGeometry(geoType);
  this->viewatmosphere = viewatmosphere;

//   this->viewatmosphere = true;

#ifdef ATMOSPHERE
  atmospherePixmap = getPixmap("earthatmosphere.png");
  atmosphereTexture = 0;
#endif

  wasSelectedNodes = new vector<MapTileTreeNode *>();
  for(int i=0; i<32*32; i++) defaultHeightfield[i]=0;
  
  /* first request the root node */
  request(mtt->getRootNode()->getCore(0)); // first texture node
  HeightfieldTreeNodeCore *htn = (HeightfieldTreeNodeCore *) mtt->getRootNode()->getCore(1);

  /* create HeightfieldTree, it automatically downloads the root node */
  htree = new HeightfieldTree(cns, htn->getRequestID());
  
  htn->setRequestID("");
  htn->setImage(32, 32, (char *) defaultHeightfield, 32*32*sizeof(float), "RAW");
  requestHeightfield(htn);
}

TreeDrawSphere::~TreeDrawSphere() {
//   delete(drmt);
//   drmt->stopDownload();
  delete(wasSelectedNodes);
  delete(htree);

#ifdef ATMOSPHERE
  if (atmosphereTexture) {
    glDeleteTextures(1, &atmosphereTexture);
  }
#endif
}

DOUBLE TreeDrawSphere::distanceFunction(DOUBLE surfacedistance, DOUBLE distance) {
//   return(distance);

  DOUBLE distdistance = 0;//surfacedistance<0.01 ? distance-surfacedistance:0;
  //  printf("-------------------- surfacedistance = %f\n", surfacedistance);
  if (surfacedistance<0.0006) surfacedistance=0.0006;

  surfacedistance = log(1./surfacedistance)/2.;
  if (surfacedistance<1) surfacedistance = 1;
  return(distance*surfacedistance+distdistance*10.);
}

DOUBLE TreeDrawSphere::getDistance(Point3D *p, Rect2D *rect) {
  DOUBLE surfacedistance = p->length()-DRAWRADIUS-0.01; // distance is distance from surface
  if (surfacedistance<0.0000001) surfacedistance=0.0000001;

  /* get sphere coordinates */
  Point2D coord = gSphere->inverse(*p);
  Point2D result2d; // nearest point

//   printf("coord: %f, %f\n", coord.x, coord.y);

  /* get coordinate of nearest point in 2D grid */
  if (coord.x>rect->p.x && coord.x<rect->p.x+rect->size.x) {
    result2d.x = coord.x;

    // upper or lower edge
    if (coord.y>rect->p.y && coord.y<rect->p.y+rect->size.y) {
      // inside
//       printf("INSIDE %f\n", p->length()-DRAWRADIUS);
      DOUBLE distance = p->length()-DRAWRADIUS; // distance is distance from surface
      return(distanceFunction(surfacedistance, distance));
    }
  }
  else {
    DOUBLE distx = fabs(coord.x-rect->p.x);
    if (1.-distx<distx) distx=1.-distx;

    DOUBLE distx2 = fabs(coord.x-(rect->p.x+rect->size.x));
    if (1.-distx2<distx2) distx2=1.-distx2;

    if (distx<distx2) {
      result2d.x = rect->p.x;
    }
    else {
      result2d.x = rect->p.x + rect->size.x;
    }
  }

  DOUBLE disty = fabs(coord.y-rect->p.y);
  if (1.-disty<disty) disty=1.-disty;
  
  DOUBLE disty2 = fabs(coord.y-(rect->p.y+rect->size.y));
  if (1.-disty2<disty2) disty2=1.-disty2;

  if (disty<disty2) {
    // upper edge
    result2d.y = rect->p.y;
  }
  else {
    // lower edge
    result2d.y = rect->p.y+rect->size.y;
  }

  // inside?
  if (coord.y>rect->p.y && coord.y<rect->p.y+rect->size.y) {
    result2d.y = coord.y;
  }

  assert(result2d.x>=rect->p.x && result2d.x<=rect->p.x+rect->size.x &&
       result2d.y>=rect->p.y && result2d.y<=rect->p.y+rect->size.y);

  Point3D result3d = gSphere->getPoint(result2d);

  DOUBLE distance = (*p-result3d).length();
  return(distanceFunction(surfacedistance, distance));
}


DOUBLE TreeDrawSphere::getDistance(const Point3D *p, Point3D rect[]) {
  // for now I calculate the distance between the middle of the rectangle and the point
  Point3D middle = (rect[0] + rect[1] + rect[2] + rect[3]) / 4;
  Point3D distvector = middle - *p;
  DOUBLE distance_m = distvector.length();
  DOUBLE distance0 = (rect[0]-*p).length();
  DOUBLE distance1 = (rect[1]-*p).length();
  DOUBLE distance2 = (rect[2]-*p).length();
  DOUBLE distance3 = (rect[3]-*p).length();

  DOUBLE distance = min(distance_m, min(min(distance0, distance1), min(distance2, distance3)));

//   cout << "middle: " << middle.x << "," << middle.y << "," << middle.z << " length=" << middle.length() << endl;
  return(distance);
}

float TreeDrawSphere::getMaxEdgeSize(const Point3D *p, Point3D rect[], DOUBLE distance) {
  // size of projection of largest edge of the rectangle

  return(max((rect[2]-rect[0]).length(), (rect[3]-rect[1]).length())/distance); // pow(distance,1.5));
}

void TreeDrawSphere::selectNode(MapTileTreeNode *currentNode, vector<MapTileTreeNode *> *selectedNodes, bool visible) {
  if (!currentNode->getSelectedForDrawing()) {
    selectedNodes->push_back(currentNode);
    currentNode->setSelectedForDrawing(true);
    currentNode->setVisible(visible);
    currentNode->checkThisInterpolates();

    if (currentNode->getParent()) {
      assert(!currentNode->getParent()->getSelectedForDrawing());
    }
    for(int i=0; i<4; i++) {
      if (currentNode->getChild(i)) {
      assert(!currentNode->getChild(i)->getSelectedForDrawing());
      }
    }
  }
}

void TreeDrawSphere::clearWasSelected(vector<MapTileTreeNode *> *wasSelectedNodes) {
  vector<MapTileTreeNode *>::iterator it;
  for(it = wasSelectedNodes->begin(); it!=wasSelectedNodes->end(); it++) {
    (*it)->setWasSelectedForDrawing(false);
  }  
}

void TreeDrawSphere::clearSelections(vector<MapTileTreeNode *> *selectedNodes) {
  vector<MapTileTreeNode *>::iterator it;
  for(it = selectedNodes->begin(); it!=selectedNodes->end(); it++) {
    (*it)->setSelectedForDrawing(false);
    (*it)->setWasSelectedForDrawing(true);
  }
}

void TreeDrawSphere::drawQuad(Point3D a, Point3D b) {
  glTexCoord2f(1,1);
  glVertex3f(-b.x, -b.y, -b.z);
  
  glTexCoord2f(1,0);
  glVertex3f(a.x-b.x, a.y-b.y, a.z-b.z);
  
  glTexCoord2f(0,0);
  glVertex3f(a.x, a.y, a.z);
  
  glTexCoord2f(0,1);
  glVertex3f(0, 0, 0);
}

void TreeDrawSphere::draw(Point3D *viewer, bool viewculling, QGLWidget *widget, Point3D direction, int phase) {
  if (phase!=1) return;

//   printf("TreeDrawSphere::draw start\n");

#ifdef ATMOSPHERE
  /* load atmosphere texture */
  if (atmosphereTexture==0) {
    QImage img  = QGLWidget::convertToGLFormat( atmospherePixmap.convertToImage() );  // flipped 32bit RGBA
    glGenTextures(1, &atmosphereTexture);

#ifdef EARTH3DDEBUG
    printf("bind 1\n");
#endif
    glBindTexture(GL_TEXTURE_2D, atmosphereTexture);   // 2d texture (x and y size)
    /* if width or height is not 2^x, we need to rescale the image */

#ifdef EARTH3DDEBUG
    printf("tex 1\n");
#endif
    if (cacheUseTextureCompression) {
      glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_ARB, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
    }
    else {
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
    }
        
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);     // Linear Filtering
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);     // Linear Filtering
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // prevent wrap artifacts
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // prevent wrap artifacts
  }

  /* view atmosphere texture */
  if (viewatmosphere) {
    Point3D px(1,0,0);
    Point3D n(viewer->normalize());
    Point3D a,b;
    if (n.x==0) {
      a = Point3D(1,0,0);
      b = n.crossproduct(a).normalize();
    }
    else {
      Point3D y(0,1,0);
      a = n.crossproduct(y).normalize(); //       a = Point3D(-n.y/n.x, 1, 0).normalize();
      b = n.crossproduct(a).normalize(); //Point3D(-n.z/n.x, 0, 1).normalize();
    }
#ifdef EARTH3DDEBUG
    printf("skalarprodukt: %f, %f\n", n.skalarprodukt(a), n.skalarprodukt(b));
#endif

    a*=2;
    b*=2;

    /* get parametric plane formula of n*x=0 */

    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glEnable(GL_ALPHA_TEST);
    glAlphaFunc(GL_GREATER, 0.01);

    /* draw ALWAYS ON BACK OF THE SCENE */
    GLfloat range[2];
    glGetFloatv(GL_DEPTH_RANGE, range);
    glDepthRange(0.9,1);
    glDepthFunc(GL_LESS);

#ifdef EARTH3DDEBUG
    printf("bind 2\n");
#endif
    glBindTexture(GL_TEXTURE_2D, atmosphereTexture);

//     glBegin(GL_QUADS);
//     glTexCoord2f(1,1);
//     glVertex3f(0, -2, 0);

//     glTexCoord2f(1,0);
//     glVertex3f(2, -2, 0);

//     glTexCoord2f(0,0);
//     glVertex3f(2, 0, 0);

//     glTexCoord2f(0,1);
//     glVertex3f(0, 0, 0);
//     glEnd();

    GLboolean cullface = glIsEnabled(GL_CULL_FACE);
    glDisable(GL_CULL_FACE);

    glBegin(GL_QUADS);
    drawQuad(a,b);
    drawQuad(-a,b);
    drawQuad(a,-b);
    drawQuad(-a,-b);
    glEnd();

    /* restore environment */
    if (cullface) glEnable(GL_CULL_FACE);
    glDisable(GL_ALPHA_TEST);
    glDepthFunc(GL_LESS);
    glDepthRange(range[0],range[1]);
  }
#endif

//   QMutexLocker mlock(&heightfieldTreeMutex);
  QMutexLocker mlock2(&treelock);

  /* select all nodes that should be drawn
   *
   * it uses a branch and bound algorithm that determines based on
   * the current camera position how deep to descend in the tree
   * before a tile is choosen to be drawn.
   *
   * It creates a vector that keeps track of the selected tiles. It makes
   * it faster to find them when they should be drawn and to deselect them
   * afterwards. */
  vector<MapTileTreeNode *> selectedNodes;

  MapTileTreeNode *currentNode = mtt->getRootNode();


  /* get the current projection and modelview matrix for visibility checking */
  GLfloat projection[16];
  glGetFloatv(GL_PROJECTION_MATRIX, projection);
  GLfloat modelview[16];
  glGetFloatv(GL_MODELVIEW_MATRIX, modelview);

  /* get the resulting matrix */
  GLfloat projmodelmatrix[16];
  Matrix::multiply(projection, modelview, projmodelmatrix);

  frustum.CalculateFrustum();

  /* check if the object/tree should be drawn at all
   */
  
  //   checkHeightfields(&wasSelectedNodes);
  /* distance to surface */
  float distsurface = (*viewer - Point3D(0,0,0)).length()-1; 

#ifdef FORWARD_VIEW
  /* get projection and modelview matrix and multiply forward vector (0,0,1,1) with them */
  Point3D virtualviewer = getVirtualViewer(Point3D(0,0,1), *viewer);
  if (virtualviewer==Point3D(0,0,0)) { // square root cannot be solved, earth not visible in center
    virtualviewer = getVirtualViewer(Point3D(0,-0.2,1), *viewer);
  }
  if (virtualviewer==Point3D(0,0,0)) { // square root cannot be solved, earth not visible in center
    virtualviewer = getVirtualViewer(Point3D(0,-0.4,1), *viewer);
  }
  if (virtualviewer==Point3D(0,0,0)) { // square root cannot be solved, earth not visible in center
    virtualviewer = getVirtualViewer(Point3D(0,-1,1), *viewer);
  }
  if (virtualviewer==Point3D(0,0,0)) { // square root cannot be solved, earth not visible in center
    virtualviewer = getVirtualViewer(Point3D(0,-3,1), *viewer);
  }
  if (virtualviewer==Point3D(0,0,0)) { // square root cannot be solved, earth not visible in center
//     distance = getDistance(&(viewer->normalize()*(1+distsurface/CENTERWEIGHT)), ((HeightfieldTreeNodeCore *)(currentNode->getCore(1)))->getRect());
//     edgeSize = getMaxEdgeSize(viewer, ((TextureTreeNodeCore *)(currentNode->getCore(0)))->vertex, distance);
  }
  else {
    virtualviewer *= 1+distsurface/CENTERWEIGHT;

#ifdef FORWARD_VIEW_DRAW
    glColor3f(1,0,0);
    glEnable(GL_COLOR_MATERIAL);
    glDisable(GL_TEXTURE_2D);
    if (distsurface>0.1) {
      glPushMatrix();
      glTranslatef(virtualviewer.x, virtualviewer.y, virtualviewer.z);
      glutSolidSphere(0.01, 10, 10);
      glPopMatrix();
    }
    
    glBegin(GL_LINES);
    glVertex3f(0,0,0);
    glVertex3f(2*virtualviewer.x, 2*virtualviewer.y, 2*virtualviewer.z);
    glEnd();
    glEnable(GL_TEXTURE_2D);
    glDisable(GL_COLOR_MATERIAL);
#endif

  }
#else
  Point3D virtualviewer = *viewer;

  // Calculate distance between viewer and tile
  DOUBLE distance = getDistance(viewer, ((HeightfieldTreeNodeCore *)(currentNode->getCore(1)))->getRect());
#endif
  
     
  /* start selecting the nodes */
  checkNode(currentNode, &selectedNodes, viewer, &virtualviewer, Rect2D(Point2D(0,0), Point2D(1,1)), projmodelmatrix, modelview, 0, distsurface, direction);

  /* check selected nodes if they are new selected and then inform them and their
     neighbors to adjust their heightfield borders */
  checkHeightfields(&selectedNodes);

  /* draw selected nodes */
  drawNodes(&selectedNodes, viewculling);

#ifdef STATISTIC_NODECOUNT
  statistic_nodecount_stream << (viewer->length()-1.) << " " << drawnNodes << endl; // selectedNodes.size() << endl;
#ifdef EARTH3DDEBUG
  printf("************************* selectedNodes.size: %i\n", selectedNodes.size());
#endif
#endif

  /* clear wasSelected in nodes */
  clearWasSelected(wasSelectedNodes);

  /* run garbage collection to free memory */
  mtt->garbageCollect();
  htree->garbageCollect();
  
  /* clear selection in nodes and set wasSelected */
  clearSelections(&selectedNodes);

  wasSelectedNodes->swap(selectedNodes);

  /* finish this timeframe */
  globaltime++;
}

void TreeDrawSphere::checkHeightfields(vector<MapTileTreeNode *> *selectedNodes) {
  QMutexLocker qml(&heightfieldtreenodecorechanges);

  /* adjust heightfield */
  vector<MapTileTreeNode *>::iterator it;
  for(it = selectedNodes->begin(); it!=selectedNodes->end(); it++) {
    if (((*it)->getSelectedForDrawing()==true && (*it)->getWasSelectedForDrawing()==false) ||
      ((HeightfieldTreeNodeCore *) (*it)->getCore(1))->getInformedNeighbors()==false) {
      (*it)->informNeighborNodes();

      /* if it was due to a heightfield change, start from the beginning */
      if (((HeightfieldTreeNodeCore *) (*it)->getCore(1))->getInformedNeighbors()==false) {
      ((HeightfieldTreeNodeCore *) (*it)->getCore(1))->resetInformedNeighbors();
      it = selectedNodes->begin();
      }
    }
  }

  /* recalculate vertex arrays */
  it = selectedNodes->begin();
  while(it!=selectedNodes->end()) {
    if ((*it)->getSelectedForDrawing()==true/* &&(*it)->getWasSelectedForDrawing()==false*/) {
      HeightfieldTreeNodeCore *hcore = (HeightfieldTreeNodeCore *) (*it)->getCore(1);
      if (hcore) {
        hcore->setBaseGeometry(gSphere, 6378140. / heightfieldmultiplier);
      hcore->generateVertexArray();
      }
    }
    it++;
  }
}

void TreeDrawSphere::bindSingleGLTexture(int textureid, int width, int height, char *image) {
#ifdef EARTH3DDEBUG
  printf("bind 3\n");
#endif
  glBindTexture(GL_TEXTURE_2D, textureid);   // 2d texture (x and y size)
  /* if width or height is not 2^x, we need to rescale the image */

#ifdef EARTH3DDEBUG
  printf("tex 2\n");
#endif

  if (cacheUseTextureCompression) {
    glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_ARB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
  }
  else {
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
  }

  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // prevent wrap artifacts
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // prevent wrap artifacts
}

// static GLuint blendtexture = 0;

void TreeDrawSphere::bindTexture(TextureTreeNodeCore *core) {
  /* get a texture id */
//   glActiveTextureARB(GL_TEXTURE1_ARB);
//   glClientActiveTextureARB(GL_TEXTURE1_ARB);

  if (core->textureid==0 && core->hasImage()) {
    glGenTextures(1, &(core->textureid));
  }

  /* bind texture */
  if ((!core->textureBound || alwaysBind) && core->hasImage()) {
    core->textureBound = true;

    char *image = core->getScaledUncompressedImage(); // calls generate if neccessary
    bindSingleGLTexture(core->textureid, core->getScaledWidth(), core->getScaledHeight(), image);

    core->discardUncompressedImage();
  }

  if (core->textureid) {
    glBindTexture(GL_TEXTURE_2D, core->textureid);   // choose the texture to use.
  }
  else {
    //    glColor3f(((color++) % 13)/13.f,((color++) % 7)/7.f,((color++) % 11)/11.f);
#ifdef EARTH3DDEBUG
    printf("bind 5\n");
#endif
    glBindTexture(GL_TEXTURE_2D, NULL);
  }
  //     glBindTexture(GL_TEXTURE_2D, NULL);
  //     glShadeModel(GL_SMOOTH);
}

void TreeDrawSphere::drawNodes(vector<MapTileTreeNode *> *selectedNodes, bool test) {
  vector<MapTileTreeNode *>::iterator it = selectedNodes->begin();
  int color = 0;

#ifdef STATISTIC_NODECOUNT
  drawnNodes=0;
#endif

  /* disabled, since fog uses origin to measure distance */
//   glEnable(GL_FOG);
//   float fogcolor[4] = {1,1,1,1};
//   glFogfv(GL_FOG_COLOR, fogcolor);
//   glFogf(GL_FOG_START, 0.3);
//   glFogf(GL_FOG_END, 1);
//   glFogi(GL_FOG_MODE, GL_LINEAR);

  /* Set up texture unit 0 */
  glActiveTextureARB(GL_TEXTURE0_ARB);
  glClientActiveTextureARB(GL_TEXTURE0_ARB);
  glEnable(GL_TEXTURE_2D);                    // Enable texture mapping.
  glEnable(GL_COLOR_MATERIAL);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  glColor4f(1., 1., 1., 1.f);

  /* Set up texture unit 1 */
  glActiveTextureARB(GL_TEXTURE1_ARB);
  glClientActiveTextureARB(GL_TEXTURE1_ARB);
  glEnable(GL_TEXTURE_2D);                    // Enable texture mapping.
  glEnable(GL_COLOR_MATERIAL);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE_EXT);
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PRIMARY_COLOR_EXT);
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR);

  glActiveTextureARB(GL_TEXTURE0_ARB);

//   QMutexLocker mlock(&heightfieldTreeMutex);

  while(it!=selectedNodes->end()) {
//     cout << "drawNodes: " << (*it)->getCore(0)->getRequestID() << endl;
    assert((*it)->getSelectedForDrawing());

    TextureTreeNodeCore *core = (TextureTreeNodeCore *)(*it)->getCore(0);
    HeightfieldTreeNodeCore *hcore = (HeightfieldTreeNodeCore *)(*it)->getCore(1);

    /* Vertices */
    if (hcore && (*it)->getVisible()) {
      /* Interpolation */
      (*it)->checkThisInterpolates();
      //     if ((*it)->getThisInterpolates()) {
      
      /* set up second texture unit with target texture */
      glActiveTextureARB(GL_TEXTURE1_ARB);
      glClientActiveTextureARB(GL_TEXTURE1_ARB);
      float blendvalue = (*it)->getInterpolationCounter();
      glColor4f(blendvalue, blendvalue, blendvalue, 1.f);
      glColor4f(1.f, 0.1f, 1.f, 0.5f);
      
      glActiveTextureARB(GL_TEXTURE0_ARB);
      glClientActiveTextureARB(GL_TEXTURE0_ARB);
      
      /* Texture */
      bindTexture(core);

#ifdef RELATIVETRANSFORM
      /* Transform */
      glPushMatrix();
      glTranslatef(hcore->vertexorigin.x, hcore->vertexorigin.y, hcore->vertexorigin.z);
      glScalef(hcore->vertexscale, hcore->vertexscale, hcore->vertexscale);
#endif

#ifdef STATISTIC_NODECOUNT
      drawnNodes++;
#endif
      Point3D *vertexarray = hcore->vertexarray;
      Point2D *texcoordarray = hcore->texcoordarray;

      float heightblendvalue = (*it)->getInterpolationCounter();
      Point3D *vertex = hcore->getInterpolationVertexArray(heightblendvalue); // vertexarray;
      Point2D *texcoord = texcoordarray;

      /* Initialize texture units */
      glActiveTextureARB(GL_TEXTURE0_ARB);
      glClientActiveTextureARB(GL_TEXTURE0_ARB);
      glEnableClientState(GL_VERTEX_ARRAY);
      glEnableClientState(GL_NORMAL_ARRAY);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
      glEnable(GL_COLOR_MATERIAL);
      glColor4f(1.f, 1.f, 1.f, 1.f);

      /* Set second texture only if the user wants multitexturing */
      if (cacheUseMultiTexturing) {
      glActiveTextureARB(GL_TEXTURE1_ARB);
      glClientActiveTextureARB(GL_TEXTURE1_ARB);
      glEnable(GL_TEXTURE_2D);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      
      int interpolationtextureID = core->getInterpolationTextureID();
      if (interpolationtextureID==0) {
        blendvalue = 0;
      }
      else {
        glColor4f(blendvalue, blendvalue, blendvalue, 1.f);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, interpolationtextureID);
      }
      }
      else {
      blendvalue = 0;
      }

      for(int row=0; row<hcore->vertexcount/hcore->stripsize; row++) {
      glActiveTextureARB(GL_TEXTURE0_ARB);
      glClientActiveTextureARB(GL_TEXTURE0_ARB);
      glVertexPointer(3, GLDOUBLE, 0, vertex);
      glNormalPointer(GLDOUBLE, 0, vertex);
      glTexCoordPointer(2, GLDOUBLE, 0, texcoord);

      glActiveTextureARB(GL_TEXTURE1_ARB);
      glClientActiveTextureARB(GL_TEXTURE1_ARB);
      glTexCoordPointer(2, GLDOUBLE, 0, texcoord);

      glActiveTextureARB(GL_TEXTURE0_ARB);
      glClientActiveTextureARB(GL_TEXTURE0_ARB);

#ifdef LINE_MODE
      glDrawArrays(GL_LINE_STRIP, 0, hcore->stripsize);
#else
      if (maptiledrawtype==0) {
        glDrawArrays(GL_TRIANGLE_STRIP, 0, hcore->stripsize);
      }
      else {
        if (maptiledrawtype==1) {
          glDrawArrays(GL_LINE_STRIP, 0, hcore->stripsize);
        }
        else {
          glBegin(GL_LINE_STRIP);
          glVertex3f(hcore->vertex[0].x, hcore->vertex[0].y, hcore->vertex[0].z);
          glVertex3f(hcore->vertex[1].x, hcore->vertex[1].y, hcore->vertex[1].z);
          glVertex3f(hcore->vertex[2].x, hcore->vertex[2].y, hcore->vertex[2].z);
          glVertex3f(hcore->vertex[3].x, hcore->vertex[3].y, hcore->vertex[3].z);
          glVertex3f(hcore->vertex[0].x, hcore->vertex[0].y, hcore->vertex[0].z);
          glEnd();
        }
      }
#endif
      vertex+=hcore->stripsize;
      texcoord+=hcore->stripsize;
      }

      /* draw fans */
      for(int direction=0; direction<4; direction++) {
      Point3D *fanvertexarray = hcore->fanvertexarray[direction];
        Point2D *fantexcoordarray = hcore->fantexcoordarray[direction];
//    glColor3f(0.f, 1.f, 0.f);
//    glBindTexture(GL_TEXTURE_2D, NULL);

      Point3D *vertex = fanvertexarray;
      Point2D *texcoord = fantexcoordarray;

      for(int fan=0; fan<hcore->fancount[direction]; fan++) {
#ifdef LINE_MODE
        glBegin(GL_LINE_STRIP);
#else
        if (maptiledrawtype==0) {
          glBegin(GL_TRIANGLE_FAN);
        }
        else {
          if (maptiledrawtype==1) {
            glBegin(GL_LINE_STRIP);
          }
        }
#endif

        if (cacheUseMultiTexturing) {
          for(int vertexnr=0; vertexnr<hcore->fansize[direction][fan]; vertexnr++) {

            glNormal3f(vertex->x, vertex->y, vertex->z); 
            glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texcoord->x, texcoord->y);
            glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texcoord->x, texcoord->y);
            GLVERTEX3D(vertex->x, vertex->y, vertex->z);

            vertex++;
            texcoord++;
          }
        }
        else {
          for(int vertexnr=0; vertexnr<hcore->fansize[direction][fan]; vertexnr++) {

            glNormal3f(vertex->x, vertex->y, vertex->z); 
            glTexCoord2f(texcoord->x, texcoord->y); 
            /* glTexCoord2f((1./(hcore->tile.width-1))*x, (1./(hcore->tile.height-1))*row); */ 
            glVertex3f(vertex->x, vertex->y, vertex->z);

            vertex++;
            texcoord++;
          }
        }

        glEnd();
      }
      }
    }

#ifdef RELATIVETRANSFORM
    /* Transform */
    glPopMatrix();
#endif
    
    it++;
  }

#ifdef DEPTH_STATISTIC
  /* draw node selection statistic */
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  glOrtho(-3,1,1,-3,0,1);
  glMatrixMode(GL_MODELVIEW);

  glActiveTextureARB(GL_TEXTURE1_ARB);
  glClientActiveTextureARB(GL_TEXTURE1_ARB);
  glDisable(GL_TEXTURE_2D);                    // Disable texture mapping.
  glDisable(GL_LIGHTING);

  glActiveTextureARB(GL_TEXTURE0_ARB);
  glClientActiveTextureARB(GL_TEXTURE0_ARB);
  glDisable(GL_TEXTURE_2D);                    // Disable texture mapping.
  glDisable(GL_LIGHTING);
  glEnable(GL_COLOR_MATERIAL);
//   glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
  it = selectedNodes->begin();
//   glColor4f(1,0,0,1);
//   glRectf(0.5,0,0,0.5);
  while(it!=selectedNodes->end()) {
    HeightfieldTreeNodeCore *hcore = (HeightfieldTreeNodeCore *)(*it)->getCore(1);
    int depth = (*it)->depth;
    glColor3f(0.0*depth, 0.1*depth, 0.1*depth);
    glRectf(hcore->getRect()->p.x+hcore->getRect()->size.x, 
          hcore->getRect()->p.y, 
          hcore->getRect()->p.x,  
          hcore->getRect()->p.y+hcore->getRect()->size.y);

    it++;
  }
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
#endif

  glActiveTextureARB(GL_TEXTURE1_ARB);
  glClientActiveTextureARB(GL_TEXTURE1_ARB);
  glDisable(GL_TEXTURE_2D);                    // Disable texture mapping.
  glDisable(GL_LIGHTING);
  glDisable(GL_COLOR_MATERIAL);
  glDisableClientState(GL_VERTEX_ARRAY);
  glDisableClientState(GL_NORMAL_ARRAY);
  glDisableClientState(GL_TEXTURE_COORD_ARRAY);

  glActiveTextureARB(GL_TEXTURE0_ARB);
  glClientActiveTextureARB(GL_TEXTURE0_ARB);
}

Point3D TreeDrawSphere::getPointOnSphere(Point2D p) {
  return(gSphere->getPoint(p));
}

Point3D TreeDrawSphere::getVirtualViewer(const Point3D &direction, const Point3D &viewer) {
  float v[4];
  for(int x=0; x<4; x++) {
    v[x] = direction.x*frustum.clip[0+x*4] + direction.y*frustum.clip[1+x*4] + direction.z*frustum.clip[2+x*4] + frustum.clip[3+x*4];
  }

  /* find intersection with sphere */
  Point3D pv(v[0], v[1], v[2]);
  pv = pv.normalize();

  Point3D pp(viewer);
  DOUBLE pvpp = pv.skalarprodukt(pp);
  DOUBLE pvpv = pv.skalarprodukt(pv);
  DOUBLE p = 2*pvpp/pvpv;
  DOUBLE q = ((pp.skalarprodukt(pp))-1)/pvpv;

  DOUBLE intersection1 = -p/2.+sqrt(p*p/4-q);
  DOUBLE intersection2 = -p/2.-sqrt(p*p/4-q);
  DOUBLE intersection = min(intersection1, intersection2);

  if (p*p/4-q<0) { // square root cannot be solved, earth not visible in center
    return(Point3D(0,0,0));
  }
  else {
    return(Point3D(viewer.x+pv.x*intersection, 
               viewer.y+pv.y*intersection, 
               viewer.z+pv.z*intersection));
  }  
}

void TreeDrawSphere::checkNode(MapTileTreeNode *currentNode, vector<MapTileTreeNode *> *selectedNodes, Point3D *viewer, Point3D *virtualviewer, Rect2D nodeRect, GLfloat *projmodelmatrix, GLfloat *modelviewmatrix, int depth, float distsurface, Point3D direction) {
  // set this node as used
  currentNode->setLastNeeded(globaltime);

  DOUBLE distance;
  float edgeSize;

#ifdef FORWARD_VIEW
  if (*virtualviewer==Point3D(0,0,0)) { // square root cannot be solved, earth not visible in center
    distance = getDistance(&(viewer->normalize()*(1+distsurface/CENTERWEIGHT)), ((HeightfieldTreeNodeCore *)(currentNode->getCore(1)))->getRect());
  }
  else {
    distance = getDistance(virtualviewer, ((HeightfieldTreeNodeCore *)(currentNode->getCore(1)))->getRect());
  }
#else
  // Calculate distance between viewer and tile
  distance = getDistance(viewer, ((HeightfieldTreeNodeCore *)(currentNode->getCore(1)))->getRect());
#endif

  // Calculate size of the tile
  edgeSize = getMaxEdgeSize(virtualviewer, ((TextureTreeNodeCore *)(currentNode->getCore(0)))->vertex, distance);
//   edgeSize = getMaxEdgeSize(virtualviewer, ((HeightfieldTreeNodeCore *)(currentNode->getCore(1)))->getRect(), distance);

  bool visible = checkVisible(viewer, projmodelmatrix, modelviewmatrix, currentNode, depth, distance);

  //  visible=true;

  for(int childnr=0; childnr<4; childnr++) {
    MapTileTreeNode *child = currentNode->getChild(childnr);
    TextureTreeNodeCore *textureCore = NULL;
    HeightfieldTreeNodeCore *heightCore = NULL;
    int texturewidth = 128;

    if (currentNode) {
      textureCore = (TextureTreeNodeCore *) currentNode->getCore(0);
      heightCore = (HeightfieldTreeNodeCore *) currentNode->getCore(1);
      texturewidth = textureCore->getWidth();
//       printf("texture width: %i heightfield width: %i\n", textureCore->getWidth(), heightCore->getWidth());
    }

    /* check if the currentNode should be drawn in more detail or in
     * the current detail.
     */

    // check if the node needs more detail

    if (depth<MINIMUMDEPTH || (visible && /*distsurface/distance<1*/edgeSize>MAXTILESIZE &&/* || depth<2*/depth<MAXDEPTH && texturewidth>=HEIGHTFIELDWIDTH*3 && (textureCore && textureCore->getDownloaded() && heightCore && heightCore->getDownloaded()))) {
      /* if the child was not yet created and can be requested because it has a RequestID */
      if (child==NULL) {
        if (((TextureTreeNodeCore *)(currentNode->getCore(0)))->getDownloaded()) {
//          ((HeightfieldTreeNodeCore *)(currentNode->getCore(1)))->getDownloaded()) {
//      if (!((TextureTreeNodeCore *)(currentNode->getCore(0)))->getGenerated() &&
//          !((HeightfieldTreeNodeCore *)(currentNode->getCore(1)))->getGenerated()) {
//      if (((TextureTreeNodeCore *)(currentNode->getCore(0)))->getChildRequestID(childnr)!=NULL &&
//          ((HeightfieldTreeNodeCore *)(currentNode->getCore(1)))->getChildRequestID(childnr)!=NULL) {

          /* create the node. Use nodeRect for calculation of coordinates */
          MapTileTreeNode *newNode = new MapTileTreeNode(currentNode);
          newNode->depth = depth;

          Rect2D newNodeRect = getChildRect(childnr, nodeRect);

          /* create texture core */
          TextureTreeNodeCore *newTextureCore = createTextureCore(currentNode, childnr, newNodeRect);

          /* insert core */
          newNode->setCore(0, newTextureCore);

          /* create heightfield core */
          HeightfieldTreeNodeCore *newHeightfieldCore = createHeightfieldCore(currentNode, childnr, newNodeRect, newTextureCore->vertex);

          /* insert core */
          assert(newHeightfieldCore);
          newNode->setCore(1, newHeightfieldCore);

          /* generate bounding sphere */
          newNode->generateBoundingSphere();

          // insert into parent node
          currentNode->setChild(childnr, newNode);
//        newNode->informNeighborNodes();

          // request the nodes
          if (newTextureCore->getRequestID()!=NULL) {
            request(newTextureCore);
          }
          else {
            newTextureCore->setGenerated(false);
            newTextureCore->setDownloaded(true);
          }
          requestHeightfield(newHeightfieldCore);
            
          // select currentNode for drawing or generate deeper node from known data
          selectNode(newNode, selectedNodes, visible);

          /* set interpolation value for the new node */
          float newDistance = getDistance(viewer, ((HeightfieldTreeNodeCore *)(newNode->getCore(1)))->getRect());
          float newEdgeSize = getMaxEdgeSize(viewer, ((TextureTreeNodeCore *)(newNode->getCore(0)))->vertex, newDistance);
          if (newEdgeSize>MAXTILESIZE_2) {
            newNode->setInterpolationCounter(1-(newEdgeSize-MAXTILESIZE_2)/MAXTILESIZE_2);
          }
          else {
            newNode->setInterpolationCounter(1);
          }
        }
        else {
          //        printf("CHECKNODE FOUND CHILD\n");
          /* the tile cannot be yet requested because the download of the parent
             tile is not finished. The parent needs to be drawn */
          selectNode(currentNode, selectedNodes, visible);

          if (edgeSize>MAXTILESIZE_2) {
            currentNode->setInterpolationCounter(1-(edgeSize-MAXTILESIZE_2)/MAXTILESIZE_2);
          }
          else {
            currentNode->setInterpolationCounter(1);
          }
        }
      }
      else {
        /* Calculate angle rectangle of child node */
        Rect2D newNodeRect = getChildRect(childnr, nodeRect);
        
        /* Check this node */
        checkNode(child, selectedNodes, viewer, virtualviewer, newNodeRect, projmodelmatrix, modelviewmatrix,  depth+1, distsurface, direction);
      }
      }
      else {
      // this node has enough detail, draw this one
      selectNode(currentNode, selectedNodes, visible);
//    printf("edgeSize: %f\n", edgeSize);
      if (edgeSize>MAXTILESIZE_2) {
        currentNode->setInterpolationCounter(1-(edgeSize-MAXTILESIZE_2)/MAXTILESIZE_2);
      }
      else {
        currentNode->setInterpolationCounter(1);
      }
      }
  }
}

Rect2D TreeDrawSphere::getChildRect(int childnr, Rect2D &nodeRect) {
  Rect2D newNodeRect = nodeRect;
  if (childnr&1) { // down
    newNodeRect.p.y += newNodeRect.size.y/2.;
  }
  if (childnr<2) { // right
    newNodeRect.p.x += newNodeRect.size.x/2.;
  }
  newNodeRect.size.x/=2.;
  newNodeRect.size.y/=2.;
  
  return(newNodeRect);
}

void TreeDrawSphere::request(MapTileTreeNodeCore *core) {
#ifdef EARTH3DDEBUG
  printf("TreeDrawSphere::request\n");
#endif

  if (core && !core->getRequested()) {
    if (core->getRequestID()!=NULL) {
#ifdef EARTH3DDEBUG
      printf("TreeDrawSphere::request: %s\n", core->getRequestID());
#endif

      core->setRequested(true);
      cns->getOne(core->getRequestID(), core, core, 10);
    }
    else {
      /* it has no request ID so it is like a failed download */
      core->setRequested(true);
      core->setDownloaded(true);
    }
  }
}

void TreeDrawSphere::requestHeightfield(MapTileTreeNodeCore *core) {
#ifdef EARTH3DDEBUG
  printf("TreeDrawSphere::requestHeightfield\n");
#endif

  if (core && !core->getRequested()) {
#ifdef EARTH3DDEBUG  
    printf("TreeDrawSphere::requestHeightfield: %s\n", core->getRequestID());
#endif

    /* ask the HeightfieldTree object to update this core */
    core->setRequested(true);
    htree->request((HeightfieldTreeNodeCore *) core);
//     cns->getOne(core->getRequestID(), drmt, core, 10);
  }
  else {
    core->setRequested(true);
    core->setDownloaded(true);
  }
}

TextureTreeNodeCore *TreeDrawSphere::createTextureCore(MapTileTreeNode *currentNode, int childnr, Rect2D newNodeRect) {
  TextureTreeNodeCore *newTextureCore = new TextureTreeNodeCore();
  newTextureCore->setRequestID(((TextureTreeNodeCore *)(currentNode->getCore(0)))->getChildRequestID(childnr));

  /* Calculate angle rectangle of child node */
  newTextureCore->setVertex(0, getPointOnSphere(newNodeRect.p));
  newTextureCore->setVertex(1, getPointOnSphere(Point2D(newNodeRect.p.x+newNodeRect.size.x, newNodeRect.p.y)));
  newTextureCore->setVertex(2, getPointOnSphere(Point2D(newNodeRect.p.x+newNodeRect.size.x, newNodeRect.p.y+newNodeRect.size.y)));
  newTextureCore->setVertex(3, getPointOnSphere(Point2D(newNodeRect.p.x, newNodeRect.p.y+newNodeRect.size.y)));
        
  /* generate data for core */
  TextureTreeNodeCore *currentTextureCore = (TextureTreeNodeCore *) currentNode->getCore(0);

  int newWidth, newHeight;
  int texWidth, texHeight;
  char *uncompressedimage;

  /* get best available texture */
  if (currentTextureCore->getInterpolationTexture()) {
    texWidth = currentTextureCore->getInterpolationTextureWidth();
    texHeight = currentTextureCore->getInterpolationTextureHeight();
    uncompressedimage = currentTextureCore->getInterpolationTexture();
  }
  else {
    texWidth = currentTextureCore->getWidth();
    texHeight = currentTextureCore->getHeight();
    uncompressedimage = currentTextureCore->getUncompressedImage();
  }

  newWidth = texWidth/2;
  newHeight= texHeight/2;

  int generatedImageSize = newWidth*newHeight*3;
  char *generatedImage = new char[generatedImageSize];
  int xoffset = childnr<2 ? newWidth:0;
  int yoffset = childnr&1 ? newHeight:0;


  /* copy 1/4 of the current texture to the generated texture */
  for(int y=0; y<newHeight; y++) {
    memcpy(generatedImage+y*newWidth*3,
         uncompressedimage+(y+yoffset)*texWidth*3+xoffset*3,
         newWidth*3);      
  }
  newTextureCore->setImage(newWidth, 
                     newHeight,
                     generatedImage, generatedImageSize, "RAW");
  newTextureCore->setGenerated(true);
  delete[](generatedImage);

  return(newTextureCore);
}

HeightfieldTreeNodeCore *TreeDrawSphere::createHeightfieldCore(MapTileTreeNode *currentNode, int childnr, Rect2D newNodeRect, Point3D *vertex) {
  HeightfieldTreeNodeCore *newHeightfieldCore = new HeightfieldTreeNodeCore();
#ifdef EARTH3DDEBUG
  printf("new %xli\n", newHeightfieldCore);
#endif

  newHeightfieldCore->setRequestID(((HeightfieldTreeNodeCore *)(currentNode->getCore(1)))->getChildRequestID(childnr));

  /* generate data for core */
  HeightfieldTreeNodeCore *currentHeightfieldCore = (HeightfieldTreeNodeCore *) currentNode->getCore(1);
  for(int vertexnr=0; vertexnr<4; vertexnr++) {
    newHeightfieldCore->setVertex(vertexnr, vertex[vertexnr]);
  }

  int generatedImageSize = HEIGHTFIELDWIDTH*HEIGHTFIELDHEIGHT;
  float *generatedImageFloat = new float[generatedImageSize];
  //            for(int i=0; i<32*32; i++) generatedImageFloat[i]=depth>2 ? 30:0.;//random()/(RAND_MAX/30);
  //            for(int i=0; i<32*32; i++) generatedImageFloat[i]=random()/(RAND_MAX/30);
  //            for(int i=0; i<32*32; i++) generatedImageFloat[i]=sin(float(i/32)/5)*cos(float(i%32)/5)*20; //random()/(RAND_MAX/30);
            
  /* generate heightfield from current heightfield */
  if (currentHeightfieldCore) {
    float *currentHeightImage = (float *) currentHeightfieldCore->getUncompressedImage();

    int hwidth = currentHeightfieldCore->getWidth();
    int hheight = currentHeightfieldCore->getHeight();
    int hxoffset = childnr<2 ? (hwidth/2):0;
    int hyoffset = childnr&1 ? (hheight/2):0;
    int sx = 2;//(HEIGHTFIELDWIDTH*2)/hwidth;
    int sy = 2;//(HEIGHTFIELDHEIGHT*2)/hheight;

    for(int hy=0; hy<HEIGHTFIELDHEIGHT; hy+=2) {
      for(int hx=0; hx<HEIGHTFIELDWIDTH; hx+=2) {
      /* 0,0 */
      generatedImageFloat[hx+hy*HEIGHTFIELDWIDTH] = 
        currentHeightImage[hxoffset+hx/sx+
                       (hyoffset+hy/sy)*currentHeightfieldCore->getWidth()];
              
      /* 0,1 */
      generatedImageFloat[hx+(hy+1)*HEIGHTFIELDWIDTH] = 
        (currentHeightImage[hxoffset+hx/sx+(hyoffset+hy/sy)*currentHeightfieldCore->getWidth()]
         +currentHeightImage[hxoffset+hx/sx+(hyoffset+hy/sy+1)*currentHeightfieldCore->getWidth()])
        /2.;

      if (hx==HEIGHTFIELDWIDTH-2 || hy==HEIGHTFIELDHEIGHT-2) {
        /* 1,0 */
        generatedImageFloat[(hx+1)+hy*HEIGHTFIELDWIDTH] =
          (currentHeightImage[hxoffset+hx/sx+(hyoffset+hy/sy)*currentHeightfieldCore->getWidth()]);
            
        /* 1,1 */
        generatedImageFloat[(hx+1)+(hy+1)*HEIGHTFIELDWIDTH] = 
          (currentHeightImage[hxoffset+(hx/sx)+(hyoffset+hy/sy)*currentHeightfieldCore->getWidth()]);
      }
      else {
        /* 1,0 */
        generatedImageFloat[(hx+1)+hy*HEIGHTFIELDWIDTH] =
          (currentHeightImage[hxoffset+hx/sx+(hyoffset+hy/sy)*currentHeightfieldCore->getWidth()]
           +currentHeightImage[hxoffset+(hx/sx+1)+(hyoffset+hy/sy)*currentHeightfieldCore->getWidth()])
          /2.;

        /* 1,1 */
        generatedImageFloat[(hx+1)+(hy+1)*HEIGHTFIELDWIDTH] = 
          (currentHeightImage[hxoffset+(hx/sx+1)+(hyoffset+hy/sy)*currentHeightfieldCore->getWidth()]
           +currentHeightImage[hxoffset+hx/sx+(hyoffset+hy/sy+1)*currentHeightfieldCore->getWidth()])
          /2.;
      }
      }
    }
  }
            
  newHeightfieldCore->setBaseGeometry(gSphere, 6378140. / heightfieldmultiplier);
  newHeightfieldCore->setRect(&newNodeRect);
  newHeightfieldCore->setImage(HEIGHTFIELDWIDTH, HEIGHTFIELDHEIGHT, (char *)generatedImageFloat, generatedImageSize*sizeof(float), "RAW");
  newHeightfieldCore->setGenerated(true);

  newHeightfieldCore->generateVertexArray();
  delete[](generatedImageFloat);

  return(newHeightfieldCore);
}

bool TreeDrawSphere::checkVisible(Point3D *viewer, GLfloat *projmodelmatrix, GLfloat *modelviewmatrix, MapTileTreeNode *node, int depth, float distance) {
  if (!node) return(true);

  /* multiply one vector with the matrix */
//   Point3D v = ((TextureTreeNodeCore *)(node->getCore(0)))->vertex[0];

  BoundingSphere *bs = node->getBoundingSphere();
  bool result = frustum.SphereInFrustum(bs->center.x, bs->center.y, bs->center.z, bs->radius);

  if (!result) return(result);

#ifdef DAVE
  return(result);
#endif

  /* calculate sphere cone */
  Point3D spherecenter(0,0,0);
  Point3D axis = spherecenter-*viewer;
  float o = asin(DRAWRADIUS/axis.length());
  Point3D b = bs->center - *viewer;
  float o2 = acos(Matrix::skalarproduct(&axis,&b)/(axis.length()*b.length()));
  bool occresult = o2<o;
//   printf("occresult: %i bs.center: x: %f y: %f z: %f bs.radius: %f v.x: %f v.y: %f v.z: %f axis.x: %f axis.y: %f axis.z: %f o: %f bs.length: %f s.length: %f\n", occresult, bs->center.x, bs->center.y, bs->center.z, bs->radius, viewer->x, viewer->y, viewer->z, axis.x, axis.y, axis.z, o, (*viewer-bs->center).length(), (*viewer-spherecenter).length());
  if (occresult) {
    if (distance/*(*viewer-bs->center).length()*/>(*viewer-spherecenter).length()) {
      occresult = false;
    }
  }
    
//   printf("result: %i\n", occresult);
  if (result) {
    result = occresult;
  }

#ifdef DEBUG_SPHERES  
  if (depth>4) {
    glPushMatrix();
    //   glDisable(GL_TEXTURE_2D);                    // Enable texture mapping.
    glEnable(GL_COLOR_MATERIAL);
    if (result) {
      glColor3f(1.f, 0.f, 0.f);
    }
    else {
      glColor3f(0.f, 1.f, 0.f);
    }
    glTranslatef(bs->center.x, bs->center.y, bs->center.z);
    glutWireSphere(bs->radius,15,15);
    glPopMatrix();
  }
#endif

//   return(true);
  return(result);

}

char *TreeDrawSphere::getType() {
  return("sphere");
}

QImage TreeDrawSphere::getTextureAtCoordinates(DOUBLE x, DOUBLE y) {
  /* get node at coordinates */
  MapTileTreeNode *currentNode = mtt->getRootNode();
  Rect2D nodeRect(Point2D(0,0), Point2D(1,1));
  int childnr;
  while(1) {
    if (x>nodeRect.p.x+nodeRect.size.x/2.) {
      childnr = 0;
    }
    else {
      childnr = 2;
    }
    if (y>nodeRect.p.y+nodeRect.size.y/2.) {
      childnr += 1;
    }

    nodeRect = getChildRect(childnr, nodeRect);

    MapTileTreeNode *child = currentNode->getChild(childnr);
    if (child) {
      currentNode = child;
    }
    else {
      break;
    }
  }

  /* get texture from node */
  TextureTreeNodeCore *texture = (TextureTreeNodeCore *) currentNode->getCore(0);
  QImage resultimage(texture->getWidth(), texture->getHeight(), 32);

  unsigned char *tchar = (unsigned char *) texture->getUncompressedImage();
  for(int y=0; y<texture->getHeight(); y++) {
    for(int x=0; x<texture->getWidth(); x++) {
      resultimage.setPixel(x,y,qRgb(tchar[(x+y*texture->getWidth())*3+0], tchar[(x+y*texture->getWidth())*3+1], tchar[(x+y*texture->getWidth())*3+2]));
    }
  }

  resultimage.detach();
  return(resultimage);
}


Generated by  Doxygen 1.6.0   Back to index