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

drawScene.cpp

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

#include "drawScene.h"
#include "drawSceneObject.h"
#include "drawSceneObjectTriangle.h"
#include "drawSceneObjectSphere.h"
#include "drawSceneObjectQuad.h"
#include "drawSceneObjectTexture.h"
#include "drawSceneObjectTranslate.h"
#include "drawSceneObjectScale.h"
#include "drawSceneObjectRotatequaternion.h"
#include "drawSceneObjectGroup.h"
#include "drawSceneObjectUseGroup.h"
#include "qGLWidgetDrawScene.h"
#include "globalsettings.h"
#include <assert.h>
#include "glcontext.h"

#include <GL/glext.h>

using namespace std;

openglarray *openglarray::clone() {
  openglarray *result = new openglarray();
  result->texture = texture;
  result->vertexcount = vertexcount;
  result->vertexarray = new Point3D[vertexcount];
  memcpy(result->vertexarray, vertexarray, vertexcount * sizeof(Point3D));
  result->texcoordarray = new Point2D[vertexcount];
  memcpy(result->texcoordarray, texcoordarray, vertexcount * sizeof(Point2D));

  return(result);
}

firstLevelOpenGLArray::firstLevelOpenGLArray(std::vector<openglarray *> &openglarrayList) {
  this->openglarrayList = openglarrayList;

  for(int i=0; i<PBR_ANGLES_COUNT+2; i++) {
    delete[](pbrlist[i].vertexarray);
    pbrlist[i].vertexarray = NULL;
    delete[](pbrlist[i].colorarray);
    pbrlist[i].colorarray = NULL;
  }
}

DrawScene::DrawScene(int drawphase, bool usePBR) {
  printf("DrawScene %i\n", usePBR);
  this->drawphase = drawphase;
  this->usePBR = usePBR;

  unfinishedDownloads = 0;
  downloadsFinished = false;
  parseFinished = false;

  /* create glwidget for off screen rendering */
  if (usePBR) {
    glwidget = new QGLWidgetDrawScene(this);
    GLContext *context = new GLContext(glwidget->format(), glwidget);
    glwidget->setContext(context);
    glwidget->setFixedSize(QSize(PBR_IMAGE_SIZE, PBR_IMAGE_SIZE));
  }
  else {
    glwidget = NULL;
  }

  pointbasedrendering_generated = false;
  pbrphase=0;
  printf("DrawScene end\n");
}

DrawScene::~DrawScene() {
  printf("~DrawScene\n");
  clear();
  if (glwidget) delete(glwidget);
  eraseFirstLevelArray(firstlevelcompilelist);
  eraseFirstLevelArray(groupcompilelist);
  eraseGroupPBRList();
}

