Source

Coin / src / base / SbGLUTessellator.cpp

Full commit
Morten Eriksen bb5bbdc 
Marius Kintel 3ba6b41 




























Morten Eriksen bb5bbdc 























Lars J. Aas 5286419 
Morten Eriksen bb5bbdc 

Marius Kintel a8750f3 
Lars J. Aas 5286419 
Morten Eriksen bb5bbdc 













Morten Eriksen d64c569 
Morten Eriksen bb5bbdc 

Tom Fredrik Blen… 9244e9d 
Morten Eriksen bb5bbdc 





Morten Eriksen d64c569 
Morten Eriksen bb5bbdc 

Tom Fredrik Blen… 9244e9d 
Morten Eriksen bb5bbdc 









































Morten Eriksen d64c569 
Morten Eriksen bb5bbdc 






Morten Eriksen a304b46 















Morten Eriksen bb5bbdc 














Tom Fredrik Blen… 9244e9d 


Morten Eriksen bb5bbdc 




















































/**************************************************************************\
 * Copyright (c) Kongsberg Oil & Gas Technologies AS
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\**************************************************************************/

#include "SbGLUTessellator.h"

#include <Inventor/errors/SoDebugError.h>
#include <Inventor/C/tidbits.h>
#include <Inventor/system/gl.h>

// *************************************************************************

SbBool
SbGLUTessellator::available(void)
{
  return GLUWrapper()->available &&
    GLUWrapper()->gluNewTess &&
    GLUWrapper()->gluTessBeginPolygon &&
    GLUWrapper()->gluTessBeginContour &&
    GLUWrapper()->gluTessEndContour &&
    GLUWrapper()->gluTessEndPolygon &&
    GLUWrapper()->gluDeleteTess;
}

// *************************************************************************

SbGLUTessellator::SbGLUTessellator(void (* cb)(void *, void *, void *, void *),
                                   void * userdata)
{
  assert(cb && "tessellation without callback is meaningless");
  this->callback = cb;
  this->cbdata = userdata;

  // allocated later on demand, so there is no resource allocation
  // when just putting an SbGLUTessellator on the current stack frame:
  this->tessobj = NULL;
}

SbGLUTessellator::~SbGLUTessellator()
{
  if (this->tessobj) { GLUWrapper()->gluDeleteTess(this->tessobj); }
}

// *************************************************************************

void APIENTRY
SbGLUTessellator::cb_begin(GLenum mode, void * x)
{
  SbGLUTessellator * t = static_cast<SbGLUTessellator *>(x);

  t->triangletessmode = mode;
  t->vertexidx = 0;
  t->stripflipflop = FALSE;
}

void APIENTRY
SbGLUTessellator::cb_vertex(void * vertex_data, void * x)
{
  SbGLUTessellator * t = static_cast<SbGLUTessellator *>(x);

  switch (t->triangletessmode) {
  case GL_TRIANGLE_FAN:
    if (t->vertexidx == 0) { t->vertexdata[0] = vertex_data; }
    else if (t->vertexidx == 1) { t->vertexdata[1] = vertex_data; }
    else {
      t->callback(t->vertexdata[0], t->vertexdata[1], vertex_data, t->cbdata);
      t->vertexdata[1] = vertex_data;
    }
    break;

  case GL_TRIANGLE_STRIP:
    if (t->vertexidx == 0) { t->vertexdata[0] = vertex_data; }
    else if (t->vertexidx == 1) { t->vertexdata[1] = vertex_data; }
    else {
      t->callback(t->vertexdata[t->stripflipflop ? 1 : 0],
                  t->vertexdata[t->stripflipflop ? 0 : 1],
                  vertex_data,
                  t->cbdata);

      t->vertexdata[0] = t->vertexdata[1];
      t->vertexdata[1] = vertex_data;
      t->stripflipflop = t->stripflipflop ? FALSE : TRUE;
    }
    break;

  case GL_TRIANGLES:
    if (t->vertexidx % 3 == 0) { t->vertexdata[0] = vertex_data; }
    else if (t->vertexidx % 3 == 1) { t->vertexdata[1] = vertex_data; }
    else if (t->vertexidx % 3 == 2) {
      t->callback(t->vertexdata[0], t->vertexdata[1], vertex_data, t->cbdata);
    }
    break;

  default:
    assert(FALSE);
    break;
  }

  t->vertexidx++;
}

