diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 1dbe5761..1850449a 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -56,3 +56,5 @@ # add_subdirectory(glutViewer) + +add_subdirectory(mayaViewer) diff --git a/examples/glutViewer/CMakeLists.txt b/examples/glutViewer/CMakeLists.txt index 7f9646ab..549adfec 100644 --- a/examples/glutViewer/CMakeLists.txt +++ b/examples/glutViewer/CMakeLists.txt @@ -57,7 +57,6 @@ find_package(IlmBase REQUIRED) find_package(OpenGL REQUIRED) -find_package(GLEW REQUIRED) find_package(GLUT REQUIRED) find_package(CUDA REQUIRED) @@ -94,6 +93,5 @@ target_link_libraries(glutViewer ${ILMBASE_LIBS_DIRECTORY} ${OPENGL_LIBRARY} ${GLUT_LIBRARIES} - ${} ) diff --git a/examples/glutViewer/cudaInit.h b/examples/glutViewer/cudaInit.h new file mode 100644 index 00000000..4053e24d --- /dev/null +++ b/examples/glutViewer/cudaInit.h @@ -0,0 +1,140 @@ +// +// 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. +// +#ifndef OSD_CUDA_INIT_H +#define OSD_CUDA_INIT_H + +// From "NVIDIA GPU Computing SDK 4.2/C/common/inc/cutil_inline_runtime.h": + +// Beginning of GPU Architecture definitions +inline int _ConvertSMVer2Cores_local(int major, int minor) +{ + // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM + typedef struct { + int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version + int Cores; + } sSMtoCores; + + sSMtoCores nGpuArchCoresPerSM[] = + { { 0x10, 8 }, // Tesla Generation (SM 1.0) G80 class + { 0x11, 8 }, // Tesla Generation (SM 1.1) G8x class + { 0x12, 8 }, // Tesla Generation (SM 1.2) G9x class + { 0x13, 8 }, // Tesla Generation (SM 1.3) GT200 class + { 0x20, 32 }, // Fermi Generation (SM 2.0) GF100 class + { 0x21, 48 }, // Fermi Generation (SM 2.1) GF10x class + { 0x30, 192}, // Fermi Generation (SM 3.0) GK10x class + { -1, -1 } + }; + + int index = 0; + while (nGpuArchCoresPerSM[index].SM != -1) { + if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor) ) { + return nGpuArchCoresPerSM[index].Cores; + } + index++; + } + printf("MapSMtoCores undefined SMversion %d.%d!\n", major, minor); + return -1; +} +// end of GPU Architecture definitions + +// This function returns the best GPU (with maximum GFLOPS) +inline int cutGetMaxGflopsDeviceId() +{ + int current_device = 0, sm_per_multiproc = 0; + int max_compute_perf = 0, max_perf_device = 0; + int device_count = 0, best_SM_arch = 0; + cudaDeviceProp deviceProp; + + cudaGetDeviceCount( &device_count ); + // Find the best major SM Architecture GPU device + while ( current_device < device_count ) { + cudaGetDeviceProperties( &deviceProp, current_device ); + if (deviceProp.major > 0 && deviceProp.major < 9999) { + best_SM_arch = std::max(best_SM_arch, deviceProp.major); + } + current_device++; + } + + // Find the best CUDA capable GPU device + current_device = 0; + while( current_device < device_count ) { + cudaGetDeviceProperties( &deviceProp, current_device ); + if (deviceProp.major == 9999 && deviceProp.minor == 9999) { + sm_per_multiproc = 1; + } else { + sm_per_multiproc = _ConvertSMVer2Cores_local(deviceProp.major, deviceProp.minor); + } + int compute_perf = deviceProp.multiProcessorCount * sm_per_multiproc * deviceProp.clockRate; + if( compute_perf > max_compute_perf ) { + // If we find GPU with SM major > 2, search only these + if ( best_SM_arch > 2 ) { + // If our device==dest_SM_arch, choose this, or else pass + if (deviceProp.major == best_SM_arch) { + max_compute_perf = compute_perf; + max_perf_device = current_device; + } + } else { + max_compute_perf = compute_perf; + max_perf_device = current_device; + } + } + ++current_device; + } + return max_perf_device; +} + +#endif //OSD_CUDA_INIT_H diff --git a/examples/glutViewer/viewer.cpp b/examples/glutViewer/viewer.cpp index d3fd0559..b0c2f287 100644 --- a/examples/glutViewer/viewer.cpp +++ b/examples/glutViewer/viewer.cpp @@ -55,11 +55,10 @@ // a particular purpose and non-infringement. // - -#include #if defined(__APPLE__) #include #else + #include #include #endif @@ -77,7 +76,6 @@ #include #include - #include "cudaInit.h" #endif #include diff --git a/examples/mayaViewer/CMakeLists.txt b/examples/mayaViewer/CMakeLists.txt new file mode 100644 index 00000000..80f9b57b --- /dev/null +++ b/examples/mayaViewer/CMakeLists.txt @@ -0,0 +1,140 @@ +# +# 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. +# + +set(MAYA_FIND_QUIETLY TRUE) + +find_package(Maya) + +if(NOT MAYA_FOUND) + message(WARNING + "Maya could not be found, so the OpenSubdiv Maya plugin will not " + "be available. If you do have Maya installed and see this message, " + "please add your Maya path to cmake/FindMaya.cmake or set it in " + "the MAYA_LOCATION environment variable." + ) + return() +endif() + +include_directories( + ${PROJECT_SOURCE_DIR}/opensubdiv + ${MAYA_INCLUDE_DIRS} + ${ILMBASE_INCLUDE_DIR} +) + +set(SOURCE_FILES + OpenSubdivDrawOverride.cpp + hbrUtil.cpp +) + +set(HEADER_FILES +) + +if(UNIX) + set(PLATFORM_COMPILE_FLAGS + -D_BOOL + -DREQUIRE_IOSTREAM + ) + set(PLATFORM_LIBRARIES + ) + set(PLATFORM_PLUGIN_EXTENSION + .so + ) + set(PLATFORM_LINK_FLAGS + ) +endif(UNIX) + +if(WIN32) + set(PLATFORM_COMPILE_FLAGS + /D_AFXDLL + /DNT_PLUGIN + /DREQUIRE_IOSTREAM + ) + set(PLATFORM_LIBRARIES + ) + set(PLATFORM_PLUGIN_EXTENSION + .mll + ) + set(PLATFORM_LINK_FLAGS + "/export:initializePlugin /export:uninitializePlugin" + ) +endif(WIN32) + +add_definitions( + ${PLATFORM_COMPILE_FLAGS} +) + +add_library(maya_plugin SHARED + ${SOURCE_FILES} + ${HEADER_FILES} +) + +set_target_properties(maya_plugin + PROPERTIES + OUTPUT_NAME "mayaViewer" + SUFFIX ${PLATFORM_PLUGIN_EXTENSION} + LINK_FLAGS "${PLATFORM_LINK_FLAGS}" +) + +target_link_libraries(maya_plugin + osd + ${MAYA_Foundation_LIBRARY} + ${MAYA_OpenMaya_LIBRARY} + ${MAYA_OpenMayaRender_LIBRARY} + ${MAYA_tbb_LIBRARY} + ${PLATFORM_LIBRARIES} + GLEW +) diff --git a/examples/mayaViewer/OpenSubdivDrawOverride.cpp b/examples/mayaViewer/OpenSubdivDrawOverride.cpp new file mode 100644 index 00000000..de2f6815 --- /dev/null +++ b/examples/mayaViewer/OpenSubdivDrawOverride.cpp @@ -0,0 +1,537 @@ +// Include this first to avoid winsock2.h problems on Windows: +#include + +#include +#include + +#include "hbrUtil.h" + +#include + +// Maya API includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Viewport 2.0 includes +#include +#include +#include +#include +#include +#include + +//--------------------------------------------------------------------------- +template static int +FindAttribute( MFnDependencyNode &fnDN, const char *nm, T *val ) +{ + MStatus s; + MPlug p; + T ss; + p = fnDN.findPlug(nm, &s); + if(s != MS::kSuccess) return -1; + s = p.getValue(ss); + if( s != MS::kSuccess ) return -1; + *val = ss; + return 0; +} + +//--------------------------------------------------------------------------- +template static bool +CompareArray(const T &a, const T &b) +{ + if(a.length() != b.length()) return false; + for(unsigned int i = 0; i < a.length(); ++i){ + if(a[i] != b[i]) return false; + } + return true; +} +//--------------------------------------------------------------------------- + +class SubdivUserData : public MUserData +{ +public: + SubdivUserData(bool loop); + virtual ~SubdivUserData(); + + void Populate(MObject mesh); + void UpdatePoints(MObject mesh); + + int GetElementBuffer() const { return _index; } + int GetNumIndices() const { return _numIndices; } + int GetVertexBuffer() const { return _osdmesh->GetVertexBuffer(); } + int GetVaryingBuffer() const { return _osdmesh->GetVaryingBuffer(); } + int GetVertexStride() const { return _osdmesh->GetNumVertexElements()*sizeof(float); } + int GetVaryingStride() const { return _osdmesh->GetNumVaryingElements()*sizeof(float); } + int GetPrimType() const { return _loop ? GL_TRIANGLES : GL_QUADS; } + + // XXX + bool fIsSelected; + +private: + // topology cache + MIntArray _vertexList; + MUintArray _edgeIds, _vtxIds; + MDoubleArray _edgeCreaseData, _vtxCreaseData; + + int _level; + int _interpBoundary; + bool _loop; + + OpenSubdiv::OsdMesh *_osdmesh; + GLuint _index; + + int _numIndices; + float _cachedTotal; +}; + +//--------------------------------------------------------------------------- + +class OpenSubdivDrawOverride : public MHWRender::MPxDrawOverride +{ +public: + static MHWRender::MPxDrawOverride* Creator(const MObject& obj) { + return new OpenSubdivDrawOverride(obj); + } + + virtual ~OpenSubdivDrawOverride(); + + virtual MBoundingBox boundingBox( + const MDagPath& objPath, + const MDagPath& cameraPath) const; + + virtual MUserData* prepareForDraw( + const MDagPath& objPath, + const MDagPath& cameraPath, + MUserData* oldData); + + static void draw(const MHWRender::MDrawContext& context, const MUserData* data); + + static void setLoopSubdivision(bool loop) { _loop = loop; } + +private: + OpenSubdivDrawOverride(const MObject& obj); + + bool getSelectionStatus(const MDagPath& objPath) const; + static bool _loop; +}; + +bool OpenSubdivDrawOverride::_loop = false; + +//--------------------------------------------------------------------------- + +SubdivUserData::SubdivUserData(bool loop) : + MUserData(false /*don't delete after draw */), + _loop(loop) +{ + _osdmesh = new OpenSubdiv::OsdMesh(6 /*numVertexElements*/, + 0 /*numVaryingElements*/ ); + glGenBuffers(1, &_index); +} + +SubdivUserData::~SubdivUserData() +{ + delete _osdmesh; + glDeleteBuffers(1, &_index); +} + +void +SubdivUserData::Populate(MObject mesh) +{ + MStatus s; + MFnMesh meshFn(mesh); + MIntArray vertexCount, vertexList; + meshFn.getVertices(vertexCount, vertexList); + MUintArray edgeIds; + MDoubleArray edgeCreaseData; + meshFn.getCreaseEdges(edgeIds, edgeCreaseData); + MUintArray vtxIds; + MDoubleArray vtxCreaseData; + meshFn.getCreaseVertices(vtxIds, vtxCreaseData ); + + short level = 1; + FindAttribute(meshFn, "smoothLevel", &level); + if(level < 1) level = 1; + + short interpBoundary = 0; + FindAttribute(meshFn, "boundaryRule", &interpBoundary); + + if(CompareArray(_vertexList, vertexList) && + CompareArray(_edgeIds, edgeIds) && + CompareArray(_edgeCreaseData, edgeCreaseData) && + CompareArray(_vtxIds, vtxIds) && + CompareArray(_vtxCreaseData, vtxCreaseData) && + _level == level && + _interpBoundary == interpBoundary) + { + return; + } + + // update topology + _vertexList = vertexList; + _edgeIds = edgeIds; + _edgeCreaseData = edgeCreaseData; + _vtxIds = vtxIds; + _vtxCreaseData = vtxCreaseData; + _level = level; + _interpBoundary = interpBoundary; + + if(_loop){ + MIntArray triangleCounts; + meshFn.getTriangles(triangleCounts, vertexList); + int numTriangles = vertexList.length()/3; + vertexCount.clear(); + for(int i = 0; i < numTriangles; ++i){ + vertexCount.append(3); + } + } + + // XXX redundant copy... replace _vertexList with numIndices, etc + + // create Osd mesh + std::vector numIndices, faceIndices, edgeCreaseIndices, vtxCreaseIndices; + std::vector edgeCreases, vtxCreases; + numIndices.resize(vertexCount.length()); + faceIndices.resize(vertexList.length()); + for(int i = 0; i < (int)vertexCount.length(); ++i) numIndices[i] = vertexCount[i]; + for(int i = 0; i < (int)vertexList.length(); ++i) faceIndices[i] = vertexList[i]; + vtxCreaseIndices.resize(vtxIds.length()); + for(int i = 0; i < (int)vtxIds.length(); ++i) vtxCreaseIndices[i] = vtxIds[i]; + vtxCreases.resize(vtxCreaseData.length()); + for(int i = 0; i < (int)vtxCreaseData.length(); ++i) vtxCreases[i] = (float)vtxCreaseData[i]; + edgeCreases.resize(edgeCreaseData.length()); + for(int i = 0; i < (int)edgeCreaseData.length(); ++i) edgeCreases[i] = (float)edgeCreaseData[i]; + + // edge crease index is stored as pair of ... + int nEdgeIds = edgeIds.length(); + edgeCreaseIndices.resize(nEdgeIds*2); + for(int i = 0; i < nEdgeIds; ++i){ + int2 vertices; + if (meshFn.getEdgeVertices(edgeIds[i], vertices) != MS::kSuccess) { + s.perror("ERROR can't get creased edge vertices"); + continue; + } + edgeCreaseIndices[i*2] = vertices[0]; + edgeCreaseIndices[i*2+1] = vertices[1]; + } + + std::string kernel = "omp"; + + OpenSubdiv::OsdHbrMesh *hbrMesh = ConvertToHBR(meshFn.numVertices(), numIndices, faceIndices, + vtxCreaseIndices, vtxCreases, + std::vector(), std::vector(), + edgeCreaseIndices, edgeCreases, + interpBoundary, _loop); + + _osdmesh->Create(hbrMesh, level, kernel); + + delete hbrMesh; + + // update element array buffer + const std::vector indices = _osdmesh->GetFarMesh()->GetFaceVertices(level); + _numIndices = indices.size(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _index); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*_numIndices, + &(indices[0]), GL_STATIC_DRAW); + + _cachedTotal = -1; + UpdatePoints(mesh); +} + +void +SubdivUserData::UpdatePoints(MObject mesh) +{ + // update coarse vertex array + MFnMesh meshFn(mesh); + MStatus status; + + int nPoints = meshFn.numVertices(); + const float *points = meshFn.getRawPoints(&status); + + // XXX: looking for other good way to detect change + float total = 0; + for(int i = 0; i < 3*nPoints; ++i) total += points[i]; + if(_cachedTotal == total) return; + _cachedTotal = total; + + MFloatVectorArray normals; + meshFn.getVertexNormals(true, normals); + if (nPoints != normals.length()) return; // XXX: error + + + // Update vertex + std::vector vertex; + vertex.resize(nPoints*6); + + for(int i = 0; i < nPoints; ++i){ + vertex[i*6+0] = points[i*3+0]; + vertex[i*6+1] = points[i*3+1]; + vertex[i*6+2] = points[i*3+2]; + vertex[i*6+3] = normals[i].x; + vertex[i*6+4] = normals[i].y; + vertex[i*6+5] = normals[i].z; + } + + _osdmesh->UpdatePoints(vertex); + +/* XXX + float *varying = new float[_osdmesh.GetNumVaryingElements()]; + _osdmesh.BeginUpdateCoarseVertexVarying(); + for(int i = 0; i < nPoints; ++i){ + varying[0] = normals[i].x; + varying[1] = normals[i].y; + varying[2] = normals[i].z; + _osdmesh.UpdateCoarseVertexVarying(i, varying); + } + _osdmesh.EndUpdateCoarseVertexVarying(); + delete[] varying; +*/ + + // subdivide + _osdmesh->Subdivide(); +} + +//--------------------------------------------------------------------------- + +OpenSubdivDrawOverride::OpenSubdivDrawOverride(const MObject& obj) + : MHWRender::MPxDrawOverride(obj, OpenSubdivDrawOverride::draw) +{ +} + +OpenSubdivDrawOverride::~OpenSubdivDrawOverride() +{ +} + +bool OpenSubdivDrawOverride::getSelectionStatus(const MDagPath& objPath) const +{ + // retrieve the selection status of the node + MStatus status; + MSelectionList selectedList; + status = MGlobal::getActiveSelectionList(selectedList); + if(!status) + return false; + + MDagPath pathCopy = objPath; + do { + if(selectedList.hasItem(pathCopy)) return true; + status = pathCopy.pop(); + } while(status); + + return false; +} + +MBoundingBox OpenSubdivDrawOverride::boundingBox(const MDagPath& objPath, const MDagPath& cameraPath) const +{ + MPoint corner1( -1.0, -1.0, -1.0 ); + MPoint corner2( 1.0, 1.0, 1.0); + + return MBoundingBox(corner1, corner2); +} + +MUserData* OpenSubdivDrawOverride::prepareForDraw( + const MDagPath& objPath, + const MDagPath& cameraPath, + MUserData* oldData) +{ + SubdivUserData* data = dynamic_cast(oldData); + if (!data) + { + // data did not exist or was incorrect type, create new + // XXX by the way, who release this object? + bool loop = _loop; + data = new SubdivUserData(loop); + } + data->fIsSelected = getSelectionStatus(objPath); + data->Populate(objPath.node()); + data->UpdatePoints(objPath.node()); + + return data; +} + +void OpenSubdivDrawOverride::draw(const MHWRender::MDrawContext& context, const MUserData* data) +{ + // get cached data + bool isSelected = false; + SubdivUserData* mesh = const_cast(dynamic_cast(data)); + if (mesh) + { + isSelected = mesh->fIsSelected; + } + + // set colour + static const float colorData[] = {1.0f, 0.0f, 0.0f}; + static const float selectedColorData[] = {0.0f, 1.0f, 0.0f}; + if(isSelected) + glColor3fv(selectedColorData); + else + glColor3fv(colorData); + MStatus status; + + // set world matrix + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + MMatrix transform = + context.getMatrix(MHWRender::MDrawContext::kWorldViewMtx, &status); + if (status) + { + glLoadMatrixd(transform.matrix[0]); + } + + // set projection matrix + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + MMatrix projection = + context.getMatrix(MHWRender::MDrawContext::kProjectionMtx, &status); + if (status) + { + glLoadMatrixd(projection.matrix[0]); + } + + + const int displayStyle = context.getDisplayStyle(); + glPushAttrib( GL_CURRENT_BIT ); + glPushAttrib( GL_ENABLE_BIT); + + if(displayStyle & MHWRender::MDrawContext::kGouraudShaded) { + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + }else if(displayStyle & MHWRender::MDrawContext::kWireFrame){ + glDisable(GL_LIGHTING); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } + + { + int vertexStride = mesh->GetVertexStride(); + int varyingStride = mesh->GetVaryingStride(); + //printf("Draw. stride = %d\n", stride); + glBindBuffer(GL_ARRAY_BUFFER, mesh->GetVertexBuffer()); + glVertexPointer(3, GL_FLOAT, vertexStride, ((char*)(0))); + glEnableClientState(GL_VERTEX_ARRAY); + + glBindBuffer(GL_ARRAY_BUFFER, mesh->GetVertexBuffer()); + glNormalPointer(GL_FLOAT, vertexStride, ((char*)(12))); +// glBindBuffer(GL_ARRAY_BUFFER, mesh->GetVaryingBuffer()); +// glNormalPointer(GL_FLOAT, varyingStride, ((char*)(0))); + glEnableClientState(GL_NORMAL_ARRAY); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->GetElementBuffer()); + glDrawElements(mesh->GetPrimType(), mesh->GetNumIndices(), GL_UNSIGNED_INT, NULL); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + glPopAttrib(); + glPopAttrib(); + + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glColor3f(1, 1, 1); +} +//--------------------------------------------------------------------------- +// Control command + +class OpenSubdivCommand : public MPxCommand +{ +public: + virtual MStatus doIt(const MArgList &args); + static void *Creator(); +}; + +void* +OpenSubdivCommand::Creator() +{ + return new OpenSubdivCommand(); +} + +MStatus +OpenSubdivCommand::doIt(const MArgList &args) +{ + MSyntax syntax; + syntax.addFlag("m", "method", MSyntax::kString); + MArgDatabase argDB(syntax, args); + + if(argDB.isFlagSet("m")){ + MString method; + argDB.getFlagArgument("m", 0, method); + if(method == "loop"){ + OpenSubdivDrawOverride::setLoopSubdivision(true); + }else{ + OpenSubdivDrawOverride::setLoopSubdivision(false); + } + } + + return MS::kSuccess; +} + +//--------------------------------------------------------------------------- +// Plugin Registration +//--------------------------------------------------------------------------- + +MString drawDbClassification("drawdb/geometry/mesh"); +MString drawRegistrantId("OpenSubdivDrawOverridePlugin"); + +MStatus initializePlugin( MObject obj ) +{ +#if defined(_WIN32) && defined(_DEBUG) + // Disable buffering for stdout and stderr when using debug versions + // of the C run-time library. + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif + + MStatus status; + MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any"); + + status = MHWRender::MDrawRegistry::registerDrawOverrideCreator( + drawDbClassification, + drawRegistrantId, + OpenSubdivDrawOverride::Creator); + if (!status) { + status.perror("registerDrawOverrideCreator"); + return status; + } + + status = plugin.registerCommand("openSubdivControl", OpenSubdivCommand::Creator); + if (!status) { + status.perror("registerCommand"); + return status; + } + + glewInit(); + + //XXX:cleanup Need to register other kernel dispatchers. + OpenSubdiv::OsdCpuKernelDispatcher::Register(); + + return status; +} + +MStatus uninitializePlugin( MObject obj) +{ + MStatus status; + MFnPlugin plugin( obj ); + + status = MHWRender::MDrawRegistry::deregisterDrawOverrideCreator( + drawDbClassification, + drawRegistrantId); + if (!status) { + status.perror("deregisterDrawOverrideCreator"); + return status; + } + + status = plugin.deregisterCommand("openSubdivControl"); + + return status; +} diff --git a/examples/mayaViewer/hbrUtil.cpp b/examples/mayaViewer/hbrUtil.cpp new file mode 100644 index 00000000..a95dd52d --- /dev/null +++ b/examples/mayaViewer/hbrUtil.cpp @@ -0,0 +1,136 @@ +#include "hbrUtil.h" +#include +#include +#include +#include +#include + +#define OSD_ERROR printf // XXXX + +OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices, + std::vector const & numIndices, + std::vector const & faceIndices, + std::vector const & vtxCreaseIndices, + std::vector const & vtxCreases, + std::vector const & edgeCrease1Indices, // face index, local edge index + std::vector const & edgeCreases1, + std::vector const & edgeCrease2Indices, // 2 vertex indices (Maya friendly) + std::vector const & edgeCreases2, + int interpBoundary, bool loop) +{ + static HbrBilinearSubdivision _bilinear; + static HbrLoopSubdivision _loop; + static HbrCatmarkSubdivision _catmark; + + OpenSubdiv::OsdHbrMesh *hbrMesh; + if (loop) + hbrMesh = new OpenSubdiv::OsdHbrMesh(&_loop); + else + hbrMesh = new OpenSubdiv::OsdHbrMesh(&_catmark); + + OpenSubdiv::OsdVertex v; + for(int i = 0; i < nVertices; ++i){ + // create empty vertex : actual vertices will be initialized in UpdatePoints(); + hbrMesh->NewVertex(i, v); + } + + // get face indices + std::vector vIndex; + int nFaces = (int)numIndices.size(), offset = 0; + for (int i = 0; i < nFaces; ++i) { + int numVertex = numIndices[i]; + vIndex.resize(numVertex); + + bool valid=true; + for (int j=0; jGetVertex( vIndex[j] ); + OpenSubdiv::OsdHbrVertex * destination = hbrMesh->GetVertex( vNextIndex ); + if (!origin || !destination) { + OSD_ERROR("ERROR : An edge was specified that connected a nonexistent vertex"); + valid=false; + } + + if (origin == destination) { + OSD_ERROR("ERROR : An edge was specified that connected a vertex to itself"); + valid=false; + } + + OpenSubdiv::OsdHbrHalfedge * opposite = destination->GetEdge(origin); + if (opposite && opposite->GetOpposite()) { + OSD_ERROR("ERROR : A non-manifold edge incident to more than 2 faces was found"); + valid=false; + } + + if (origin->GetEdge(destination)) { + OSD_ERROR("ERROR : An edge connecting two vertices was specified more than once. " + "It's likely that an incident face was flipped"); + valid=false; + } + } + + if ( valid ) + hbrMesh->NewFace(numVertex, &(vIndex[0]), 0); + else + OSD_ERROR("Face %d will be ignored\n", i); + + offset += numVertex; + } + + // XXX: use hbr enum or redefine same enum in gsd + hbrMesh->SetInterpolateBoundaryMethod((OpenSubdiv::OsdHbrMesh::InterpolateBoundaryMethod)interpBoundary); + + // set edge crease in two different indexing way + int nEdgeCreases = (int)edgeCreases1.size(); + for (int i = 0; i < nEdgeCreases; ++i) { + if( edgeCreases1[i] <= 0. ) + continue; + + OpenSubdiv::OsdHbrHalfedge * e = hbrMesh->GetFace(edgeCrease1Indices[i*2])->GetEdge(edgeCrease1Indices[i*2+1]); + if (!e) { + OSD_ERROR("Can't find edge (face %d edge %d)\n", edgeCrease1Indices[i*2], edgeCrease1Indices[i*2+1]); + continue; + } + e->SetSharpness( (float)edgeCreases1[i] ); + } + nEdgeCreases = (int)edgeCreases2.size(); + for (int i = 0; i < nEdgeCreases; ++i) { + if( edgeCreases1[i] <= 0. ) + continue; + + OpenSubdiv::OsdHbrVertex * v0 = hbrMesh->GetVertex(edgeCrease2Indices[i*2]); + OpenSubdiv::OsdHbrVertex * v1 = hbrMesh->GetVertex(edgeCrease2Indices[i*2+1]); + OpenSubdiv::OsdHbrHalfedge * e = NULL; + + if ( v0 && v1 ) + if ( ! (e = v0->GetEdge(v1)) ) + e = v1->GetEdge(v0); + if (!e) { + OSD_ERROR("ERROR can't find edge"); + continue; + } + e->SetSharpness( (float)edgeCreases2[i] ); + } + + // set corner + { + int nVertexCreases = (int)vtxCreases.size(); + for ( int i = 0; i< nVertexCreases; ++i ) { + if( vtxCreases[i] <= 0. ) + continue; + OpenSubdiv::OsdHbrVertex * v = hbrMesh->GetVertex(vtxCreaseIndices[i]); + if (!v) { + OSD_ERROR("Can't find vertex %d\n", vtxCreaseIndices[i]); + continue; + } + v->SetSharpness( (float)vtxCreases[i] ); + } + } + + hbrMesh->Finish(); + return hbrMesh; +} + diff --git a/examples/mayaViewer/hbrUtil.h b/examples/mayaViewer/hbrUtil.h new file mode 100644 index 00000000..5afea2c3 --- /dev/null +++ b/examples/mayaViewer/hbrUtil.h @@ -0,0 +1,18 @@ +#ifndef OSD_HBR_UTIL_H +#define OSD_HBR_UTIL_H + +#include +#include + +extern "C" OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices, + std::vector const & numIndices, + std::vector const & faceIndices, + std::vector const & vtxCreaseIndices, + std::vector const & vtxCreases, + std::vector const & edgeCrease1Indices, + std::vector const & edgeCreases1, + std::vector const & edgeCrease2Indices, + std::vector const & edgeCreases2, + int interpBoundary, + bool loop); +#endif diff --git a/opensubdiv/osd/CMakeLists.txt b/opensubdiv/osd/CMakeLists.txt index 90f788eb..593e0b50 100644 --- a/opensubdiv/osd/CMakeLists.txt +++ b/opensubdiv/osd/CMakeLists.txt @@ -100,10 +100,10 @@ set(PUBLIC_HEADERS # CPU (omp) code & dependencies if(APPLE) set(PLATFORM_COMPILE_FLAGS - -fopenmp + -fopenmp ) set(PLATFORM_LIBRARIES - gomp + gomp ) elseif(UNIX) set(PLATFORM_COMPILE_FLAGS @@ -119,7 +119,9 @@ elseif(WIN32 or WIN64) ) endif() - +add_definitions( + ${PLATFORM_COMPILE_FLAGS} +) #------------------------------------------------------------------------------- # GL code & dependencies