OpenSubdiv/examples/glutViewer/viewer.cpp
2012-06-12 16:36:53 -07:00

671 lines
21 KiB
C++

//
// Copyright (C) Pixar. All rights reserved.
//
// This license governs use of the accompanying software. If you
// use the software, you accept this license. If you do not accept
// the license, do not use the software.
//
// 1. Definitions
// The terms "reproduce," "reproduction," "derivative works," and
// "distribution" have the same meaning here as under U.S.
// copyright law. A "contribution" is the original software, or
// any additions or changes to the software.
// A "contributor" is any person or entity that distributes its
// contribution under this license.
// "Licensed patents" are a contributor's patent claims that read
// directly on its contribution.
//
// 2. Grant of Rights
// (A) Copyright Grant- Subject to the terms of this license,
// including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide,
// royalty-free copyright license to reproduce its contribution,
// prepare derivative works of its contribution, and distribute
// its contribution or any derivative works that you create.
// (B) Patent Grant- Subject to the terms of this license,
// including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide,
// royalty-free license under its licensed patents to make, have
// made, use, sell, offer for sale, import, and/or otherwise
// dispose of its contribution in the software or derivative works
// of the contribution in the software.
//
// 3. Conditions and Limitations
// (A) No Trademark License- This license does not grant you
// rights to use any contributor's name, logo, or trademarks.
// (B) If you bring a patent claim against any contributor over
// patents that you claim are infringed by the software, your
// patent license from such contributor to the software ends
// automatically.
// (C) If you distribute any portion of the software, you must
// retain all copyright, patent, trademark, and attribution
// notices that are present in the software.
// (D) If you distribute any portion of the software in source
// code form, you may do so only under this license by including a
// complete copy of this license with your distribution. If you
// distribute any portion of the software in compiled or object
// code form, you may only do so under a license that complies
// with this license.
// (E) The software is licensed "as-is." You bear the risk of
// using it. The contributors give no express warranties,
// guarantees or conditions. You may have additional consumer
// rights under your local laws which this license cannot change.
// To the extent permitted under your local laws, the contributors
// exclude the implied warranties of merchantability, fitness for
// a particular purpose and non-infringement.
//
#if defined(__APPLE__)
#include <GLUT/glut.h>
#else
#include <GL/glew.h>
#include <GL/glut.h>
#endif
#include <osd/vertex.h>
#include <osd/mesh.h>
#include <osd/cpuDispatcher.h>
#include <osd/glslDispatcher.h>
#include <common/shape_utils.h>
#include "../common/stopwatch.h"
#ifdef OPENSUBDIV_HAS_CUDA
#include <osd/cudaDispatcher.h>
#include <cuda_runtime_api.h>
#include <cuda_gl_interop.h>
#include "cudaInit.h"
#endif
#include <omp.h>
#include <vector>
//------------------------------------------------------------------------------
struct SimpleShape {
std::string name;
Scheme scheme;
char const * data;
SimpleShape( char const * idata, char const * iname, Scheme ischeme )
: name(iname), scheme(ischeme), data(idata) { }
};
std::vector<SimpleShape> g_defaultShapes;
int g_currentShape = 0;
void
initializeShapes( ) {
#include <shapes/bilinear_cube.h>
g_defaultShapes.push_back(SimpleShape(bilinear_cube, "bilinear_cube", kBilinear));
#include <shapes/catmark_cube_corner0.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_corner0, "catmark_cube_corner0", kCatmark));
#include <shapes/catmark_cube_corner1.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_corner1, "catmark_cube_corner1", kCatmark));
#include <shapes/catmark_cube_corner2.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_corner2, "catmark_cube_corner2", kCatmark));
#include <shapes/catmark_cube_corner3.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_corner3, "catmark_cube_corner3", kCatmark));
#include <shapes/catmark_cube_corner4.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_corner4, "catmark_cube_corner4", kCatmark));
#include <shapes/catmark_cube_creases0.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_creases0, "catmark_cube_creases0", kCatmark));
#include <shapes/catmark_cube_creases1.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_creases1, "catmark_cube_creases1", kCatmark));
#include <shapes/catmark_cube.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube, "catmark_cube", kCatmark));
#include <shapes/catmark_dart.h>
g_defaultShapes.push_back(SimpleShape(catmark_dart, "catmark_dart", kCatmark));
#include <shapes/catmark_edgecorner.h>
g_defaultShapes.push_back(SimpleShape(catmark_edgecorner ,"catmark_edgecorner", kCatmark));
#include <shapes/catmark_edgeonly.h>
g_defaultShapes.push_back(SimpleShape(catmark_edgeonly, "catmark_edgeonly", kCatmark));
#include <shapes/catmark_pyramid_creases0.h>
g_defaultShapes.push_back(SimpleShape(catmark_pyramid_creases0, "catmark_pyramid_creases0", kCatmark));
#include <shapes/catmark_pyramid_creases1.h>
g_defaultShapes.push_back(SimpleShape(catmark_pyramid_creases1, "catmark_pyramid_creases1", kCatmark));
#include <shapes/catmark_pyramid.h>
g_defaultShapes.push_back(SimpleShape(catmark_pyramid, "catmark_pyramid", kCatmark));
#include <shapes/catmark_tent_creases0.h>
g_defaultShapes.push_back(SimpleShape(catmark_tent_creases0, "catmark_tent_creases0", kCatmark));
#include <shapes/catmark_tent_creases1.h>
g_defaultShapes.push_back(SimpleShape(catmark_tent_creases1, "catmark_tent_creases1", kCatmark));
#include <shapes/catmark_tent.h>
g_defaultShapes.push_back(SimpleShape(catmark_tent, "catmark_tent", kCatmark));
#include <shapes/loop_cube_creases0.h>
g_defaultShapes.push_back(SimpleShape(loop_cube_creases0, "loop_cube_creases0", kLoop));
#include <shapes/loop_cube_creases1.h>
g_defaultShapes.push_back(SimpleShape(loop_cube_creases1, "loop_cube_creases1", kLoop));
#include <shapes/loop_cube.h>
g_defaultShapes.push_back(SimpleShape(loop_cube, "loop_cube", kLoop));
#include <shapes/loop_icosahedron.h>
g_defaultShapes.push_back(SimpleShape(loop_icosahedron, "loop_icosahedron", kLoop));
#include <shapes/loop_saddle_edgecorner.h>
g_defaultShapes.push_back(SimpleShape(loop_saddle_edgecorner, "loop_saddle_edgecorner", kLoop));
#include <shapes/loop_saddle_edgeonly.h>
g_defaultShapes.push_back(SimpleShape(loop_saddle_edgeonly, "loop_saddle_edgeonly", kLoop));
#include <shapes/loop_triangle_edgecorner.h>
g_defaultShapes.push_back(SimpleShape(loop_triangle_edgecorner, "loop_triangle_edgecorner", kLoop));
#include <shapes/loop_triangle_edgeonly.h>
g_defaultShapes.push_back(SimpleShape(loop_triangle_edgeonly, "loop_triangle_edgeonly", kLoop));
}
//------------------------------------------------------------------------------
int g_frame = 0,
g_repeatCount = 0;
// GLUT GUI variables
int g_wire = 0,
g_mbutton;
float g_rx = 0,
g_ry = 0,
g_prev_x = 0,
g_prev_y = 0,
g_dolly = 5;
int g_width,
g_height;
// performance
float g_cpuTime = 0;
float g_gpuTime = 0;
// geometry
std::vector<float> g_positions,
g_normals;
Scheme g_scheme;
int g_numIndices = 0;
int g_level = 2;
std::string g_kernel;
GLuint g_indexBuffer;
OpenSubdiv::OsdMesh * g_osdmesh = 0;
OpenSubdiv::OsdVertexBuffer * g_vertexBuffer = 0;
enum { KERNEL_CPU, KERNEL_OMP, KERNEL_GLSL, KERNEL_CL, KERNEL_CUDA };
//------------------------------------------------------------------------------
inline void
cross(float *n, const float *p0, const float *p1, const float *p2) {
float a[3] = { p1[0]-p0[0], p1[1]-p0[1], p1[2]-p0[2] };
float b[3] = { p2[0]-p0[0], p2[1]-p0[1], p2[2]-p0[2] };
n[0] = a[1]*b[2]-a[2]*b[1];
n[1] = a[2]*b[0]-a[0]*b[2];
n[2] = a[0]*b[1]-a[1]*b[0];
float rn = 1.0f/sqrtf(n[0]*n[0] + n[1] * n[1] + n[2] * n[2]);
n[0] *= rn;
n[1] *= rn;
n[2] *= rn;
}
//------------------------------------------------------------------------------
inline void
normalize(float * p) {
float dist = sqrtf( p[0]*p[0] + p[1]*p[1] + p[2]*p[2] );
p[0]/=dist;
p[1]/=dist;
p[2]/=dist;
}
//------------------------------------------------------------------------------
static void
calcNormals(OpenSubdiv::OsdHbrMesh * mesh, std::vector<float> const & pos, std::vector<float> & result ) {
// calc normal vectors
int nverts = (int)pos.size()/3;
int nfaces = mesh->GetNumCoarseFaces();
for (int i = 0; i < nfaces; ++i) {
OpenSubdiv::OsdHbrFace * f = mesh->GetFace(i);
float const * p0 = &pos[f->GetVertex(0)->GetID()*3],
* p1 = &pos[f->GetVertex(1)->GetID()*3],
* p2 = &pos[f->GetVertex(2)->GetID()*3];
float n[3];
cross( n, p0, p1, p2 );
for (int j = 0; j < f->GetNumVertices(); j++) {
int idx = f->GetVertex(j)->GetID() * 3;
result[ idx ] += n[0];
result[ idx+1] += n[1];
result[ idx+2] += n[2];
}
}
for (int i = 0; i < nverts; ++i)
normalize( &result[i*3] );
}
//------------------------------------------------------------------------------
void
updateGeom()
{
int nverts = (int)g_positions.size() / 3;
std::vector<float> vertex;
vertex.reserve(nverts*6);
const float *p = &g_positions[0];
const float *n = &g_normals[0];
for (int i = 0; i < nverts; ++i) {
float move = 0.05*cos(p[0]*20+g_frame*0.01);
vertex.push_back(p[0]);
vertex.push_back(p[1]+move);
vertex.push_back(p[2]);
vertex.push_back(n[0]);
vertex.push_back(n[1]);
vertex.push_back(n[2]);
p += 3;
n += 3;
}
if (!g_vertexBuffer) g_vertexBuffer = g_osdmesh->InitializeVertexBuffer(6);
g_vertexBuffer->UpdateData(&vertex[0], nverts);
Stopwatch s;
s.Start();
g_osdmesh->Subdivide(g_vertexBuffer, NULL);
s.Stop();
g_cpuTime = s.GetElapsed() * 1000.0f;
s.Start();
g_osdmesh->Synchronize();
s.Stop();
g_gpuTime = s.GetElapsed() * 1000.0f;
glBindBuffer(GL_ARRAY_BUFFER, g_vertexBuffer->GetGpuBuffer());
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
//------------------------------------------------------------------------------
void
createOsdMesh( const char * shape, int level, std::string kernel="omp", Scheme scheme=kCatmark ) {
// generate Hbr representation from "obj" description
OpenSubdiv::OsdHbrMesh * hmesh = simpleHbr<OpenSubdiv::OsdVertex>(shape, g_positions, scheme);
g_normals.resize(g_positions.size(),0.0f);
calcNormals( hmesh, g_positions, g_normals );
// generate Osd mesh from Hbr mesh
if (g_osdmesh) delete g_osdmesh;
g_osdmesh = new OpenSubdiv::OsdMesh();
g_osdmesh->Create(hmesh, level, kernel);
if (g_vertexBuffer) {
delete g_vertexBuffer;
g_vertexBuffer = NULL;
}
// Hbr mesh can be deleted
delete hmesh;
// update element array buffer
const std::vector<int> &indices = g_osdmesh->GetFarMesh()->GetFaceVertices(level);
g_numIndices = indices.size();
g_scheme = scheme;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*g_numIndices, &(indices[0]), GL_STATIC_DRAW);
updateGeom();
}
//------------------------------------------------------------------------------
void
reshape(int width, int height) {
g_width = width;
g_height = height;
}
#define drawString(x, y, fmt, ...) \
{ char line[1024]; \
snprintf(line, 1024, fmt, __VA_ARGS__); \
char *p = line; \
glWindowPos2f(x, y); \
while(*p) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *p++); } }
//------------------------------------------------------------------------------
void
display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, g_width, g_height);
double aspect = g_width/(double)g_height;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, aspect, 0.001, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -g_dolly);
glRotatef(g_ry, 1, 0, 0);
glRotatef(g_rx, 0, 1, 0);
GLuint bVertex = g_vertexBuffer->GetGpuBuffer();
#ifdef VARYING_NORMAL
GLuint bVarying = g_varyingBuffer->GetGpuBuffer();
glBindBuffer(GL_ARRAY_BUFFER, bVertex);
glVertexPointer(3, GL_FLOAT, 12, ((float*)(0)));
glBindBuffer(GL_ARRAY_BUFFER, bVarying);
glNormalPointer(GL_FLOAT, 12, ((float*)(0)));
#else
glBindBuffer(GL_ARRAY_BUFFER, bVertex);
glVertexPointer(3, GL_FLOAT, 24, ((float*)(0)));
glNormalPointer(GL_FLOAT, 24, ((float*)(12)));
#endif
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBuffer);
if(g_wire == 0){
glColor3f(1.0f, 1.0f, 1.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_LIGHTING);
glDrawElements(g_scheme==kLoop ? GL_TRIANGLES : GL_QUADS, g_numIndices, GL_UNSIGNED_INT, NULL);
}else{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_LIGHTING);
glDrawElements(g_scheme==kLoop ? GL_TRIANGLES : GL_QUADS, g_numIndices, GL_UNSIGNED_INT, NULL);
if(g_wire == 2){
glColor3f(0.0f, 0.0f, 0.5f);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_LIGHTING);
glDrawElements(g_scheme==kLoop ? GL_TRIANGLES : GL_QUADS, g_numIndices, GL_UNSIGNED_INT, NULL);
}
glColor3f(1.0f, 1.0f, 1.0f);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
drawString(10, 10, "LEVEL = %d", g_level);
drawString(10, 30, "# of Vertices = %d", g_osdmesh->GetFarMesh()->GetNumVertices());
drawString(10, 50, "KERNEL = %s", g_kernel.c_str());
drawString(10, 70, "CPU TIME = %.3f ms", g_cpuTime);
drawString(10, 90, "GPU TIME = %.3f ms", g_gpuTime);
drawString(10, 110, "SUBDIVISION = %s", g_scheme==kLoop ? "LOOP" : "CATMARK");
glFinish();
glutSwapBuffers();
}
//------------------------------------------------------------------------------
void motion(int x, int y)
{
if(g_mbutton == 0){
g_rx += x - g_prev_x;
g_ry += y - g_prev_y;
}else if(g_mbutton == 1){
g_dolly -= 0.01*(x - g_prev_x);
if(g_dolly <= 0.01) g_dolly = 0.01;
}
g_prev_x = x;
g_prev_y = y;
}
//------------------------------------------------------------------------------
void mouse(int button, int state, int x, int y)
{
g_prev_x = x;
g_prev_y = y;
g_mbutton = button;
}
//------------------------------------------------------------------------------
void quit()
{
if(g_osdmesh)
delete g_osdmesh;
#ifdef OPENSUBDIV_HAS_CUDA
cudaDeviceReset();;
#endif
exit(0);
}
//------------------------------------------------------------------------------
void kernelMenu(int k)
{
switch (k) {
case KERNEL_CPU : { g_kernel = "omp";
omp_set_num_threads(1);
} break;
case KERNEL_OMP : { g_kernel = "omp";
omp_set_num_threads(omp_get_num_procs());
} break;
case KERNEL_GLSL: g_kernel = "glsl"; break;
case KERNEL_CL : g_kernel = "cl"; break;
case KERNEL_CUDA: g_kernel = "cuda"; break;
default: break;
}
createOsdMesh( g_defaultShapes[ g_currentShape ].data, g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme );
}
//------------------------------------------------------------------------------
void
modelMenu(int m)
{
if (m < 0)
m = 0;
if (m >= (int)g_defaultShapes.size())
m = g_defaultShapes.size() - 1;
g_currentShape = m;
glutSetWindowTitle( g_defaultShapes[m].name.c_str() );
createOsdMesh( g_defaultShapes[m].data, g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme );
}
//------------------------------------------------------------------------------
void
levelMenu(int l)
{
g_level = l;
createOsdMesh( g_defaultShapes[g_currentShape].data, g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme );
}
//------------------------------------------------------------------------------
void
menu(int m)
{
}
//------------------------------------------------------------------------------
void
keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'q': quit();
case 'w': g_wire = (g_wire+1)%3; break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': levelMenu(key-'0'); break;
case 'n': modelMenu(++g_currentShape); break;
case 'p': modelMenu(--g_currentShape); break;
}
}
//------------------------------------------------------------------------------
void
idle()
{
g_frame++;
updateGeom();
glutPostRedisplay();
if(g_repeatCount != 0 && g_frame >= g_repeatCount){
quit();
}
}
//------------------------------------------------------------------------------
void
initGL()
{
glClearColor(0, 0, 0, 1);
glEnable(GL_LIGHT0);
glColor3f(1, 1, 1);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
GLfloat color[4] = {1, 1, 1, 1};
GLfloat position[4] = {0, 1, 0, 1};
GLfloat ambient[4] = {0.2f, 0.2f, 0.2f, 1.0f};
GLfloat diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
}
//------------------------------------------------------------------------------
int main(int argc, char ** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA |GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(1024, 1024);
glutCreateWindow("OpenSubdiv test");
initializeShapes();
int smenu = glutCreateMenu(modelMenu);
for(int i = 0; i < (int)g_defaultShapes.size(); ++i){
glutAddMenuEntry( g_defaultShapes[i].name.c_str(), i);
}
int lmenu = glutCreateMenu(levelMenu);
for(int i = 1; i < 8; ++i){
char level[16];
sprintf(level, "Level %d\n", i);
glutAddMenuEntry(level, i);
}
int kmenu = glutCreateMenu(kernelMenu);
glutAddMenuEntry("CPU", KERNEL_CPU);
glutAddMenuEntry("OpenMP", KERNEL_OMP);
glutAddMenuEntry("GLSL", KERNEL_GLSL);
glutAddMenuEntry("OpenCL", KERNEL_CL);
#if OPENSUBDIV_HAS_CUDA
glutAddMenuEntry("CUDA", KERNEL_CUDA);
#endif
glutCreateMenu(menu);
glutAddSubMenu("Level", lmenu);
glutAddSubMenu("Model", smenu);
glutAddSubMenu("Kernel", kmenu);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutMotionFunc(motion);
glewInit();
initGL();
// Register Osd compute kernels
OpenSubdiv::OsdCpuKernelDispatcher::Register();
OpenSubdiv::OsdGlslKernelDispatcher::Register();
#if OPENSUBDIV_HAS_CUDA
OpenSubdiv::OsdCudaKernelDispatcher::Register();
cudaGLSetGLDevice( cutGetMaxGflopsDeviceId() );
#endif
const char *filename = NULL;
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-d"))
g_level = atoi(argv[++i]);
else if (!strcmp(argv[i], "-c"))
g_repeatCount = atoi(argv[++i]);
else if (!strcmp(argv[i], "-k")) {
++i;
g_kernel = argv[i];
} else
filename = argv[i];
}
omp_set_num_threads(1);
g_kernel = "omp";
glGenBuffers(1, &g_indexBuffer);
modelMenu(0);
glutIdleFunc(idle);
glutMainLoop();
quit();
}
//------------------------------------------------------------------------------