VEFViewer.cpp
author Dmitriy Morozov <dmitriy@mrzv.org>
Tue, 21 Jul 2009 09:57:31 -0700
changeset 16 bff3d7c294ff
parent 10 240ec9bb3d92
permissions -rw-r--r--
Fixed lights and spheres according to Martin's instructions

#include "VEFViewer.h"
#include <QtDebug>
#include <cstdio>
// #include "sphere.h"
#include <GL/glut.h>

VEFViewer::VEFViewer(QWidget* parent): QGLViewer(parent)
{
	restoreStateFromFile();
}

void VEFViewer::init()
{
	setBackgroundColor(QColor(0xAA, 0xAA, 0xAA));
	setWheelBinding(Qt::AltModifier, CAMERA, MOVE_FORWARD);

	// Lights
	glEnable(GL_LIGHTING);
	glDisable(GL_LIGHT0);
	glEnable(GL_LIGHT1);

	GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
	GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
	GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };

	glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular);
	//glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 120.0);
	//glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 3.0);

	// Basic settings
	glShadeModel(GL_SMOOTH);
	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_NORMALIZE);
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_POINT_SMOOTH);
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
	glPointSize(2.0);

    glEnable(GL_CULL_FACE);
}

void VEFViewer::addFile(QString s)
{
	GLuint display_list;
	
	QFileInfo fi(s);
	QString ext = fi.suffix();

	if (ext == "vrt")
		readVertexFile(s);
	else if (ext == "edg")
		readEdgeFile(s);
	else if (ext == "stl")
		readSTLFile(s);
	else
		return;
	
	setSceneBoundingBox(min, max);
	setSceneCenter(center);

	if (modelList->count() == 1)
	{
		camera()->centerScene();
		camera()->showEntireScene();
	}

	std::cout << "Min: " << min << std::endl;
	std::cout << "Max: " << max << std::endl;
	std::cout << "Center: " << center << std::endl;
}

void VEFViewer::draw()
{
	// GL_LIGHT0
	const GLfloat light_pos0[4] = {center.x, center.y, center.z, 1.0};
	glLightfv(GL_LIGHT0, GL_POSITION, light_pos0);

	// GL_LIGHT1
	qglviewer::Vec camera_pos = camera()->position();
	qglviewer::Vec camera_dir = camera()->viewDirection();
	const GLfloat light_pos1[4] = {camera_pos.x, camera_pos.y, camera_pos.z, 1.0};
	const GLfloat light_spot_dir1[3] = {camera_dir.x, camera_dir.y, camera_dir.z};
	glLightfv(GL_LIGHT1, GL_POSITION, light_pos1);
	//glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light_spot_dir1);
	
	for (int i = 0; i < modelList->count(); i++)
	{
		QDisplayListLWI* dl = static_cast<QDisplayListLWI*>(modelList->item(i));
		dl->draw();
	}

	//drawLight(GL_LIGHT0);
	//drawLight(GL_LIGHT1);
}

void VEFViewer::drawWithNames()
{
	int offset = 0;
	for (int i = 0; i < modelList->count(); i++)
	{
		QDisplayListLWI* dl = static_cast<QDisplayListLWI*>(modelList->item(i));
		dl->drawWithNames(offset);
		offset += dl->numElements();
	}
}

void VEFViewer::postSelection(const QPoint& point)
{
	int i;
	int selected = selectedName();
	QDisplayListLWI* dl;

	for (i = 0; i < modelList->count(); i++)
	{
		dl = static_cast<QDisplayListLWI*>(modelList->item(i));
		if (selected < dl->numElements())
			break;
		selected -= dl->numElements();
	}
	
	dl->highlight(selected);
}

QString VEFViewer::helpString() const
{
  QString text("<h2>VEFViewer</h2>");
  text += "Displays vertices (vrt), edges (edg), and face (stl) files.";
  return text;
}

void VEFViewer::listItemDoubleClicked(QListWidgetItem* item)		
{ 
	(static_cast<QDisplayListLWI*>(item))->toggleVisible(); 
	updateGL();
}