void DrawScene::draw(Point3D *viewer, bool viewculling, QGLWidget *widget, Point3D direction, int phase) {
  printf("DrawScene::draw phase=%i drawphase=%i downloadsFinished=%i  pointbasedrendering_generated=%i\n", phase, drawphase, downloadsFinished, pointbasedrendering_generated);
  if (phase != drawphase) return;

  QMutexLocker qml(&changeMutex);

  if (downloadsFinished && pointbasedrendering_generated) {
    /* draw compiled scene */
    printf("DrawScene::draw pointbased\n");

    /* set environment */
    glEnable(GL_DEPTH_TEST);

    glActiveTextureARB(GL_TEXTURE1_ARB);
    glClientActiveTextureARB(GL_TEXTURE1_ARB);
    glDisableClientState(GL_COLOR_ARRAY);
    glDisable(GL_TEXTURE_2D);                    // Disable texture mapping.
    glDisable(GL_LIGHTING);
    glDisable(GL_COLOR_MATERIAL);
    glBindTexture(GL_TEXTURE_2D, NULL);
  
    glActiveTextureARB(GL_TEXTURE0_ARB);
    glClientActiveTextureARB(GL_TEXTURE0_ARB);
    glDisable(GL_COLOR_MATERIAL);
    glDisable(GL_LIGHTING);
    glColor4f(1,1,1,1);
    
    GLboolean cullface = glIsEnabled(GL_CULL_FACE);
    glDisable(GL_CULL_FACE);

#ifndef WIN32
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glEnable(GL_ALPHA_TEST);
    glAlphaFunc(GL_GREATER, 0.1);
#endif
//     glAlphaFunc(GL_GREATER, 0.9);
    
    GLint viewport[4];
    glGetIntegerv( GL_VIEWPORT, viewport );

    /* draw first level objects */
    std::vector<firstLevelOpenGLArray *>::iterator fi;
    for (fi = firstlevelcompilelist.begin(); fi != firstlevelcompilelist.end(); fi++) {
      firstLevelOpenGLArray *current = (firstLevelOpenGLArray *) (*fi);

      /* get size of object */
      float distance = (current->bs_center-*viewer).length()-current->bs_radius;
      float sizeobject = (viewport[2]*current->bs_radius)/(distance+1); // old: viewport[2]/(distance+1)
      printf("sizeobject: %f\n", sizeobject);
      if (usePBR && sizeobject<PBR_IMAGE_SIZE/42) {
      /* draw points */
      glPointSize(3);
      
      /* use nearest angle */
      float alpha;
      
      Point2D p2d = sphere.inverse(*viewer-current->bs_center);
      alpha = 1-p2d.x;
      
      int a = PBR_ANGLES_COUNT+float(PBR_ANGLES_COUNT)*alpha-0.5;
      printf("alpha: %f a: %i na: %f\n", alpha, a, float(PBR_ANGLES_COUNT)*alpha-0.5);
      a+=PBR_ANGLES_COUNT-1;
      a = a % PBR_ANGLES_COUNT;

      glEnableClientState(GL_COLOR_ARRAY);
      glEnableClientState(GL_VERTEX_ARRAY);
      glDisableClientState(GL_TEXTURE_COORD_ARRAY);
      glDisable(GL_TEXTURE_2D);
      glEnable(GL_COLOR_MATERIAL);
      
      for(int i=a-PBR_USE_ANGLES_AROUND; i<=a+PBR_USE_ANGLES_AROUND; i++) {
        int pentry = (i+PBR_ANGLES_COUNT) % PBR_ANGLES_COUNT;

//      for(int a=0; a<current->pbrlist[pentry].vertexcount; a++) {
//        assert((current->pbrlist[pentry].vertexarray[a]-current->bs_center).length()<current->bs_radius);
//      }

        glVertexPointer(3, GLDOUBLE, 0, current->pbrlist[pentry].vertexarray);
        glColorPointer(3, GLDOUBLE, 0, current->pbrlist[pentry].colorarray);
        glDrawArrays(GL_POINTS, 0, 10/*current->pbrlist[pentry].vertexcount*//*/10*CENTERWEIGHT*/);
        //  printf("vertexcount[%i]=%i\n", i, pbrlist[pentry].vertexcount);
      }

      // top/bottom
      if (p2d.y<0.5) { // top
        int pentry = PBR_ANGLES_COUNT;
        glVertexPointer(3, GLDOUBLE, 0, current->pbrlist[pentry].vertexarray);
        glColorPointer(3, GLDOUBLE, 0, current->pbrlist[pentry].colorarray);
        glDrawArrays(GL_POINTS, 0, 10/*current->pbrlist[pentry].vertexcount*//*/10*CENTERWEIGHT*/);
      }
      else { // bottom
        int pentry = PBR_ANGLES_COUNT+1;
        glVertexPointer(3, GLDOUBLE, 0, current->pbrlist[pentry].vertexarray);
        glColorPointer(3, GLDOUBLE, 0, current->pbrlist[pentry].colorarray);
        glDrawArrays(GL_POINTS, 0, 10/*current->pbrlist[pentry].vertexcount*//*/10*CENTERWEIGHT*/);
      }

      glDisableClientState(GL_COLOR_ARRAY);
      }
      else {
      /* draw triangles */
      printf("DrawScene::draw triangles\n");

      glEnable(GL_TEXTURE_2D);
      glDisable(GL_COLOR_MATERIAL);
      glDisableClientState(GL_COLOR_ARRAY);
      glEnableClientState(GL_VERTEX_ARRAY);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

      std::vector<openglarray *>::iterator i;
      for (i = current->openglarrayList.begin(); i != current->openglarrayList.end(); i++) {
        openglarray *ocurrent = *i;
#ifdef WIN32
        assert((*i)->magic==1234);
#endif
        /* set texture */
#ifdef WIN32
        if (ocurrent->texture->hasAlpha()) {
          glEnable (GL_BLEND);
          glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
          
          glEnable(GL_ALPHA_TEST);
          glAlphaFunc(GL_GREATER, 0.1);
        }
#endif
        glBindTexture(GL_TEXTURE_2D, ocurrent->texture->getTextureID(false));   // choose the texture to use.
        
        /* draw arrays */
        //       printf("DrawScene::vertexcount=%i\n", current->vertexcount);
        glVertexPointer(3, GLDOUBLE, 0, ocurrent->vertexarray);
        glTexCoordPointer(2, GLDOUBLE, 0, ocurrent->texcoordarray);
        printf("draw: %i %li %li %i\n", ocurrent->texture->getTextureID(false), ocurrent->vertexarray, ocurrent->texcoordarray, ocurrent->vertexcount);
        glDrawArrays(GL_TRIANGLES, 0, ocurrent->vertexcount);
        printf("draw done\n");

#ifdef WIN32
        if (ocurrent->texture->hasAlpha()) {
          glDisable (GL_BLEND);
          glDisable(GL_ALPHA_TEST);
        }
#endif
      }
      }
    }
    printf("DrawScene::draw end\n");

    /* restore environment */
    if (cullface) glEnable(GL_CULL_FACE);
    glDisable(GL_ALPHA_TEST);
    glDisable (GL_BLEND);
  }

}

