Rev 299 | 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 <CGLA/Vec2i.h>
#include <CGLA/Vec2f.h>
#include <IL/il.h>
#include <IL/ilu.h>
#include <CGLA/Vec3f.h>
#include <CGLA/Mat4x4f.h>
#include "GLGraphics/gel_glut.h"
#include "GLGraphics/QuatTrackBall.h"
#include "GLGraphics/draw.h"
#include "Geometry/TriMesh.h"
#include "Geometry/obj_load.h"
using namespace std;
using namespace CGLA;
using namespace Geometry;
using namespace GLGraphics;
namespace
{
int win_size_x = 800;
int win_size_y = 800;
QuatTrackBall* ball;
int spin_timer = 20;
void spin(int x);
int main_window;
bool load_image_into_texture(const std::string& name, GLuint& id)
{
unsigned char* image = 0;
unsigned int bpp = 0;
unsigned int size_x = 0;
unsigned int size_y = 0;
unsigned int load_size_x = 0;
unsigned int load_size_y = 0;
ILenum Error;
ILuint ImgId;
static bool washere = false;
if(!washere)
{
ilInit();
iluInit();
washere=true;
}
ilEnable(IL_CONV_PAL);
ilEnable(IL_ORIGIN_SET);
ilOriginFunc(IL_ORIGIN_LOWER_LEFT);
ilGenImages(1, &ImgId);
ilBindImage(ImgId);
char* name_cstr = const_cast<char*>(name.c_str());
if(!ilLoadImage(name_cstr))
{
cout << "could not load <" << name_cstr << ">" << endl;
return false;
}
load_size_x = ilGetInteger(IL_IMAGE_WIDTH);
load_size_y = ilGetInteger(IL_IMAGE_HEIGHT);
bpp = ilGetInteger(IL_IMAGE_BITS_PER_PIXEL);
if (bpp==24)
ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
else if (bpp==32)
ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);
else if (bpp==8)
ilConvertImage(IL_LUMINANCE, IL_UNSIGNED_BYTE);
else
assert(0);
unsigned int i;
for (i=2;i<=4096 ;i*=2)
if (i>=load_size_x)
break;
size_x = i;
for (i=2;i<=4096 ;i*=2)
if (i>=load_size_y)
break;
size_y = i;
if(size_x != load_size_x || size_y != load_size_y)
{
iluImageParameter(ILU_FILTER, ILU_BILINEAR);
iluScale(size_x, size_y, 1);
}
const int image_size =size_x*size_y*ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
image = new unsigned char[image_size];
memcpy(image, ilGetData(), image_size);
ilDeleteImages(1, &ImgId);
bool any_errors=false;
while ((Error = ilGetError())) {
cout << __LINE__ << "Error: " << iluErrorString(Error) << endl;
any_errors = true;
}
if(any_errors) return false;
GLint internalFormat=0;
GLenum format=0;
glGenTextures(1, &id);
switch (bpp)
{
case 8:
internalFormat = GL_LUMINANCE;
format = GL_LUMINANCE;
break;
case 24:
internalFormat = GL_RGB;
format = GL_RGB;
break;
case 32:
internalFormat = GL_RGBA;
format = GL_RGBA;
break;
default:
return false;
}
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, size_x, size_y, 0,
format, GL_UNSIGNED_BYTE, image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
return true;
}
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;
GLuint tex_id;
if(load_image_into_texture(name, tex_id))
mat.tex_id = tex_id;
}
}
}
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;
}
TriMesh mesh;
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 idle()
{
if ( glutGetWindow() != main_window )
glutSetWindow(main_window);
glutPostRedisplay();
}
*/
void display()
{
static bool washere = false;
static unsigned int l;
if(!washere)
{
cout << "Creating display list" << endl;
l = glGenLists(1);
glNewList(l, GL_COMPILE);
draw(mesh);
glEndList();
washere = true;
glutTimerFunc(spin_timer, spin, 0);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
ball->set_gl_modelview();
glCallList(l);
glutSwapBuffers();
}
void keyboard(unsigned char key, int x, int y)
{
switch(key)
{
case '\033': exit(0); break;
//case '+': ball->closer(); break;
//case '-': ball->farther(); break;
//default:
// ball->up_axis(key);
}
}
}
int main(int argc, char** argv)
{
// 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);
// 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(argc>1)
fn = argv[1];
else
fn = "../../data/head.obj";
cout << "Loading " << fn << endl;
if(fn == "") exit(0);
obj_load(fn, mesh);
enable_textures(mesh);
if(!mesh.has_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);
// Pass control to GLUT
glutMainLoop();
return 0;
}