void VEFViewer::customContextMenuRequested(const QPoint& pos)
{
	QDisplayListLWI* dl = static_cast<QDisplayListLWI*>(modelList->itemAt(pos));
	if (dl == 0) return;

	QMenu m(this);
	dl->setupMenu(m);
	m.exec(modelList->mapToGlobal(pos) + QPoint(10,10));
	updateGL();
}

		
void VEFViewer::setModelList(QListWidget* l)			
{ 
	modelList = l; 
	connect(modelList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
			this, SLOT(listItemDoubleClicked(QListWidgetItem*))); 
	connect(modelList, SIGNAL(customContextMenuRequested(const QPoint&)),
			this, SLOT(customContextMenuRequested(const QPoint&))); 
}

void VEFViewer::keyPressEvent(QKeyEvent* e) 
{
	const Qt::KeyboardModifiers modifiers = e->modifiers();

	bool handled = false;
	if ((e->key() == Qt::Key_O) && (modifiers == Qt::NoButton))
	{
		QString s = QFileDialog::getOpenFileName(this, "Choose file to open", ".", "3D data (*.vrt *.edg *.stl)");
		if (!s.isNull())
			addFile(s);
	}

	if (!handled)
		QGLViewer::keyPressEvent(e);
}

void VEFViewer::readVertexFile(const QString& s)
{
	modelList->addItem(new QVerticesLWI(s, this));
}

void VEFViewer::readEdgeFile(const QString& s)
{
	modelList->addItem(new QEdgesLWI(s, this));
}

void VEFViewer::readSTLFile(const QString& s)
{
	modelList->addItem(new QFacesLWI(s, this));
}


void VEFViewer::updateMinMax(float x, float y, float z)
{
	if (x < min.x)	min.x = x;
	if (y < min.y)	min.y = y;
	if (z < min.z)	min.z = z;
	
	if (x > max.x)	max.x = x;
	if (y > max.y)	max.y = y;
	if (z > max.z)	max.z = z;

	updateWeightedCenter(x, y, z);
}

void VEFViewer::updateWeightedCenter(float x, float y, float z)
{
	vertex_count++;
	center.x = float(vertex_count - 1)/vertex_count * center.x + x/vertex_count;
	center.y = float(vertex_count - 1)/vertex_count * center.y + y/vertex_count;
	center.z = float(vertex_count - 1)/vertex_count * center.z + z/vertex_count;
}


// QDisplayListLWI
void QDisplayListLWI::draw() const
{
	if (!isVisible()) return;
		
	glColor3f(color_.redF(), color_.greenF(), color_.blueF());
	glCallList(display_list_);
}

// QVertices
void QVerticesLWI::draw() const
{
	if (!isVisible()) return;

	glColor3f(color_.redF(), color_.greenF(), color_.blueF());
	if (!isSphere())
    {
        glDisable(GL_LIGHTING);
		glCallList(display_list_);
        glEnable(GL_LIGHTING);
    }
	else
		glCallList(sphere_display_list_);
	
}
void QVerticesLWI::drawWithNames(int offset) const
{}
int QVerticesLWI::numElements() const
{ return 0; }
void QVerticesLWI::highlight(int selected)
{}

QVerticesLWI::QVerticesLWI(QString fname, VEFViewer* v): 
	QDisplayListLWI(fname, QColor::fromRgbF(.66, 0, .5)), isSphere_(false), viewer_(v)
{
	filename_ = fname;
	QFileInfo fi(filename_);
	setText(fi.baseName());
	init();
}

void QVerticesLWI::init()
{
	FILE* file;
	if ((file = fopen(filename_.toLocal8Bit().data(), "r")) == NULL)
	{
		qDebug() << "Could not open file " << filename_ << " for reading";
		return;
	}

	// Read in vertices
	Point p;
	int result = fscanf(file, "%f %f %f", &p.x, &p.y, &p.z);
	while(result != EOF)
	{
		vertices_.push_back(p);
		viewer_->updateMinMax(p.x,p.y,p.z);
		result = fscanf(file, "%f %f %f", &p.x, &p.y, &p.z);
	}

	// Create display list of points
	display_list_ = glGenLists(1);
	glNewList(display_list_, GL_COMPILE);
	glBegin(GL_POINTS);
		for (VertexContainer::const_iterator cur = vertices_.begin(); cur != vertices_.end(); ++cur)
			glVertex3f(cur->x,cur->y,cur->z);
	glEnd();
	glEndList();

	// Create display list of spheres
	sphere_display_list_ = glGenLists(1);
	glNewList(sphere_display_list_, GL_COMPILE);
	for (VertexContainer::const_iterator cur = vertices_.begin(); cur != vertices_.end(); ++cur)
	{
		// XYZ c;
		// c.x = cur->x; c.y = cur->y; c.z = cur->z;
		// CreateSphere(c, .25, 10);
        glTranslatef(cur->x, cur->y, cur->z);
        glutSolidSphere(.25, 10, 10);
        glTranslatef(-cur->x, -cur->y, -cur->z);
	}
	glEnd();
	glEndList();

	fclose(file);
}

