Subversion Repositories gelsvn

Rev

Rev 387 | Rev 394 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 *  MeshEdit is a small application which allows you to load and edit a mesh.
 *  The mesh will be stored in GEL's half edge based Manifold data structure.
 *  A number of editing operations are supported. Most of these are accessible from the 
 *  console that pops up when you hit 'esc'.
 *
 *  Created by J. Andreas Bærentzen on 15/08/08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */
#include <iostream>
#include <CGLA/eigensolution.h>
#include <CGLA/Vec2d.h>
#include <CGLA/Vec3d.h>
#include <CGLA/Mat3x3d.h>
#include <CGLA/Mat2x2d.h>
#include <CGLA/Mat2x3d.h>

#include <LinAlg/Matrix.h>
#include <LinAlg/Vector.h>
#include <LinAlg/LapackFunc.h>

#include <Util/Timer.h>
#include <Util/ArgExtracter.h>

#include <GL/glew.h>
#include <GLGraphics/gel_glut.h>
#include <GLGraphics/draw.h>
#include <GLGraphics/glsl_shader.h>
#include <GLGraphics/GLViewController.h>

#include <HMesh/Manifold.h>
#include <HMesh/VertexCirculator.h>
#include <HMesh/FaceCirculator.h>
#include <HMesh/build_manifold.h>
#include <HMesh/mesh_optimization.h>
#include <HMesh/triangulate.h>
#include <HMesh/load.h>
#include <HMesh/quadric_simplify.h>
#include <HMesh/smooth.h>
#include <HMesh/x3d_save.h>
#include <HMesh/obj_save.h>
#include <HMesh/mesh_optimization.h>
#include <HMesh/triangulate.h>
#include <HMesh/close_holes.h>
#include <HMesh/caps_and_needles.h>
#include <HMesh/refine_edges.h>
#include <HMesh/subdivision.h>

#include <GLConsole/GLConsole.h>

#include "harmonics.h"
#include "wireframe.h"


// Single global instance so glut can get access
GLConsole theConsole;

////////////////////////////////////////////////////////////////////////////////
char* ConsoleHelp(std::vector<std::string> &args)
{
    theConsole.Printf("");
    theConsole.Printf("----------------- HELP -----------------");
    theConsole.Printf("Press ~ key to open and close console");
    theConsole.Printf("Press TAB to see the available commands and functions");
    theConsole.Printf("Functions are shown in green and variables in yellow");
    theConsole.Printf("Setting a value: [command] = value");
    theConsole.Printf("Getting a value: [command]");
    theConsole.Printf("Functions: [function] [arg1] [arg2] ...");
    theConsole.Printf("Entering just the function name will give a description.");
    theConsole.Printf("History: Up and Down arrow keys move through history.");
    theConsole.Printf("Tab Completion: TAB does tab completion and makes suggestions.");
    theConsole.Printf("----------------- HELP -----------------");
    theConsole.Printf("");
    return "";
}

using namespace std;
using namespace HMesh;
using namespace Geometry;
using namespace GLGraphics;
using namespace CGLA;
using namespace Util;
using namespace LinAlg;



namespace 
{
        GLViewController* view_ctrl;
        int WINX=800, WINY=800;
        string file;
        
        Manifold mani;  
        bool create_display_list = true;
}

char* console_save(std::vector<std::string> &args)
{
        string& file_name = args[0];
        if(args.size() == 1)
        {
                if(file_name.substr(file_name.length()-4,file_name.length())==".obj")
                {
                        obj_save(file_name, mani);
                        return "";
                }
                else if(file_name.substr(file_name.length()-4,file_name.length())==".x3d")
                {
                        x3d_save(file_name, mani);
                        return "";
                }
                return "unknown format";
        }
        return "usage: save <name.x3d|name.obj> ";
}

char* console_refine_edges(std::vector<std::string> &args)
{
        float thresh = 0.5;
        if(args.size()>0)
        {
                istringstream a0(args[0]);
                a0 >> thresh;
        }
        float avg_length = average_edge_length(mani);
        refine_edges(mani, thresh * avg_length);
        return "";

}

char* console_refine_faces(std::vector<std::string> &args)
{
        safe_triangulate(mani);
        return "";

}

char* console_cc_subdivide(std::vector<std::string> &args)
{
        cc_split(mani,mani);
        return "";
}



