wfobj-view/wfobj-view.cc
2011-05-16 16:12:41 -04:00

324 lines
8.8 KiB
C++

/* Libraries we use */
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <iostream>
#include "wfobj/WFObj.h"
#include "loadTexture/loadTexture.h"
#include "glslUtil/glslUtil.h"
using namespace std;
/* Some definitions */
#define WIDTH 800
#define HEIGHT 800
#define TITLE "Josh's Wavefront Object Viewer"
enum Locations {
LOC_POSITION,
LOC_NORMAL,
LOC_TEXTURE
};
class Viewer
{
public:
Viewer(const char * filename);
void run();
private:
void initgl();
void display();
void setProjection();
WFObj m_obj;
GLuint m_list;
float m_rotationMatrix[16];
int m_startx, m_starty;
bool m_dragging;
float m_dist;
GLuint m_program, m_tex_program;
GLint m_ambient_loc, m_diffuse_loc, m_specular_loc, m_shininess_loc;
GLint m_tex_ambient_loc, m_tex_specular_loc, m_tex_shininess_loc,
m_tex_tex_loc;
};
static GLuint load_texture(const char *fname)
{
GLuint id = loadTexture(fname);
if (id != 0)
{
glBindTexture(GL_TEXTURE_2D, id);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
return id;
}
/* The program's main entry point */
int main(int argc, char * argv[])
{
if (argc < 2)
{
cerr << "Usage: " << argv[0] << " <filename>" << endl;
return -1;
}
if (SDL_Init(SDL_INIT_VIDEO))
{
printf("Failed to initialize SDL!\n");
return -2;
}
atexit(SDL_Quit);
SDL_Surface * screen;
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if (!(screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_OPENGL)))
{
printf("Failed to set video mode!\n");
SDL_Quit();
return -3;
}
SDL_WM_SetCaption(TITLE, TITLE);
Viewer v(argv[1]);
v.run();
return 0;
}
Viewer::Viewer(const char * filename)
{
m_dist = 5.0;
m_dragging = false;
if (!m_obj.load(filename, NULL, load_texture))
{
cerr << "Error loading " << filename << endl;
exit(1);
}
const static guAttribBinding bindings[] = {
{LOC_POSITION, "pos"},
{LOC_NORMAL, "normal"},
{0, NULL}
};
m_program = guMakeProgramFromFiles("v_shader.glsl", "f_shader.glsl",
bindings);
const static guAttribBinding tex_bindings[] = {
{LOC_POSITION, "pos"},
{LOC_NORMAL, "normal"},
{LOC_TEXTURE, "tex_coord"},
{0, NULL}
};
m_tex_program = guMakeProgramFromFiles("v_tex_shader.glsl",
"f_tex_shader.glsl", tex_bindings);
if (m_program == 0 || m_tex_program == 0)
{
exit(1);
}
guUniformLocation uniforms[] = {
{&m_ambient_loc, "ambient"},
{&m_diffuse_loc, "diffuse"},
{&m_specular_loc, "specular"},
{&m_shininess_loc, "shininess"},
{NULL, NULL}
};
guGetUniformLocations(m_program, uniforms);
guUniformLocation tex_uniforms[] = {
{&m_tex_ambient_loc, "ambient"},
{&m_tex_specular_loc, "specular"},
{&m_tex_shininess_loc, "shininess"},
{&m_tex_tex_loc, "tex"},
{NULL, NULL}
};
guGetUniformLocations(m_tex_program, tex_uniforms);
glUseProgram(m_program);
glUniform4f(m_ambient_loc, 0.2, 0.2, 0.2, 1.0);
glUniform4f(m_diffuse_loc, 1.0, 1.0, 1.0, 1.0);
glUniform4f(m_specular_loc, 1.0, 1.0, 1.0, 1.0);
glUniform1f(m_shininess_loc, 85.0);
glUseProgram(m_tex_program);
glUniform4f(m_tex_ambient_loc, 0.2, 0.2, 0.2, 1.0);
glUniform4f(m_tex_specular_loc, 1.0, 1.0, 1.0, 1.0);
glUniform1f(m_tex_shininess_loc, 85.0);
/* Print out the object's size */
const float * aabb = m_obj.getAABB();
cout << "Object width: " << (aabb[3]-aabb[0]) << endl;
cout << "Object depth: " << (aabb[4]-aabb[1]) << endl;
cout << "Object height: " << (aabb[5]-aabb[2]) << endl;
}
void Viewer::initgl()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, WIDTH, HEIGHT);
setProjection();
glLoadIdentity();
glGetFloatv(GL_MODELVIEW_MATRIX, m_rotationMatrix);
}
void Viewer::setProjection()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)WIDTH/(GLfloat)WIDTH, 0.01, 10000.0);
// gluLookAt(0, m_dist, 0, 0, 0, 0, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
}
void Viewer::display()
{
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0, -m_dist, 0, 0, 0, 0, 0, 0, 1);
glMultMatrixf(m_rotationMatrix);
m_obj.bindBuffers();
GLuint program = m_program;
glUseProgram(m_program);
glEnableVertexAttribArray(LOC_POSITION);
glEnableVertexAttribArray(LOC_NORMAL);
int stride = m_obj.getStride();
glVertexAttribPointer(LOC_POSITION, 3, GL_FLOAT, GL_FALSE,
stride, (GLvoid *) m_obj.getVertexOffset());
glVertexAttribPointer(LOC_NORMAL, 3, GL_FLOAT, GL_FALSE,
stride, (GLvoid *) m_obj.getNormalOffset());
if (m_obj.doTextures())
{
glVertexAttribPointer(LOC_TEXTURE, 2, GL_FLOAT, GL_FALSE,
stride, (GLvoid *) m_obj.getTextureCoordOffset());
}
for (map<string, WFObj::Material>::iterator it =
m_obj.getMaterials().begin();
it != m_obj.getMaterials().end();
it++)
{
WFObj::Material & m = it->second;
if (m.flags & WFObj::Material::TEXTURE_BIT)
{
if (program != m_tex_program)
{
glUseProgram(m_tex_program);
program = m_tex_program;
glEnableVertexAttribArray(LOC_TEXTURE);
}
}
else
{
if (program != m_program)
{
glUseProgram(m_program);
program = m_program;
glDisableVertexAttribArray(LOC_TEXTURE);
}
}
if (m.flags & WFObj::Material::SHININESS_BIT)
{
if (program == m_tex_program)
glUniform1f(m_tex_shininess_loc, m.shininess);
else
glUniform1f(m_shininess_loc, m.shininess);
}
if (m.flags & WFObj::Material::AMBIENT_BIT)
{
if (program == m_tex_program)
glUniform4fv(m_tex_ambient_loc, 1, &m.ambient[0]);
else
glUniform4fv(m_ambient_loc, 1, &m.ambient[0]);
}
if (m.flags & WFObj::Material::DIFFUSE_BIT)
{
if (program != m_tex_program)
glUniform4fv(m_diffuse_loc, 1, &m.diffuse[0]);
}
if (m.flags & WFObj::Material::SPECULAR_BIT)
{
if (program == m_tex_program)
glUniform4fv(m_tex_specular_loc, 1, &m.specular[0]);
else
glUniform4fv(m_specular_loc, 1, &m.specular[0]);
}
glDrawElements(GL_TRIANGLES, m.num_vertices,
GL_UNSIGNED_SHORT,
(GLvoid *) (sizeof(GLushort) * m.first_vertex));
}
SDL_GL_SwapBuffers();
}
void Viewer::run()
{
initgl();
display();
SDL_Event event;
while (SDL_WaitEvent(&event))
{
if (event.type == SDL_QUIT)
break;
else if (event.type == SDL_KEYDOWN)
{
if (event.key.keysym.sym == SDLK_ESCAPE)
break;
if (event.key.keysym.sym == SDLK_q)
break;
}
else if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
if (event.button.state == SDL_PRESSED)
{
m_dragging = true;
m_startx = event.button.x;
m_starty = event.button.y;
}
}
else if (event.button.button == 4)
{
m_dist *= 0.85;
if (m_dist < 1.0f)
m_dist = 1.0f;
setProjection();
display();
}
else if (event.button.button == 5)
{
m_dist *= 1.2;
setProjection();
display();
}
}
else if (event.type == SDL_MOUSEBUTTONUP)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
m_dragging = false;
}
}
else if (event.type == SDL_MOUSEMOTION)
{
if (m_dragging)
{
glLoadIdentity();
glRotatef(event.motion.y - m_starty, 1, 0, 0);
glRotatef(event.motion.x - m_startx, 0, 0, 1);
glMultMatrixf(m_rotationMatrix);
glGetFloatv(GL_MODELVIEW_MATRIX, m_rotationMatrix);
m_startx = event.motion.x;
m_starty = event.motion.y;
display();
}
}
}
}