void QVerticesLWI::destroy()
{
	vertices_.clear();
	glDeleteLists(sphere_display_list_, 1);
	QDisplayListLWI::destroy();
}


/* QFaces */
void QFacesLWI::draw() const
{
	if (!isVisible()) return;

	// Draw selected
	if (highlighted_ >= 0)
	{
		glColor3f(color_.light(200).redF(), color_.light(200).greenF(), color_.light(200).blueF());
		glBegin(GL_TRIANGLES);
			const Triangle& t = triangles_[highlighted_];
			glNormal3f(t.nx, t.ny, t.nz);
			glVertex3f(t.x0, t.y0, t.z0);
			glVertex3f(t.x1, t.y1, t.z1);
			glVertex3f(t.x2, t.y2, t.z2);
		glEnd();
	}
	
	// Draw the object
	if (!isWireframe())	
    {
		glColor3f(color_.light(150).redF(), color_.light(150).greenF(), color_.light(150).blueF());
		glCallList(display_list_);
    }
	else
    {
		glColor3f(color_.redF(), color_.greenF(), color_.blueF());
		glCallList(wireframe_display_list_);
    }
}

void QFacesLWI::drawWithNames(int offset) const
{
	if (!isVisible()) return;
	if (isWireframe()) return;
		
	for (int i = 0; i < triangles_.size(); i++)
	{
		const Triangle& t = triangles_[i];
		glPushName(offset + i);
		glBegin(GL_TRIANGLES);
		glVertex3f(t.x0, t.y0, t.z0);
		glVertex3f(t.x1, t.y1, t.z1);
		glVertex3f(t.x2, t.y2, t.z2);
		glEnd();
		glPopName();
	}
}

int QFacesLWI::numElements() const
{ return triangles_.size(); }

void QFacesLWI::highlight(int selected)
{
	highlighted_ = selected;
	if (highlighted_ < 0) return;

	const Triangle& t = triangles_[highlighted_];
	std::cout << "Highlighted: (" << t.x0 << " " << t.y0 << " " << t.z0 << std::endl;
	std::cout << "              " << t.x1 << " " << t.y1 << " " << t.z1 << std::endl;
	std::cout << "              " << t.x2 << " " << t.y2 << " " << t.z2 << ")" << std::endl;
}

QFacesLWI::QFacesLWI(QString fname, VEFViewer* v):
	QDisplayListLWI(fname, QColor::fromRgbF(0,.4,.6)), highlighted_(-1), isWireframe_(false), viewer_(v)
{
	filename_ = fname;
	QFileInfo fi(filename_);
	setText(fi.baseName());
	init();
}

void QFacesLWI::init()
{
	FILE* file;
	if ((file = fopen(filename_.toLocal8Bit().data(), "r")) == NULL)
	{
		qDebug() << "Could not open file " << filename_ << " for reading";
		return;
	}

	float nx,ny,nz;			// not used
	float x0,y0,z0;
	float x1,y1,z1;
	float x2,y2,z2;
	
	// Read in the vector of Triangles
	int result = readFacet(file, nx,ny,nz, x0,y0,z0, x1,y1,z1, x2,y2,z2);
	while(result != EOF)
	{
		qglviewer::Vec n = computeNormal(qglviewer::Vec(x0,y0,z0), 
										 qglviewer::Vec(x1,y1,z1), 
										 qglviewer::Vec(x2,y2,z2)); 
		triangles_.push_back(Triangle(n.x,n.y,n.z, x0,y0,z0, x1,y1,z1, x2,y2,z2));

		viewer_->updateMinMax(x0,y0,z0);
		viewer_->updateMinMax(x1,y1,z1);
		viewer_->updateMinMax(x2,y2,z2);

		result = readFacet(file, nx,ny,nz, x0,y0,z0, x1,y1,z1, x2,y2,z2);
	}
	fclose(file);
	
	std::cout << "Triangles read: " << triangles_.size() << std::endl;
	
	// Create triangles display list
	display_list_ = glGenLists(1);
	glNewList(display_list_, GL_COMPILE);
	drawTriangles(GL_TRIANGLES);
	glEndList();

	// Create wireframe display list
	wireframe_display_list_ = glGenLists(1);
	glNewList(wireframe_display_list_, GL_COMPILE);
	drawTriangles(GL_LINE_LOOP);
	glEndList();
}

