2013-09-23 19:53:41 +00:00
|
|
|
//
|
2013-09-26 19:04:57 +00:00
|
|
|
// Copyright 2013 Pixar
|
2013-09-23 19:53:41 +00:00
|
|
|
//
|
2013-09-26 19:04:57 +00:00
|
|
|
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
|
|
|
// with the following modification; you may not use this file except in
|
|
|
|
// compliance with the Apache License and the following modification to it:
|
|
|
|
// Section 6. Trademarks. is deleted and replaced with:
|
2013-09-23 19:53:41 +00:00
|
|
|
//
|
2013-09-26 19:04:57 +00:00
|
|
|
// 6. Trademarks. This License does not grant permission to use the trade
|
|
|
|
// names, trademarks, service marks, or product names of the Licensor
|
|
|
|
// and its affiliates, except as required to comply with Section 4(c) of
|
|
|
|
// the License and to reproduce the content of the NOTICE file.
|
2013-09-23 19:53:41 +00:00
|
|
|
//
|
2013-09-26 19:04:57 +00:00
|
|
|
// You may obtain a copy of the Apache License at
|
2013-09-23 19:53:41 +00:00
|
|
|
//
|
2013-09-26 19:04:57 +00:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2013-09-23 19:53:41 +00:00
|
|
|
//
|
2013-09-26 19:04:57 +00:00
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the Apache License with the above modification is
|
|
|
|
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
// KIND, either express or implied. See the Apache License for the specific
|
|
|
|
// language governing permissions and limitations under the Apache License.
|
2013-09-23 19:53:41 +00:00
|
|
|
//
|
|
|
|
|
2015-05-30 05:33:51 +00:00
|
|
|
#include "../common/glUtils.h"
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
#include <GLFW/glfw3.h>
|
|
|
|
GLFWwindow* g_window = 0;
|
|
|
|
GLFWmonitor* g_primary = 0;
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2014-12-04 01:19:07 +00:00
|
|
|
#include <far/error.h>
|
2015-05-09 00:31:26 +00:00
|
|
|
#include <osd/cpuEvaluator.h>
|
2013-09-23 19:53:41 +00:00
|
|
|
#include <osd/cpuGLVertexBuffer.h>
|
|
|
|
#include <osd/glMesh.h>
|
2014-09-05 22:07:46 +00:00
|
|
|
OpenSubdiv::Osd::GLMeshInterface *g_mesh = NULL;
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-31 05:10:07 +00:00
|
|
|
#include "../../regression/common/far_utils.h"
|
2013-09-23 19:53:41 +00:00
|
|
|
#include "../common/stopwatch.h"
|
|
|
|
#include "../common/simple_math.h"
|
2015-05-31 22:08:37 +00:00
|
|
|
#include "../common/glControlMeshDisplay.h"
|
2015-05-19 01:04:38 +00:00
|
|
|
#include "../common/glHud.h"
|
2015-05-14 00:35:46 +00:00
|
|
|
#include "../common/glShaderCache.h"
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
#include <osd/glslPatchShaderSource.h>
|
2013-09-23 19:53:41 +00:00
|
|
|
static const char *shaderSource =
|
|
|
|
#if defined(GL_ARB_tessellation_shader) || defined(GL_VERSION_4_0)
|
2014-01-04 00:59:26 +00:00
|
|
|
#include "shader.gen.h"
|
2013-09-23 19:53:41 +00:00
|
|
|
#else
|
2014-01-04 00:59:26 +00:00
|
|
|
#include "shader_gl3.gen.h"
|
2013-09-23 19:53:41 +00:00
|
|
|
#endif
|
|
|
|
;
|
|
|
|
|
|
|
|
#include <cfloat>
|
|
|
|
#include <vector>
|
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <utility>
|
|
|
|
#include <string>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
enum DisplayStyle { kWire = 0,
|
|
|
|
kShaded,
|
|
|
|
kWireShaded };
|
|
|
|
|
|
|
|
int g_currentShape = 0;
|
|
|
|
|
|
|
|
int g_frame = 0,
|
|
|
|
g_repeatCount = 0;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-10-10 18:57:43 +00:00
|
|
|
OpenSubdiv::Sdc::Options::FVarLinearInterpolation g_fvarBoundary =
|
|
|
|
OpenSubdiv::Sdc::Options::FVAR_LINEAR_ALL;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
// GUI variables
|
|
|
|
int g_fullscreen = 0,
|
|
|
|
g_freeze = 0,
|
|
|
|
g_displayStyle = kWireShaded,
|
|
|
|
g_adaptive = 0,
|
|
|
|
g_mbutton[3] = {0, 0, 0},
|
|
|
|
g_mouseUvView = 0,
|
|
|
|
g_running = 1;
|
|
|
|
|
|
|
|
float g_moveScale = 0.0f;
|
|
|
|
|
|
|
|
float g_rotate[2] = {0, 0},
|
|
|
|
g_dolly = 5,
|
|
|
|
g_pan[2] = {0, 0},
|
|
|
|
g_center[3] = {0, 0, 0},
|
|
|
|
g_size = 0,
|
|
|
|
g_uvPan[2] = {0, 0},
|
|
|
|
g_uvScale = 1.0;
|
|
|
|
|
|
|
|
int g_prev_x = 0,
|
|
|
|
g_prev_y = 0;
|
|
|
|
|
|
|
|
int g_width = 1600,
|
|
|
|
g_height = 800;
|
|
|
|
|
|
|
|
GLhud g_hud;
|
2015-05-31 22:08:37 +00:00
|
|
|
GLControlMeshDisplay g_controlMeshDisplay;
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
// geometry
|
|
|
|
std::vector<float> g_orgPositions,
|
|
|
|
g_positions,
|
|
|
|
g_normals;
|
|
|
|
|
|
|
|
Scheme g_scheme;
|
|
|
|
|
|
|
|
int g_level = 2;
|
|
|
|
int g_tessLevel = 1;
|
|
|
|
int g_tessLevelMin = 1;
|
|
|
|
|
|
|
|
GLuint g_transformUB = 0,
|
|
|
|
g_transformBinding = 0,
|
|
|
|
g_tessellationUB = 0,
|
|
|
|
g_tessellationBinding = 0;
|
|
|
|
|
|
|
|
struct Transform {
|
|
|
|
float ModelViewMatrix[16];
|
|
|
|
float ProjectionMatrix[16];
|
|
|
|
float ModelViewProjectionMatrix[16];
|
|
|
|
float ModelViewInverseMatrix[16];
|
|
|
|
float UvViewMatrix[16];
|
|
|
|
} g_transformData;
|
|
|
|
|
|
|
|
GLuint g_vao = 0;
|
|
|
|
|
|
|
|
std::vector<int> g_coarseEdges;
|
|
|
|
std::vector<float> g_coarseEdgeSharpness;
|
|
|
|
std::vector<float> g_coarseVertexSharpness;
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
struct Program {
|
2013-09-23 19:53:41 +00:00
|
|
|
GLuint program;
|
|
|
|
GLuint uniformModelViewProjectionMatrix;
|
|
|
|
GLuint attrPosition;
|
|
|
|
GLuint attrColor;
|
|
|
|
} g_defaultProgram;
|
|
|
|
|
2015-05-20 21:36:57 +00:00
|
|
|
struct FVarData
|
|
|
|
{
|
|
|
|
FVarData() :
|
|
|
|
textureBuffer(0) {
|
|
|
|
}
|
|
|
|
~FVarData() {
|
|
|
|
Release();
|
|
|
|
}
|
|
|
|
void Release() {
|
|
|
|
if (textureBuffer)
|
|
|
|
glDeleteTextures(1, &textureBuffer);
|
|
|
|
textureBuffer = 0;
|
|
|
|
}
|
2015-05-22 18:50:01 +00:00
|
|
|
void Create(OpenSubdiv::Far::PatchTable const *patchTable,
|
2015-05-20 21:36:57 +00:00
|
|
|
int fvarWidth, std::vector<float> const & fvarSrcData) {
|
|
|
|
Release();
|
|
|
|
OpenSubdiv::Far::ConstIndexArray indices =
|
2015-05-22 18:50:01 +00:00
|
|
|
patchTable->GetFVarPatchesValues(0);
|
2015-05-20 21:36:57 +00:00
|
|
|
|
|
|
|
// expand fvardata to per-patch array
|
|
|
|
std::vector<float> data;
|
|
|
|
data.reserve(indices.size() * fvarWidth);
|
|
|
|
|
|
|
|
for (int fvert = 0; fvert < (int)indices.size(); ++fvert) {
|
|
|
|
int index = indices[fvert] * fvarWidth;
|
|
|
|
for (int i = 0; i < fvarWidth; ++i) {
|
|
|
|
data.push_back(fvarSrcData[index++]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GLuint buffer;
|
|
|
|
glGenBuffers(1, &buffer);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, data.size()*sizeof(float),
|
|
|
|
&data[0], GL_STATIC_DRAW);
|
|
|
|
|
2015-05-27 22:23:26 +00:00
|
|
|
glGenTextures(1, &textureBuffer);
|
2015-05-20 21:36:57 +00:00
|
|
|
glBindTexture(GL_TEXTURE_BUFFER, textureBuffer);
|
|
|
|
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer);
|
|
|
|
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
|
|
|
glBindTexture(GL_ARRAY_BUFFER, 0);
|
|
|
|
|
|
|
|
glDeleteBuffers(1, &buffer);
|
|
|
|
}
|
|
|
|
GLuint textureBuffer;
|
|
|
|
} g_fvarData;
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static GLuint
|
2014-09-05 22:07:46 +00:00
|
|
|
compileShader(GLenum shaderType, const char *source) {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
GLuint shader = glCreateShader(shaderType);
|
|
|
|
glShaderSource(shader, 1, &source, NULL);
|
|
|
|
glCompileShader(shader);
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2014-09-05 22:07:46 +00:00
|
|
|
linkDefaultProgram() {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
#if defined(GL_ARB_tessellation_shader) || defined(GL_VERSION_4_0)
|
|
|
|
#define GLSL_VERSION_DEFINE "#version 400\n"
|
|
|
|
#else
|
|
|
|
#define GLSL_VERSION_DEFINE "#version 150\n"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static const char *vsSrc =
|
|
|
|
GLSL_VERSION_DEFINE
|
|
|
|
"in vec3 position;\n"
|
|
|
|
"in vec3 color;\n"
|
|
|
|
"out vec4 fragColor;\n"
|
|
|
|
"uniform mat4 ModelViewProjectionMatrix;\n"
|
|
|
|
"void main() {\n"
|
|
|
|
" fragColor = vec4(color, 1);\n"
|
|
|
|
" gl_Position = ModelViewProjectionMatrix * "
|
|
|
|
" vec4(position, 1);\n"
|
|
|
|
"}\n";
|
|
|
|
|
|
|
|
static const char *fsSrc =
|
|
|
|
GLSL_VERSION_DEFINE
|
|
|
|
"in vec4 fragColor;\n"
|
|
|
|
"out vec4 color;\n"
|
|
|
|
"void main() {\n"
|
|
|
|
" color = fragColor;\n"
|
|
|
|
"}\n";
|
|
|
|
|
|
|
|
GLuint program = glCreateProgram();
|
|
|
|
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vsSrc);
|
|
|
|
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fsSrc);
|
|
|
|
|
|
|
|
glAttachShader(program, vertexShader);
|
|
|
|
glAttachShader(program, fragmentShader);
|
|
|
|
|
|
|
|
glLinkProgram(program);
|
|
|
|
|
|
|
|
GLint status;
|
|
|
|
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
|
|
|
if (status == GL_FALSE) {
|
|
|
|
GLint infoLogLength;
|
|
|
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
|
|
|
|
char *infoLog = new char[infoLogLength];
|
|
|
|
glGetProgramInfoLog(program, infoLogLength, NULL, infoLog);
|
|
|
|
printf("%s\n", infoLog);
|
|
|
|
delete[] infoLog;
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_defaultProgram.program = program;
|
|
|
|
g_defaultProgram.uniformModelViewProjectionMatrix =
|
|
|
|
glGetUniformLocation(program, "ModelViewProjectionMatrix");
|
|
|
|
g_defaultProgram.attrPosition = glGetAttribLocation(program, "position");
|
|
|
|
g_defaultProgram.attrColor = glGetAttribLocation(program, "color");
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
#include "init_shapes.h"
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
calcNormals(OpenSubdiv::Far::TopologyRefiner const & refiner,
|
|
|
|
std::vector<float> const & pos, std::vector<float> & normals) {
|
|
|
|
|
2014-12-15 18:23:13 +00:00
|
|
|
typedef OpenSubdiv::Far::ConstIndexArray IndexArray;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2015-05-22 02:52:25 +00:00
|
|
|
OpenSubdiv::Far::TopologyLevel const & refBaseLevel = refiner.GetLevel(0);
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
// calc normal vectors
|
|
|
|
int nverts = (int)pos.size()/3;
|
|
|
|
|
2015-05-22 02:52:25 +00:00
|
|
|
int nfaces = refBaseLevel.GetNumFaces();
|
2014-09-05 22:07:46 +00:00
|
|
|
for (int face = 0; face < nfaces; ++face) {
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-22 02:52:25 +00:00
|
|
|
IndexArray fverts = refBaseLevel.GetFaceVertices(face);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
assert(fverts.size()>=2);
|
|
|
|
|
|
|
|
float const * p0 = &pos[fverts[0]*3],
|
|
|
|
* p1 = &pos[fverts[1]*3],
|
|
|
|
* p2 = &pos[fverts[2]*3];
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
float n[3];
|
|
|
|
cross(n, p0, p1, p2);
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
for (int j = 0; j < fverts.size(); j++) {
|
|
|
|
int idx = fverts[j] * 3;
|
|
|
|
normals[idx ] += n[0];
|
|
|
|
normals[idx+1] += n[1];
|
|
|
|
normals[idx+2] += n[2];
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
for (int i = 0; i < nverts; ++i)
|
2014-09-05 22:07:46 +00:00
|
|
|
normalize(&normals[i*3]);
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
updateGeom() {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
int nverts = (int)g_orgPositions.size() / 3;
|
|
|
|
|
|
|
|
std::vector<float> vertex;
|
|
|
|
vertex.reserve(nverts*3);
|
|
|
|
|
|
|
|
const float *p = &g_orgPositions[0];
|
|
|
|
|
|
|
|
float r = sin(g_frame*0.001f) * g_moveScale;
|
|
|
|
for (int i = 0; i < nverts; ++i) {
|
|
|
|
float ct = cos(p[2] * r);
|
|
|
|
float st = sin(p[2] * r);
|
|
|
|
g_positions[i*3+0] = p[0]*ct + p[1]*st;
|
|
|
|
g_positions[i*3+1] = -p[0]*st + p[1]*ct;
|
|
|
|
g_positions[i*3+2] = p[2];
|
|
|
|
|
|
|
|
p += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = &g_orgPositions[0];
|
|
|
|
const float *pp = &g_positions[0];
|
|
|
|
for (int i = 0; i < nverts; ++i) {
|
|
|
|
vertex.push_back(pp[0]);
|
|
|
|
vertex.push_back(pp[1]);
|
|
|
|
vertex.push_back(pp[2]);
|
|
|
|
pp += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_mesh->UpdateVertexBuffer(&vertex[0], 0, nverts);
|
|
|
|
|
|
|
|
g_mesh->Refine();
|
|
|
|
|
|
|
|
g_mesh->Synchronize();
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2015-05-31 22:08:37 +00:00
|
|
|
rebuildMesh() {
|
|
|
|
ShapeDesc const &shapeDesc = g_defaultShapes[g_currentShape];
|
|
|
|
int level = g_level;
|
|
|
|
Scheme scheme = g_defaultShapes[g_currentShape].scheme;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
Shape * shape = Shape::parseObj(shapeDesc.data.c_str(), shapeDesc.scheme);
|
|
|
|
|
2015-05-31 05:10:07 +00:00
|
|
|
// create Far mesh (topology)
|
2015-01-07 01:40:11 +00:00
|
|
|
OpenSubdiv::Sdc::SchemeType sdctype = GetSdcType(*shape);
|
2014-09-05 22:07:46 +00:00
|
|
|
OpenSubdiv::Sdc::Options sdcoptions = GetSdcOptions(*shape);
|
|
|
|
|
2014-10-10 18:57:43 +00:00
|
|
|
sdcoptions.SetFVarLinearInterpolation(g_fvarBoundary);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
OpenSubdiv::Far::TopologyRefiner * refiner =
|
2015-01-06 08:03:21 +00:00
|
|
|
OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Create(*shape,
|
|
|
|
OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions));
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
// save coarse topology (used for coarse mesh drawing)
|
2015-05-31 22:08:37 +00:00
|
|
|
g_controlMeshDisplay.SetTopology(refiner->GetLevel(0));
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
g_orgPositions=shape->verts;
|
|
|
|
g_normals.resize(g_orgPositions.size(), 0.0f);
|
|
|
|
calcNormals(*refiner, g_orgPositions, g_normals);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
g_positions.resize(g_orgPositions.size(),0.0f);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
g_scheme = scheme;
|
|
|
|
|
|
|
|
// Adaptive refinement currently supported only for catmull-clark scheme
|
2014-09-05 22:07:46 +00:00
|
|
|
bool doAdaptive = (g_adaptive!=0 and g_scheme==kCatmark);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
OpenSubdiv::Osd::MeshBitset bits;
|
|
|
|
bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive);
|
|
|
|
bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
int numVertexElements = 3;
|
|
|
|
int numVaryingElements = 0;
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
delete g_mesh;
|
|
|
|
g_mesh = new OpenSubdiv::Osd::Mesh<OpenSubdiv::Osd::CpuGLVertexBuffer,
|
2015-05-22 18:50:01 +00:00
|
|
|
OpenSubdiv::Far::StencilTable,
|
2015-05-09 00:31:26 +00:00
|
|
|
OpenSubdiv::Osd::CpuEvaluator,
|
2015-05-20 21:36:57 +00:00
|
|
|
OpenSubdiv::Osd::GLPatchTable>(
|
2015-05-09 00:31:26 +00:00
|
|
|
refiner,
|
|
|
|
numVertexElements,
|
|
|
|
numVaryingElements,
|
|
|
|
level, bits);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
std::vector<float> fvarData;
|
|
|
|
|
|
|
|
InterpolateFVarData(*refiner, *shape, fvarData);
|
|
|
|
|
2015-05-20 21:36:57 +00:00
|
|
|
// set fvardata to texture buffer
|
2015-05-22 18:50:01 +00:00
|
|
|
g_fvarData.Create(g_mesh->GetFarPatchTable(),
|
2015-05-20 21:36:57 +00:00
|
|
|
shape->GetFVarWidth(), fvarData);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
delete shape;
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
// compute model bounding
|
|
|
|
float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX};
|
|
|
|
float max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
|
|
|
|
for (size_t i = 0; i < g_orgPositions.size()/3; ++i) {
|
|
|
|
for (int j = 0; j < 3; ++j) {
|
|
|
|
float v = g_orgPositions[i*3+j];
|
|
|
|
min[j] = std::min(min[j], v);
|
|
|
|
max[j] = std::max(max[j], v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int j = 0; j < 3; ++j) {
|
|
|
|
g_center[j] = (min[j] + max[j]) * 0.5f;
|
|
|
|
g_size += (max[j]-min[j])*(max[j]-min[j]);
|
|
|
|
}
|
|
|
|
g_size = sqrtf(g_size);
|
|
|
|
|
|
|
|
updateGeom();
|
|
|
|
|
|
|
|
// -------- VAO
|
|
|
|
glBindVertexArray(g_vao);
|
|
|
|
|
2015-05-20 21:36:57 +00:00
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_mesh->GetPatchTable()->GetPatchIndexBuffer());
|
2013-09-23 19:53:41 +00:00
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, g_mesh->BindVertexBuffer());
|
|
|
|
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, 0);
|
|
|
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
glBindVertexArray(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
fitFrame() {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
g_pan[0] = g_pan[1] = 0;
|
|
|
|
g_dolly = g_size;
|
|
|
|
g_uvPan[0] = g_uvPan[1] = 0;
|
|
|
|
g_uvScale = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
union Effect {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
Effect(int displayStyle_, int uvDraw_) : value(0) {
|
|
|
|
displayStyle = displayStyle_;
|
|
|
|
uvDraw = uvDraw_;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct {
|
|
|
|
unsigned int displayStyle:3;
|
|
|
|
unsigned int uvDraw:1;
|
|
|
|
};
|
|
|
|
int value;
|
|
|
|
|
|
|
|
bool operator < (const Effect &e) const {
|
|
|
|
return value < e.value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
static Effect
|
|
|
|
GetEffect(bool uvDraw = false) {
|
|
|
|
|
|
|
|
return Effect(g_displayStyle, uvDraw);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2015-05-12 01:06:46 +00:00
|
|
|
struct EffectDesc {
|
|
|
|
EffectDesc(OpenSubdiv::Far::PatchDescriptor desc,
|
|
|
|
Effect effect) : desc(desc), effect(effect),
|
|
|
|
maxValence(0), numElements(0) { }
|
|
|
|
|
|
|
|
OpenSubdiv::Far::PatchDescriptor desc;
|
|
|
|
Effect effect;
|
|
|
|
int maxValence;
|
|
|
|
int numElements;
|
|
|
|
|
|
|
|
bool operator < (const EffectDesc &e) const {
|
2015-05-28 20:09:44 +00:00
|
|
|
return
|
|
|
|
(desc < e.desc || ((desc == e.desc &&
|
|
|
|
(maxValence < e.maxValence || ((maxValence == e.maxValence) &&
|
|
|
|
(numElements < e.numElements || ((numElements == e.numElements) &&
|
|
|
|
(effect < e.effect))))))));
|
2015-05-12 01:06:46 +00:00
|
|
|
}
|
|
|
|
};
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
class ShaderCache : public GLShaderCache<EffectDesc> {
|
|
|
|
public:
|
|
|
|
virtual GLDrawConfig *CreateDrawConfig(EffectDesc const &effectDesc) {
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
using namespace OpenSubdiv;
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
// compile shader program
|
2013-09-23 19:53:41 +00:00
|
|
|
#if defined(GL_ARB_tessellation_shader) || defined(GL_VERSION_4_0)
|
2015-05-14 00:35:46 +00:00
|
|
|
const char *glslVersion = "#version 400\n";
|
2013-09-23 19:53:41 +00:00
|
|
|
#else
|
2015-05-14 00:35:46 +00:00
|
|
|
const char *glslVersion = "#version 330\n";
|
2013-09-23 19:53:41 +00:00
|
|
|
#endif
|
2015-05-14 00:35:46 +00:00
|
|
|
GLDrawConfig *config = new GLDrawConfig(glslVersion);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
Far::PatchDescriptor::Type type = effectDesc.desc.GetType();
|
2015-05-12 01:06:46 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
// common defines
|
|
|
|
std::stringstream ss;
|
2015-05-12 01:06:46 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
if (type == Far::PatchDescriptor::QUADS) {
|
|
|
|
ss << "#define PRIM_QUAD\n";
|
|
|
|
} else {
|
|
|
|
ss << "#define PRIM_TRI\n";
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
if (effectDesc.effect.uvDraw) {
|
|
|
|
ss << "#define GEOMETRY_OUT_FILL\n";
|
|
|
|
ss << "#define GEOMETRY_UV_VIEW\n";
|
|
|
|
} else {
|
|
|
|
switch (effectDesc.effect.displayStyle) {
|
|
|
|
case kWire:
|
|
|
|
ss << "#define GEOMETRY_OUT_WIRE\n";
|
|
|
|
break;
|
|
|
|
case kWireShaded:
|
|
|
|
ss << "#define GEOMETRY_OUT_LINE\n";
|
|
|
|
break;
|
|
|
|
case kShaded:
|
|
|
|
ss << "#define GEOMETRY_OUT_FILL\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
// for legacy gregory
|
|
|
|
ss << "#define OSD_MAX_VALENCE " << effectDesc.maxValence << "\n";
|
|
|
|
ss << "#define OSD_NUM_ELEMENTS " << effectDesc.numElements << "\n";
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
// face varying width
|
|
|
|
ss << "#define OSD_FVAR_WIDTH 2\n";
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-06-02 15:49:11 +00:00
|
|
|
if (not effectDesc.desc.IsAdaptive()) {
|
|
|
|
ss << "#define SHADING_FACEVARYING_UNIFORM_SUBDIVISION\n";
|
|
|
|
}
|
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
// include osd PatchCommon
|
|
|
|
ss << Osd::GLSLPatchShaderSource::GetCommonShaderSource();
|
|
|
|
std::string common = ss.str();
|
|
|
|
ss.str("");
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
// vertex shader
|
|
|
|
ss << common
|
|
|
|
// enable local vertex shader
|
|
|
|
<< (effectDesc.desc.IsAdaptive() ? "" : "#define VERTEX_SHADER\n")
|
|
|
|
<< shaderSource
|
|
|
|
<< Osd::GLSLPatchShaderSource::GetVertexShaderSource(type);
|
|
|
|
config->CompileAndAttachShader(GL_VERTEX_SHADER, ss.str());
|
|
|
|
ss.str("");
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
if (effectDesc.desc.IsAdaptive()) {
|
|
|
|
// tess control shader
|
|
|
|
ss << common
|
|
|
|
<< shaderSource
|
|
|
|
<< Osd::GLSLPatchShaderSource::GetTessControlShaderSource(type);
|
|
|
|
config->CompileAndAttachShader(GL_TESS_CONTROL_SHADER, ss.str());
|
|
|
|
ss.str("");
|
|
|
|
|
|
|
|
// tess eval shader
|
|
|
|
ss << common
|
|
|
|
<< shaderSource
|
|
|
|
<< Osd::GLSLPatchShaderSource::GetTessEvalShaderSource(type);
|
|
|
|
config->CompileAndAttachShader(GL_TESS_EVALUATION_SHADER, ss.str());
|
|
|
|
ss.str("");
|
|
|
|
}
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
// geometry shader
|
|
|
|
ss << common
|
|
|
|
<< "#define GEOMETRY_SHADER\n"
|
|
|
|
<< shaderSource;
|
|
|
|
config->CompileAndAttachShader(GL_GEOMETRY_SHADER, ss.str());
|
|
|
|
ss.str("");
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
// fragment shader
|
|
|
|
ss << common
|
|
|
|
<< "#define FRAGMENT_SHADER\n"
|
|
|
|
<< shaderSource;
|
|
|
|
config->CompileAndAttachShader(GL_FRAGMENT_SHADER, ss.str());
|
|
|
|
ss.str("");
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
if (!config->Link()) {
|
|
|
|
delete config;
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-05-12 01:06:46 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
// assign uniform locations
|
|
|
|
GLuint uboIndex;
|
|
|
|
GLuint program = config->GetProgram();
|
|
|
|
g_transformBinding = 0;
|
|
|
|
uboIndex = glGetUniformBlockIndex(program, "Transform");
|
|
|
|
if (uboIndex != GL_INVALID_INDEX)
|
|
|
|
glUniformBlockBinding(program, uboIndex, g_transformBinding);
|
|
|
|
|
|
|
|
g_tessellationBinding = 1;
|
|
|
|
uboIndex = glGetUniformBlockIndex(program, "Tessellation");
|
|
|
|
if (uboIndex != GL_INVALID_INDEX)
|
|
|
|
glUniformBlockBinding(program, uboIndex, g_tessellationBinding);
|
|
|
|
|
|
|
|
// assign texture locations
|
|
|
|
GLint loc;
|
|
|
|
glUseProgram(program);
|
|
|
|
if ((loc = glGetUniformLocation(program, "OsdPatchParamBuffer")) != -1) {
|
2015-05-20 21:36:57 +00:00
|
|
|
glUniform1i(loc, 0); // GL_TEXTURE0
|
2015-05-14 00:35:46 +00:00
|
|
|
}
|
|
|
|
if ((loc = glGetUniformLocation(program, "OsdFVarDataBuffer")) != -1) {
|
2015-05-20 21:36:57 +00:00
|
|
|
glUniform1i(loc, 1); // GL_TEXTURE1
|
2015-05-14 00:35:46 +00:00
|
|
|
}
|
2015-05-12 01:06:46 +00:00
|
|
|
|
2015-05-20 21:36:57 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
return config;
|
2015-05-12 01:06:46 +00:00
|
|
|
}
|
2015-05-14 00:35:46 +00:00
|
|
|
};
|
2015-05-12 01:06:46 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
ShaderCache g_shaderCache;
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
|
|
|
updateUniformBlocks() {
|
2013-09-23 19:53:41 +00:00
|
|
|
if (!g_transformUB) {
|
|
|
|
glGenBuffers(1, &g_transformUB);
|
|
|
|
glBindBuffer(GL_UNIFORM_BUFFER, g_transformUB);
|
|
|
|
glBufferData(GL_UNIFORM_BUFFER,
|
|
|
|
sizeof(g_transformData), NULL, GL_STATIC_DRAW);
|
|
|
|
};
|
|
|
|
glBindBuffer(GL_UNIFORM_BUFFER, g_transformUB);
|
|
|
|
glBufferSubData(GL_UNIFORM_BUFFER,
|
|
|
|
0, sizeof(g_transformData), &g_transformData);
|
|
|
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
|
|
|
|
|
|
|
glBindBufferBase(GL_UNIFORM_BUFFER, g_transformBinding, g_transformUB);
|
|
|
|
|
|
|
|
// Update and bind tessellation state
|
|
|
|
struct Tessellation {
|
|
|
|
float TessLevel;
|
|
|
|
} tessellationData;
|
|
|
|
|
|
|
|
tessellationData.TessLevel = static_cast<float>(1 << g_tessLevel);
|
|
|
|
|
|
|
|
if (!g_tessellationUB) {
|
|
|
|
glGenBuffers(1, &g_tessellationUB);
|
|
|
|
glBindBuffer(GL_UNIFORM_BUFFER, g_tessellationUB);
|
|
|
|
glBufferData(GL_UNIFORM_BUFFER,
|
|
|
|
sizeof(tessellationData), NULL, GL_STATIC_DRAW);
|
|
|
|
};
|
|
|
|
glBindBuffer(GL_UNIFORM_BUFFER, g_tessellationUB);
|
|
|
|
glBufferSubData(GL_UNIFORM_BUFFER,
|
|
|
|
0, sizeof(tessellationData), &tessellationData);
|
|
|
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
|
|
|
|
|
|
|
glBindBufferBase(GL_UNIFORM_BUFFER, g_tessellationBinding, g_tessellationUB);
|
2015-05-14 00:35:46 +00:00
|
|
|
}
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
static void
|
|
|
|
bindTextures() {
|
2015-05-20 21:36:57 +00:00
|
|
|
if (g_mesh->GetPatchTable()->GetPatchParamTextureBuffer()) {
|
2013-09-23 19:53:41 +00:00
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glBindTexture(GL_TEXTURE_BUFFER,
|
2015-05-20 21:36:57 +00:00
|
|
|
g_mesh->GetPatchTable()->GetPatchParamTextureBuffer());
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
2015-05-20 21:36:57 +00:00
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
|
|
glBindTexture(GL_TEXTURE_BUFFER, g_fvarData.textureBuffer);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
2015-05-14 00:35:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static GLenum
|
Osd API refactor: EvalStencils and EvalPatches
Add EvalStencils and EvalPatches API for most of CPU and GPU evaluators.
with this change, Eval API in the osd layer consists of following parts:
- Evaluators (Cpu, Omp, Tbb, Cuda, CL, GLXFB, GLCompute, D3D11Compute)
implements EvalStencils and EvalPatches(*). Both supports derivatives
(not fully implemented though)
- Interop vertex buffer classes (optional, same as before)
Note that these classes are not necessary to use Evaluators.
All evaluators have EvalStencils/Patches which take device-specific
buffer objects. For example, GLXFBEvaluator can take GLuint directly
for both stencil tables and input primvars. Although using these
interop classes makes it easy to integrate osd into relatively
simple applications.
- device-dependent StencilTable and PatchTable (optional)
These are also optional, but can be used simply a substitute of
Far::StencilTable and Far::PatchTable for osd evaluators.
- PatchArray, PatchCoord, PatchParam
They are tiny structs used for GPU based patch evaluation.
(*) TODO and known issues:
- CLEvaluator and D3D11Evaluator's EvalPatches() have not been implemented.
- GPU Gregory patch evaluation has not been implemented in EvalPatches().
- CudaEvaluator::EvalPatches() is very unstable.
- All patch evaluation kernels have not been well optimized.
- Currently GLXFB kernel doesn't support derivative evaluation.
There's a technical difficulty for the multi-stream output.
2015-05-26 04:51:55 +00:00
|
|
|
bindProgram(Effect effect, OpenSubdiv::Osd::PatchArray const & patch) {
|
2015-05-14 00:35:46 +00:00
|
|
|
|
|
|
|
EffectDesc effectDesc(patch.GetDescriptor(), effect);
|
|
|
|
|
|
|
|
typedef OpenSubdiv::Far::PatchDescriptor Descriptor;
|
|
|
|
|
|
|
|
// lookup shader cache (compile the shader if needed)
|
|
|
|
GLDrawConfig *config = g_shaderCache.GetDrawConfig(effectDesc);
|
|
|
|
if (!config) return 0;
|
|
|
|
|
|
|
|
GLuint program = config->GetProgram();
|
|
|
|
|
|
|
|
glUseProgram(program);
|
|
|
|
|
|
|
|
// bind standalone uniforms
|
|
|
|
GLint uniformPrimitiveIdBase =
|
|
|
|
glGetUniformLocation(program, "PrimitiveIdBase");
|
|
|
|
if (uniformPrimitiveIdBase >=0)
|
2015-05-20 21:36:57 +00:00
|
|
|
glUniform1i(uniformPrimitiveIdBase, patch.GetPrimitiveIdBase());
|
2015-05-14 00:35:46 +00:00
|
|
|
|
|
|
|
// return primtype
|
|
|
|
GLenum primType;
|
|
|
|
switch(effectDesc.desc.GetType()) {
|
|
|
|
case Descriptor::QUADS:
|
|
|
|
primType = GL_LINES_ADJACENCY;
|
|
|
|
break;
|
|
|
|
case Descriptor::TRIANGLES:
|
|
|
|
primType = GL_TRIANGLES;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
#if defined(GL_ARB_tessellation_shader) || defined(GL_VERSION_4_0)
|
|
|
|
primType = GL_PATCHES;
|
|
|
|
glPatchParameteri(GL_PATCH_VERTICES, effectDesc.desc.GetNumControlVertices());
|
|
|
|
#else
|
|
|
|
primType = GL_POINTS;
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
return primType;
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
display() {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
Stopwatch s;
|
|
|
|
s.Start();
|
|
|
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
glViewport(0, 0, g_width/2, g_height);
|
2015-06-01 03:13:21 +00:00
|
|
|
g_hud.FillBackground();
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
// prepare view matrix
|
|
|
|
double aspect = (g_width/2)/(double)g_height;
|
|
|
|
identity(g_transformData.ModelViewMatrix);
|
|
|
|
translate(g_transformData.ModelViewMatrix, -g_pan[0], -g_pan[1], -g_dolly);
|
|
|
|
rotate(g_transformData.ModelViewMatrix, g_rotate[1], 1, 0, 0);
|
|
|
|
rotate(g_transformData.ModelViewMatrix, g_rotate[0], 0, 1, 0);
|
|
|
|
rotate(g_transformData.ModelViewMatrix, -90, 1, 0, 0);
|
|
|
|
translate(g_transformData.ModelViewMatrix,
|
|
|
|
-g_center[0], -g_center[1], -g_center[2]);
|
|
|
|
perspective(g_transformData.ProjectionMatrix,
|
|
|
|
45.0f, (float)aspect, 0.01f, 500.0f);
|
|
|
|
multMatrix(g_transformData.ModelViewProjectionMatrix,
|
|
|
|
g_transformData.ModelViewMatrix,
|
|
|
|
g_transformData.ProjectionMatrix);
|
|
|
|
|
|
|
|
identity(g_transformData.UvViewMatrix);
|
|
|
|
scale(g_transformData.UvViewMatrix, g_uvScale, g_uvScale, 1);
|
|
|
|
translate(g_transformData.UvViewMatrix, -g_uvPan[0], -g_uvPan[1], 0);
|
|
|
|
|
2014-09-10 21:28:55 +00:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
// make sure that the vertex buffer is interoped back as a GL resources.
|
2015-05-31 22:08:37 +00:00
|
|
|
GLuint vbo = g_mesh->BindVertexBuffer();
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
glBindVertexArray(g_vao);
|
|
|
|
|
Osd API refactor: EvalStencils and EvalPatches
Add EvalStencils and EvalPatches API for most of CPU and GPU evaluators.
with this change, Eval API in the osd layer consists of following parts:
- Evaluators (Cpu, Omp, Tbb, Cuda, CL, GLXFB, GLCompute, D3D11Compute)
implements EvalStencils and EvalPatches(*). Both supports derivatives
(not fully implemented though)
- Interop vertex buffer classes (optional, same as before)
Note that these classes are not necessary to use Evaluators.
All evaluators have EvalStencils/Patches which take device-specific
buffer objects. For example, GLXFBEvaluator can take GLuint directly
for both stencil tables and input primvars. Although using these
interop classes makes it easy to integrate osd into relatively
simple applications.
- device-dependent StencilTable and PatchTable (optional)
These are also optional, but can be used simply a substitute of
Far::StencilTable and Far::PatchTable for osd evaluators.
- PatchArray, PatchCoord, PatchParam
They are tiny structs used for GPU based patch evaluation.
(*) TODO and known issues:
- CLEvaluator and D3D11Evaluator's EvalPatches() have not been implemented.
- GPU Gregory patch evaluation has not been implemented in EvalPatches().
- CudaEvaluator::EvalPatches() is very unstable.
- All patch evaluation kernels have not been well optimized.
- Currently GLXFB kernel doesn't support derivative evaluation.
There's a technical difficulty for the multi-stream output.
2015-05-26 04:51:55 +00:00
|
|
|
OpenSubdiv::Osd::PatchArrayVector const & patches =
|
2015-05-20 21:36:57 +00:00
|
|
|
g_mesh->GetPatchTable()->GetPatchArrays();
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
if (g_displayStyle == kWire)
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
updateUniformBlocks();
|
|
|
|
bindTextures();
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
// patch drawing
|
|
|
|
for (int i = 0; i < (int)patches.size(); ++i) {
|
Osd API refactor: EvalStencils and EvalPatches
Add EvalStencils and EvalPatches API for most of CPU and GPU evaluators.
with this change, Eval API in the osd layer consists of following parts:
- Evaluators (Cpu, Omp, Tbb, Cuda, CL, GLXFB, GLCompute, D3D11Compute)
implements EvalStencils and EvalPatches(*). Both supports derivatives
(not fully implemented though)
- Interop vertex buffer classes (optional, same as before)
Note that these classes are not necessary to use Evaluators.
All evaluators have EvalStencils/Patches which take device-specific
buffer objects. For example, GLXFBEvaluator can take GLuint directly
for both stencil tables and input primvars. Although using these
interop classes makes it easy to integrate osd into relatively
simple applications.
- device-dependent StencilTable and PatchTable (optional)
These are also optional, but can be used simply a substitute of
Far::StencilTable and Far::PatchTable for osd evaluators.
- PatchArray, PatchCoord, PatchParam
They are tiny structs used for GPU based patch evaluation.
(*) TODO and known issues:
- CLEvaluator and D3D11Evaluator's EvalPatches() have not been implemented.
- GPU Gregory patch evaluation has not been implemented in EvalPatches().
- CudaEvaluator::EvalPatches() is very unstable.
- All patch evaluation kernels have not been well optimized.
- Currently GLXFB kernel doesn't support derivative evaluation.
There's a technical difficulty for the multi-stream output.
2015-05-26 04:51:55 +00:00
|
|
|
OpenSubdiv::Osd::PatchArray const & patch = patches[i];
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
GLenum primType = bindProgram(GetEffect(), patch);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-20 21:36:57 +00:00
|
|
|
glDrawElements(
|
|
|
|
primType,
|
|
|
|
patch.GetNumPatches()*patch.GetDescriptor().GetNumControlVertices(),
|
|
|
|
GL_UNSIGNED_INT,
|
|
|
|
(void *)(patch.GetIndexBase() * sizeof(unsigned int)));
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
if (g_displayStyle == kWire)
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
|
|
|
|
glBindVertexArray(0);
|
|
|
|
glUseProgram(0);
|
|
|
|
|
2015-05-31 22:08:37 +00:00
|
|
|
// draw the control mesh
|
|
|
|
g_controlMeshDisplay.Draw(vbo, 3*sizeof(float),
|
|
|
|
g_transformData.ModelViewProjectionMatrix);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
// ---------------------------------------------
|
|
|
|
// uv viewport
|
|
|
|
glViewport(g_width/2, 0, g_width/2, g_height);
|
|
|
|
|
|
|
|
g_mesh->BindVertexBuffer();
|
|
|
|
|
|
|
|
glBindVertexArray(g_vao);
|
|
|
|
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
|
|
|
|
|
|
for (int i = 0; i < (int)patches.size(); ++i) {
|
Osd API refactor: EvalStencils and EvalPatches
Add EvalStencils and EvalPatches API for most of CPU and GPU evaluators.
with this change, Eval API in the osd layer consists of following parts:
- Evaluators (Cpu, Omp, Tbb, Cuda, CL, GLXFB, GLCompute, D3D11Compute)
implements EvalStencils and EvalPatches(*). Both supports derivatives
(not fully implemented though)
- Interop vertex buffer classes (optional, same as before)
Note that these classes are not necessary to use Evaluators.
All evaluators have EvalStencils/Patches which take device-specific
buffer objects. For example, GLXFBEvaluator can take GLuint directly
for both stencil tables and input primvars. Although using these
interop classes makes it easy to integrate osd into relatively
simple applications.
- device-dependent StencilTable and PatchTable (optional)
These are also optional, but can be used simply a substitute of
Far::StencilTable and Far::PatchTable for osd evaluators.
- PatchArray, PatchCoord, PatchParam
They are tiny structs used for GPU based patch evaluation.
(*) TODO and known issues:
- CLEvaluator and D3D11Evaluator's EvalPatches() have not been implemented.
- GPU Gregory patch evaluation has not been implemented in EvalPatches().
- CudaEvaluator::EvalPatches() is very unstable.
- All patch evaluation kernels have not been well optimized.
- Currently GLXFB kernel doesn't support derivative evaluation.
There's a technical difficulty for the multi-stream output.
2015-05-26 04:51:55 +00:00
|
|
|
OpenSubdiv::Osd::PatchArray const & patch = patches[i];
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-14 00:35:46 +00:00
|
|
|
GLenum primType = bindProgram(GetEffect(/*uvDraw=*/ true), patch);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-20 21:36:57 +00:00
|
|
|
glDrawElements(
|
|
|
|
primType,
|
|
|
|
patch.GetNumPatches()*patch.GetDescriptor().GetNumControlVertices(),
|
|
|
|
GL_UNSIGNED_INT,
|
|
|
|
(void *)(patch.GetIndexBase() * sizeof(unsigned int)));
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
|
|
|
|
|
|
// full viewport
|
|
|
|
glViewport(0, 0, g_width, g_height);
|
|
|
|
|
|
|
|
if (g_hud.IsVisible()) {
|
|
|
|
g_hud.DrawString(10, -40, "Tess level : %d", g_tessLevel);
|
|
|
|
g_hud.Flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
glFinish();
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
motion(GLFWwindow *, double dx, double dy) {
|
2013-09-23 19:53:41 +00:00
|
|
|
int x=(int)dx, y=(int)dy;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
if (g_mouseUvView) {
|
|
|
|
if (!g_mbutton[0] && !g_mbutton[1] && g_mbutton[2]) {
|
|
|
|
// pan
|
|
|
|
g_uvPan[0] -= (x - g_prev_x) * 2 / g_uvScale / static_cast<float>(g_width/2);
|
|
|
|
g_uvPan[1] += (y - g_prev_y) * 2 / g_uvScale / static_cast<float>(g_height);
|
|
|
|
} else if ((g_mbutton[0] && !g_mbutton[1] && g_mbutton[2]) or
|
|
|
|
(!g_mbutton[0] && g_mbutton[1] && !g_mbutton[2])) {
|
|
|
|
// scale
|
|
|
|
g_uvScale += g_uvScale*0.01f*(x - g_prev_x);
|
|
|
|
g_uvScale = std::max(std::min(g_uvScale, 100.0f), 0.01f);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (g_mbutton[0] && !g_mbutton[1] && !g_mbutton[2]) {
|
|
|
|
// orbit
|
|
|
|
g_rotate[0] += x - g_prev_x;
|
|
|
|
g_rotate[1] += y - g_prev_y;
|
|
|
|
} else if (!g_mbutton[0] && !g_mbutton[1] && g_mbutton[2]) {
|
|
|
|
// pan
|
|
|
|
g_pan[0] -= g_dolly*(x - g_prev_x)/g_width;
|
|
|
|
g_pan[1] += g_dolly*(y - g_prev_y)/g_height;
|
|
|
|
} else if ((g_mbutton[0] && !g_mbutton[1] && g_mbutton[2]) or
|
|
|
|
(!g_mbutton[0] && g_mbutton[1] && !g_mbutton[2])) {
|
|
|
|
// dolly
|
|
|
|
g_dolly -= g_dolly*0.01f*(x - g_prev_x);
|
|
|
|
if (g_dolly <= 0.01) g_dolly = 0.01f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_prev_x = x;
|
|
|
|
g_prev_y = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
mouse(GLFWwindow *, int button, int state, int /* mods */) {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
if (button == 0 && state == GLFW_PRESS && g_hud.MouseClick(g_prev_x, g_prev_y))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (button < 3) {
|
|
|
|
g_mbutton[button] = (state == GLFW_PRESS);
|
|
|
|
}
|
|
|
|
|
2015-05-28 20:09:44 +00:00
|
|
|
// window size might not match framebuffer size on a high DPI display
|
|
|
|
int windowWidth = g_width, windowHeight = g_height;
|
|
|
|
glfwGetWindowSize(g_window, &windowWidth, &windowHeight);
|
|
|
|
|
|
|
|
g_mouseUvView = (g_prev_x > windowWidth/2);
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
uninitGL() {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
glDeleteVertexArrays(1, &g_vao);
|
|
|
|
if (g_mesh)
|
|
|
|
delete g_mesh;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
reshape(GLFWwindow *, int width, int height) {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
g_width = width;
|
|
|
|
g_height = height;
|
|
|
|
|
2014-02-22 03:25:00 +00:00
|
|
|
int windowWidth = g_width, windowHeight = g_height;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-02-22 03:25:00 +00:00
|
|
|
// window size might not match framebuffer size on a high DPI display
|
|
|
|
glfwGetWindowSize(g_window, &windowWidth, &windowHeight);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-10-24 18:15:19 +00:00
|
|
|
g_hud.Rebuild(windowWidth, windowHeight, width, height);
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
2014-09-05 22:07:46 +00:00
|
|
|
void windowClose(GLFWwindow*) {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
g_running = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
|
|
|
toggleFullScreen() {
|
|
|
|
// XXXX manuelk : to re-implement from glut
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
keyboard(GLFWwindow *, int key, int /* scancode */, int event, int /* mods */) {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
if (event == GLFW_RELEASE) return;
|
|
|
|
if (g_hud.KeyDown(tolower(key))) return;
|
|
|
|
|
|
|
|
switch (key) {
|
|
|
|
case 'Q': g_running = 0; break;
|
|
|
|
case 'F': fitFrame(); break;
|
|
|
|
case GLFW_KEY_TAB: toggleFullScreen(); break;
|
|
|
|
case '+':
|
|
|
|
case '=': g_tessLevel++; break;
|
|
|
|
case '-': g_tessLevel = std::max(g_tessLevelMin, g_tessLevel-1); break;
|
|
|
|
case GLFW_KEY_ESCAPE: g_hud.SetVisible(!g_hud.IsVisible()); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
callbackDisplayStyle(int b) {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
g_displayStyle = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
callbackLevel(int l) {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
g_level = l;
|
2015-05-31 22:08:37 +00:00
|
|
|
rebuildMesh();
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
callbackModel(int m) {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
int maxShapes = static_cast<int>(g_defaultShapes.size());
|
|
|
|
g_currentShape = std::max(0, std::min(m, maxShapes-1));
|
2015-05-31 22:08:37 +00:00
|
|
|
rebuildMesh();
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
callbackAdaptive(bool checked, int /* a */) {
|
|
|
|
|
2015-05-19 01:04:38 +00:00
|
|
|
if (GLUtils::SupportsAdaptiveTessellation()) {
|
2013-09-23 19:53:41 +00:00
|
|
|
g_adaptive = checked;
|
2015-05-31 22:08:37 +00:00
|
|
|
rebuildMesh();
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
callbackBoundary(int b) {
|
|
|
|
|
|
|
|
typedef OpenSubdiv::Sdc::Options SdcOptions;
|
|
|
|
|
|
|
|
switch (b) {
|
2014-10-01 23:38:06 +00:00
|
|
|
|
2014-10-10 18:57:43 +00:00
|
|
|
case SdcOptions::FVAR_LINEAR_NONE :
|
|
|
|
g_fvarBoundary = SdcOptions::FVAR_LINEAR_NONE; break;
|
2014-10-01 23:38:06 +00:00
|
|
|
|
2014-10-10 18:57:43 +00:00
|
|
|
case SdcOptions::FVAR_LINEAR_CORNERS_ONLY :
|
|
|
|
g_fvarBoundary = SdcOptions::FVAR_LINEAR_CORNERS_ONLY; break;
|
2014-10-01 23:38:06 +00:00
|
|
|
|
2014-10-10 18:57:43 +00:00
|
|
|
case SdcOptions::FVAR_LINEAR_CORNERS_PLUS1 :
|
|
|
|
g_fvarBoundary = SdcOptions::FVAR_LINEAR_CORNERS_PLUS1; break;
|
2014-10-01 23:38:06 +00:00
|
|
|
|
2014-10-10 18:57:43 +00:00
|
|
|
case SdcOptions::FVAR_LINEAR_CORNERS_PLUS2 :
|
|
|
|
g_fvarBoundary = SdcOptions::FVAR_LINEAR_CORNERS_PLUS2; break;
|
|
|
|
|
|
|
|
case SdcOptions::FVAR_LINEAR_BOUNDARIES :
|
|
|
|
g_fvarBoundary = SdcOptions::FVAR_LINEAR_BOUNDARIES; break;
|
|
|
|
|
|
|
|
case SdcOptions::FVAR_LINEAR_ALL :
|
|
|
|
g_fvarBoundary = SdcOptions::FVAR_LINEAR_ALL; break;
|
2014-10-01 23:38:06 +00:00
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
2015-05-31 22:08:37 +00:00
|
|
|
rebuildMesh();
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
initHUD() {
|
|
|
|
|
2014-09-10 20:17:52 +00:00
|
|
|
int windowWidth = g_width, windowHeight = g_height,
|
|
|
|
frameBufferWidth = g_width, frameBufferHeight = g_height;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-02-22 03:25:00 +00:00
|
|
|
// window size might not match framebuffer size on a high DPI display
|
|
|
|
glfwGetWindowSize(g_window, &windowWidth, &windowHeight);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-10 20:17:52 +00:00
|
|
|
g_hud.Init(windowWidth, windowHeight, frameBufferWidth, frameBufferHeight);
|
|
|
|
|
2014-10-10 18:57:43 +00:00
|
|
|
int shading_pulldown = g_hud.AddPullDown("Shading (W)", 375, 10, 250, callbackDisplayStyle, 'w');
|
2014-04-28 23:36:39 +00:00
|
|
|
g_hud.AddPullDownButton(shading_pulldown, "Wire", kWire, g_displayStyle==kWire);
|
|
|
|
g_hud.AddPullDownButton(shading_pulldown, "Shaded", kShaded, g_displayStyle==kShaded);
|
|
|
|
g_hud.AddPullDownButton(shading_pulldown, "Wire+Shaded", kWireShaded, g_displayStyle==kWireShaded);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-19 01:04:38 +00:00
|
|
|
if (GLUtils::SupportsAdaptiveTessellation())
|
2014-04-28 17:10:10 +00:00
|
|
|
g_hud.AddCheckBox("Adaptive (`)", g_adaptive != 0, 10, 250, callbackAdaptive, 0, '`');
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
for (int i = 1; i < 11; ++i) {
|
|
|
|
char level[16];
|
|
|
|
sprintf(level, "Lv. %d", i);
|
2014-04-28 17:10:10 +00:00
|
|
|
g_hud.AddRadioButton(3, level, i == 2, 10, 270 + i*20, callbackLevel, i, '0'+(i%10));
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
typedef OpenSubdiv::Sdc::Options SdcOptions;
|
|
|
|
|
2014-10-01 18:27:57 +00:00
|
|
|
int boundary_pulldown = g_hud.AddPullDown("Boundary (B)", 10, 10, 250, callbackBoundary, 'b');
|
2014-10-10 18:57:43 +00:00
|
|
|
g_hud.AddPullDownButton(boundary_pulldown, "None (edge only)",
|
|
|
|
SdcOptions::FVAR_LINEAR_NONE, g_fvarBoundary==SdcOptions::FVAR_LINEAR_NONE);
|
|
|
|
g_hud.AddPullDownButton(boundary_pulldown, "Corners Only",
|
|
|
|
SdcOptions::FVAR_LINEAR_CORNERS_ONLY, g_fvarBoundary==SdcOptions::FVAR_LINEAR_CORNERS_ONLY);
|
|
|
|
g_hud.AddPullDownButton(boundary_pulldown, "Corners 1 (edge corner)",
|
|
|
|
SdcOptions::FVAR_LINEAR_CORNERS_PLUS1, g_fvarBoundary==SdcOptions::FVAR_LINEAR_CORNERS_PLUS1);
|
|
|
|
g_hud.AddPullDownButton(boundary_pulldown, "Corners 2 (edge corner prop)",
|
|
|
|
SdcOptions::FVAR_LINEAR_CORNERS_PLUS2, g_fvarBoundary==SdcOptions::FVAR_LINEAR_CORNERS_PLUS2);
|
|
|
|
g_hud.AddPullDownButton(boundary_pulldown, "Boundaries (always sharp)",
|
|
|
|
SdcOptions::FVAR_LINEAR_BOUNDARIES, g_fvarBoundary==SdcOptions::FVAR_LINEAR_BOUNDARIES);
|
|
|
|
g_hud.AddPullDownButton(boundary_pulldown, "All (bilinear)",
|
|
|
|
SdcOptions::FVAR_LINEAR_ALL, g_fvarBoundary==SdcOptions::FVAR_LINEAR_ALL);
|
2014-04-28 01:38:51 +00:00
|
|
|
|
2014-04-28 23:36:39 +00:00
|
|
|
int pulldown_handle = g_hud.AddPullDown("Shape (N)", -300, 10, 300, callbackModel, 'n');
|
2014-04-28 01:38:51 +00:00
|
|
|
for (int i = 0; i < (int)g_defaultShapes.size(); ++i) {
|
2014-04-28 06:05:18 +00:00
|
|
|
g_hud.AddPullDownButton(pulldown_handle, g_defaultShapes[i].name.c_str(),i);
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
2014-09-10 22:29:24 +00:00
|
|
|
|
2014-10-24 18:15:19 +00:00
|
|
|
g_hud.Rebuild(windowWidth, windowHeight, frameBufferWidth, frameBufferHeight);
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
initGL() {
|
|
|
|
|
2014-09-10 20:17:52 +00:00
|
|
|
glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
|
2013-09-23 19:53:41 +00:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
glCullFace(GL_BACK);
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
|
|
|
|
glGenVertexArrays(1, &g_vao);
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-09-05 22:07:46 +00:00
|
|
|
idle() {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
if (not g_freeze)
|
|
|
|
g_frame++;
|
|
|
|
|
|
|
|
updateGeom();
|
|
|
|
|
|
|
|
if (g_repeatCount != 0 and g_frame >= g_repeatCount)
|
|
|
|
g_running = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
2014-12-04 01:19:07 +00:00
|
|
|
callbackError(OpenSubdiv::Far::ErrorType err, const char *message) {
|
|
|
|
printf("Error: %d\n", err);
|
2013-09-23 19:53:41 +00:00
|
|
|
printf("%s", message);
|
|
|
|
}
|
|
|
|
|
2014-12-20 22:44:50 +00:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void
|
|
|
|
callbackErrorGLFW(int error, const char* description) {
|
|
|
|
fprintf(stderr, "GLFW Error (%d) : %s\n", error, description);
|
|
|
|
}
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
2014-09-05 22:07:46 +00:00
|
|
|
int main(int argc, char ** argv) {
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
bool fullscreen = false;
|
|
|
|
std::string str;
|
|
|
|
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], "-f"))
|
|
|
|
fullscreen = true;
|
|
|
|
else {
|
|
|
|
std::ifstream ifs(argv[1]);
|
|
|
|
if (ifs) {
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << ifs.rdbuf();
|
|
|
|
ifs.close();
|
|
|
|
str = ss.str();
|
2014-09-05 22:07:46 +00:00
|
|
|
g_defaultShapes.push_back(ShapeDesc(argv[1], str.c_str(), kCatmark));
|
2013-09-23 19:53:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
initShapes();
|
|
|
|
|
2014-12-04 01:19:07 +00:00
|
|
|
OpenSubdiv::Far::SetErrorCallback(callbackError);
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2014-12-20 22:44:50 +00:00
|
|
|
glfwSetErrorCallback(callbackErrorGLFW);
|
2013-09-23 19:53:41 +00:00
|
|
|
if (not glfwInit()) {
|
|
|
|
printf("Failed to initialize GLFW\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
static const char windowTitle[] = "OpenSubdiv glFVarViewer " OPENSUBDIV_VERSION_STRING;
|
2013-09-23 19:53:41 +00:00
|
|
|
|
2015-05-30 05:33:51 +00:00
|
|
|
GLUtils::SetMinimumGLVersion();
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
if (fullscreen) {
|
|
|
|
g_primary = glfwGetPrimaryMonitor();
|
|
|
|
|
|
|
|
// apparently glfwGetPrimaryMonitor fails under linux : if no primary,
|
|
|
|
// settle for the first one in the list
|
|
|
|
if (not g_primary) {
|
|
|
|
int count = 0;
|
|
|
|
GLFWmonitor ** monitors = glfwGetMonitors(&count);
|
|
|
|
|
|
|
|
if (count)
|
|
|
|
g_primary = monitors[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_primary) {
|
|
|
|
GLFWvidmode const * vidmode = glfwGetVideoMode(g_primary);
|
|
|
|
g_width = vidmode->width;
|
|
|
|
g_height = vidmode->height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (not (g_window=glfwCreateWindow(g_width, g_height, windowTitle,
|
|
|
|
fullscreen and g_primary ? g_primary : NULL, NULL))) {
|
2015-05-30 05:33:51 +00:00
|
|
|
std::cerr << "Failed to create OpenGL context.\n";
|
2013-09-23 19:53:41 +00:00
|
|
|
glfwTerminate();
|
|
|
|
return 1;
|
|
|
|
}
|
2015-05-30 05:33:51 +00:00
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
glfwMakeContextCurrent(g_window);
|
2015-05-30 05:33:51 +00:00
|
|
|
GLUtils::PrintGLVersion();
|
2014-02-22 03:25:00 +00:00
|
|
|
|
|
|
|
// accommodate high DPI displays (e.g. mac retina displays)
|
|
|
|
glfwGetFramebufferSize(g_window, &g_width, &g_height);
|
|
|
|
glfwSetFramebufferSizeCallback(g_window, reshape);
|
|
|
|
|
2013-09-23 19:53:41 +00:00
|
|
|
glfwSetKeyCallback(g_window, keyboard);
|
|
|
|
glfwSetCursorPosCallback(g_window, motion);
|
|
|
|
glfwSetMouseButtonCallback(g_window, mouse);
|
|
|
|
glfwSetWindowCloseCallback(g_window, windowClose);
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(OSD_USES_GLEW)
|
|
|
|
#ifdef CORE_PROFILE
|
|
|
|
// this is the only way to initialize glew correctly under core profile context.
|
|
|
|
glewExperimental = true;
|
|
|
|
#endif
|
|
|
|
if (GLenum r = glewInit() != GLEW_OK) {
|
|
|
|
printf("Failed to initialize glew. Error = %s\n", glewGetErrorString(r));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
#ifdef CORE_PROFILE
|
|
|
|
// clear GL errors which was generated during glewInit()
|
|
|
|
glGetError();
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
initGL();
|
|
|
|
linkDefaultProgram();
|
|
|
|
|
|
|
|
glfwSwapInterval(0);
|
|
|
|
|
|
|
|
initHUD();
|
2015-05-31 22:08:37 +00:00
|
|
|
rebuildMesh();
|
2013-09-23 19:53:41 +00:00
|
|
|
|
|
|
|
while (g_running) {
|
|
|
|
idle();
|
|
|
|
display();
|
|
|
|
|
|
|
|
glfwPollEvents();
|
|
|
|
glfwSwapBuffers(g_window);
|
|
|
|
|
|
|
|
glFinish();
|
|
|
|
}
|
|
|
|
|
|
|
|
uninitGL();
|
|
|
|
glfwTerminate();
|
|
|
|
}
|