void DrawScene::clear() {
  /* delete all scene objects */
  std::vector<DrawSceneObject *>::iterator i;
  for (i = fullList.begin(); i != fullList.end(); i++) {
    delete(*i);
  }

  fullList.clear();
}

void DrawScene::fillSceneData(QDomNode n) {
  printf("fillSceneData\n");
  QMutexLocker qml(&changeMutex);

  /* parse document */
  while( !n.isNull() ) {
    /* parse the object, it will register itself automatically with this object 
       in the fulllist */
    DrawSceneObject *object = parseObject(n);

    if (object) {
      rootList.push_back(object);
    }

    n = n.nextSibling();
  }

  parseFinished = true;

  /* see if we can start drawing */
  if (unfinishedDownloads==0) {
    /* clear pbr data and compiled data */
    eraseFirstLevelArray(firstlevelcompilelist);
    eraseFirstLevelArray(groupcompilelist);
    eraseGroupPBRList();
    pointbasedrendering_generated = false;

    /* compile scene */
    compile();

    /* start drawing */
    downloadsFinished = true;
  }
  printf("fillSceneData end\n");
}

void DrawScene::eraseFirstLevelArray(std::vector<firstLevelOpenGLArray *> &firstlevelcompilelist) {
  std::vector<firstLevelOpenGLArray *>::iterator fi;
  for (fi = firstlevelcompilelist.begin(); fi != firstlevelcompilelist.end(); fi++) {
    firstLevelOpenGLArray *current = (firstLevelOpenGLArray *) (*fi);

    /* openglarray list */
    DrawSceneObject::deleteList(current->openglarrayList);
    current->openglarrayList.clear();

    /* point based rendering list */
    // pbr_list contains deletes
//     for(int i=0; i<PBR_ANGLES_COUNT+2; i++) {
//       delete[](current->pbrlist[i].vertexarray);
//       delete[](current->pbrlist[i].colorarray);
//     }

    /* delete object itself */
    delete(current);
  }
  firstlevelcompilelist.clear();
}

void DrawScene::eraseGroupPBRList() {
  /* erase old pbrlist */
  for(int g=0; g<PBR_ANGLES_COUNT+2; g++) {
    grouppbrlist[g].vertexcount = 0;
    delete[](grouppbrlist[g].vertexarray);
    delete[](grouppbrlist[g].colorarray);
    grouppbrlist[g].vertexarray = new Point3D[1];
    grouppbrlist[g].colorarray = new Point3D[1];
  }
}