void QFacesLWI::destroy()
{
	triangles_.clear();
	glDeleteLists(wireframe_display_list_, 1);
	QDisplayListLWI::destroy();
}

void QFacesLWI::drawTriangles(GLenum mode) const
{
	for (TrianglesContainer::const_iterator cur = triangles_.begin(); cur != triangles_.end(); ++cur)
	{
		glBegin(mode);
		glNormal3f(cur->nx,cur->ny,cur->nz);
		glVertex3f(cur->x0,cur->y0,cur->z0);
		glVertex3f(cur->x1,cur->y1,cur->z1);
		glVertex3f(cur->x2,cur->y2,cur->z2);
		glEnd();
	}
}

qglviewer::Vec QFacesLWI::computeNormal(qglviewer::Vec v0, qglviewer::Vec v1, qglviewer::Vec v2) const
{
	qglviewer::Vec n = cross((v1 - v0), (v2 - v0));
	return n;
}

int QFacesLWI::readFacet(FILE* file,
						  float& nx, float& ny, float& nz, 
						  float& x0, float& y0, float& z0,
						  float& x1, float& y1, float& z1,
						  float& x2, float& y2, float& z2)
{
	
	int result;
	result = fscanf(file, "%*s %*s %f %f %f", &nx, &ny, &nz);
	result = fscanf(file, "%*s %*s");
	result = fscanf(file, "%*s %f %f %f", &x0, &y0, &z0);
	result = fscanf(file, "%*s %f %f %f", &x1, &y1, &z1);
	result = fscanf(file, "%*s %f %f %f", &x2, &y2, &z2);
	result = fscanf(file, "%*s");
	result = fscanf(file, "%*s");

	return result;
}


/* QEdges */
void QEdgesLWI::drawWithNames(int offset) const
{}
int QEdgesLWI::numElements() const
{ return 0; }
void QEdgesLWI::highlight(int selected)
{}

QEdgesLWI::QEdgesLWI(QString fname, VEFViewer* v):
	QDisplayListLWI(fname, QColor::fromRgbF(.6,.2,.6)), viewer_(v)
{
	filename_ = fname;
	QFileInfo fi(filename_);
	setText(fi.baseName());
	init();
}

void QEdgesLWI::init()
{
	FILE* file;
	if ((file = fopen(filename_.toLocal8Bit().data(), "r")) == NULL)
	{
		qDebug() << "Could not open file " << filename_ << " for reading";
		return;
	}

	display_list_ = glGenLists(1);
	glNewList(display_list_, GL_COMPILE);
	glBegin(GL_LINES);
	
		float nx,ny,nz;
		float x0,y0,z0;
		float x1,y1,z1;

		int result = readEdge(file, x0,y0,z0, x1,y1,z1);
		while(result != EOF)
		{
			glVertex3f(x0,y0,z0);
			glVertex3f(x1,y1,z1);

			viewer_->updateMinMax(x0,y0,z0);
			viewer_->updateMinMax(x1,y1,z1);

			result = readEdge(file, x0,y0,z0, x1,y1,z1);
		}

	glEnd();
	glEndList();

	fclose(file);
}

int QEdgesLWI::readEdge  (FILE* file,
						  float& x0, float& y0, float& z0,
						  float& x1, float& y1, float& z1)
{
	int result = fscanf(file, "%f %f %f", &x0, &y0, &z0);
		result = fscanf(file, "%f %f %f", &x1, &y1, &z1);

	return result;
}