Subversion Repositories gelsvn

Rev

Rev 341 | Rev 365 | 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 <IL/il.h>
#include <IL/ilu.h>

#include <CGLA/Vec2i.h>
#include <CGLA/Vec2f.h>
#include <CGLA/Vec3f.h>
#include <CGLA/Mat4x4f.h>
#include "glsl_shader.h"
#include "GLGraphics/gel_glut.h"
#include "GLGraphics/QuatTrackBall.h"
#include "GLGraphics/draw.h"
#include "Geometry/TriMesh.h"
#include "Geometry/obj_load.h"

#include "ply_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;
        TriMesh mesh;
        
        
        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;
                        }
                }
        }
        
        void toggle_wire()
        {
                static bool wire= false;
                static string shader_path = "/Users/jab/SrcTree/Appsrc/wireframepaper/";
                static GLhandleARB prog_P0;
                
                wire = !wire;
                static bool washere = false;
                if(!washere)
                {
                        washere = true;
                        
                        // Create s     haders directly from file
                        GLuint vs = create_glsl_shader(GL_VERTEX_SHADER, shader_path, "tri.vert");
                        GLuint gs = create_glsl_shader(GL_GEOMETRY_SHADER_EXT, shader_path, "tri.geom");
                        GLuint fs = create_glsl_shader(GL_FRAGMENT_SHADER, shader_path, "tri.frag");
                        
                        // Create the program
                        prog_P0 = glCreateProgram();
                        
                        // Attach all shaders
                        if(vs) glAttachShader(prog_P0, vs);
                        if(gs) glAttachShader(prog_P0, gs);
                        if(fs) glAttachShader(prog_P0, fs);
                        
                        // Specify input and output for the geometry shader. Note that this must be
                        // done before linking the program.
                        glProgramParameteriEXT(prog_P0,GL_GEOMETRY_INPUT_TYPE_EXT,GL_TRIANGLES);
                        glProgramParameteriEXT(prog_P0,GL_GEOMETRY_VERTICES_OUT_EXT,3);
                        glProgramParameteriEXT(prog_P0,GL_GEOMETRY_OUTPUT_TYPE_EXT,GL_TRIANGLE_STRIP);
                        
                        // Link the program object and print out the info log
                        glLinkProgram(prog_P0);
                }
                if(wire)
                {
                        glUseProgram(prog_P0);
                        // Set the value of a uniform
                        glUniform2f(glGetUniformLocation(prog_P0,"WIN_SCALE"), win_size_x/2.0, win_size_y/2.0);
                }
                else
                        glUseProgram(0);                
        }
        
        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 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 'w': toggle_wire(); break;
    }
}
}

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);
        
        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(argc>1)
        fn = argv[1];
    else
        fn = "../../data/head.obj";
                
        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
        {
                cout << "Either the format was unrecognized or the file did not have the appropriate extension" << endl;
                exit(0);
        }               
    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;
}