char* console_minimize_curvature(std::vector<std::string> &args)
{
        bool anneal=false;
        if(args.size()>0)
        {
                istringstream a0(args[0]);
                a0 >> anneal;
        }

        minimize_curvature(mani, anneal);
        create_display_list = true;
        return "";
}

char* console_minimize_dihedral(std::vector<std::string> &args)
{
        int iter = 1000;
        if(args.size()>0)
        {
                istringstream a0(args[0]);
                a0 >> iter;
        }

        bool anneal = false;
        if(args.size()>1)
        {
                istringstream a0(args[0]);
                a0 >> anneal;
        }

        bool use_alpha = true;
        if(args.size()>2)
        {
                istringstream a0(args[0]);
                a0 >> use_alpha;
        }

        float gamma = 4.0;
        if(args.size()>3)
        {
                istringstream a0(args[0]);
                a0 >> gamma;
        }
        
        
        minimize_dihedral_angle(mani, iter, anneal, use_alpha, gamma);
        return "";
}

char* console_maximize_min_angle(std::vector<std::string> &args)
{
        float thresh=0.0;
        if(args.size()>0)
        {
                istringstream a0(args[0]);
                a0 >> thresh;
        }
        bool anneal=false;
        if(args.size()>1)
        {
                istringstream a0(args[0]);
                a0 >> anneal;
        }
        maximize_min_angle(mani,thresh,anneal);
        return "";
}


char* console_optimize_valency(std::vector<std::string> &args)
{
        bool anneal=false;
        if(args.size()>0)
        {
                istringstream a0(args[0]);
                a0 >> anneal;
        }
        optimize_valency(mani, anneal);
        return "";
}

char* console_analyze(std::vector<std::string> &args)
{
        analyze_mesh(mani);
        return "";
}


char* console_partial_reconstruct(std::vector<std::string> &args)
{
        int E0,E1;
        float scale;
        istringstream a0(args[0]);
        a0 >> E0;
        istringstream a1(args[1]);
        a1 >> E1;
        istringstream a2(args[2]);
        a2 >> scale;
        partial_reconstruct(mani, E0,E1,scale);
        return "";
}

char* console_reset_shape(std::vector<std::string> &args)
{
        reset_shape(mani);
        return "";
}

void reshape(int W, int H)
{
        view_ctrl->reshape(W,H);
}

char* console_close_holes(std::vector<std::string> &args)
{
        close_holes(mani);
        return "";
}

char* console_reload(std::vector<std::string> &args)
{
        if(args.size()>0)
                file = args[0];
        mani.clear();
        load(file, mani); 
        Vec3f c(0,0,0);
        float r = 5;
        mani.get_bsphere(c,r);
        delete view_ctrl;
        view_ctrl = new GLViewController(WINX,WINY, c,r*2);
        return "";
}


char* console_simplify(std::vector<std::string> &args)
{
        float keep_fraction;
        if(args.size()==0) return "you must specify fraction of vertices to keep";
        istringstream a0(args[0]);
        a0 >> keep_fraction;

        Vec3f p0, p7;
        mani.get_bbox(p0, p7);
        Vec3f d = p7-p0;
        float s = 1.0/d.max_coord();
        Vec3f pcentre = (p7+p0)/2.0;
        for(VertexIter vi = mani.vertices_begin(); vi != mani.vertices_end(); ++vi)
                vi->pos = (vi->pos - pcentre) * s;
        quadric_simplify(mani,keep_fraction,0.0001f,true);
        for(VertexIter vi = mani.vertices_begin(); vi != mani.vertices_end(); ++vi)
                vi->pos = vi->pos*d.max_coord() + pcentre;
        return "";
}

char* console_laplacian_smooth(std::vector<std::string> &args)
{
        float t=1.0;
        if(args.size()>0)
        {
                istringstream a0(args[0]);
                a0 >> t;
        }
        /// Simple laplacian smoothing with an optional weight.
        laplacian_smooth(mani, t);
        return "";
}

char* console_taubin_smooth(std::vector<std::string> &args)
{
        int iter=1;
        if(args.size()>0)
        {
                istringstream a0(args[0]);
                a0 >> iter;
        }
        
        /// Taubin smoothing is similar to laplacian smoothing but reduces shrinkage
        taubin_smooth(mani,  iter);
        return "";
}

