Merge pull request #116 from prideout/master

Python Bindings for Grandma

This is probably not the final word on python bindings... but it gives us a place to start.

Note : tested only in linux environments so far
This commit is contained in:
Manuel Kraemer 2013-02-07 16:40:12 -08:00
commit ca1e294c70
32 changed files with 3699 additions and 0 deletions

4
.gitignore vendored
View File

@ -2,3 +2,7 @@
# ignore stringified kernels
*.inc
*.inc.rule
*.pyc
osdshim_wrap.cpp
shim.py

View File

@ -201,6 +201,8 @@ find_package(OpenCL 1.1)
find_package(CUDA 4.0)
find_package(GLFW 2.7.0)
find_package(PTex 2.0)
find_package(PythonInterp 2.6)
find_package(SWIG 1.3.40)
if (NOT APPLE AND OPENGL_FOUND)
find_package(GLEW REQUIRED)
@ -323,6 +325,40 @@ else()
)
endif()
if(PYTHONINTERP_FOUND AND SWIG_FOUND)
message(STATUS "Python and SWIG found. Looking for numpy...")
execute_process(
COMMAND
${PYTHON_EXECUTABLE} -c "import numpy; print numpy.get_include()"
OUTPUT_VARIABLE NUMPY_INCLUDE_PATH
RESULT_VARIABLE NUMPY_ERR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NUMPY_ERR)
message(WARNING "Unable to import numpy.")
else()
message(STATUS "Numpy package has been located.")
set(PYCMD ${PYTHON_EXECUTABLE} setup.py build )
list(APPEND PYCMD --osddir=${LIBRARY_OUTPUT_PATH} )
list(APPEND PYCMD --build-platlib=${PROJECT_BINARY_DIR}/python )
list(APPEND PYCMD --build-temp=${PROJECT_BINARY_DIR}/temp )
add_custom_command(
OUTPUT ${PROJECT_BINARY_DIR}/python/osd
COMMAND ${PYCMD}
WORKING_DIRECTORY ../python
DEPENDS osd_static_cpu osd_dynamic_cpu
COMMENT "Building Python bindings with distutils"
)
add_custom_target(python ALL
DEPENDS ${PROJECT_BINARY_DIR}/python/osd
)
install(CODE "execute_process(
WORKING_DIRECTORY ../python
COMMAND ${PYCMD} install --user)"
)
endif()
endif()
# Link examples & regressions dynamically against Osd
set( OSD_LINK_TARGET osd_dynamic_cpu osd_dynamic_gpu )

13
examples/python/README.md Normal file
View File

@ -0,0 +1,13 @@
This folder defines a small demo application that requires PyQt, PyOpenGL, and the Python bindings for OpenSubdiv (which in turn require numpy and SWIG).
![Screenshot](http://raw.github.com/PixarAnimationStudios/OpenSubdiv/master/examples/python/screenshot.png)
- **main.py** This what you invoke from the command line. All calls to the `osd` module go here. Creates a `QApplication` and periodically pushes new VBO data into the renderer. (see below)
- **renderer.py** Defines the renderer; implements `draw` and `init`. All OpenGL calls are made in this file, and there's no dependency on Qt or `osd`.
- **canvas.py** Inherits from `QGLWidget` and calls out to the renderer object (see above)
- **shaders.py** Implements a miniature FX format by extracting named strings from a file and pasting them together
- **simple.glsl** Specifies the GLSL shaders for the demo using the miniature FX format
- **utility.py** Some linear algebra stuff to make it easier to use Modern OpenGL
- **window.py** Inherits from `QMainWindow`, instances a canvas object
- **interactive.py** Invoke this from the command line to spawn an alternative demo that has an interactive prompt.
- **\_\_init\_\_.py** Exports `main` into the package namespace to make it easy to run the demo from `setup.py`

View File

@ -0,0 +1,60 @@
#
# 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.
#
from main import main
from interactive import interactive

97
examples/python/canvas.py Normal file
View File

@ -0,0 +1,97 @@
#
# 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.
#
from PyQt4 import QtCore
from PyQt4.QtOpenGL import *
from OpenGL.GL import *
from time import time
# Set this to 'None' to refresh as rapidly as possible
# (assuming that vsync is disabled.)
ThrottleFps = 60
class Canvas(QGLWidget):
def __init__(self, parent, client):
self.client = client
f = QGLFormat(QGL.SampleBuffers)
if hasattr(QGLFormat, 'setVersion'):
f.setVersion(3, 2)
f.setProfile(QGLFormat.CoreProfile)
else:
pass
if f.sampleBuffers():
f.setSamples(16)
c = QGLContext(f, None)
QGLWidget.__init__(self, c, parent)
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.updateGL)
interval = 1000.0 / ThrottleFps if ThrottleFps else 0
self.timer.start(interval)
self.setMinimumSize(500, 500)
def paintGL(self):
self.client.draw()
def updateGL(self):
self.client.draw()
self.update()
def resizeGL(self, w, h):
self.client.resize(w, h)
def initializeGL(self):
self.client.init()

136
examples/python/interactive.py Executable file
View File

@ -0,0 +1,136 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# 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.
#
from PyQt4 import QtGui, QtCore
from window import Window
from renderer import Renderer
import sys
import numpy as np
import osd
import utility
from time import time
import math
def interactive():
app = QtGui.QApplication(sys.argv)
renderer = Renderer()
win = Window(renderer)
win.raise_()
cage = [ 0.0, -1.414214, 1.0, # 0
1.414214, 0.0, 1.0, # 1
-1.414214, 0.0, 1.0, # 2
0.0, 1.414214, 1.0, # 3
-1.414214, 0.0, -1.0, # 4
0.0, 1.414214, -1.0, # 5
0.0, -1.414214, -1.0, # 6
1.414214, 0.0, -1.0 ] # 7
cage = np.array(cage, np.float32).reshape((-1, 3))
faces = [ (0,1,3,2), # 0
(2,3,5,4), # 1
(4,5,7,6), # 2
(6,7,1,0), # 3
(1,7,5,3), # 4
(6,0,2,4) ] # 5
topo = osd.Topology(faces)
dtype = [('x', np.float32),
('y', np.float32),
('z', np.float32)]
def updateTopo(numLevels = 4):
global subdivider
topo.reset()
topo.finalize()
subdivider = osd.Subdivider(
topo,
vertexLayout = dtype,
indexType = np.uint32,
levels = numLevels)
quads = subdivider.getRefinedQuads()
renderer.updateIndicesVbo(quads)
def updateCoarseVertices():
global subdivider
subdivider.setCoarseVertices(cage)
subdivider.refine()
pts = subdivider.getRefinedVertices()
renderer.updatePointsVbo(pts)
updateTopo()
updateCoarseVertices()
renderer.drawHook = updateCoarseVertices
# Start an interactive session
import code
from time import time
timer = QtCore.QTimer()
code.interact(local=dict(globals(), **locals()))
sys.exit(0)
if __name__ == '__main__':
interactive()

146
examples/python/main.py Executable file
View File