void DrawScene::compile() {
  compileMutex.lock();

  if (pbrphase==1 && usePBR) {
    /* save the pbr data in the group objects */
    std::vector<firstLevelOpenGLArray *>::iterator gi;
    for (gi = groupcompilelist.begin(); gi != groupcompilelist.end(); gi++) {
      firstLevelOpenGLArray *current = (firstLevelOpenGLArray *) (*gi);
      current->group->setPBR(current->pbrlist);
    }
  }

  /* erase old list */
  eraseFirstLevelArray(firstlevelcompilelist);

  /* create new list */
  std::vector<DrawSceneObject *>::iterator i;
  for (i = rootList.begin(); i != rootList.end(); i++) {
    std::vector<openglarray *> compilelist;

    eraseGroupPBRList();

    (*i)->compile(compilelist, grouppbrlist);

    /* do not insert empty elements, e.g. group or texture objects */
    if (compilelist.size()>0) {
      firstLevelOpenGLArray *fa = new firstLevelOpenGLArray(compilelist);
      for(int p=0; p<PBR_ANGLES_COUNT+2; p++) {
      fa->pbrlist[p].vertexcount = grouppbrlist[p].vertexcount;
      fa->pbrlist[p].vertexarray = grouppbrlist[p].vertexarray;
      grouppbrlist[p].vertexarray = new Point3D[1];
      fa->pbrlist[p].colorarray = grouppbrlist[p].colorarray;
      grouppbrlist[p].colorarray = new Point3D[1];

//    for(int a=0; a<fa->pbrlist[p].vertexcount; a++) {
//      assert((fa->pbrlist[p].vertexarray[a]-fa->bs_center).length()<fa->bs_radius);
//    }

      }
      firstlevelcompilelist.push_back(fa);
    }
  }

  /* create bounding spheres */
  createBoundingSpheres(firstlevelcompilelist);

  /* create PBR */
  if (!pointbasedrendering_generated) {

    if (pbrphase==0) {
      pbrphase++;

      /* erase old list */
      eraseFirstLevelArray(groupcompilelist);

      /* generate group objects */
      std::vector<DrawSceneObjectGroup *>::iterator gi;
      for (gi = groupList.begin(); gi != groupList.end(); gi++) {

      /* compile single group object */
      std::vector<openglarray *> targetlist;
      (*gi)->compileGroup(targetlist, NULL);

      /* add to pbr phase 0 list */
      firstLevelOpenGLArray *fa = new firstLevelOpenGLArray(targetlist);
      fa->group = (*gi);
      groupcompilelist.push_back(fa);
      }

      createBoundingSpheres(groupcompilelist);

      /* get pbr data for this list */
      if (groupcompilelist.size()>0 && usePBR) {
      glwidget->setPBRList(groupcompilelist);
      glwidget->show();
      glwidget->start();
      compileMutex.unlock();
      }
      else {
      compileMutex.unlock();
      setFinishedPBR();
      }
    }
    else {
      pbrphase++;

      int entries = 0;
      std::vector<firstLevelOpenGLArray *>::iterator fi;
      for (fi = firstlevelcompilelist.begin(); fi != firstlevelcompilelist.end(); fi++) {
      if ((*fi)->pbrlist[0].vertexcount==0 && (*fi)->openglarrayList.size()>0) {
        entries++;
      }
      }

      /* generate first level objects using data from group objects */
      if (entries>0 && usePBR) {
      glwidget->setPBRList(firstlevelcompilelist);
      glwidget->show();
      compileMutex.unlock();
      if (glwidget->running) {
        glwidget->run();
      }
      else {
        glwidget->start();
      }
      }
      else {
      compileMutex.unlock();
      setFinishedPBR();
      }
    }

    
    /* Generate point based rendering data */
    /* render object in background buffer */
//     glwidget->renderPBRData(pbrlist, PBR_ANGLES_COUNT, PBR_ANGLES_ELEVATION, PBR_USE_ANGLES_AROUND);
//     QPixmap pixmap = glwidget->renderPixmap(500, 500);
    
//     /* DEBUG save image */
//     pixmap.save("pixmap.png", "PNG");

  }
  else {
    compileMutex.unlock();
  }
}