char* console_fvm_smooth(std::vector<std::string> &args)
{       
        int iter=1;
        if(args.size()>0)
        {
                istringstream a0(args[0]);
                a0 >> iter;
        }
        /** Fuzzy vector median smoothing is effective when it comes to
         preserving sharp edges. */
        fvm_smooth(mani,  iter);
        return "";

}

char* console_triangulate(std::vector<std::string> &args)
{       
        shortest_edge_triangulate(mani);
        return "";
}


char* console_remove_caps(std::vector<std::string> &args)
{       
        remove_caps_from_trimesh(mani, static_cast<float>(M_PI) * 0.85f);
        return "";
}

char* console_remove_needles(std::vector<std::string> &args)
{       
        float thresh = 0.1;
        if(args.size()>0)
        {
                istringstream a0(args[0]);
                a0 >> thresh;
        }
        float avg_length = average_edge_length(mani);
        remove_needles_from_trimesh(mani, thresh * avg_length);
        return "";
}

void display() 
{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        static CVar<int> display_wireframe("display.wireframe",0);
        static CVar<int> display_eigenmodes("display.eigenmodes",0);
        static CVar<int> display_flat("display.flatshading",0);
        
        glPushMatrix();
        
        view_ctrl->set_gl_modelview();
        
        if(create_display_list)
        {
                create_display_list = false;
                
                glNewList(1,GL_COMPILE);
                if(display_wireframe)
                        {
                                enable_wireframe();
                                draw(mani);
                                glUseProgram(0);        
                        }
                else if(display_eigenmodes)
                        draw_eigenvalues(mani);
                else 
                        draw(mani,!display_flat);
                glEndList();
        }
        glCallList(1);
        
        glPopMatrix();
        
        glUseProgram(0);
        theConsole.RenderConsole();
        
        glutSwapBuffers();
}

void animate() 
{       
        usleep( (int)1e4 );
        view_ctrl->try_spin();
        glutPostRedisplay();
}


void mouse(int button, int state, int x, int y) 
{
        Vec2i pos(x,y);
        if (state==GLUT_DOWN) 
        {
                if (button==GLUT_LEFT_BUTTON) 
                        view_ctrl->grab_ball(ROTATE_ACTION,pos);
                else if (button==GLUT_MIDDLE_BUTTON) 
                        view_ctrl->grab_ball(ZOOM_ACTION,pos);
                else if (button==GLUT_RIGHT_BUTTON) 
                        view_ctrl->grab_ball(PAN_ACTION,pos);
        }
        else if (state==GLUT_UP)
                view_ctrl->release_ball();
}

void motion(int x, int y) {
        Vec2i pos(x,y);
        view_ctrl->roll_ball(Vec2i(x,y));
}

void keyboard_spec(int key, int x, int y)
{
   int mod = glutGetModifiers();
   if( theConsole.isOpen() ) {
        // If shift held, scroll the console
        if( mod == GLUT_ACTIVE_SHIFT ) {
            switch (key){
                case GLUT_KEY_UP:
                    theConsole.ScrollDownLine();
                    break;
                case GLUT_KEY_DOWN: 
                    theConsole.ScrollUpLine();
                    break;
            }
        } else {
            theConsole.StandardKeyBindings( key );
        }
    }
}

template<typename T>
T& get_CVar_ref(const std::string& s)
{
        return *reinterpret_cast<T*> (GetCVarData(s));
}

void keyboard(unsigned char key, int x, int y) 
{       
        if(theConsole.isOpen())
                {
                switch(key) {
                        case '\033': 
                                theConsole.ToggleConsole();
                        default:      
                                //send keystroke to console
                                if( theConsole.isOpen() ){
                                        theConsole.EnterCommandCharacter(key);
                                }
                                break;
                }
                if(key == 13)   create_display_list = true;

                }       
        else {
                int& display_eigenvalue = get_CVar_ref<int>("display.harmonics.eigenvalue");
                int& display_wireframe = get_CVar_ref<int>("display.wireframe");
                int& display_diffuse = get_CVar_ref<int>("display.harmonics.diffuse");
                int& display_highlight = get_CVar_ref<int>("display.harmonics.highlight");
                int& display_flat = get_CVar_ref<int>("display.flatshading");
                
                switch(key) {
                        case 'q': exit(0);
                        case '\033':
                                theConsole.ToggleConsole();
                                break;
                        case 'f': display_flat = !display_flat;
                        case '+': 
                                display_eigenvalue = min(display_eigenvalue+1, MAX_E); 
                                break;
                        case '-': 
                                display_eigenvalue = max(display_eigenvalue-1, 0); 
                                break;
                        case '1': E = 1; reconstruct(mani,E); 
                                break;
                        case '>': if(E < MAX_E) partial_reconstruct(mani,E,++E); 
                                break;
                        case '<': E = max(E-1, 0); reconstruct(mani,E); 
                                break;
                        case 'd':       
                                display_diffuse = !display_diffuse; 
                                break;
                        case 'h':
                                display_highlight = !display_highlight;
                                break;                  
                        case 'w':
                                display_wireframe = !display_wireframe;
                                break;
                }
                create_display_list = true;

        }
}