@ -0,0 +1,146 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# 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.
#
from PyQt4 import QtGui, QtCore
from window import Window
from renderer import Renderer
import sys
import numpy as np
import osd
def main():
app = QtGui.QApplication(sys.argv)
renderer = Renderer()
win = Window(renderer)
win.raise_()
verts = [ 0.0, -1.414214, 1.0, # 0
1.414214, 0.0, 1.0, # 1
-1.414214, 0.0, 1.0, # 2
0.0, 1.414214, 1.0, # 3
-1.414214, 0.0, -1.0, # 4
0.0, 1.414214, -1.0, # 5
0.0, -1.414214, -1.0, # 6
1.414214, 0.0, -1.0 ] # 7
verts = np.array(verts, np.float32).reshape((-1, 3))
faces = [ (0,1,3,2), # 0
(2,3,5,4), # 1
(4,5,7,6), # 2
(6,7,1,0), # 3
(1,7,5,3), # 4
(6,0,2,4) ] # 5
dtype = [ ('x', np.float32),
('y', np.float32),
('z', np.float32) ]
topo = osd.Topology(faces)
topo.boundaryMode = osd.BoundaryMode.EDGE_ONLY
for v in (2, 3, 4, 5):
topo.vertices[v].sharpness = 2.0
for e in xrange(4):
topo.faces[3].edges[e].sharpness = 3
topo.finalize()
subdivider = osd.Subdivider(
topo,
vertexLayout = 'f4, f4, f4',
indexType = np.uint32,
levels = 4)
subdivider.setCoarseVertices(verts)
subdivider.refine()
inds = subdivider.getRefinedQuads()
renderer.updateIndicesVbo(inds)
def animateVerts():
from time import time
import math
t = 4 * time()
t = 0
t = 0.5 + 0.5 * math.sin(t)
t = 0.25 + t * 0.75
a = np.array([ 0.0, -1.414214, 1.0])
b = np.array([ 1.414214, 0.0, 1.0])
c = np.array([ 0.0, -1.414214, -1.0])
d = np.array([1.414214, 0.0, -1.0 ])
center = (a + b + c + d) / 4
center = np.multiply(center, 1-t)
verts[0] = center + np.multiply(a, t)
verts[1] = center + np.multiply(b, t)
verts[6] = center + np.multiply(c, t)
verts[7] = center + np.multiply(d, t)
def updateAnimation():
animateVerts()
subdivider.setCoarseVertices(verts)
subdivider.refine()
pts = subdivider.getRefinedVertices()
renderer.updatePointsVbo(pts)
updateAnimation()
renderer.drawHook = updateAnimation
retcode = app.exec_()
sys.exit(retcode)
if __name__ == '__main__':
main()

154
examples/python/renderer.py Normal file
View File

@ -0,0 +1,154 @@
#
# 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.
#
import math
import numpy as np
from OpenGL.GL import *
from shaders import *
from utility import *
from canvas import *
class Renderer:
def __init__(self):
self.indexCount = 0
def draw(self):
if hasattr(self, "drawHook"):
self.drawHook()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
if not self.indexCount:
return
theta = time() * math.pi / 2
eye = V3(0, 0, 10)
target = V3(0, 0, 0)
up = V3(0, 1, 0)
view = look_at(eye, target, up)
model = np.identity(4, 'f')
model = rotation(-1.1 + theta, [0,1,0])
objToEye = view * model
eyeToClip = perspective(15, self.aspect, 5, 200)
normalM = np.identity(3, 'f')
normalM[:3,:3] = objToEye[:3,:3]
glUseProgram(self.programs['BareBones'])
glUniformMatrix4fv(U("Projection"), 1, True, eyeToClip)
glUniformMatrix4fv(U("Modelview"), 1, True, objToEye)
glUniformMatrix3fv(U("NormalMatrix"), 1, True, normalM)
glBindVertexArray(self.vao)
# Since quads are deprecated we use LINES_ADJACENCY
# simply because they're 4 verts per prim, and we can
# expand them to triangles in the GS.
glDrawElements(
GL_LINES_ADJACENCY,
self.indexCount,
GL_UNSIGNED_INT,
None)
def resize(self, w, h):
self.aspect = float(w) / float(h)
glViewport(0, 0, w, h)
def init(self):
print glGetString(GL_VERSION)
glClearColor(0.0, 0.25, 0.5, 1.0)
self.programs = load_shaders()
try:
self.vao = glGenVertexArrays(1)
except:
import sys
print "glGenVertexArrays isn't available, so you might need a newer version of PyOpenGL."
sys.exit(1)
self.pointsVbo = glGenBuffers(1)
self.normalsVbo = None
self.indicesVbo = glGenBuffers(1)
glBindVertexArray(self.vao)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.indicesVbo)
glBindBuffer(GL_ARRAY_BUFFER, self.pointsVbo)
glVertexAttribPointer(Attribs.POSITION, 3, GL_FLOAT, GL_FALSE, 12, None)
glEnableVertexAttribArray(Attribs.POSITION)
glEnable(GL_CULL_FACE)
glEnable(GL_DEPTH_TEST)
def updatePointsVbo(self, points):
glBindBuffer(GL_ARRAY_BUFFER, self.pointsVbo)
glBufferData(GL_ARRAY_BUFFER, points, GL_STATIC_DRAW)
def updateNormalsVbo(self, normals):
if not self.normalsVbo:
self.normalsVbo = glGenBuffers(1)
glBindVertexArray(self.vao)
glBindBuffer(GL_ARRAY_BUFFER, self.normalsVbo)
glVertexAttribPointer(Attribs.NORMAL, 3, GL_FLOAT, GL_FALSE, 12, None)
glEnableVertexAttribArray(Attribs.NORMAL)
glBindBuffer(GL_ARRAY_BUFFER, self.normalsVbo)
glBufferData(GL_ARRAY_BUFFER, normals, GL_STATIC_DRAW)
def updateIndicesVbo(self, indices):
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.indicesVbo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW)
self.indexCount = len(indices)

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

149
examples/python/shaders.py Normal file
View File

@ -0,0 +1,149 @@
#
# 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.
#
from OpenGL.GL import *
ProgramFiles = ['simple.glsl']
Programs = {
"BareBones" : {
"GL_VERTEX_SHADER" : "simple.xforms simple.vert",
"GL_GEOMETRY_SHADER" : "simple.xforms simple.geom",
"GL_FRAGMENT_SHADER" : "simple.xforms simple.frag"
}
}
class Attribs:
POSITION = 0
NORMAL = 1
def load_shaders(
glslFiles = ProgramFiles,
attribs = Attribs,
programMap = Programs):
"""Parse a series of simple text files, each of which is composed
series of shader snippets. The given 'attribs' class defines an
enumeration of attribute slots to bind (aka semantics).
In each text file, lines starting with two dash characters start a new
shader snippet with the given name. For example:
-- S1
uniform float foo;
-- Prefix
#version 150
-- S2
uniform float bar;
"""
import os.path
# First parse the file to populate 'snippetMap'
class ParserState:
HEADER = 0
SOURCE = 1
parserState = ParserState.HEADER
snippetMap = {}
for glslFile in glslFiles:
basename = os.path.basename(glslFile)
snippetPrefix = os.path.splitext(basename)[0] + '.'
for line in open(glslFile):
if line.startswith('--'):
if parserState is ParserState.HEADER:
parserState = ParserState.SOURCE
elif len(source):
snippetMap[snippetName] = ''.join(source)
snippetName = snippetPrefix + line[2:].strip()
source = []
continue
if parserState is ParserState.HEADER:
pass
else:
source.append(line)
if len(source):
snippetMap[snippetName] = ''.join(source)
# Now, glue together the strings and feed them to OpenGL
stagePrefix = "#version 150\n"
programs = {}
for key, val in programMap.items():
programHandle = glCreateProgram()
for stageName, snippetList in val.items():
snippets = map(snippetMap.get, snippetList.split())
stageSource = stagePrefix + ''.join(snippets)
stage = getattr(OpenGL.GL, stageName)
sHandle = glCreateShader(stage)
glShaderSource(sHandle, stageSource)
glCompileShader(sHandle)
success = glGetShaderiv(sHandle, GL_COMPILE_STATUS)
if not success:
print 'Error in', stageName, snippetList
infolog = glGetShaderInfoLog(sHandle)
raise SystemExit(infolog)
glAttachShader(programHandle, sHandle)
for attrib in dir(attribs):
if attrib.startswith('__'):
continue
slot = getattr(attribs, attrib)
name = attrib[0] + attrib[1:].lower()
glBindAttribLocation(programHandle, slot, name)
glLinkProgram(programHandle)
success = glGetProgramiv(programHandle, GL_LINK_STATUS);
if not success:
infolog = glGetProgramInfoLog(programHandle)
raise SystemExit(infolog)
programs[key] = programHandle
return programs

143
examples/python/simple.glsl Normal file
View File

