//
// File: glmesh_common.cc
//
// (C) 2000-2008 Helmut Cantzler
//
// Licensed under the terms of the Lesser General Public License.
//
#include <stdlib.h>
#include "glmesh.h"
void GLMesh::checkForTraps(const char *string, int value)
{
GLenum errorCode = glGetError();
if( errorCode!= GL_NO_ERROR)
{
printf("\n\n\n");
printf("During processing %s (%d) an internal error occurred!\n",
string, value);
printf("OpenGL error: %d ", errorCode);
printf("(%s)\n", gluErrorString(errorCode));
//exit(0);
}
}
void GLMesh::setMaterialColor(GLenum face, GLenum pname, int color)
{
static float colors[8][4] = {{0.0, 0.0, 0.0, 0.0}, // black
{0.0, 0.0, 1.0, 1.0}, // blue
{0.0, 1.0, 0.0, 1.0}, // green
{1.0, 0.0, 0.0, 1.0}, // red
{1.0, 1.0, 0.0, 1.0}, // yellow
{1.0, 0.0, 1.0, 1.0}, // purple
{0.0, 1.0, 1.0, 1.0}, // cyan
{1.0, 1.0, 1.0, 1.0}}; // white
float b;
int c, j;
color--;
// b = 0.0 until 0.9
b = color / 7 < 10 ? color / 7 * 0.1 : 0.9;
// c = 0 until 7
c = color != -1 ? color % 7 + 1 : 0;
for (j=0; j < 3; j++)
colors[c][j]= colors[c][j] ? 1.0 - b : 0.0;
glMaterialfv(face, pname, colors[c]);
}
void GLMesh::setMaterialColorGrey(GLenum face, GLenum pname, int b)
{
static float grey[4] = {1.0, 1.0, 1.0, 1.0};
int j;
for (j=0; j < 3; j++)
grey[j] = 1.0 - 0.15 * b;
glMaterialfv(face, pname, grey);
}
void GLMesh::displayNormals(void)
{
list<Triangle*>::iterator it;
list<Triangle*> *triangles;
setMaterialColor(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, BLUE);
glBegin(GL_LINES);
for (int i=0; i < numberOfShapes; i++)
{
triangles=settings->mesh->getShape(i)->triangles;
if (triangles != NULL)
for (it=triangles->begin(); it != triangles->end(); it++)
if (settings->displayPolygons || !(*it)->isFromPolygon())
{
const float *dnorm = (*it)->floatNormal();
const float *dcent = (*it)->centroid();
glVertex3fv((GLfloat*) dcent);
glVertex3f( dcent[0] + surfaceNormalLength*dnorm[0],
dcent[1] + surfaceNormalLength*dnorm[1],
dcent[2] + surfaceNormalLength*dnorm[2]);
}
}
glEnd();
}
void GLMesh::displayBoundingBox(void)
{
if (settings->mesh == NULL)
return;
const float xMin = settings->mesh->getXMin() - 0.1;
const float xMax = settings->mesh->getXMax() + 0.1;
const float yMin = settings->mesh->getYMin() - 0.1;
const float yMax = settings->mesh->getYMax() + 0.1;
const float zMin = settings->mesh->getZMin() - 0.1;
const float zMax = settings->mesh->getZMax() + 0.1;
int size;
glGetIntegerv(GL_LINE_WIDTH, &size);
glLineWidth(2);
setMaterialColor(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, WHITE);
glBegin(GL_LINES);
glVertex3f(xMin, yMin, zMin); glVertex3f(xMin, yMin, zMax);
glVertex3f(xMin, yMin, zMin); glVertex3f(xMin, yMax, zMin);
glVertex3f(xMin, yMin, zMin); glVertex3f(xMax, yMin, zMin);
glVertex3f(xMin, yMax, zMax); glVertex3f(xMax, yMax, zMax);
glVertex3f(xMin, yMax, zMax); glVertex3f(xMin, yMin, zMax);
glVertex3f(xMin, yMax, zMax); glVertex3f(xMin, yMax, zMin);
glVertex3f(xMax, yMin, zMax); glVertex3f(xMax, yMax, zMax);
glVertex3f(xMax, yMin, zMax); glVertex3f(xMax, yMin, zMin);
glVertex3f(xMax, yMin, zMax); glVertex3f(xMin, yMin, zMax);
glVertex3f(xMax, yMax, zMin); glVertex3f(xMax, yMax, zMax);
glVertex3f(xMax, yMax, zMin); glVertex3f(xMax, yMin, zMin);
glVertex3f(xMax, yMax, zMin); glVertex3f(xMin, yMax, zMin);
glEnd();
glLineWidth(size);
}
void GLMesh::displayPoints(list<Vertex*> *vertices)
{
list<Vertex*>::iterator iv;
for (iv=vertices->begin(); iv != vertices->end(); iv++)
{
glLoadName((*iv)->name);
glBegin(GL_POINTS);
if ( (*iv)->floatNormal() != NULL )
glNormal3fv( (GLfloat*) (*iv)->floatNormal() );
glVertex3fv( (GLfloat*) (*iv)->floatData() );
glEnd();
}
}
void GLMesh::displayEdges(list<Edge*> *edges)
{
list<Edge*>::iterator ie;
for (ie=edges->begin(); ie != edges->end(); ie++)
{
glLoadName((*ie)->name);
glBegin(GL_LINES);
glVertex3fv((GLfloat*) (*ie)->vertices[0]->floatData() );
glVertex3fv((GLfloat*) (*ie)->vertices[1]->floatData() );
glEnd();
}
}
void GLMesh::displayFeatures()
{
setMaterialColor(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, RED);
//setMaterialColor(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, BLACK);
//glDisable(GL_DEPTH_TEST);
switch (settings->featuresDisplayMode)
{
case VERTICES:
displayPoints(settings->features->getVertices());
break;
case EDGES:
displayEdges(settings->features->getEdges());
break;
}
//glEnable(GL_DEPTH_TEST);
}
void GLMesh::displayShapePoints(void)
{
list<Vertex*> *vertices;
Shape* shape;
int nr;
for (int i=0; i < numberOfShapes; i++)
{
shape=settings->mesh->getShape(i);
vertices=shape->vertices;
if (vertices != NULL)
{
if (!settings->displayShapeColors || i+1 == numberOfShapes)
nr = CYAN; // BLUE;
else
nr = i+1 == CYAN ? i+2 : i+1;
// Set color
setMaterialColor(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, nr);
displayPoints(vertices);
}
}
}
void GLMesh::displayMesh(void)
{
list<Triangle*>::iterator it;
list<Triangle*> *triangles;
Shape* shape;
int nr;
for (int i=0; i < numberOfShapes; i++)
{
shape=settings->mesh->getShape(i);
triangles=shape->triangles;
if (triangles != NULL)
if (settings->meshDisplayMode == TEXTURE && shape->getTextureId() != -1)
{
setMaterialColor(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, WHITE);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, shape->getTextureId());
for (it=triangles->begin(); it != triangles->end(); it++)
if (settings->displayPolygons || !(*it)->isFromPolygon())
{
glLoadName((*it)->name);
glBegin(GL_TRIANGLES);
glNormal3fv( (GLfloat*) (*it)->floatNormal() );
glTexCoord2f( (GLfloat) (*it)->getTextS(0),
(GLfloat) (*it)->getTextT(0));
glVertex3fv( (GLfloat*) (*it)->vertices[0]->floatData() );
glTexCoord2f( (GLfloat) (*it)->getTextS(1),
(GLfloat) (*it)->getTextT(1));
glVertex3fv( (GLfloat*) (*it)->vertices[1]->floatData() );
glTexCoord2f( (GLfloat) (*it)->getTextS(2),
(GLfloat) (*it)->getTextT(2));
glVertex3fv( (GLfloat*) (*it)->vertices[2]->floatData() );
glEnd();
}
glDisable(GL_TEXTURE_2D);
}
else
{
// no different colors or last shape
if (!settings->displayShapeColors || i+1 == numberOfShapes)
nr = CYAN; // BLUE;
else
nr = i+1 == CYAN ? i+2 : i+1;
// Set color
setMaterialColor(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, nr);
for (it=triangles->begin(); it != triangles->end(); it++)
if (settings->displayPolygons || !(*it)->isFromPolygon())
{
glLoadName((*it)->name);
glBegin(GL_TRIANGLES);
glNormal3fv( (GLfloat*) (*it)->floatNormal() );
glVertex3fv( (GLfloat*) (*it)->vertices[0]->floatData() );
glVertex3fv( (GLfloat*) (*it)->vertices[1]->floatData() );
glVertex3fv( (GLfloat*) (*it)->vertices[2]->floatData() );
glEnd();
}
}
}
}
void GLMesh::displayMeshWithStencil(void)
{
list<Triangle*>::iterator it;
list<Triangle*> *triangles;
int nr;
glEnable(GL_STENCIL_TEST);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 0, 1);
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
for (int i=0; i < numberOfShapes; i++)
{
triangles=settings->mesh->getShape(i)->triangles;
if (triangles != NULL)
{
// no different colors or last shape
if (!settings->displayShapeColors || i+1 == numberOfShapes)
nr = CYAN; // BLUE;
else
nr = i+1 == CYAN ? i+2 : i+1;
setMaterialColor(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, nr);
for (it=triangles->begin(); it != triangles->end(); it++)
if (settings->displayPolygons || !(*it)->isFromPolygon())
{
glLoadName((*it)->name);
glBegin(GL_TRIANGLES);
glVertex3fv( (GLfloat*) (*it)->vertices[0]->floatData() );
glVertex3fv( (GLfloat*) (*it)->vertices[1]->floatData() );
glVertex3fv( (GLfloat*) (*it)->vertices[2]->floatData() );
glEnd();
glStencilFunc(GL_EQUAL, 0, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
setMaterialColor(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, nr);
glBegin(GL_TRIANGLES);
glNormal3fv( (GLfloat*) (*it)->floatNormal() );
glVertex3fv( (GLfloat*) (*it)->vertices[0]->floatData() );
glVertex3fv( (GLfloat*) (*it)->vertices[1]->floatData() );
glVertex3fv( (GLfloat*) (*it)->vertices[2]->floatData() );
glEnd();
glStencilFunc(GL_ALWAYS, 0, 1);
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
setMaterialColor(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, RED);
glBegin(GL_TRIANGLES);
glNormal3fv( (GLfloat*) (*it)->floatNormal() );
glVertex3fv( (GLfloat*) (*it)->vertices[0]->floatData() );
glVertex3fv( (GLfloat*) (*it)->vertices[1]->floatData() );
glVertex3fv( (GLfloat*) (*it)->vertices[2]->floatData() );
glEnd();
}
}
}
glDisable(GL_STENCIL_TEST);
}
void GLMesh::tbPointToVector(int x, int y, float v[3])
{
float d, a;
// project x, y onto a hemi-sphere centered within width, height
v[0] = (2.0 * x - width()) / width();
v[1] = (height() - 2.0 * y) / height();
d = sqrt(v[0] * v[0] + v[1] * v[1]);
v[2] = cos((3.14159265 / 2.0) * ((d < 1.0) ? d : 1.0));
a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] *= a;
v[1] *= a;
v[2] *= a;
}
void GLMesh::initLighting(void)
{
// light from a light source
const GLfloat diffuseLight[] = {0.4, 0.4, 0.4, 1.0};
// light from no particulat light source
const GLfloat ambientLight[] = {0.1, 0.1, 0.1, 1.0};
// light positions for 4 lights
const GLfloat lightPositions[4][4] = {{ 1.0, 1.0, 0.0, 0.0},
{-1.0, -1.0, 0.0, 0.0},
{-0.1, -0.1, 1.0, 0.0},
{ 0.1, 0.1, -1.0, 0.0}};
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_POSITION, lightPositions[0]);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT1, GL_POSITION, lightPositions[1]);
glEnable(GL_LIGHT1);
glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT2, GL_POSITION, lightPositions[2]);
glEnable(GL_LIGHT2);
glLightfv(GL_LIGHT3, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT3, GL_POSITION, lightPositions[3]);
glEnable(GL_LIGHT3);
if (settings->enableLighting)
glEnable(GL_LIGHTING);
else
glDisable(GL_LIGHTING);
}
void GLMesh::setShapeTexture(int j)
{
Texture texture;
Shape *shape = settings->mesh->getShape(j);
GLint filter = settings->enableTextureFilter ? GL_LINEAR : GL_NEAREST;
if (shape->getTextureId() != -1)
{
// we have already one texture for this shape
// => delete old texture & create a new one
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteTextures(1, &textureList[j]);
glGenTextures(1, &textureList[j]);
shape->setTextureId(-1);
}
const char* textureName = shape->getTextureName();
if (textureName != NULL && strlen(textureName) != 0)
{
// try reading texture image from current directory
if (texture.read(textureName) != 0)
{
// try reading texture image from 3d model directory
char *path = new char[strlen(textureName) +
strlen(settings->mesh->getPath()) +1];
strcpy(path, settings->mesh->getPath());
strcat(path, textureName);
if (texture.read(path) != 0)
{
printf("Failed loading texture image: %s\n", textureName);
return;
}
delete path;
}
shape->setTextureId(textureList[j]);
glBindTexture(GL_TEXTURE_2D, textureList[j]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
// Create MipMapped Texture
//glBindTexture(GL_TEXTURE_2D, texture[2]);
//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,
// GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
// GL_LINEAR_MIPMAP_NEAREST);
//gluBuild2DMipmaps(GL_TEXTURE_2D, texture.colorComponents(),
// texture.width(),texture.height(),
// texture.format(), GL_UNSIGNED_BYTE,
// texture.data());
glTexImage2D(GL_TEXTURE_2D, 0, texture.colorComponents(),
texture.width(),texture.height(), 0, texture.format(),
GL_UNSIGNED_BYTE, texture.data());
//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
}
}
void GLMesh::initTexture(void)
{
// create textures, one per shape
textureList = new GLuint[numberOfShapes];
glGenTextures(numberOfShapes, textureList);
for (int j=0; j < numberOfShapes; j++)
setShapeTexture(j);
}