void init_glut(int argc, char** argv)
{
        glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
        glutInitWindowSize(WINX, WINY);
        glutInit(&argc, argv);
        glutCreateWindow("Shape Harmonics");
        glutDisplayFunc(display);
        glutKeyboardFunc(keyboard);
        glutSpecialFunc(keyboard_spec);
        glutReshapeFunc(reshape);
        glutMouseFunc(mouse);
        glutMotionFunc(motion);
        glutIdleFunc(animate);
}

void init_gl()
{
        glewInit();
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
        Vec3f c(0,0,0);
        float r = 5;
        mani.get_bsphere(c,r);
        view_ctrl = new GLViewController(WINX,WINY, c,r*2);
        
        initialize_wireframe_shaders();
        
        
        // Set the value of a uniform
        //glUniform2f(glGetUniformLocation(prog_P0,"WIN_SCALE"), win_size_x/2.0, win_size_y/2.0);
        
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glClearColor(0.50f, 0.50f, 0.50f, 0.f);
        glColor4f(1.0f, 1.0f, 1.0f, 0.f);
        glEnable(GL_DEPTH_TEST);
        
        static CVar<ConsoleFunc> help( "help", ConsoleHelp );
        static CVar<ConsoleFunc> rs("harmonics_reset_shape", console_reset_shape);
        static CVar<ConsoleFunc> ha("harmonics_analyze", console_analyze);
        static CVar<ConsoleFunc> pr("harmonics_partial_reconstruct", console_partial_reconstruct);
        static CVar<ConsoleFunc> simpl("simplify", console_simplify);
        static CVar<ConsoleFunc> lsmooth("laplacian_smooth", console_laplacian_smooth);
        static CVar<ConsoleFunc> tsmooth("taubin_smooth", console_taubin_smooth);
        static CVar<ConsoleFunc> fsmooth("fvm_smooth", console_fvm_smooth);

        static CVar<ConsoleFunc> opt_val("optimize_valency", console_optimize_valency);
        static CVar<ConsoleFunc> min_dih("minimize_dihedral", console_minimize_dihedral);
        static CVar<ConsoleFunc> min_curv("minimize_curvature", console_minimize_curvature);
        static CVar<ConsoleFunc> max_min_angle("maximize_min_angle", console_maximize_min_angle);
        static CVar<ConsoleFunc> close_holes_fun("close_holes", console_close_holes);
        static CVar<ConsoleFunc> reload_fun("reload", console_reload);

        static CVar<ConsoleFunc> rem_caps_fun("remove_caps", console_remove_caps);
        static CVar<ConsoleFunc> rem_needles_fun("remove_needles", console_remove_needles);
        static CVar<ConsoleFunc> triangulate_fun("triangulate", console_triangulate);
        static CVar<ConsoleFunc> refine_fun("refine_edges", console_refine_edges);
        static CVar<ConsoleFunc> refine_face_fun("refine_faces", console_refine_faces);
        static CVar<ConsoleFunc> subd_fun("refine_catmull_clark", console_cc_subdivide);
        static CVar<ConsoleFunc> save_fun("save", console_save);
        
        
}

int main(int argc, char** argv)
{
        ArgExtracter ae(argc, argv);
        ae.extract("-E", E);
    if(argc>1)
        {               
                 file = ae.get_last_arg();
                load(file, mani);
        }

        
        init_glut(argc,argv);
        init_gl();
        init_harmonics();

        glutMainLoop();
}