PyVRML97 2.3.4b3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,181 @@
1
+ """Scenegraph node-like "prototype" for VRML97"""
2
+ from vrml import node, protofunctions, protonamespace, fieldtypes, route
3
+ from vrml import copier as copiermodule
4
+ from vrml.vrml97 import nodetypes
5
+ import weakref
6
+ from .._bytes import unicode
7
+
8
+ class SceneGraph( nodetypes.Traversable, node.Node ):
9
+ ''' A VRML 97 sceneGraph
10
+ Attributes:
11
+ __gi__ -- constant string "sceneGraph"
12
+ DEF -- constant string ""
13
+ children -- Node list
14
+ List of the root children of the sceneGraph, nodes/scripts only
15
+ routes -- ROUTE list
16
+ List of the routes within the sceneGraph
17
+ defNames -- string DEFName: Node node
18
+ Mapping of DEF names to their respective nodes
19
+ protoTypes -- Namespace prototypes
20
+ Namespace (with chaining lookup) collection of prototypes
21
+ getattr( sceneGraph.protoTypes, 'nodeGI' ) retrieves a prototype
22
+ '''
23
+ PROTO = "sceneGraph"
24
+ children = node.MFNode( 'children',)
25
+ routes = route.MFRoute(
26
+ 'routes',
27
+ )
28
+ baseURI = fieldtypes.SFString(
29
+ 'baseURI',
30
+ 1,
31
+ "",
32
+ )
33
+ def __init__(
34
+ self, root=None, protoTypes=None,
35
+ routes=None, defNames=None,
36
+ children=None,
37
+ *args, **namedargs
38
+ ):
39
+ '''
40
+ root -- sceneGraph root or Dictionary root or Module root or None
41
+ Base object for root of protoType namespace hierarchy
42
+ protoTypes -- string nodeGI: Prototype PROTO
43
+ Dictionary of prototype definitions
44
+ routes -- ROUTE list or (string sourcenode, string sourceeventOut, string destinationnode, string destinationeventOut) list
45
+ List of route objects or tuples to be added to the sceneGraph
46
+ see attribute routes
47
+ defNames -- string DEFName: Node node
48
+ see attribute defNames
49
+ children -- Node list
50
+ see attribute children
51
+ '''
52
+ if root is not None:
53
+ self.root = weakref.ref( root )
54
+ else:
55
+ self.root = None
56
+ if protoTypes is None:
57
+ protoTypes = protonamespace.ProtoNamespace()
58
+ self.protoTypes = protoTypes
59
+ if defNames is None:
60
+ defNames = {}
61
+ self.defNames = defNames
62
+ namedargs['children'] = children
63
+ super( SceneGraph, self ).__init__(
64
+ *args,
65
+ **namedargs
66
+ )
67
+ node.Node.rootSceneGraph.fset( self, self )
68
+ if routes:
69
+ for route in routes:
70
+ self.addRoute( route )
71
+ def getProto( self, name ):
72
+ """Get a prototype by name
73
+
74
+ go up the scenegraph chain to try to resolve
75
+ """
76
+ current = self.protoTypes.get( name )
77
+ if current is not None:
78
+ return current
79
+ elif hasattr( self, 'root'):
80
+ root = self.root
81
+ if root:
82
+ root = root()
83
+ if root:
84
+ return root.getProto( name )
85
+ return None
86
+
87
+ def getDEF( self, name ):
88
+ """Get a node by DEF name"""
89
+ return self.defNames.get(name)
90
+
91
+ def regDefName(self, defName, object):
92
+ ''' Register a DEF name for a particular object
93
+
94
+ defName -- string DEFName
95
+ object -- Node node
96
+
97
+ Eliminates previous references to the object by
98
+ its current DEFName and sets the object's new
99
+ DEFName.
100
+ '''
101
+ current = protofunctions.defName( object )
102
+ if self.defNames.get(current) is object:
103
+ del self.defNames[current]
104
+ protofunctions.defName( object, defName )
105
+ self.defNames[defName] = object
106
+ def addProto(self, proto):
107
+ '''Register a Prototype for this sceneGraph
108
+ proto -- Prototype PROTO
109
+ '''
110
+ self.protoTypes[protofunctions.name( proto ) ] = proto
111
+ def addRoute(self, route, *args):
112
+ '''Add a route to the scenegraph
113
+
114
+ route,args -- Possible forms:
115
+
116
+ ROUTE object -- added to routes
117
+ ((source)node,field,(destination)node,field) -- ROUTE
118
+ created, nodes may be strings, in which case
119
+ getDEF( node ) is called for each
120
+ ((source)node,field,target( signal, sender, value )) --
121
+ field.watch( target ) is called for the source
122
+ node (which can be a DEF name).
123
+ '''
124
+ if args:
125
+ route = (route,) + args
126
+ if isinstance( route, (tuple,list)):
127
+ if len(route) == 4:
128
+ # 4-element route definition, e.g. from strings...
129
+ from vrml.route import ROUTE
130
+ source,sourceField,destination,destinationField = route
131
+ if isinstance( source, (str,unicode)):
132
+ source = self.getDEF( source )
133
+ if isinstance( destination, (str,unicode)):
134
+ destination = self.getDEF( destination )
135
+ route = ROUTE(
136
+ source = source,
137
+ sourceField = sourceField,
138
+ destination = destination,
139
+ destinationField = destinationField,
140
+ )
141
+ elif len(route) == 3:
142
+ # 2-element source plus a function to receive...
143
+ source,sourceField,target = route
144
+ if not callable( target ):
145
+ raise TypeError(
146
+ """Need a callable target object!"""
147
+ )
148
+ if isinstance( source, (str,unicode)):
149
+ source = self.getDEF( source )
150
+ field = protofunctions.getField( source, sourceField )
151
+ field.watch( source, target, ('set',field) )
152
+ field.watch( source, target, ('del',field) )
153
+ self.routes.append( route )
154
+ return route
155
+ ## def addIsMap( self, name, node, field ):
156
+ ## """Add an isMap for the given name to the given node+field"""
157
+ ## self.isMaps.setdefault( name, []).append( (node,field) )
158
+
159
+ def copy( self, copier=None ):
160
+ """Copy this node for copier"""
161
+ if copier is None:
162
+ copier = copiermodule.Copier()
163
+ # order for creation is going to be important to make sure
164
+ # that prototypes are available to nodes getting re-built
165
+ # if we aren't sharing protos...
166
+ if not copier.shareProtos:
167
+ newPrototypes = protonamespace.ProtoNamespace()
168
+ for key,value in self.protoTypes.items():
169
+ newPrototypes[key] = protofunctions.copyProto( value, copier )
170
+ else:
171
+ newPrototypes = self.protoTypes.copy()
172
+ newDefs = {}
173
+ for key,value in self.defNames.items():
174
+ if (not key) or value is None:
175
+ continue
176
+ newDefs[key] = value.copy( copier )
177
+ node = super( SceneGraph, self).copy( copier )
178
+ node.protoTypes = newPrototypes
179
+ node.defNames = newDefs
180
+ return node
181
+
vrml/vrml97/script.py ADDED
@@ -0,0 +1,25 @@
1
+ """VRML97 Script-node stub"""
2
+ from vrml import node, fieldtypes
3
+ from vrml.vrml97 import nodetypes
4
+
5
+ class _Script( nodetypes.Children, node.Node ):
6
+ """A sub-type of node with scripting/pseudo-proto support
7
+
8
+ The class here just handles basic node-like functionality,
9
+ a special constructor factory takes care of the PROTO-like
10
+ functionality.
11
+ """
12
+ url = fieldtypes.MFString(
13
+ 'url', 1,
14
+ )
15
+ directOutput = fieldtypes.SFBool(
16
+ 'directOutput', default = 0,
17
+ )
18
+ mustEvaluate = fieldtypes.SFBool(
19
+ 'mustEvaluate', default = 0,
20
+ )
21
+
22
+ def Script( fields, **namedarguments ):
23
+ """Create a new script prototype and an instance of that prototype"""
24
+ proto = node.prototype( 'Script', fields, baseClasses = (_Script,) )
25
+ return proto( **namedarguments )
vrml/vrml97/shaders.py ADDED
@@ -0,0 +1,123 @@
1
+ """Node definitions for a non-standard Programable Shaders extension
2
+ """
3
+ from vrml.vrml97 import nodetypes
4
+ from vrml import field, node, fieldtypes
5
+
6
+ class ShaderGeometry( nodetypes.Children, nodetypes.Rendering, node.Node ):
7
+ """Generic geometry definition for a shader-based renderer
8
+
9
+ attributes -- define the attribute pointers which feed the
10
+ shader, the individual attributes may share a buffer or
11
+ define one per attribute
12
+ indices -- if present, node defining index array to be used
13
+ to index into buffers, will be uploaded to an element
14
+ buffer
15
+ uniforms -- Uniform nodes which are bound/updated on the
16
+ shader before rendering this geometry, binds to the
17
+ shader's location == to the uniform's name.
18
+ slices -- slices of the array to render, if not specified
19
+ then we'll render the whole data-set
20
+ """
21
+ PROTO = "ShaderGeometry"
22
+ indices = field.newField( 'indices', 'MFInt32', 1, list )
23
+ attributes = field.newField( 'attributes','MFNode',1,list )
24
+ slices = field.newField( 'slices', 'MFNode',1,list )
25
+ uniforms = field.newField( 'uniforms','MFNode',1,list )
26
+ appearance = field.newField( 'appearance', 'SFNode',1,list )
27
+
28
+ class ShaderSlice( node.Node ):
29
+ """Segment of a shader geometry element to render"""
30
+ offset = field.newField( 'offset', 'SFUInt32',1, -1 )
31
+ count = field.newField( 'count', 'SFUInt32',1, -1 )
32
+ uniforms = field.newField( 'uniforms','MFNode',1,list)
33
+
34
+ class ShaderAttribute( node.Node ):
35
+ """Attribute (variable) binding for a shader
36
+ """
37
+ name = field.newField( 'name', 'SFString', 1, '' )
38
+ offset = field.newField( 'offset','SFUInt32',1, 0 )
39
+ stride = field.newField( 'stride', 'SFUInt32',1, 0 ) # default to buffer natural stride
40
+ size = field.newField( 'size','SFUInt32',1,3 ) # default num of elements
41
+ dataType = field.newField( 'dataType','SFString', 1, 'FLOAT' )
42
+ # the buffer into which we index...
43
+ buffer = field.newField( 'buffer','SFNode',1,node.NULL )
44
+ isCoord = field.newField( 'isCoord','SFBool',1,False)
45
+ bufferKey = field.newField( 'bufferKey', 'SFString', 1,'')
46
+
47
+ class ShaderBuffer( node.Node ):
48
+ """Buffer of data into which pointers can be generated"""
49
+ type = field.newField( 'type','SFString', 1, 'ARRAY' )
50
+ usage = field.newField( 'usage','SFString', 1, 'DYNAMIC_DRAW' )
51
+ buffer = field.newField( 'buffer','SFArray32', 1, list )
52
+ class ShaderIndexBuffer( ShaderBuffer ):
53
+ """Buffer of data from which indices are generated"""
54
+ type = field.newField( 'type','SFString', 1, 'ELEMENT' )
55
+ usage = field.newField( 'usage','SFString', 1, 'DYNAMIC_DRAW' )
56
+ buffer = field.newField( 'buffer','MFUInt32', 1, list )
57
+
58
+ class FloatUniform( node.Node ):
59
+ """Uniform (variable) binding for a shader
60
+
61
+ The FloatUniform is the base class for FloatUniforms,
62
+ that is, there are FloatUniform1f, FloatUniform2f,
63
+ FloatUniformm3x2, etceteras Node-types, but not a
64
+ FloatUniform node-type.
65
+ """
66
+ name = field.newField( 'name', 'SFString', 1, '' )
67
+ # type values, 1f, 2f, 3f, 4f, m2, m3, m4, m2x3,m3x2,m2x4,m4x2,m3x4,m4x3
68
+ value = field.newField( 'value', 'SFArray32', 1, list )
69
+
70
+ class IntUniform( node.Node ):
71
+ """Uniform (variable) binding for a shader (integer form)
72
+ """
73
+ PROTO = "IntUniform"
74
+ name = field.newField( 'name', 'SFString', 1, '' )
75
+ # type values, 1i,2i,3i,4i
76
+ value = field.newField( 'value', 'MFInt32', 1, list )
77
+
78
+ class TextureUniform( node.Node ):
79
+ """Uniform which specifies a texture sampler"""
80
+ PROTO = 'TextureUniform'
81
+ name = field.newField( 'name','SFString', 1, '' )
82
+ value = field.newField( 'value', 'SFNode', 1, node.NULL )
83
+ class TextureBufferUniform( node.Node ):
84
+ """Uniform which specifies a texture across vbo data"""
85
+ PROTO = 'TextureBufferUniform'
86
+ name = field.newField( 'name','SFString', 1, '' )
87
+ value = field.newField( 'value', 'SFNode', 1, node.NULL )
88
+ format = field.newField( 'format', 'SFString',1,'RGBA32F' )
89
+
90
+ class GLSLShader( node.Node ):
91
+ """GLSL-based shader node"""
92
+ PROTO = "GLSLShader"
93
+ url = field.newField( 'url', 'MFString', 1, list)
94
+ source = field.newField( 'source','MFString',1, list)
95
+ imports = field.newField( 'imports', 'MFNode', 1, list )
96
+ # type values, VERTEX or FRAGMENT
97
+ type = field.newField( 'type', 'SFString', 1, 'VERTEX' )
98
+
99
+ class GLSLImport( node.Node ):
100
+ """GLSL-base shader source-code import"""
101
+ PROTO = "GLSLImport"
102
+ url = field.newField( 'url', 'MFString', 1, list)
103
+ source = field.newField( 'source','MFString',1, list)
104
+
105
+ class GLSLObject( node.Node ):
106
+ """GLSL-based shader object (compiled set of shaders)"""
107
+ PROTO = "GLSLObject"
108
+ # role values, VISIBLE, DEPTH, SELECT
109
+ role = field.newField( 'role', 'SFString', 1, 'VISIBLE' )
110
+ uniforms = field.newField( 'uniforms', 'MFNode', 1, list )
111
+ shaders = field.newField( 'shaders', 'MFNode', 1, list )
112
+ # textures is a set of texture uniforms...
113
+ textures = field.newField( 'textures', 'MFNode', 1, list )
114
+
115
+ class Shader( node.Node ):
116
+ """Shader is a programmable substitute for an Appearance node"""
117
+ PROTO = 'Shader'
118
+ #Fields
119
+ material = field.newField( 'material', 'SFNode', 1, node.NULL)
120
+ objects = field.newField( 'objects', 'MFNode', 1, list )
121
+
122
+ implementation = field.newField( 'implementation','SFNode',1,node.NULL)
123
+
@@ -0,0 +1,193 @@
1
+ """Utility module for creating transformation matrices
2
+
3
+ Basically this gives you the ability to construct
4
+ transformation matrices without needing OpenGL
5
+ or similar run-time engines. The result is that
6
+ design-time utilities can process files without
7
+ trading dependencies on a particular run-time.
8
+
9
+ This code is originally from the mcf.vrml processing
10
+ engine, and has only been cosmetically altered to
11
+ fit the new organizational pattern.
12
+
13
+ Note: to apply these matrices to a particular coordinate,
14
+ you would do the following:
15
+
16
+ p = ones( 4 )
17
+ p[:3] = coordinate
18
+ return dot( p, matrix)
19
+
20
+ That is, you use the homogenous coordinate, and
21
+ make it the first item in the dot'ing.
22
+ """
23
+ from math import *
24
+ from vrml.arrays import *
25
+ try:
26
+ from vrml.vrml97._transformmatrix_accel import (
27
+ rotMatrix,
28
+ scaleMatrix,
29
+ transMatrix,
30
+ perspectiveMatrix,
31
+ orthoMatrix,
32
+ )
33
+ except ImportError:
34
+ from vrml.vrml97._transformmatrix import (
35
+ rotMatrix,
36
+ scaleMatrix,
37
+ transMatrix,
38
+ perspectiveMatrix,
39
+ orthoMatrix,
40
+ )
41
+
42
+ assert perspectiveMatrix
43
+ assert orthoMatrix
44
+
45
+ # used to determine whether angles are non-null
46
+ TWOPI = pi * 2.0
47
+ RADTODEG = 360./TWOPI
48
+ DEGTORAD = TWOPI/360.
49
+ # used to determine the center point of a transform
50
+ ORIGINPOINT = array([0,0,0,1],'f')
51
+ VERY_SMALL = 1e-300
52
+
53
+ def transformMatrix(
54
+ translation = (0,0,0),
55
+ center = (0,0,0),
56
+ rotation = (0,1,0,0),
57
+ scale = (1,1,1),
58
+ scaleOrientation = (0,1,0,0),
59
+ parentMatrix = None,
60
+ ):
61
+ """Convert VRML transform values to an overall matrix
62
+
63
+ Returns 4x4 transformation matrix
64
+ Note that this uses VRML standard for rotations
65
+ (angle last, and in radians).
66
+
67
+ This should return matrices which, when applied to
68
+ local-space coordinates, give you parent-space
69
+ coordinates.
70
+
71
+ parentMatrix if provided, should be the parent's
72
+ transformation matrix, a 4x4 matrix of such as
73
+ returned by this function.
74
+ """
75
+ T,T1 = transMatrix( translation )
76
+ C,C1 = transMatrix( center )
77
+ R,R1 = rotMatrix( rotation )
78
+ SO,SO1 = rotMatrix( scaleOrientation )
79
+ S,S1 = scaleMatrix( scale )
80
+ return compressMatrices( parentMatrix, T,C,R,SO,S,SO1,C1 )
81
+
82
+ def itransformMatrix(
83
+ translation = (0,0,0),
84
+ center = (0,0,0),
85
+ rotation = (0,1,0,0),
86
+ scale = (1,1,1),
87
+ scaleOrientation = (0,1,0,0),
88
+ parentMatrix = None,
89
+ ):
90
+ """Convert VRML transform values to an inverse transform matrix
91
+
92
+ Returns 4x4 transformation matrix
93
+ Note that this uses VRML standard for rotations
94
+ (angle last, and in radians).
95
+
96
+ This should return matrices which, when applied to
97
+ parent-space coordinates, give you local-space
98
+ coordinates for the corresponding transform.
99
+
100
+ Note: this is a substantially un-tested algorithm
101
+ though it seems to be properly constructed as far
102
+ as I can see. Whether to use dot(x, parentMatrix)
103
+ or the reverse is not immediately clear to me.
104
+
105
+ parentMatrix if provided, should be the child's
106
+ transformation matrix, a 4x4 matrix of such as
107
+ returned by this function.
108
+ """
109
+ T,T1 = transMatrix( translation )
110
+ C,C1 = transMatrix( center )
111
+ R,R1 = rotMatrix( rotation )
112
+ SO,SO1 = rotMatrix( scaleOrientation )
113
+ S,S1 = scaleMatrix( scale )
114
+ return compressMatrices( parentMatrix, C,SO, S1, SO1, R1, C1, T1)
115
+
116
+ def transformMatrices(
117
+ translation = (0,0,0),
118
+ center = (0,0,0),
119
+ rotation = (0,1,0,0),
120
+ scale = (1,1,1),
121
+ scaleOrientation = (0,1,0,0),
122
+ parentMatrix = None,
123
+ ):
124
+ """Calculate both forward and backward matrices for these parameters"""
125
+ T,T1 = transMatrix( translation )
126
+ C,C1 = transMatrix( center )
127
+ R,R1 = rotMatrix( rotation )
128
+ SO,SO1 = rotMatrix( scaleOrientation )
129
+ S,S1 = scaleMatrix( scale )
130
+ return (
131
+ compressMatrices( parentMatrix, T,C,R,SO,S,SO1,C1 ),
132
+ compressMatrices( parentMatrix, C,SO, S1, SO1, R1, C1, T1)
133
+ )
134
+
135
+ def localMatrices(
136
+ translation = (0,0,0),
137
+ center = (0,0,0),
138
+ rotation = (0,1,0,0),
139
+ scale = (1,1,1),
140
+ scaleOrientation = (0,1,0,0),
141
+ parentMatrix = None,
142
+ ):
143
+ """Calculate (forward,inverse) matrices for this transform element"""
144
+ T,T1 = transMatrix( translation )
145
+ C,C1 = transMatrix( center )
146
+ R,R1 = rotMatrix( rotation )
147
+ SO,SO1 = rotMatrix( scaleOrientation )
148
+ S,S1 = scaleMatrix( scale )
149
+ return (
150
+ compressMatrices( T,C,R,SO,S,SO1,C1 ),
151
+ compressMatrices( C,SO, S1, SO1, R1, C1, T1)
152
+ )
153
+
154
+ def compressMatrices( *matrices ):
155
+ """Compress a set of matrices
156
+
157
+ Any (or all) of the matrices may be None,
158
+ if *all* are None, then the result will be None,
159
+ otherwise will be the dot product of all of the
160
+ matrices...
161
+ """
162
+ if not matrices:
163
+ return None
164
+ else:
165
+ first = matrices[0]
166
+ matrices = matrices[1:]
167
+ for item in matrices:
168
+ if item is not None:
169
+ if first is None:
170
+ first = item
171
+ else:
172
+ first = dot( item, first )
173
+ return first
174
+
175
+
176
+ def center(
177
+ translation = (0,0,0),
178
+ center = (0,0,0),
179
+ parentMatrix = None,
180
+ ):
181
+ """Determine the center of rotation for a transform node
182
+
183
+ Returns the parent-space coordinate of the
184
+ node's center of rotation.
185
+ """
186
+ if parentMatrix is None:
187
+ parentMatrix = identity(4)
188
+ T,T1 = transMatrix( translation )
189
+ C,C1 = transMatrix( center )
190
+ for x in (T,C):
191
+ if x:
192
+ parentMatrix = dot( x, parentMatrix)
193
+ return dot( ORIGINPOINT, parentMatrix )
vrml/weakkeydictfix.py ADDED
@@ -0,0 +1,36 @@
1
+ """Module providing patched weakkeydictionary operation"""
2
+ import weakref
3
+ ref = weakref.ref
4
+
5
+ class WeakKeyDictionary( weakref.WeakKeyDictionary ):
6
+ """Sub-class to work around error in WeakKeyDictionary implementation
7
+
8
+ Python 2.2.2 and 2.2.3c1 both have an annoying
9
+ problem in their __delitem__ for the
10
+ WeakKeyDictionary class. This class provides
11
+ a work-around for it.
12
+ """
13
+ def __init__(self, dict=None):
14
+ """Initialize the WeakKeyDictionary
15
+
16
+ dict -- previously-existing weak key records or
17
+ None to create a new dictionary
18
+ """
19
+ self.data = {}
20
+ def remove(k, selfref=ref(self)):
21
+ self = selfref()
22
+ if self is not None and self.data:
23
+ try:
24
+ v = self.data.get( k )
25
+ del self.data[k]
26
+ except (KeyError,RuntimeError):
27
+ pass
28
+ # now v goes out of scope and is deleted...
29
+ self._remove = remove
30
+ if dict is not None: self.update(dict)
31
+ def __delitem__(self, key):
32
+ """Overridden delitem to avoid scanning"""
33
+ try:
34
+ del self.data[weakref.ref(key)]
35
+ except KeyError:
36
+ raise KeyError( """Item %r does not appear as a key"""%( key,))