void DrawScene::createBoundingSpheres(std::vector<firstLevelOpenGLArray *> &firstlevelcompilelist) {
  std::vector<firstLevelOpenGLArray *>::iterator fi;
  for (fi = firstlevelcompilelist.begin(); fi != firstlevelcompilelist.end(); fi++) {
    firstLevelOpenGLArray *current = (firstLevelOpenGLArray *) (*fi);

    createBoundingSphere(current->openglarrayList, current->bs_center, current->bs_radius);
  }
}

void DrawScene::createBoundingSphere(std::vector<openglarray *> &compilelist, Point3D &bs_center, float &bs_radius) {
  /* get outer coordinates */
  Point3D pmin(9999,9999,9999), pmax(-9999,-9999,-9999);

  std::vector<openglarray *>::iterator it;
  for (it = compilelist.begin(); it != compilelist.end(); it++) {
    openglarray *current = *it;
    for(int v=0; v<current->vertexcount; v++) {
      if (current->vertexarray[v].x<pmin.x) pmin.x = current->vertexarray[v].x;
      if (current->vertexarray[v].y<pmin.y) pmin.y = current->vertexarray[v].y;
      if (current->vertexarray[v].z<pmin.z) pmin.z = current->vertexarray[v].z;

      if (current->vertexarray[v].x>pmax.x) pmax.x = current->vertexarray[v].x;
      if (current->vertexarray[v].y>pmax.y) pmax.y = current->vertexarray[v].y;
      if (current->vertexarray[v].z>pmax.z) pmax.z = current->vertexarray[v].z;
    }
  }

  /* get center */
  bs_center.x = (pmin.x+pmax.x)/2.;
  bs_center.y = (pmin.y+pmax.y)/2.;
  bs_center.z = (pmin.z+pmax.z)/2.;

  /* get radius */
  bs_radius = 0;
  for (it = compilelist.begin(); it != compilelist.end(); it++) {
    openglarray *current = *it;
    for(int v=0; v<current->vertexcount; v++) {
      if ((current->vertexarray[v]-bs_center).length() > bs_radius) {
      bs_radius = (current->vertexarray[v]-bs_center).length();
      }
    }
  }

  printf("bs center: %f, %f, %f radius: %f\n", bs_center.x, bs_center.y, bs_center.z, bs_radius);
}

void DrawScene::registerDrawSceneObjectName(QString name, DrawSceneObject *object) {
  drawSceneObjectNamespaceList[name] = object;
}

DrawSceneObject *DrawScene::getRegisteredDrawSceneObject(QString name) {
//   assert(drawSceneObjectNamespaceList[name]!=NULL);

  return(drawSceneObjectNamespaceList[name]);
}

void DrawScene::deregisterDrawSceneObjectName(DrawSceneObject *object) {
  QValueList<QString>::iterator i;
  QValueList<QString> list = drawSceneObjectNamespaceList.keys();
  bool finished = false;
  while(!finished) {
    finished = true;
    for(i=list.begin(); i!=list.end(); i++) {
      if (getRegisteredDrawSceneObject(*i) == object) {
      drawSceneObjectNamespaceList.erase(*i);
      finished = false;
      break;
      }
    }    
  } 
}

void DrawScene::addDrawSceneObject(DrawSceneObject *object) {
  if (object) fullList.push_back(object);
}

void DrawScene::removeDrawSceneObject(DrawSceneObject *object) {
  std::vector<DrawSceneObject *>::iterator i;
  for(i=fullList.begin(); i!=fullList.end(); i++) {
    if (*i==object) {
      fullList.erase(i);
      break;
    }
  }

  for(i=rootList.begin(); i!=rootList.end(); i++) {
    if (*i==object) {
      rootList.erase(i);
      break;
    }
  }
}