void APIENTRY
SbGLUTessellator::cb_error(GLenum err, void *)
{
  // These would be user errrors on our side, so catch them:
  assert(err != GLU_TESS_MISSING_BEGIN_POLYGON);
  assert(err != GLU_TESS_MISSING_END_POLYGON);
  assert(err != GLU_TESS_MISSING_BEGIN_CONTOUR);
  assert(err != GLU_TESS_MISSING_END_CONTOUR);
  
  // We will get this error if there are polygons with intersecting
  // edges (a "bow-tie" polygon, for instance), but this may be hard
  // to avoid for the app programmer, so we have made it possible to
  // silence this error messages by an envvar (according to the GLU
  // docs, the tessellator will be ok, it just ignored those polygons
  // and generate no output):
  if (err == GLU_TESS_NEED_COMBINE_CALLBACK) {
    static int v = -1;
    if (v == -1) {
      const char * env = coin_getenv("COIN_GLU_SILENCE_TESS_COMBINE_WARNING");
      v = env && (atoi(env) > 0);
    }
    // requested to be silenced
    if (v) { return; }
  }

  SoDebugError::post("SbGLUTessellator::cb_error",
                     "GLU library tessellation error: '%s'",
                     GLUWrapper()->gluErrorString(err));
}

// *************************************************************************

void
SbGLUTessellator::beginPolygon(const SbVec3f & normal)
{
  if (!this->tessobj) {
    coin_GLUtessellator * t = this->tessobj = GLUWrapper()->gluNewTess();

    const gluTessCallback_t f = GLUWrapper()->gluTessCallback;
    (*f)(t, GLU_TESS_BEGIN_DATA, reinterpret_cast<gluTessCallback_cb_t>(SbGLUTessellator::cb_begin));
    (*f)(t, GLU_TESS_VERTEX_DATA, reinterpret_cast<gluTessCallback_cb_t>(SbGLUTessellator::cb_vertex));
    (*f)(t, GLU_TESS_ERROR_DATA, reinterpret_cast<gluTessCallback_cb_t>(SbGLUTessellator::cb_error));
  }

  GLUWrapper()->gluTessBeginPolygon(this->tessobj, this);
  if (normal != SbVec3f(0, 0, 0)) {
    GLUWrapper()->gluTessNormal(this->tessobj, normal[0], normal[1], normal[2]);
  }

  GLUWrapper()->gluTessBeginContour(this->tessobj);
}

void
SbGLUTessellator::addVertex(const SbVec3f & v, void * data)
{
  struct v c = { { v[0], v[1], v[2] } };
  this->coords.append(c); // needs to be stored until gluTessEndPolygon()

  const int l = this->coords.getLength();
  GLUWrapper()->gluTessVertex(this->tessobj, this->coords[l - 1].c, data);
}

void
SbGLUTessellator::endPolygon(void)
{
  GLUWrapper()->gluTessEndContour(this->tessobj);
  GLUWrapper()->gluTessEndPolygon(this->tessobj);

  this->coords.truncate(0);
}

// *************************************************************************

// Whether or not the SbGLUTessellator should be preferred over our
// own Coin SbTesselator class, for tessellating faceset polygons.
SbBool
SbGLUTessellator::preferred(void)
{
  static int v = -1;
  if (v == -1) {
    const char * e = coin_getenv("COIN_PREFER_GLU_TESSELLATOR");
    v = (e && (atoi(e) > 0)) ? 1 : 0;

    if (v && !SbGLUTessellator::available()) {
      SoDebugError::postWarning("SbGLUTessellator::preferred",
                                "Preference setting "
                                "COIN_PREFER_GLU_TESSELLATOR indicates that "
                                "GLU tessellation is wanted, but GLU library "
                                "detected to not have this capability.");
      v = 0;
    }
  }
  return v ? TRUE : FALSE;
}

// *************************************************************************