Rev 368 | Rev 374 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
// ----------------------------------------
// A simple OBJ viewer.
//
// Controls:
// - left mouse down + mouse motion : rotate
// - Scroll button and +- buttons : zoom
// - right mouse click : centre trackball
// - esc : exits
// - x,y,z buttons : switch trackball up axis
// ----------------------------------------
#if (_MSC_VER >= 1200)
#pragma warning (disable: 4786)
#endif
#include <list>
#include <vector>
#include <assert.h>
#include <stdio.h>
#ifdef WIN32
#include <windows.h>
#include <io.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <Util/ArgExtracter.h>
#include <CGLA/Vec2i.h>
#include <CGLA/Vec2f.h>
#include <CGLA/Vec3f.h>
#include <CGLA/Mat4x4f.h>
#include "GLGraphics/glsl_shader.h"
#include "GLGraphics/gel_glut.h"
#include "GLGraphics/QuatTrackBall.h"
#include "GLGraphics/draw.h"
#include "GLGraphics/SOIL.h"
#include "Geometry/TriMesh.h"
#include "Geometry/obj_load.h"
#include "Geometry/ply_load.h"
#include "HMesh/x3d_load.h"
#include "HMesh/FaceCirculator.h"
#include "wireframe.h"
using namespace std;
using namespace CGLA;
using namespace Geometry;
using namespace HMesh;
using namespace GLGraphics;
int win_size_x = 800;
int win_size_y = 800;
bool per_vertex_normals = 1;
bool redo_display_list = 1;
bool do_wireframe = false;
Vec3f line_col = Vec3f(1,0,0);
QuatTrackBall* ball;
int spin_timer = 20;
void spin(int x);
int main_window;
TriMesh mesh;
void enable_textures(TriMesh& tm)
{
for(unsigned int i=0;i<tm.materials.size(); ++i)
{
Material& mat = tm.materials[i];
if(mat.tex_name != "")
{
string name = mat.tex_path + mat.tex_name;
mat.tex_id = SOIL_load_OGL_texture(name.data(), 0, 0, SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_POWER_OF_TWO);
}
}
}
void load_mesh(const string& fn)
{
if(fn.substr(fn.length()-4,fn.length())==".obj")
{
obj_load(fn, mesh);
}
else if(fn.substr(fn.length()-4,fn.length())==".ply")
{
ply_load(fn, mesh);
}
else if(fn.substr(fn.length()-4,fn.length())==".x3d")
{
Manifold m;
x3d_load(fn, m);
for(VertexIter v=m.vertices_begin(); v != m.vertices_end();++v)
v->touched = mesh.geometry.add_vertex(v->pos);
for(FaceIter f = m.faces_begin(); f!= m.faces_end(); ++f)
{
Vec3i face;
int i=0;
for(FaceCirculator fc(f); !fc.end(); ++fc,++i)
{
if(i<2)
face[i] = fc.get_vertex()->touched;
else
{
face[2] = fc.get_vertex()->touched;
mesh.geometry.add_face(face);
face[1] = face[2];
}
}
}
}
else
{
cout << "Either the format was unrecognized or the file did not have the appropriate extension" << endl;
exit(0);
}
enable_textures(mesh);
}
bool depth_pick(int x, int y,Vec3f& wp)
{
// Enquire about the viewport dimensions
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
// Get the minimum and maximum depth values.
float minmax_depth[2];
glGetFloatv(GL_DEPTH_RANGE, minmax_depth);
// Read a single pixel at the position of the mouse cursor.
float depth;
glReadPixels(x, viewport[3]-y, 1,1, GL_DEPTH_COMPONENT,
GL_FLOAT, (void*) &depth);
// If the depth corresponds to the far plane, we clicked on the
// background.
if(depth == minmax_depth[1])
return false;
// The lines below copy the viewing transformation from OpenGL
// to local variables. The call to gluLookAt must have exactly
// the same parameters as when the scene is drawn.
glLoadIdentity();
ball->set_gl_modelview();
double mvmat[16];
glGetDoublev(GL_MODELVIEW_MATRIX, mvmat);
// Copy the projection matrix. We assume it is unchanged.
double prjmat[16];
glGetDoublev(GL_PROJECTION_MATRIX, prjmat);
// Now unproject the point from screen to world coordinates.
double ox, oy, oz;
gluUnProject(x,viewport[3]-y,depth,
mvmat,prjmat,viewport,
&ox, &oy, &oz);
wp = Vec3f(ox,oy,oz);
return true;
}
void mouse_motion(int x, int y)
{
ball->roll_ball(Vec2i(x,y));
}
void mouse(int btn, int state, int x, int y)
{
if(state == GLUT_DOWN)
{
if(btn == GLUT_LEFT_BUTTON)
ball->grab_ball(ROTATE_ACTION, Vec2i(x,y));
else if(btn == GLUT_MIDDLE_BUTTON)
ball->grab_ball(ZOOM_ACTION, Vec2i(x, y));
else if(btn == GLUT_RIGHT_BUTTON)
ball->grab_ball(PAN_ACTION, Vec2i(x, y));
}
else if(state == GLUT_UP)
ball->release_ball();
}
void spin(int x)
{
ball->do_spin();
glutTimerFunc(spin_timer, spin, 0);
glutPostRedisplay();
}
void display()
{
static unsigned int l;
if(redo_display_list)
{
cout << "Creating display list" << endl;
l = glGenLists(1);
glNewList(l, GL_COMPILE);
draw(mesh, per_vertex_normals);
glEndList();
redo_display_list = false;
glutTimerFunc(spin_timer, spin, 0);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
ball->set_gl_modelview();
if(do_wireframe)
{
if(GLEW_EXT_geometry_shader4)
{
enable_wireframe();
glCallList(l);
glUseProgram(0);
}
else
{
glDisable(GL_LIGHTING);
glColor3f(1,1,1);
glCallList(l);
glEnable(GL_POLYGON_OFFSET_LINE);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3fv(line_col.get());
glPolygonOffset(0,-5);
glCallList(l);
glEnable(GL_LIGHTING);
glDisable(GL_POLYGON_OFFSET_LINE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
else
glCallList(l);
glutSwapBuffers();
}
void keyboard(unsigned char key, int x, int y)
{
switch(key)
{
case '\033': exit(0); break;
case 'w': do_wireframe = !do_wireframe; break;
case 'f': per_vertex_normals = !per_vertex_normals; redo_display_list = true; break;
}
}
int main(int argc, char** argv)
{
Util::ArgExtracter ae(argc, argv);
bool redo_normals = ae.extract("-n");
// GLUT INIT
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(win_size_x, win_size_y);
glutInit(&argc, argv);
main_window = glutCreateWindow("OBJ Viewer");
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMotionFunc(mouse_motion);
glutMouseFunc(mouse);
//glutIdleFunc(idle);
glewInit();
// GL INIT
glClearColor(.8f, 0.9f, 1.0f, 0.f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
glShadeModel(GL_SMOOTH);
// LOAD OBJ
string fn;
if(ae.no_remaining_args())
fn = ae.get_last_arg();
else
fn = "../../data/head.obj";
load_mesh(fn);
if(!mesh.has_normals() || redo_normals)
{
cout << "Computing normals" << endl;
mesh.compute_normals();
}
// Initialize Trackball
Vec3f c;
float r;
mesh.get_bsphere(c,r);
r *= 1.5;
ball = new QuatTrackBall(c,r,800,800);
// Setup projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(53,1.0f,r/100.0,r*3.0);
glMatrixMode(GL_MODELVIEW);
if(GLEW_EXT_geometry_shader4)
initialize_wireframe_shaders();
// Pass control to GLUT
glutMainLoop();
return 0;
}