@ -0,0 +1,143 @@
#
# 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.
#
-- xforms
uniform mat4 Projection;
uniform mat4 Modelview;
uniform mat3 NormalMatrix;
-- vert
in vec4 Position;
in vec3 Normal;
out vec4 vPosition;
out vec3 vNormal;
void main()
{
vPosition = Position;
vNormal = Normal;
gl_Position = Projection * Modelview * Position;
}
-- geom
in vec4 vPosition[4];
in vec3 vNormal[4];
out vec3 gNormal;
const bool facets = true;
layout(lines_adjacency) in;
layout(triangle_strip, max_vertices = 4) out;
void emit(int index)
{
if (!facets) {
gNormal = NormalMatrix * vNormal[index];
}
gl_Position = Projection * Modelview * vPosition[index];
gl_Position.z = 1 - gl_Position.z;
EmitVertex();
}
void main()
{
if (facets) {
vec3 A = vPosition[0].xyz;
vec3 B = vPosition[1].xyz;
vec3 C = vPosition[2].xyz;
gNormal = NormalMatrix * normalize(cross(B - A, C - A));
}
emit(0);
emit(1);
emit(3);
emit(2);
EndPrimitive();
}
-- frag
in vec3 gNormal;
out vec4 FragColor;
uniform vec4 LightPosition = vec4(0.75, -0.25, 1, 1);
uniform vec3 AmbientMaterial = vec3(0.2, 0.1, 0.1);
uniform vec4 DiffuseMaterial = vec4(1.0, 209.0/255.0, 54.0/255.0, 1.0);
uniform vec3 SpecularMaterial = vec3(0.4, 0.4, 0.3);
uniform float Shininess = 200.0;
uniform float Fresnel = 0.1;
void main()
{
vec3 N = normalize(gNormal);
vec3 L = normalize((LightPosition).xyz);
vec3 Eye = vec3(0, 0, 1);
vec3 H = normalize(L + Eye);
float df = max(0.0, dot(N, L));
float sf = pow(max(0.0, dot(N, H)), Shininess);
float rfTheta = Fresnel + (1-Fresnel) * pow(1-dot(N,Eye), 5);
vec3 color = AmbientMaterial +
df * DiffuseMaterial.rgb +
sf * SpecularMaterial +
rfTheta;
FragColor = vec4(color, DiffuseMaterial.a);
}

135
examples/python/utility.py Normal file
View File

@ -0,0 +1,135 @@
#
# 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.
#
from OpenGL.GL import *
from time import time
import math
import numpy as np
from numpy import linalg as LA
# Provide a terse way to get a uniform location from its name
def U(name):
p = glGetIntegerv(GL_CURRENT_PROGRAM)
return glGetUniformLocation(p, name)
# Provide a terse way to create a f32 numpy 3-tuple
def V3(x, y, z):
return np.array([x, y, z], 'f')
def translation(direction):
M = np.identity(4, 'f')
M[:3, 3] = direction[:3]
return M
def unit_vector(data, axis=None, out=None):
if out is None:
data = np.array(data, dtype=np.float32, copy=True)
if data.ndim == 1:
data /= math.sqrt(np.dot(data, data))
return data
else:
if out is not data:
out[:] = np.array(data, copy=False)
data = out
length = np.atleast_1d(np.sum(data*data, axis))
np.sqrt(length, length)
if axis is not None:
length = np.expand_dims(length, axis)
data /= length
if out is None:
return data
def rotation3(angle, direction):
sina = math.sin(angle)
cosa = math.cos(angle)
direction = unit_vector(direction[:3])
R = np.diag([cosa, cosa, cosa])
R += np.outer(direction, direction) * (1.0 - cosa)
direction *= sina
R += np.array([[ 0.0, -direction[2], direction[1]],
[ direction[2], 0.0, -direction[0]],
[-direction[1], direction[0], 0.0]])
return R
def rotation(angle, direction):
R = rotation3(angle, direction)
M = np.identity(4, 'f')
M[:3, :3] = R
return M
def look_at(eye, target, up):
F = target[:3] - eye[:3]
f = F / LA.norm(F)
U = up / LA.norm(up)
s = np.cross(f, U)
u = np.cross(s, f)
M = np.matrix(np.identity(4))
M[:3,:3] = [s,u,-f]
T = translation(-eye)
return np.matrix(M * T, 'f')
def perspective(fovy, aspect, f, n):
s = 1.0/math.tan(math.radians(fovy)/2.0)
sx, sy = s / aspect, s
zz = (f+n)/(n-f)
zw = 2*f*n/(n-f)
m = np.matrix([[sx,0,0,0],
[0,sy,0,0],
[0,0,zz,zw],
[0,0,-1,0]], 'f')
return m

72
examples/python/window.py Normal file
View File

@ -0,0 +1,72 @@
#
# 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.
#
from PyQt4 import QtGui, QtCore
from canvas import Canvas
class Window(QtGui.QMainWindow):
def __init__(self, client):
super(Window, self).__init__()
self.canvas = Canvas(self, client)
self.setCentralWidget(self.canvas)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('PyQt')
self.show()
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Escape:
self.close()

36
python/README.md Normal file
View File

@ -0,0 +1,36 @@
# Instructions
The OpenSubdiv Python wrapper has been tested with Python 2.6 and Python 2.7.
Make sure you install SWIG and numpy before you begin.
CMake builds the extension like this:
./setup.py build --osddir='../build/lib' \
--build-platlib='../build/python' \
--build-temp='../build/temp'
If you invoke this manually, you'll need to replace `../build/lib` with the folder that has `libosdCPU.a`.
The demo that uses PyQt and PyOpenGL can be found in `../examples/python`.
You can run some unit tests like so:
./setup.py test
You can clean, build, and test in one go like this:
./setup.py clean --all build test
You can generate and view the Sphinx-generated documentation like so:
./setup.py doc
open ./doc/_build/html/index.html
# To Do Items
- Add support for face varying data by augmenting _FaceAdapter in adapters.py
- Exercise this in the demo by getting it down to GPU (maybe do "discard" for certain faces)
- Instead of using OsdCpuVertexBuffer, create a "NumpyCpuVertexBuffer" that wraps a numpy array
- Add an API that looks very similar to the RIB parameters for RiHierarchicalSubdiv
- Remove all the caveats that are listed in the Sphinx docs :)
- Sphinx documentation should be CMake-ified.

153
python/doc/Makefile Normal file
View File

@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenSubdiv.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenSubdiv.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/OpenSubdiv"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenSubdiv"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

244
python/doc/conf.py Normal file
View File

