#define _CRT_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS
#define FREEGLUT_STATIC
#include "gl_core_3_3.h"
#include <GL/glut.h>
#include <GL/freeglut_ext.h>
#define TW_STATIC
#include <AntTweakBar.h>
#include <ctime>
#include <memory>
#include <vector>
#include <string>
#include <cstdlib>
#include <thread>
#include "glprogram.h"
#include "MyImage.h"
#include "VAOImage.h"
#include "VAOMesh.h"
#include "trackball.h"
#include "matlab_utils.h"
#include "matlabDeformer.h"
GLProgram MyMesh::pickProg, MyMesh::depthTestProg, MyMesh::geometryProj2Screen, MyMesh::pointSet, MyMesh::ssaoProg, MyMesh::ssaoBlurProg, MyMesh::screenProg;
GLTexture MyMesh::colormapTex, MyMesh::chessboardTex, MyMesh:: chessboardTex_background;
std::shared_ptr<Deformer> deformer;
MyMesh M;
int actPrimType = MyMesh::PE_VERTEX;
bool showATB = true;
using MatX3f = Eigen::Matrix<float, Eigen::Dynamic, 3, Eigen::RowMajor>;
using MatX3i = Eigen::Matrix<int, Eigen::Dynamic, 3, Eigen::RowMajor>;
using MatX2f = Eigen::Matrix<float, Eigen::Dynamic, 2, Eigen::RowMajor>;
//int nIteration = 1;
float BackgroundColor[3] = { 1.0f, 1.0f, 1.0f };
int model_id = 0;
std::vector<std::string> model_names; //const char *[] = { 'hand', 'horse' };
std::vector<std::string> method_names; //const char *[] = { "newton", ... };
int method = -1;
double w_smooth = 50;
void loadMeshFromMatlab()
{
/*load vertices, faces, texcoords and vertices-norm*/
MatX3f X;
MatX3i T;
MatX2f texCoord;
matlab2eigen("single(viewX)", X, true);
matlab2eigen("int32(viewT-1)", T, true);
matlab2eigen("single(para_Coord)", texCoord, true);
MatX3f N;
matlab2eigen("single(normX)", N, true);
M.upload(X.data(), X.rows(), N.data(), T.data(), T.rows(), texCoord.data());
}
void meshDeform()
{
if (deformer)
{
deformer->deform();
}
}
int mousePressButton;
int mouseButtonDown;
int mousePos[2];
void display()
{
glClearColor(BackgroundColor[0], BackgroundColor[1], BackgroundColor[2], 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, M.vp[2], M.vp[3]);
M.draw();
if (showATB) TwDraw();
glutSwapBuffers();
glFlush();
}
void onKeyboard(unsigned char code, int x, int y)
{
if (!TwEventKeyboardGLUT(code, x, y)) {
switch (code) {
case 17:
exit(0);
case 'f':
glutFullScreenToggle();
break;
case ' ':
showATB = !showATB;
break;
}
}
glutPostRedisplay();
}
void onMouseButton(int button, int updown, int x, int y)
{
if (!showATB || !TwEventMouseButtonGLUT(button, updown, x, y)) {
mousePressButton = button;
mouseButtonDown = updown;
if (updown == GLUT_DOWN) {
if (button == GLUT_LEFT_BUTTON) {
if (glutGetModifiers()&GLUT_ACTIVE_CTRL) {
}
else {
int r = M.pick(x, y, M.PE_VERTEX, M.PO_ADD);
}
}
else if (button == GLUT_RIGHT_BUTTON) {
matlabEval("Deformation_Converged = 0;");
M.pick(x, y, M.PE_VERTEX, M.PO_REMOVE);
meshDeform();
}
}
else { // updown == GLUT_UP
if (button == GLUT_LEFT_BUTTON);
}
mousePos[0] = x;
mousePos[1] = y;
}
glutPostRedisplay();
}
void onMouseMove(int x, int y)
{
if (!showATB || !TwEventMouseMotionGLUT(x, y)) {
if (mouseButtonDown == GLUT_DOWN) {
if (mousePressButton == GLUT_MIDDLE_BUTTON) {
M.moveInScreen(mousePos[0], mousePos[1], x, y);
}
else if (mousePressButton == GLUT_LEFT_BUTTON) {
if (!M.moveCurrentVertex(x, y)) {
matlabEval("Deformation_Converged = 0;");
meshDeform();
display();
}
else {
const float s[2] = { 2.f / M.vp[2], 2.f / M.vp[3] };
auto r = Quat<float>(M.mQRotate)*Quat<float>::trackball(x*s[0] - 1, 1 - y*s[1], s[0]*mousePos[0] - 1, 1 - s[1]*mousePos[1]);
std::copy_n(r.q, 4, M.mQRotate);
}
}
}
}
mousePos[0] = x; mousePos[1] = y;
glutPostRedisplay();
}
void onMouseWheel(int wheel_number, int direction, int x, int y)
{
M.mMeshScale *= direction > 0 ? 1.1f : 0.9f;
glutPostRedisplay();
}
int initGL(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE);
glutInitWindowSize(1280, 960);
glutInitWindowPosition(200, 50);
glutCreateWindow(argv[0]);
// !Load the OpenGL functions. after the opengl context has been created
if (ogl_LoadFunctions() == ogl_LOAD_FAILED)
return -1;
glClearColor(BackgroundColor[0], BackgroundColor[1], BackgroundColor[2], 0);
glutReshapeFunc([](int w, int h) { M.resize(w, h); /*viewport[2] = w; viewport[3] = h;*/ TwWindowSize(w, h); });
glutDisplayFunc(display);
glutKeyboardFunc(onKeyboard);
glutMouseFunc(onMouseButton);
glutMotionFunc(onMouseMove);
glutMouseWheelFunc(onMouseWheel);
glutCloseFunc([]() {exit(0); });
return 0;
}
void loadMesh(std::string modelname)
{
string2matlab("model_name", modelname);
matlabEval("loadMesh");
loadMeshFromMatlab();
deformer.reset();
deformer.reset(new MatlabDeformer(M));
}
void createTweakbar()
{
TwBar *bar = TwGetBarByName("MeshViewer");
if (bar) TwDeleteBar(bar);
//Create a tweak bar
bar = TwNewBar("MeshViewer");
TwDefine(" MeshViewer size='220 250' color='0 128 255' text=dark alpha=128 position='5 5'"); // change default tweak bar size and color
model_names = matlab2strings("models");
loadMesh(model_names[0]);
TwType modelType = TwDefineEnumFromString("Models", catStr(model_names).c_str());
/*TwAddVarRW(bar, "Models", modelType, &model, " ");*/
TwAddVarCB(bar, "Shape", modelType,
[](const void *v, void *d) {
model_id = *(int*)v;
if (model_id < model_names.size()) { loadMesh(model_names[model_id]);}
},
[](void *v, void *) { *(int*)v = model_id; },
nullptr, " ");
//deformer.reset(new MatlabDeformer(M));
TwAddVarRO(bar, "#Vertex", TW_TYPE_INT32, &M.nVertex, " group='Mesh View'");
TwAddVarRO(bar, "#Face", TW_TYPE_INT32, &M.nFace, " group='Mesh View'");
TwAddVarRW(bar, "Point Size", TW_TYPE_FLOAT, &M.pointSize, " group='Mesh View' ");
TwAddVarRW(bar, "Edge Width", TW_TYPE_FLOAT, &M.edgeWidth, " group='Mesh View' ");
TwAddVarRW(bar, "Texture Scale", TW_TYPE_FLOAT, &M.mTextureScale, "min=0.01 max=10 step=0.5 group ='Mesh View' help='Texture Scale'");
TwAddVarRW(bar, "Smooth Mode", TW_TYPE_BOOLCPP, &M.isSmooth, " group='Mesh View'");
for (int i = 0; i < method_names.size(); i++)
matlabEval(method_names[i] + std::string(".set_p2p_weight(p2p_weight);"), false);
/*TwType methodType = TwDefineEnumFromString("Method", catStr(method_names).c_str());
TwAddVarCB(bar, "Method", methodType,
[](const void* v, void* d) {
method = *(int*)v;
matlabEval(method_names[method] + std::string(".ResetPointConstraints"), false);
meshDeform();
},
[](void* v, void*) { *(int*)v = method; },
nullptr, "group='Deformer'");*/
TwAddVarCB(bar, "enable GPU deformer", TW_TYPE_BOOLCPP,
[](const void* v, void* d) {
matlabEval(method_names[method] + std::string(".setGPUdeformer;"), false);
matlabEval(method_names[method] + std::string(".pre_numPoint_constraints = 0;"), false);
},
[](void* v, void* d) {
*(bool*)(v) = matlab2bool(method_names[method] + ".hasgpu", false, true);
},
nullptr, "group='Deformer'");
//////////////////////////////////////////////////////////////////////////
TwAddVarCB(bar, "P2P weight", TW_TYPE_FLOAT,
[](const void* v, void*) { scalar2matlab("p2p_weight", *(const float*)(v));
matlabEval(method_names[method] + std::string(".ResetPointConstraints;"), false);
for (int i = 0; i < method_names.size(); i++)
matlabEval(method_names[i] + std::string(".set_p2p_weight(p2p_weight);"), false);
},
[](void* v, void*) { *(float*)(v) = matlab2scalar("p2p_weight"); },
nullptr, " min=0 ");
TwAddButton(bar, "Reset View", [](void* d) {
M.updateBBox();
M.mMeshScale = 1.f;
M.mTranslate.assign(0.f);
//deformerptr(d)->M.resetmodelRotation();
M.resetViewCenter();
}, nullptr, "group='Deformer'");
TwAddButton(bar, "Reset Shape", [](void* d) {
M.constrainVertices.clear();
M.actConstrainVertex = -1;
deformer->resetDeform();
}, nullptr, " group='Deformer' key=r ");
TwAddVarCB(bar, "Pause", TW_TYPE_BOOLCPP,
[](const void* v, void* d) { deformer->needIteration = !*(bool*)(v); },
[](void* v, void* d) { *(bool*)(v) = !deformer->needIteration; },
nullptr, " group='Deformer' key=i ");
}
int main(int argc, char *argv[])
{
if (initGL(argc, argv)) {
fprintf(stderr, "!Failed to initialize OpenGL!Exit...");
exit(-1);
}
getMatEngine().connect("");
MyMesh::buildShaders();
//////////////////////////////////////////////////////////////////////////
TwInit(TW_OPENGL_CORE, NULL);
//Send 'glutGetModifers' function pointer to AntTweakBar;
//required because the GLUT key event functions do not report key modifiers states.
TwGLUTModifiersFunc(glutGetModifiers);
glutSpecialFunc([](int key, int x, int y) { TwEventSpecialGLUT(key, x, y); glutPostRedisplay(); }); // important for special keys like UP/DOWN/LEFT/RIGHT ...
TwCopyStdStringToClientFunc([](std::string& dst, const std::string& src) {dst = src; });
//////////////////////////////////////////////////////////////////////////
//atexit([] { fprintf(stdout, "exiting..."); TwDeleteAllBars(); TwTerminate(); fprintf(stdout, "exited."); });
atexit([] { deformer.reset(); TwDeleteAllBars(); TwTerminate(); fprintf(stdout, "exited."); });
glutTimerFunc(1, [](int) {
matlabEval("list_models", false);
matlabEval("addfolders;");
createTweakbar();
},
0);
glutTimerFunc(5, [](int) {
display();
},
0);
glutIdleFunc([]() {
using namespace std::literals::chrono_literals;
if (deformer && deformer->needIteration && !deformer->converged() && M.getConstrainVertexIds().size())
{ meshDeform(); glutPostRedisplay(); }
else std::this_thread::sleep_for(50ms); }
);
//////////////////////////////////////////////////////////////////////////
glutMainLoop();
return 0;
}