DrawSceneObject *DrawScene::parseObject(QDomNode n) {
  if (n.isElement()) {
    QDomElement element = n.toElement();
    DrawSceneObject *newObject = NULL;

    /* see if we need to replace an object */
    if (element.attribute("name","")!=QString("")) {
      QString name = element.attribute("name");

      DrawSceneObject *obj = getRegisteredDrawSceneObject(name);

      if (obj) {
      obj->deleteChildren();
      deregisterDrawSceneObjectName(obj);
//    delete(obj);
//    removeDrawSceneObject(obj);
      obj->readXMLData(n);
      return(NULL);
      }
    }

    /* triangle */
    if (element.tagName() == QString("triangle")) {
      newObject = new DrawSceneObjectTriangle(this);
      newObject->readXMLData(n);
      return(newObject);
    }

    /* quad */
    if (element.tagName() == QString("quad")) {
      newObject = new DrawSceneObjectQuad(this);
      newObject->readXMLData(n);
      return(newObject);
    }

    /* sphere */
    if (element.tagName() == QString("sphere")) {
      newObject = new DrawSceneObjectSphere(this);
      newObject->readXMLData(n);
      return(newObject);
    }


    /* texture */
    if (element.tagName() == QString("texture")) {
      newObject = new DrawSceneObjectTexture(this);
      newObject->readXMLData(n);
      return(newObject);
    }

    /* translate */
    if (element.tagName() == QString("translate")) {
      newObject = new DrawSceneObjectTranslate(this);
      newObject->readXMLData(n);
      return(newObject);
    }

    /* scale */
    if (element.tagName() == QString("scale")) {
      newObject = new DrawSceneObjectScale(this);
      newObject->readXMLData(n);
      return(newObject);
    }

    /* rotatequaternion */
    if (element.tagName() == QString("rotatequaternion")) {
      newObject = new DrawSceneObjectRotatequaternion(this);
      newObject->readXMLData(n);
      return(newObject);
    }

    /* group */
    if (element.tagName() == QString("group")) {
      newObject = new DrawSceneObjectGroup(this);
      newObject->readXMLData(n);
      return(newObject);
    }

    /* usegroup */
    if (element.tagName() == QString("usegroup")) {
      newObject = new DrawSceneObjectUseGroup(this);
      newObject->readXMLData(n);
      return(newObject);
    }
  }

  return(NULL);
}

void DrawScene::addDownload() {
  unfinishedDownloads++;
  printf("addDownload unfinishedDownloads: %i\n", unfinishedDownloads);
}

void DrawScene::removeDownload() {
  printf("removeDownload unfinishedDownloads: %i\n", unfinishedDownloads);
  unfinishedDownloads--;

  if (unfinishedDownloads<=0 && parseFinished) {
    /* clear pbr data and compiled data */
    eraseFirstLevelArray(firstlevelcompilelist);
    eraseFirstLevelArray(groupcompilelist);
    eraseGroupPBRList();
    pointbasedrendering_generated = false;

    /* compile scene */
    compile();

    /* start drawing */
    downloadsFinished = true;
  }
}

void DrawScene::setFinishedPBR() {
  if (pbrphase>=2) {
    pointbasedrendering_generated = true;

    needRedraw = true;
  }
  else {
    compile();
  }
}

void DrawScene::registerGroupObjectForPBR(DrawSceneObjectGroup *object) {
  groupList.push_back(object);
}

Draw *DrawScene::tagGeometry(QDomNode geometryNode, Draw *newDraw) {
  /* create new scene drawer */
  QDomElement geometryElement = geometryNode.toElement();
  int layer = geometryElement.attribute("layer", "1").toInt();

  DrawScene *drawScene;
  if (newDraw) {
    drawScene = (DrawScene *) newDraw;

    QString geometryMethod = geometryElement.attribute("method");
    if (geometryMethod == QString("replace")) {
      /* replace with the new data */
      drawScene->clear();
    }
    else {
      /* update/add data */
    }
  }
  else {
    QString geometryPBR = geometryElement.attribute("pbr", "on");
    drawScene = new DrawScene(layer, geometryPBR == QString("on"));
  }

  /* fill in the data */
  drawScene->fillSceneData(geometryNode.firstChild());

  return(drawScene);
}


Generated by  Doxygen 1.6.0   Back to index