@ -0,0 +1,244 @@
# -*- coding: utf-8 -*-
#
# OpenSubdiv documentation build configuration file, created by
# sphinx-quickstart on Wed Nov 21 15:45:14 2012.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.mathjax']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'OpenSubdiv'
copyright = u'2012, Pixar Animation Studios'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'OpenSubdivdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'OpenSubdiv.tex', u'OpenSubdiv Documentation',
u'Pixar Animation Studios', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'opensubdiv', u'OpenSubdiv Documentation',
[u'Pixar Animation Studios'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'OpenSubdiv', u'OpenSubdiv Documentation',
u'Pixar Animation Studios', 'OpenSubdiv', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
autodoc_member_order = 'bysource'

75
python/doc/index.rst Normal file
View File

@ -0,0 +1,75 @@
.. OpenSubdiv documentation master file, created by
sphinx-quickstart on Wed Nov 21 15:45:14 2012.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Overview and Design Philosophy
=======
The Python module for OpenSubdiv does not provide one-to-one wrapping of the native C++ APIs: Osd, Hbr, and Far. Rather, the ``osd`` module is a higher-level utility layer composed of a small handful of classes and free functions.
We do not yet support rendering or GPU-accelerated subdivision from Python, but a demo is provided that renders a subdivided surface using ``PyOpenGL`` and ``QGLWidget``. The demo uses a "modern" OpenGL context (Core Profile).
These bindings leverage numpy_ arrays for passing data. The numpy library is the de facto standard for encapsulating large swaths of typed data in Python. However, for special attributes (such as sharpness), the OpenSubdiv wrapper exposes Pythonic interfaces, using properties and list accessors. For example::
import osd
import numpy as np
faceList = np.array([[0,1,2,3],[0,1,6,7]])
topo = osd.Topology(faceList)
topo.vertices[2].sharpness = 1.3
topo.faces[0].edges[3].sharpness = 0.6
After constructing a :class:`osd.Topology` object, simply finalize it and pass it into a :class:`osd.Subdivider` instance::
topo.finalize()
subdivider = osd.Subdivider(
topology = topo,
vertexLayout = np.dtype('f4, f4, f4'),
indexType = np.uint32,
levels = 4)
The final step is to perform actual refinement. This often occurs inside an animation loop or callback function::
subdivider.setCoarseVertices(positions)
subdivider.refine()
pts = subdivider.getRefinedVertices()
Only uniform subdivision is supported from Python, which means the topology of the subdivided mesh will never change::
indices = subdivider.getRefinedQuads()
This returns a flat list of indices (four per quad) using the integer type that was specified as the ``indexType`` argument in the constructor.
.. _numpy: http://www.numpy.org
Topology Class
==============
.. autoclass:: osd.Topology
:members:
Subdivider Class
==============
.. autoclass:: osd.Subdivider
:members:
Enumerations
==============
.. autoclass:: osd.BoundaryMode
:members:
.. autoclass:: osd.Sharpness
:members:
Caveats
=======
- Hierarchical edits are not yet supported
- Face varying data is not yet supported
- Feature adaptive subdivision is not yet supported
- CUDA and GLSL tessellation shaders are not yet supported
- Only the Catmull-Clark scheme is supported (no loop or linear schemes)
- Vertex data must be 32-bit floats although API is in place to accept heterogenous interpolation data
- Index data must be 32-bit unsigned integers although API is in place to accept other types

60
python/osd/__init__.py Normal file
View File

@ -0,0 +1,60 @@
#
# 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.
#
from common import *
from topology import Topology
from subdivider import Subdivider

141
python/osd/adapters.py Normal file
View File

@ -0,0 +1,141 @@
#
# 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.
#
# Helper classes that present mesh data as a Pythonic list-like
# objects with properties. In general we prefer clients to use numpy
# arrays for data. However, for OSD-specific data such as sharpness,
# we provide these adapter classes.
class VertexListAdapter(object):
def __init__(self, shim):
self.shim = shim
self.length = shim.getNumVertices()
def __getitem__(self, index):
if index >= self.length:
raise IndexError("Index out of bounds")
return _VertexAdapter(self.shim, index)
def __len__(self):
return self.length
class _VertexAdapter(object):
def __init__(self, shim, index):
self.shim = shim
self.index = index
@property
def sharpness(self):
return self.shim.getVertexSharpness(
self.index)
@sharpness.setter
def sharpness(self, value):
self.shim.setVertexSharpness(
self.index,
value)
class FaceListAdapter(object):
def __init__(self, shim):
self.shim = shim
self.length = shim.getNumFaces()
def __getitem__(self, index):
if index >= self.length:
raise IndexError("Index out of bounds")
return _FaceAdapter(self.shim, index)
def __len__(self):
return self.length
class _FaceAdapter(object):
def __init__(self, shim, faceIndex):
self.shim = shim
self.faceIndex = faceIndex
self._edgeListAdapter = _EdgeListAdapter(self.shim, faceIndex)
@property
def hole(self):
return self.shim.getFaceHole(self.faceIndex)
@hole.setter
def hole(self, value):
self.shim.setFaceHole(self.faceIndex, value)
@property
def edges(self):
return self._edgeListAdapter
class _EdgeListAdapter(object):
def __init__(self, shim, faceIndex):
self.shim = shim
self.faceIndex = faceIndex
self.length = shim.getNumEdges(faceIndex)
def __getitem__(self, edgeIndex):
if edgeIndex >= self.length:
raise IndexError("Index out of bounds")
return _EdgeAdapter(self.shim, self.faceIndex, edgeIndex)
def __len__(self):
return self.length
class _EdgeAdapter(object):
def __init__(self, shim, faceIndex, edgeIndex):
self.shim = shim
self.faceIndex = faceIndex
self.edgeIndex = edgeIndex
@property
def sharpness(self):
return self.shim.getEdgeSharpness(
self.faceIndex,
self.edgeIndex)
@sharpness.setter
def sharpness(self, value):
self.shim.setEdgeSharpness(
self.faceIndex,
self.edgeIndex,
value)

98
python/osd/buffer.h Normal file
View File

@ -0,0 +1,98 @@
//
// 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.
//
#pragma once
#include <vector>
namespace shim {
typedef std::vector<unsigned char> Buffer;
enum DataType {
invalid,
int8,
uint8,
int16,
uint16,
int32,
uint32,
int64,
uint64,
int128,
uint128,
int256,
uint256,
float16,
float32,
float64,
float80,
float96,
float128,
};
struct HomogeneousBuffer {
shim::Buffer Buffer;
shim::DataType Type;
};
typedef std::vector<shim::DataType> Layout;
struct HeterogeneousBuffer {
shim::Buffer Buffer;
shim::Layout Layout;
};
}

94
python/osd/common.py Normal file
View File

@ -0,0 +1,94 @@
#
# 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.
#
class TopoError(Exception):
def __init__(self, message):
Exception.__init__(self, message)
class OsdTypeError(Exception):
def __init__(self, message):
Exception.__init__(self, message)
# From hbr/mesh.h
class BoundaryMode:
"Subdivision boundary rules for :class:`osd.Topology` construction."
NONE = 0
"Boundary edges are corner verts are not processed specially."
EDGE_ONLY = 1
"Boundary edges are marked infinitely sharp."
EDGE_AND_CORNER = 2
'''Boundary edges are marked infinitely sharp, and vertices with
valence=2 are marked infinitely sharp.'''
ALWAYS_SHARP = 3
"Unused."
class Sharpness:
'''Provides some floating-point constants that clients can
optionally use to set sharpness.'''
SMOOTH = 0
"As smooth as possible."
SHARP = 1
"Moderately sharp."
INFINITELY_SHARP = 2
"As sharp as possible."

82
python/osd/internal.h Normal file
View File

@ -0,0 +1,82 @@
//
// 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.
//
#include <Python.h>
#include <numpy/arrayobject.h>
#include <common/mutex.h>
#include <far/meshFactory.h>
#include <osd/vertex.h>
#include <osd/cpuComputeContext.h>
#include <osd/cpuVertexBuffer.h>
#include <osd/cpuComputeController.h>
typedef OpenSubdiv::HbrMesh<OpenSubdiv::OsdVertex> OsdHbrMesh;
typedef OpenSubdiv::HbrVertex<OpenSubdiv::OsdVertex> OsdHbrVertex;
typedef OpenSubdiv::HbrFace<OpenSubdiv::OsdVertex> OsdHbrFace;
typedef OpenSubdiv::HbrHalfedge<OpenSubdiv::OsdVertex> OsdHbrHalfedge;
struct TopologyImpl {
OsdHbrMesh *hmesh;
std::vector<OsdHbrFace*> faces;
size_t numVertices;
};
struct SubdividerImpl {
OpenSubdiv::FarMesh<OpenSubdiv::OsdVertex>* farMesh;
OpenSubdiv::OsdCpuComputeContext* computeContext;
OpenSubdiv::OsdCpuVertexBuffer* vertexBuffer;
};

251
python/osd/osdshim.i Normal file
View File

@ -0,0 +1,251 @@
//
// 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.
//
%module shim
%{
#include "subdivider.h"
#include "topology.h"
%}
%header %{
#include <numpy/arrayobject.h>
#include <iostream>
static shim::DataType
_ShimTypeFromNumpyType(int numpyType)
{
using namespace std;
switch (numpyType) {
case PyArray_FLOAT32: return shim::float32;
case PyArray_UINT32: return shim::uint32;
case PyArray_INT32: return shim::int32;
case PyArray_INT8: return shim::int8;
case PyArray_UBYTE: return shim::uint8;
case PyArray_VOID:
cerr << "Expected a type but got VOID." << endl;
abort();
return shim::invalid;
case PyArray_STRING:
case PyArray_UNICODE:
cerr << "Strings are not expected here." << endl;
return shim::invalid;
case PyArray_OBJECT:
cerr << "Complex type not allowed here." << endl;
return shim::invalid;
}
cerr << "Unsupported numpy type " << numpyType << endl;
abort();
return shim::invalid;
}
static shim::DataType
_ShimTypeFromNumpyType(PyTypeObject* item)
{
std::string numpyType = ((PyTypeObject*) item)->tp_name;
if (numpyType == "numpy.float32") return shim::float32;
if (numpyType == "numpy.uint32") return shim::uint32;
if (numpyType == "numpy.int32") return shim::int32;
if (numpyType == "numpy.uint8") return shim::uint8;
std::cerr << "Unsupported numpy type " << numpyType << std::endl;
return shim::invalid;
}
static shim::Layout
_ShimLayoutFromObject(PyObject* obj)
{
using namespace std;
shim::Layout layout;
if (!obj) {
cerr << "Missing type.\n";
} else if (PyArray_DescrCheck(obj)) {
PyArray_Descr* descr = (PyArray_Descr*) obj;
int numpyType = descr->type_num;
if (numpyType != PyArray_VOID) {
shim::DataType dtype = _ShimTypeFromNumpyType(numpyType);
layout.push_back(dtype);
} else if (PyDataType_HASFIELDS(descr)) {
PyObject* rawTypes = PyDict_Values(descr->fields);
Py_ssize_t count = PySequence_Size(rawTypes);
// Each field value is a type-offset pair. We don't honor
// the offsets, so just extract the type and move on.
for (Py_ssize_t i = 0; i < count; ++i) {
PyObject* pair = PySequence_ITEM(rawTypes, i);
PyObject* item = PySequence_ITEM(pair, 0);
shim::Layout newTypes = _ShimLayoutFromObject(item);
layout.insert(layout.end(), newTypes.begin(), newTypes.end());
Py_DECREF(item);
Py_DECREF(pair);
}
Py_DECREF(rawTypes);
} else {
cerr << "Please provide a record-style numpy type with fields." << endl;
}
} else if (PyType_Check(obj)) {
layout.push_back( _ShimTypeFromNumpyType((PyTypeObject*) obj) );
} else if (PySequence_Check(obj)) {
Py_ssize_t count = PySequence_Size(obj);
for (Py_ssize_t i = 0; i < count; ++i) {
PyObject* item = PySequence_ITEM(obj, i);
shim::Layout newTypes = _ShimLayoutFromObject(item);
layout.insert(layout.end(), newTypes.begin(), newTypes.end());
Py_DECREF(item);
}
} else {
int dtype = (int) PyInt_AsLong(obj);
if (dtype == -1) {
cerr << "Got a " << obj->ob_type->tp_name << " but wanted a data type." << endl;
} else if (dtype != shim::invalid) {
layout.push_back(_ShimTypeFromNumpyType(dtype));
}
}
return layout;
}
%}
%init %{
import_array();
%}
%typemap(in) const shim::HomogeneousBuffer& {
if (!PyArray_CheckExact($input)) {
std::cerr << "This requires a numpy array." << std::endl;
}
$1 = new shim::HomogeneousBuffer();
int byteCount = PyArray_NBYTES($input);
unsigned char* begin = (unsigned char*) PyArray_BYTES($input);
unsigned char* end = begin + byteCount;
$1->Buffer.assign(begin, end);
int dtype = PyArray_TYPE($input);
$1->Type = _ShimTypeFromNumpyType(dtype);
}
%typemap(in) shim::Layout {
$1 = _ShimLayoutFromObject($input);
}
%typemap(in) shim::DataType {
using namespace std;
shim::Layout layout = _ShimLayoutFromObject($input);
if (layout.size() < 1) {
cerr << "Can't convert PyObject " << $input << " to a shim data type." << endl;
$1 = shim::invalid;
} else if (layout.size() > 1) {
cerr << "Complex data type not allowed here." << endl;
$1 = shim::invalid;
} else {
$1 = layout[0];
}
}
%typemap(in) const shim::HeterogeneousBuffer& {
using namespace std;
if (!PyArray_CheckExact($input)) {
cerr << "This requires a numpy array." << endl;
}
$1 = new shim::HeterogeneousBuffer();
int byteCount = PyArray_NBYTES($input);
unsigned char* begin = (unsigned char*) PyArray_BYTES($input);
unsigned char* end = begin + byteCount;
$1->Buffer.assign(begin, end);
$1->Layout = _ShimLayoutFromObject((PyObject*) PyArray_DESCR($input));
}
%typemap(in) shim::Buffer* INOUT {
$1 = new shim::Buffer();
}
%typemap(argout) shim::Buffer* INOUT {
using namespace std;
PyObject* obj = (PyObject*) PyArray_DESCR($input);
shim::Layout layout = _ShimLayoutFromObject(obj);
if (layout.size() == 0) {
cerr << "Unknown type for Buffer processing." << endl;
} else if (layout[0] == shim::float32) {
npy_intp numFloats = (npy_intp) ($1->size() / sizeof(float));
float* ptrFloats = (float*) &(*$1)[0];
$result = PyArray_SimpleNew(1, &numFloats, PyArray_FLOAT32);
memcpy(PyArray_BYTES($result), ptrFloats, $1->size());
// SimpleNewFromData would avoid a copy but we'd need to keep
// the buffer around in our shim class. It's not
// impossible...
//$result = PyArray_SimpleNewFromData(
// 1, &numFloats, PyArray_FLOAT, (void*) ptrFloats);
} else if (layout[0] == shim::uint32) {
npy_intp numInts = (npy_intp) ($1->size() / sizeof(unsigned int));
unsigned int* ptrInts = (unsigned int*) &(*$1)[0];
$result = PyArray_SimpleNew(1, &numInts, PyArray_UINT32);
memcpy(PyArray_BYTES($result), ptrInts, $1->size());
} else {
cerr << layout[0] << " is not an understood shim type."
<< endl;
}
}
%typemap(freearg) shim::Buffer* INOUT {
delete $1;
}
%include "subdivider.h"
%include "topology.h"

106
python/osd/subdivider.cpp Normal file
View File

@ -0,0 +1,106 @@
#include "internal.h"
#include "subdivider.h"
#include "topology.h"
using namespace std;
using namespace shim;
OpenSubdiv::OsdCpuComputeController* g_osdComputeController = 0;
shim::Subdivider::Subdivider(
const Topology& topo,
Layout refinedLayout,
DataType refinedIndexType,
int subdivisionLevels)
{
self = new SubdividerImpl();
if (!g_osdComputeController) {
g_osdComputeController = new OpenSubdiv::OsdCpuComputeController();
}
size_t numFloatsPerVertex = 0;
Layout::const_iterator it;
for (it = refinedLayout.begin(); it != refinedLayout.end(); ++it) {
if (*it != float32) {
cerr << "Unsupported vertex type." << endl;
break;
}
++numFloatsPerVertex;
}
OpenSubdiv::FarMeshFactory<OpenSubdiv::OsdVertex> meshFactory(
topo.self->hmesh,
subdivisionLevels);
self->farMesh = meshFactory.Create();
self->computeContext = OpenSubdiv::OsdCpuComputeContext::Create(
self->farMesh);
self->vertexBuffer = OpenSubdiv::OsdCpuVertexBuffer::Create(
numFloatsPerVertex, self->farMesh->GetNumVertices());
}
shim::Subdivider::~Subdivider()
{
delete self->computeContext;
delete self->farMesh;
delete self->vertexBuffer;
delete self;
}
void
shim::Subdivider::setCoarseVertices(const HeterogeneousBuffer& cage)
{
float* pFloats = (float*) &cage.Buffer[0];
int numFloats = cage.Buffer.size() / sizeof(float);
self->vertexBuffer->UpdateData(pFloats, numFloats);
}
void
shim::Subdivider::refine()
{
g_osdComputeController->Refine(self->computeContext, self->vertexBuffer);
}
void
shim::Subdivider::getRefinedVertices(Buffer* refinedVertices)
{
float* pFloats = self->vertexBuffer->BindCpuBuffer();
int numFloats = self->vertexBuffer->GetNumElements() *
self->vertexBuffer->GetNumVertices();
unsigned char* srcBegin = (unsigned char*) pFloats;
unsigned char* srcEnd = srcBegin + numFloats * 4;
refinedVertices->assign(srcBegin, srcEnd);
}
void
shim::Subdivider::getRefinedQuads(Buffer* refinedQuads)
{
OpenSubdiv::FarPatchTables const * patchTables =
self->farMesh->GetPatchTables();
if (patchTables) {
cerr << "Feature adaptive not supported" << endl;
return;
}
const OpenSubdiv::FarSubdivisionTables<OpenSubdiv::OsdVertex> *tables =
self->farMesh->GetSubdivisionTables();
bool loop = dynamic_cast<const OpenSubdiv::FarLoopSubdivisionTables<
OpenSubdiv::OsdVertex>*>(tables);
if (loop) {
cerr << "loop subdivision not supported" << endl;
return;
}
int level = tables->GetMaxLevel();
const std::vector<int> &indices = self->farMesh->GetFaceVertices(level-1);
int numInts = (int) indices.size();
unsigned char* srcBegin = (unsigned char*) &indices[0];
unsigned char* srcEnd = srcBegin + numInts * 4;
refinedQuads->assign(srcBegin, srcEnd);
}

89
python/osd/subdivider.h Normal file
View File

@ -0,0 +1,89 @@
//
// 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.
//
#pragma once
#include "buffer.h"
struct SubdividerImpl;
namespace shim {
class Topology;
class Subdivider {
public:
Subdivider(
const Topology& topo,
shim::Layout refinedLayout,
shim::DataType refinedIndexType,
int subdivisionLevels);
~Subdivider();
void setCoarseVertices(const shim::HeterogeneousBuffer& cage);
void refine();
// These argument names must be INOUT to inform SWIG that
// they're mutable:
void getRefinedVertices(shim::Buffer* INOUT);
void getRefinedQuads(shim::Buffer* INOUT);
private:
SubdividerImpl* self;
};
}

149
python/osd/subdivider.py Normal file
View File

@ -0,0 +1,149 @@
#
# 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.
#
from osd import *
import shim, numpy
class Subdivider(object):
'''Wraps a frozen :class:`osd.Topology` object and efficiently
subdivides it into triangles.
On creation, the :class:`Subdivider` is locked to an immutable,
finalized :class:`osd.Topology` object. However, actual
subdivision computation can be requested repeatedly using dynamic
per-vertex data.
:param topo: Finalized mesh topology.
:type topo: :class:`osd.Topology`
:param vertexLayout: Describes the data structure composing each vertex.
:type vertexLayout: numpy dtype_ object or short-hand string
:param indexType: Integer type for the indices returned from `getRefinedTopology`.
:type indexType: single numpy type_
:param levels: Number of subdivisions.
:type levels: integer
.. note:: In the current implementation, ``vertexLayout`` must be
composed of ``numpy.float32``, and ``indexType`` must be
``numpy.uint32``.
.. _type: http://docs.scipy.org/doc/numpy/user/basics.types.html
.. _dtype: http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html
'''
def __init__(self, topology, vertexLayout, indexType, levels):
if levels < 2:
raise TopoError("Subdivision levels must be 2 or greater")
if type(vertexLayout) != numpy.dtype:
vertexLayout = numpy.dtype(vertexLayout)
self.vertexLayout = vertexLayout
self.indexType = indexType
self.levels = levels
self.shim = shim.Subdivider(topology.shim, vertexLayout, indexType, levels)
# Calls UpdateData on the vertexBuffer.
def setCoarseVertices(self, coarseVerts, listType = None):
'''Pushes a new set of coarse verts to the mesh without
changing topology.
If a numpy array is supplied for ``coarseVerts``, its
``dtype`` must be castable (via view_) to the ``vertexLayout``
of the :class:`Subdivider`.
If a Python list is supplied for ``coarseVerts``, the client
must also supply the ``listType`` argument to specify the
numpy type of the incoming array before it gets cast to
``vertexLayout``.
.. _view: http://docs.scipy.org/doc/numpy-1.6.0/reference/generated/numpy.ndarray.view.html
'''
if type(coarseVerts) is not numpy.ndarray:
if not listType:
raise TopoError("listType must be supplied")
coarseVerts = numpy.array(coarseVerts, listType)
coarseVerts = coarseVerts.view(self.vertexLayout)
self.shim.setCoarseVertices(coarseVerts)
# Calls Refine on the compute controller, passing it the compute
# context and vertexBuffer.
def refine(self):
'''Performs the actual subdivision work.'''
self.shim.refine()
# Calls the strangely-named "BindCpuBuffer" on the
# OsdCpuVertexBuffer to get back a float*
def getRefinedVertices(self):
'''Returns a numpy array representing the vertex data in the
subdivided mesh.
The data is returned in the format specified by the client
when instancing the subdivider (``vertexLayout``).
'''
empty = numpy.empty(0, self.vertexLayout)
return self.shim.getRefinedVertices(empty)
def getRefinedQuads(self):
'''Returns a numpy array representing the vertex indices of each quad in
subdivided mesh.
The data is returned in the format specified by the client
when instancing the subdivider (``indexType``).
'''
empty = numpy.empty(0, self.indexType)
return self.shim.getRefinedQuads(empty)
def __del__(self):
pass

252
python/osd/topology.cpp Normal file
View File

@ -0,0 +1,252 @@
//
// 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.
//
#include "internal.h"
#include "topology.h"
using namespace shim;
using namespace std;
static OpenSubdiv::HbrCatmarkSubdivision<OpenSubdiv::OsdVertex> _catmark;
shim::Topology::Topology(
const HomogeneousBuffer& indices, const HomogeneousBuffer& valences)
{
self = new TopologyImpl();
self->hmesh = new OsdHbrMesh(&_catmark);
size_t maxIndex = 0;
size_t byteCount = indices.Buffer.size();
switch (indices.Type) {
case int32: {
const int *d = (const int*) &indices.Buffer[0];
maxIndex = (size_t) *max_element(d, d + byteCount / 4);
break;
}
default:
cerr << "Unsupported index type " << indices.Type << endl;
};
size_t maxValence = 0;
switch (valences.Type) {
case uint8: {
const unsigned char *d = (const unsigned char*) &valences.Buffer[0];
maxValence = (size_t) *max_element(d, d + byteCount);
break;
}
default:
cerr << "Unsupported valence type " << valences.Type << endl;
};
self->numVertices = 1 + (int) maxIndex;
OpenSubdiv::OsdVertex vert;
for (size_t i = 0; i < self->numVertices; ++i) {
OpenSubdiv::HbrVertex<OpenSubdiv::OsdVertex>* pVert =
self->hmesh->NewVertex((int) i, vert);
if (!pVert) {
cerr << "Error: Unable to create vertex " << i << endl;
}
}
int* pIndices = (int*) &indices.Buffer[0];
unsigned char* pValence = (unsigned char*) &valences.Buffer[0];
size_t valenceCount = valences.Buffer.size();
while (valenceCount--) {
int vertsPerFace = *pValence;
OpenSubdiv::HbrFace<OpenSubdiv::OsdVertex>* pFace =
self->hmesh->NewFace(vertsPerFace, pIndices, 0);
if (!pFace) {
cerr << "Error: Unable to create face (valence = "
<< vertsPerFace << ")\n";
}
pIndices += vertsPerFace;
++pValence;
}
self->hmesh->GetFaces(back_inserter(self->faces));
}
shim::Topology::~Topology()
{
delete self->hmesh;
delete self;
}
void
shim::Topology::copyAnnotationsFrom(const Topology& topo)
{
int vertexCount = getNumVertices();
for (int i = 0; i < vertexCount; ++i) {
float s = topo.getVertexSharpness(i);
setVertexSharpness(i, s);
}
int faceCount = getNumFaces();
for (int faceIndex = 0; faceIndex < faceCount; ++faceIndex) {
int numEdges = topo.getNumEdges(faceIndex);
for (int edgeIndex = 0; edgeIndex < numEdges; ++edgeIndex) {
float s = topo.getEdgeSharpness(faceIndex, edgeIndex);
setEdgeSharpness(faceIndex, edgeIndex, s);
}
}
}
void
shim::Topology::finalize()
{
self->hmesh->Finish();
}
BoundaryMode::e
shim::Topology::getBoundaryMode() const
{
OsdHbrMesh::InterpolateBoundaryMethod bm =
self->hmesh->GetInterpolateBoundaryMethod();
switch (bm) {
case OsdHbrMesh::k_InterpolateBoundaryNone:
return BoundaryMode::NONE;
case OsdHbrMesh::k_InterpolateBoundaryEdgeOnly:
return BoundaryMode::EDGE_ONLY;
case OsdHbrMesh::k_InterpolateBoundaryEdgeAndCorner:
return BoundaryMode::EDGE_AND_CORNER;
case OsdHbrMesh::k_InterpolateBoundaryAlwaysSharp:
return BoundaryMode::ALWAYS_SHARP;
}
throw("Bad interpolation method.");
}
void
shim::Topology::setBoundaryMode(BoundaryMode::e bm)
{
switch (bm) {
case BoundaryMode::NONE:
self->hmesh->SetInterpolateBoundaryMethod(
OsdHbrMesh::k_InterpolateBoundaryNone);
break;
case BoundaryMode::EDGE_ONLY:
self->hmesh->SetInterpolateBoundaryMethod(
OsdHbrMesh::k_InterpolateBoundaryEdgeOnly);
break;
case BoundaryMode::EDGE_AND_CORNER:
self->hmesh->SetInterpolateBoundaryMethod(
OsdHbrMesh::k_InterpolateBoundaryEdgeAndCorner);
break;
case BoundaryMode::ALWAYS_SHARP:
self->hmesh->SetInterpolateBoundaryMethod(
OsdHbrMesh::k_InterpolateBoundaryAlwaysSharp);
break;
}
}
int
shim::Topology::getNumVertices() const
{
return self->numVertices;
}
float
shim::Topology::getVertexSharpness(int vertex) const
{
return self->hmesh->GetVertex(vertex)->GetSharpness();
}
void
shim::Topology::setVertexSharpness(int vertex, float sharpness)
{
self->hmesh->GetVertex(vertex)->SetSharpness(sharpness);
}
int
shim::Topology::getNumFaces() const
{
return self->hmesh->GetNumFaces();
}
bool
shim::Topology::getFaceHole(int faceIndex) const
{
return self->faces[faceIndex]->IsHole();
}
void
shim::Topology::setFaceHole(int faceIndex, bool isHole)
{
if (!isHole) {
cerr << "Unsetting holeness is not supported." << endl;
return;
}
self->faces[faceIndex]->SetHole();
}
int
shim::Topology::getNumEdges(int faceIndex) const
{
return self->faces[faceIndex]->GetNumVertices();
}
float
shim::Topology::getEdgeSharpness(int faceIndex, int edgeIndex) const
{
return self->faces[faceIndex]->GetEdge(edgeIndex)->GetSharpness();
}
void
shim::Topology::setEdgeSharpness(int faceIndex, int edgeIndex, float sharpness)
{
self->faces[faceIndex]->GetEdge(edgeIndex)->SetSharpness(sharpness);
}

106
python/osd/topology.h Normal file
View File

@ -0,0 +1,106 @@
//
// 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.
//
#pragma once
#include "buffer.h"
struct TopologyImpl;
namespace shim {
struct BoundaryMode {
enum e {
NONE,
EDGE_ONLY,
EDGE_AND_CORNER,
ALWAYS_SHARP,
};
};
class Subdivider;
class Topology {
public:
Topology(const shim::HomogeneousBuffer& indices,
const shim::HomogeneousBuffer& valences);
~Topology();
void copyAnnotationsFrom(const Topology& topo);
void finalize();
BoundaryMode::e getBoundaryMode() const;
void setBoundaryMode(BoundaryMode::e bm);
int getNumVertices() const;
float getVertexSharpness(int vertex) const;
void setVertexSharpness(int vertex, float sharpness);
int getNumFaces() const;
bool getFaceHole(int face) const;
void setFaceHole(int face, bool isHole);
int getNumEdges(int face) const;
float getEdgeSharpness(int face, int edge) const;
void setEdgeSharpness(int face, int edge, float sharpness);
private:
TopologyImpl *self;
friend class shim::Subdivider;
};
}

210
python/osd/topology.py Normal file
View File

@ -0,0 +1,210 @@
#
# 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.
#
from common import *
from adapters import *
import numpy as np
import shim
import itertools
class Topology(object):
'''Represents an abstract graph of connected polygons.
A :class:`Topology` object contains only connectivity information;
it does not contain any coordinate data. Instances are simply
populated, finalized, and submitted to an instance of
:class:`osd.Subdivider`.
The constructor can take a single two-dimensional numpy array
(``indices``), or two one-dimensional numpy arrays
(``indices`` and ``valences``). If every face has the same
valence, clients can pass in a single integer for
``valences``.
If desired, simple Python lists can be passed in rather than numpy
arrays. However they will get converted into numpy arrays
internally.
.. note:: Input data is always copied to internal storage,
rather than referenced.
:param indices: Defines each face as a list of vertex indices.
:type indices: list or numpy array
:param valences: If ``indices`` is 2D, this should be :const:`None`. If every face has the same valence, this can be a single integer. Otherwise this is a list of integers that specify the valence of each face.
:type valences: list, number, or numpy array
'''
def __init__(self, indices, valences = None):
indices, valences = _flatten_args(indices, valences)
valences = _process_valences(indices, valences)
_check_topology(indices, valences)
self.indices = np.array(indices, 'int32')
self.valences = np.array(valences, 'uint8')
self.shim = shim.Topology(self.indices, self.valences)
self.boundaryMode = BoundaryMode.EDGE_ONLY
self._vertexListAdapter = VertexListAdapter(self.shim)
self._faceListAdapter = FaceListAdapter(self.shim)
def reset(self):
'''Un-finalizes the mesh to allow adjustment of sharpness and
custom data.
This is a costly operation since it effectively recreates the
HBR mesh.
'''
topo = shim.Topology(self.indices, self.valences)
topo.copyAnnotationsFrom(self.shim)
self._vertexListAdapter = VertexListAdapter(topo)
self._faceListAdapter = FaceListAdapter(topo)
self.shim = topo
@property
def boundaryMode(self):
'''Gets or sets the boundary interpolation method for this
mesh to one of the values defined in
:class:`osd.BoundaryMode`.
'''
return self.shim.getBoundaryMode()
@boundaryMode.setter
def boundaryMode(self, value):
self.shim.setBoundaryMode(value)
@property
def vertices(self):
'''Pythonic read/write access to special attributes (e.g., sharpness) in
the HBR mesh.
This property is not an actual list-of-things; it's a short-lived
adapter that allows clients to use Pythonic properties::
topo = osd.Topology(faces)
topo.vertices[2].sharpness = 1.3
'''
return self._vertexListAdapter
@property
def faces(self):
'''Pythonic read/write access to face data and edge data in the HBR mesh.
This property is not an actual list-of-things; it's a short-lived
adapter that allows clients to use Pythonic properties::
topo = osd.Topology(faces)
topo.faces[1].edges[0].sharpness = 0.6
'''
return self._faceListAdapter
def finalize(self):
'''Calls finish on the HBR mesh, thus preparing it for subdivision.'''
self.shim.finalize()
def __del__(self):
pass
# Checks that no valence is less than 3, and that the sum of all valences
# equal to the # of indices.
def _check_topology(indices, valences):
acc = 0
for v in valences:
if v < 3:
raise TopoError("all valences must be 3 or greater")
acc = acc + v
if len(indices) != acc:
msg = "sum of valences ({0}) isn't equal to the number of indices ({1})"
raise TopoError(msg.format(acc, len(indices)))
# Given a list-of-lists, returns a list pair where the first list has
# values and the second list has the original counts.
def _flatten(faces):
flattened = list(itertools.chain(*faces))
lengths = [len(face) for face in faces]
return flattened, lengths
# If indices is two-dimensional, splits it into two lists.
# Otherwise returns the lists unchanged.
def _flatten_args(indices, valences):
try:
flattened, lengths = _flatten(indices)
if valences is not None:
raise OsdTypeError(
"valences must be None if indices is two-dimensional")
return (flattened, lengths)
except TypeError:
if valences is None:
raise OsdTypeError(
"valences must be provided if indices is one-dimensional")
return (indices, valences)
# If valences is a scalar, returns a list of valences.
# Otherwise returns the original valence list.
def _process_valences(indices, valences):
try:
v = int(valences)
faceCount = len(indices) / v
if len(indices) % v is not 0:
msg = "Scalar provided for valences argument ({0}) that " \
"does evenly divide the number of indices ({1})"
raise OsdTypeError(msg.format(len(indices), v))
valences = [v] * faceCount
except TypeError:
pass
return valences

153
python/setup.py Executable file
View File

@ -0,0 +1,153 @@
#!/usr/bin/env python
#
# 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.
#
from distutils.core import setup, Command, Extension
from distutils.command.build import build
import numpy
import os, os.path
np_include_dir = numpy.get_include()
np_library_dir = os.path.join(np_include_dir, '../lib')
osd_include_dirs = ['../opensubdiv', '../regression']
osddir = '../build/lib'
osd_shim = Extension(
'osd._shim',
include_dirs = osd_include_dirs,
library_dirs = [osddir, np_library_dir],
libraries = ['osdCPU', 'npymath'],
swig_opts = ['-c++'],
sources = [
'osd/osdshim.i',
'osd/subdivider.cpp',
'osd/topology.cpp'])
osd_shim.extra_compile_args = \
["-Wno-unused-function"]
os.environ['ARCHFLAGS'] = '-arch ' + os.uname()[4]
def setBuildFolder(folder):
osddir = folder
osd_shim.runtime_library_dirs = [folder]
osd_shim.library_dirs = [folder, np_library_dir]
def importBuildFolder():
import os.path
builddir = os.path.join(osddir, "../python")
if not os.path.exists(builddir):
print "Folder does not exist: " + builddir
print "Perhaps you need to run:"
print " python setup.py build"
else:
sys.path.insert(0, builddir)
class TestCommand(Command):
description = "runs unit tests"
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
importBuildFolder()
import unittest, test
suite = unittest.defaultTestLoader.loadTestsFromModule(test)
unittest.TextTestRunner(verbosity=2).run(suite)
class DocCommand(Command):
description = "Generate HTML documentation with Sphinx"
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
import os
os.chdir('doc')
os.system('make clean html')
class BuildCommand(build):
description = "Builds the Python bindings"
user_options = build.user_options + [
('osddir=', 'o',
'directory that contains libosdCPU.a etc')]
def initialize_options(self):
build.initialize_options(self)
self.osddir = None
def finalize_options(self):
build.finalize_options(self)
if self.osddir is None:
self.osddir = '../build/lib'
setBuildFolder(self.osddir)
def run(self):
build.run(self)
setup(name = "OpenSubdiv",
version = "0.1",
packages = ['osd'],
author = 'Pixar Animation Studios',
cmdclass = {
'build': BuildCommand,
'test': TestCommand,
'doc': DocCommand},
include_dirs = [np_include_dir],
ext_modules = [osd_shim],
description = 'Python Bindings to the Pixar Subdivision Library')

58
python/test/__init__.py Normal file
View File

@ -0,0 +1,58 @@
#
# 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.
#
from simple import *

197
python/test/simple.py Executable file
View File

@ -0,0 +1,197 @@
#!/usr/bin/env python
#
# 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.
#
import numpy as np
import unittest, sys
import osd
# Topology of a cube.
faces = [ (0,1,3,2),
(2,3,5,4),
(4,5,7,6),
(6,7,1,0),
(1,7,5,3),
(6,0,2,4) ]
# Vertex positions and "temperature" as an example of a custom
# attribute.
verts = [ 0.000000, -1.414214, 1.000000, 71,
1.414214, 0.000000, 1.000000, 82,
-1.414214, 0.000000, 1.000000, 95,
0.000000, 1.414214, 1.000000, 100,
-1.414214, 0.000000, -1.000000, 63,
0.000000, 1.414214, -1.000000, 77,
0.000000, -1.414214, -1.000000, 82,
1.414214, 0.000000, -1.000000, 32 ]
dtype = [('Px', np.float32),
('Py', np.float32),
('Pz', np.float32),
('temperature', np.float32)]
class SimpleTest(unittest.TestCase):
def test_usage(self):
mesh = osd.Topology(faces)
mesh.boundaryMode = osd.BoundaryMode.EDGE_ONLY
mesh.vertices[0].sharpness = 2.7
self.assertAlmostEqual(mesh.vertices[0].sharpness, 2.7)
self.assertEqual(len(mesh.vertices), len(verts) / len(dtype))
self.assertEqual(len(mesh.faces), len(faces))
self.assertEqual(len(mesh.faces[0].edges), len(faces[0]))
mesh.finalize()
subdivider = osd.Subdivider(
mesh,
vertexLayout = dtype,
indexType = np.uint32,
levels = 4)
subdivider.setCoarseVertices(verts, np.float32)
subdivider.refine()
numQuads = len(subdivider.getRefinedQuads()) / 4
numVerts = len(subdivider.getRefinedVertices()) / len(dtype)
self.assertEqual(numQuads, 1536, "Unexpected number of refined quads")
self.assertEqual(numVerts, 2056, "Unexpected number of refined verts")
# For now, disable the leak test by prepending "do_not_".
def do_not_test_leaks(self):
self.test_usage()
start = _get_heap_usage()
history = []
for i in xrange(1024):
self.test_usage()
if ((i+1) % 256) == 0:
history.append(_get_heap_usage() - start)
print str(history[-1]) + "...",
sys.stdout.flush()
print
total = 0
for i in xrange(1, len(history)):
delta = history[i] - history[i - 1]
if delta <= 0:
return
total = total + delta
avg = total / (len(history) - 1)
self.fail("Memory usage is strictly increasing ({0}).".format(avg))
def test_Topology_creation(self):
# Input data
indices, valences = _flatten(faces)
# Native list-of-lists, constant valence:
mesh = osd.Topology(faces)
self.assert_(mesh,
"Unable to construct Topology object from a list-of-lists")
# Native list, constant valence:
mesh = osd.Topology(indices, 4)
self.assert_(mesh,
"Unable to construct Topology object from a list")
# Native list-of-lists, variable valence:
faces2 = faces + [(8,9,10)]
mesh = osd.Topology(faces2)
self.assert_(mesh,
"Unable to construct Topology object from a list of "
"variable-sized lists")
# Two-dimensional numpy array:
numpyFaces = np.array(indices, 'uint16').reshape(-1, 4)
mesh = osd.Topology(numpyFaces)
self.assert_(mesh,
"Unable to construct Topology object from a "
"two-dimensional numpy array")
# Native index list and valence list:
mesh = osd.Topology(indices, valences)
self.assert_(mesh)
# Numpy index list and valence list:
indices = np.array(indices, 'uint16')
valences = np.array(valences, 'uint8')
mesh = osd.Topology(indices, valences)
self.assert_(mesh)
# Ensure various topology checks
self.assertRaises(osd.OsdTypeError, osd.Topology, indices, None)
self.assertRaises(osd.OsdTypeError, osd.Topology, faces, valences)
faces2 = faces + [(8,9)]
self.assertRaises(osd.TopoError, osd.Topology, faces2)
valences2 = valences + [3]
self.assertRaises(osd.TopoError, osd.Topology, indices, valences2)
def _get_heap_usage():
import resource
return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
def _flatten(faces):
import itertools
flattened = list(itertools.chain(*faces))
lengths = [len(face) for face in faces]
return flattened, lengths
if __name__ == "__main__":
unittest.main()