Merged changes in the trunk up to revision 26260.

This commit is contained in:
Tamito Kajiyama
2010-01-25 21:06:08 +00:00
345 changed files with 33456 additions and 21350 deletions

View File

@@ -0,0 +1,1779 @@
# Blender.BGL module (OpenGL wrapper)
"""
The Blender.BGL submodule (the OpenGL wrapper).
B{New}: some GLU functions: L{gluLookAt}, etc.
The Blender.BGL submodule
=========================
(when accessing it from the Game Engine use BGL instead of Blender.BGL)
This module wraps OpenGL constants and functions, making them available from
within Blender Python.
The complete list can be retrieved from the module itself, by listing its
contents: dir(Blender.BGL). A simple search on the net can point to more
than enough material to teach OpenGL programming, from books to many
collections of tutorials.
The "red book": "I{OpenGL Programming Guide: The Official Guide to Learning
OpenGL}" and the online NeHe tutorials are two of the best resources.
Example::
import Blender
from Blender.BGL import *
from Blender import Draw
R = G = B = 0
A = 1
title = "Testing BGL + Draw"
instructions = "Use mouse buttons or wheel to change the background color."
quitting = " Press ESC or q to quit."
len1 = Draw.GetStringWidth(title)
len2 = Draw.GetStringWidth(instructions + quitting)
#
def show_win():
glClearColor(R,G,B,A) # define color used to clear buffers
glClear(GL_COLOR_BUFFER_BIT) # use it to clear the color buffer
glColor3f(0.35,0.18,0.92) # define default color
glBegin(GL_POLYGON) # begin a vertex data list
glVertex2i(165, 158)
glVertex2i(252, 55)
glVertex2i(104, 128)
glEnd()
glColor3f(0.4,0.4,0.4) # change default color
glRecti(40, 96, 60+len1, 113)
glColor3f(1,1,1)
glRasterPos2i(50,100) # move cursor to x = 50, y = 100
Draw.Text(title) # draw this text there
glRasterPos2i(350,40) # move cursor again
Draw.Text(instructions + quitting) # draw another msg
glBegin(GL_LINE_LOOP) # begin a vertex-data list
glVertex2i(46,92)
glVertex2i(120,92)
glVertex2i(120,115)
glVertex2i(46,115)
glEnd() # close this list
#
def ev(evt, val): # event callback for Draw.Register()
global R,G,B,A # ... it handles input events
if evt == Draw.ESCKEY or evt == Draw.QKEY:
Draw.Exit() # this quits the script
elif not val: return
elif evt == Draw.LEFTMOUSE: R = 1 - R
elif evt == Draw.MIDDLEMOUSE: G = 1 - G
elif evt == Draw.RIGHTMOUSE: B = 1 - B
elif evt == Draw.WHEELUPMOUSE:
R += 0.1
if R > 1: R = 1
elif evt == Draw.WHEELDOWNMOUSE:
R -= 0.1
if R < 0: R = 0
else:
return # don't redraw if nothing changed
Draw.Redraw(1) # make changes visible.
#
Draw.Register(show_win, ev, None) # start the main loop
@note: you can use the L{Image} module and L{Image.Image} BPy object to load
and set textures. See L{Image.Image.glLoad} and L{Image.Image.glFree},
for example.
@see: U{www.opengl.org}
@see: U{nehe.gamedev.net}
"""
def glAccum(op, value):
"""
Operate on the accumulation buffer
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/accum.html}
@type op: Enumerated constant
@param op: The accumulation buffer operation.
@type value: float
@param value: a value used in the accumulation buffer operation.
"""
def glAlphaFunc(func, ref):
"""
Specify the alpha test function
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/alphafunc.html}
@type func: Enumerated constant
@param func: Specifies the alpha comparison function.
@type ref: float
@param ref: The reference value that incoming alpha values are compared to.
Clamped between 0 and 1.
"""
def glAreTexturesResident(n, textures, residences):
"""
Determine if textures are loaded in texture memory
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/aretexturesresident.html}
@type n: int
@param n: Specifies the number of textures to be queried.
@type textures: Buffer object I{type GL_INT}
@param textures: Specifies an array containing the names of the textures to be queried
@type residences: Buffer object I{type GL_INT}(boolean)
@param residences: An array in which the texture residence status in returned.The residence status of a
texture named by an element of textures is returned in the corresponding element of residences.
"""
def glBegin(mode):
"""
Delimit the vertices of a primitive or a group of like primatives
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/begin.html}
@type mode: Enumerated constant
@param mode: Specifies the primitive that will be create from vertices between glBegin and
glEnd.
"""
def glBindTexture(target, texture):
"""
Bind a named texture to a texturing target
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/bindtexture.html}
@type target: Enumerated constant
@param target: Specifies the target to which the texture is bound.
@type texture: unsigned int
@param texture: Specifies the name of a texture.
"""
def glBitmap(width, height, xorig, yorig, xmove, ymove, bitmap):
"""
Draw a bitmap
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/bitmap.html}
@type width, height: int
@param width, height: Specify the pixel width and height of the bitmap image.
@type xorig, yorig: float
@param xorig, yorig: Specify the location of the origin in the bitmap image. The origin is measured
from the lower left corner of the bitmap, with right and up being the positive axes.
@type xmove, ymove: float
@param xmove, ymove: Specify the x and y offsets to be added to the current raster position after
the bitmap is drawn.
@type bitmap: Buffer object I{type GL_BYTE}
@param bitmap: Specifies the address of the bitmap image.
"""
def glBlendFunc(sfactor, dfactor):
"""
Specify pixel arithmetic
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/blendfunc.html}
@type sfactor: Enumerated constant
@param sfactor: Specifies how the red, green, blue, and alpha source blending factors are
computed.
@type dfactor: Enumerated constant
@param dfactor: Specifies how the red, green, blue, and alpha destination blending factors are
computed.
"""
def glCallList(list):
"""
Execute a display list
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/calllist.html}
@type list: unsigned int
@param list: Specifies the integer name of the display list to be executed.
"""
def glCallLists(n, type, lists):
"""
Execute a list of display lists
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/calllists.html}
@type n: int
@param n: Specifies the number of display lists to be executed.
@type type: Enumerated constant
@param type: Specifies the type of values in lists.
@type lists: Buffer object
@param lists: Specifies the address of an array of name offsets in the display list.
The pointer type is void because the offsets can be bytes, shorts, ints, or floats,
depending on the value of type.
"""
def glClear(mask):
"""
Clear buffers to preset values
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clear.html}
@type mask: Enumerated constant(s)
@param mask: Bitwise OR of masks that indicate the buffers to be cleared.
"""
def glClearAccum(red, green, blue, alpha):
"""
Specify clear values for the accumulation buffer
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clearaccum.html}
@type red, green, blue, alpha: float
@param red, green, blue, alpha: Specify the red, green, blue, and alpha values used when the
accumulation buffer is cleared. The initial values are all 0.
"""
def glClearColor(red, green, blue, alpha):
"""
Specify clear values for the color buffers
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clearcolor.html}
@type red, green, blue, alpha: float
@param red, green, blue, alpha: Specify the red, green, blue, and alpha values used when the
color buffers are cleared. The initial values are all 0.
"""
def glClearDepth(depth):
"""
Specify the clear value for the depth buffer
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/cleardepth.html}
@type depth: int
@param depth: Specifies the depth value used when the depth buffer is cleared.
The initial value is 1.
"""
def glClearIndex(c):
"""
Specify the clear value for the color index buffers
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clearindex.html}
@type c: float
@param c: Specifies the index used when the color index buffers are cleared.
The initial value is 0.
"""
def glClearStencil(s):
"""
Specify the clear value for the stencil buffer
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clearstencil.html}
@type s: int
@param s: Specifies the index used when the stencil buffer is cleared. The initial value is 0.
"""
def glClipPlane (plane, equation):
"""
Specify a plane against which all geometry is clipped
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clipplane.html}
@type plane: Enumerated constant
@param plane: Specifies which clipping plane is being positioned.
@type equation: Buffer object I{type GL_FLOAT}(double)
@param equation: Specifies the address of an array of four double- precision floating-point
values. These values are interpreted as a plane equation.
"""
def glColor (red, green, blue, alpha):
"""
B{glColor3b, glColor3d, glColor3f, glColor3i, glColor3s, glColor3ub, glColor3ui, glColor3us,
glColor4b, glColor4d, glColor4f, glColor4i, glColor4s, glColor4ub, glColor4ui, glColor4us,
glColor3bv, glColor3dv, glColor3fv, glColor3iv, glColor3sv, glColor3ubv, glColor3uiv,
glColor3usv, glColor4bv, glColor4dv, glColor4fv, glColor4iv, glColor4sv, glColor4ubv,
glColor4uiv, glColor4usv}
Set a new color.
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/color.html}
@type red, green, blue, alpha: Depends on function prototype.
@param red, green, blue: Specify new red, green, and blue values for the current color.
@param alpha: Specifies a new alpha value for the current color. Included only in the
four-argument glColor4 commands. (With '4' colors only)
"""
def glColorMask(red, green, blue, alpha):
"""
Enable and disable writing of frame buffer color components
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/colormask.html}
@type red, green, blue, alpha: int (boolean)
@param red, green, blue, alpha: Specify whether red, green, blue, and alpha can or cannot be
written into the frame buffer. The initial values are all GL_TRUE, indicating that the
color components can be written.
"""
def glColorMaterial(face, mode):
"""
Cause a material color to track the current color
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/colormaterial.html}
@type face: Enumerated constant
@param face: Specifies whether front, back, or both front and back material parameters should
track the current color.
@type mode: Enumerated constant
@param mode: Specifies which of several material parameters track the current color.
"""
def glCopyPixels(x, y, width, height, type):
"""
Copy pixels in the frame buffer
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/copypixels.html}
@type x, y: int
@param x, y: Specify the window coordinates of the lower left corner of the rectangular
region of pixels to be copied.
@type width, height: int
@param width,height: Specify the dimensions of the rectangular region of pixels to be copied.
Both must be non-negative.
@type type: Enumerated constant
@param type: Specifies whether color values, depth values, or stencil values are to be copied.
"""
def glCullFace(mode):
"""
Specify whether front- or back-facing facets can be culled
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/cullface.html}
@type mode: Enumerated constant
@param mode: Specifies whether front- or back-facing facets are candidates for culling.
"""
def glDeleteLists(list, range):
"""
Delete a contiguous group of display lists
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/deletelists.html}
@type list: unsigned int
@param list: Specifies the integer name of the first display list to delete
@type range: int
@param range: Specifies the number of display lists to delete
"""
def glDeleteTextures(n, textures):
"""
Delete named textures
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/deletetextures.html}
@type n: int
@param n: Specifies the number of textures to be deleted
@type textures: Buffer I{GL_INT}
@param textures: Specifies an array of textures to be deleted
"""
def glDepthFunc(func):
"""
Specify the value used for depth buffer comparisons
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/depthfunc.html}
@type func: Enumerated constant
@param func: Specifies the depth comparison function.
"""
def glDepthMask(flag):
"""
Enable or disable writing into the depth buffer
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/depthmask.html}
@type flag: int (boolean)
@param flag: Specifies whether the depth buffer is enabled for writing. If flag is GL_FALSE,
depth buffer writing is disabled. Otherwise, it is enabled. Initially, depth buffer
writing is enabled.
"""
def glDepthRange(zNear, zFar):
"""
Specify mapping of depth values from normalized device coordinates to window coordinates
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/depthrange.html}
@type zNear: int
@param zNear: Specifies the mapping of the near clipping plane to window coordinates.
The initial value is 0.
@type zFar: int
@param zFar: Specifies the mapping of the far clipping plane to window coordinates.
The initial value is 1.
"""
def glDisable(cap):
"""
Disable server-side GL capabilities
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/enable.html}
@type cap: Enumerated constant
@param cap: Specifies a symbolic constant indicating a GL capability.
"""
def glDrawBuffer(mode):
"""
Specify which color buffers are to be drawn into
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/drawbuffer.html}
@type mode: Enumerated constant
@param mode: Specifies up to four color buffers to be drawn into.
"""
def glDrawPixels(width, height, format, type, pixels):
"""
Write a block of pixels to the frame buffer
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/drawpixels.html}
@type width, height: int
@param width, height: Specify the dimensions of the pixel rectangle to be
written into the frame buffer.
@type format: Enumerated constant
@param format: Specifies the format of the pixel data.
@type type: Enumerated constant
@param type: Specifies the data type for pixels.
@type pixels: Buffer object
@param pixels: Specifies a pointer to the pixel data.
"""
def glEdgeFlag (flag):
"""
B{glEdgeFlag, glEdgeFlagv}
Flag edges as either boundary or non-boundary
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/edgeflag.html}
@type flag: Depends of function prototype
@param flag: Specifies the current edge flag value.The initial value is GL_TRUE.
"""
def glEnable(cap):
"""
Enable server-side GL capabilities
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/enable.html}
@type cap: Enumerated constant
@param cap: Specifies a symbolic constant indicating a GL capability.
"""
def glEnd():
"""
Delimit the vertices of a primitive or group of like primitives
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/begin.html}
"""
def glEndList():
"""
Create or replace a display list
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/newlist.html}
"""
def glEvalCoord (u,v):
"""
B{glEvalCoord1d, glEvalCoord1f, glEvalCoord2d, glEvalCoord2f, glEvalCoord1dv, glEvalCoord1fv,
glEvalCoord2dv, glEvalCoord2fv}
Evaluate enabled one- and two-dimensional maps
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/evalcoord.html}
@type u: Depends on function prototype.
@param u: Specifies a value that is the domain coordinate u to the basis function defined
in a previous glMap1 or glMap2 command. If the function prototype ends in 'v' then
u specifies a pointer to an array containing either one or two domain coordinates. The first
coordinate is u. The second coordinate is v, which is present only in glEvalCoord2 versions.
@type v: Depends on function prototype. (only with '2' prototypes)
@param v: Specifies a value that is the domain coordinate v to the basis function defined
in a previous glMap2 command. This argument is not present in a glEvalCoord1 command.
"""
def glEvalMesh (mode, i1, i2):
"""
B{glEvalMesh1 or glEvalMesh2}
Compute a one- or two-dimensional grid of points or lines
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/evalmesh.html}
@type mode: Enumerated constant
@param mode: In glEvalMesh1, specifies whether to compute a one-dimensional
mesh of points or lines.
@type i1, i2: int
@param i1, i2: Specify the first and last integer values for the grid domain variable i.
"""
def glEvalPoint (i, j):
"""
B{glEvalPoint1 and glEvalPoint2}
Generate and evaluate a single point in a mesh
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/evalpoint.html}
@type i: int
@param i: Specifies the integer value for grid domain variable i.
@type j: int (only with '2' prototypes)
@param j: Specifies the integer value for grid domain variable j (glEvalPoint2 only).
"""
def glFeedbackBuffer (size, type, buffer):
"""
Controls feedback mode
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/feedbackbuffer.html}
@type size: int
@param size:Specifies the maximum number of values that can be written into buffer.
@type type: Enumerated constant
@param type:Specifies a symbolic constant that describes the information that
will be returned for each vertex.
@type buffer: Buffer object I{GL_FLOAT}
@param buffer: Returns the feedback data.
"""
def glFinish():
"""
Block until all GL execution is complete
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/finish.html}
"""
def glFlush():
"""
Force Execution of GL commands in finite time
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/flush.html}
"""
def glFog (pname, param):
"""
B{glFogf, glFogi, glFogfv, glFogiv}
Specify fog parameters
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/fog.html}
@type pname: Enumerated constant
@param pname: Specifies a single-valued fog parameter. If the function prototype
ends in 'v' specifies a fog parameter.
@type param: Depends on function prototype.
@param param: Specifies the value or values to be assigned to pname. GL_FOG_COLOR
requires an array of four values. All other parameters accept an array containing
only a single value.
"""
def glFrontFace(mode):
"""
Define front- and back-facing polygons
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/frontface.html}
@type mode: Enumerated constant
@param mode: Specifies the orientation of front-facing polygons.
"""
def glFrustum(left, right, bottom, top, zNear, zFar):
"""
Multiply the current matrix by a perspective matrix
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/frustum.html}
@type left, right: double (float)
@param left, right: Specify the coordinates for the left and right vertical
clipping planes.
@type top, bottom: double (float)
@param top, bottom: Specify the coordinates for the bottom and top horizontal
clipping planes.
@type zNear, zFar: double (float)
@param zNear, zFar: Specify the distances to the near and far depth clipping planes.
Both distances must be positive.
"""
def glGenLists(range):
"""
Generate a contiguous set of empty display lists
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/genlists.html}
@type range: int
@param range: Specifies the number of contiguous empty display lists to be generated.
"""
def glGenTextures(n, textures):
"""
Generate texture names
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/gentextures.html}
@type n: int
@param n: Specifies the number of textures name to be generated.
@type textures: Buffer object I{type GL_INT}
@param textures: Specifies an array in which the generated textures names are stored.
"""
def glGet (pname, param):
"""
B{glGetBooleanv, glGetfloatv, glGetFloatv, glGetIntegerv}
Return the value or values of a selected parameter
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/get.html}
@type pname: Enumerated constant
@param pname: Specifies the parameter value to be returned.
@type param: Depends on function prototype.
@param param: Returns the value or values of the specified parameter.
"""
def glGetClipPlane(plane, equation):
"""
Return the coefficients of the specified clipping plane
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getclipplane.html}
@type plane: Enumerated constant
@param plane: Specifies a clipping plane. The number of clipping planes depends on the
implementation, but at least six clipping planes are supported. They are identified by
symbolic names of the form GL_CLIP_PLANEi where 0 < i < GL_MAX_CLIP_PLANES.
@type equation: Buffer object I{type GL_FLOAT}
@param equation: Returns four float (double)-precision values that are the coefficients of the
plane equation of plane in eye coordinates. The initial value is (0, 0, 0, 0).
"""
def glGetError():
"""
Return error information
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/geterror.html}
"""
def glGetLight (light, pname, params):
"""
B{glGetLightfv and glGetLightiv}
Return light source parameter values
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getlight.html}
@type light: Enumerated constant
@param light: Specifies a light source. The number of possible lights depends on the
implementation, but at least eight lights are supported. They are identified by symbolic
names of the form GL_LIGHTi where 0 < i < GL_MAX_LIGHTS.
@type pname: Enumerated constant
@param pname: Specifies a light source parameter for light.
@type params: Buffer object. Depends on function prototype.
@param params: Returns the requested data.
"""
def glGetMap (target, query, v):
"""
B{glGetMapdv, glGetMapfv, glGetMapiv}
Return evaluator parameters
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getmap.html}
@type target: Enumerated constant
@param target: Specifies the symbolic name of a map.
@type query: Enumerated constant
@param query: Specifies which parameter to return.
@type v: Buffer object. Depends on function prototype.
@param v: Returns the requested data.
"""
def glGetMaterial (face, pname, params):
"""
B{glGetMaterialfv, glGetMaterialiv}
Return material parameters
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getmaterial.html}
@type face: Enumerated constant
@param face: Specifies which of the two materials is being queried.
representing the front and back materials, respectively.
@type pname: Enumerated constant
@param pname: Specifies the material parameter to return.
@type params: Buffer object. Depends on function prototype.
@param params: Returns the requested data.
"""
def glGetPixelMap (map, values):
"""
B{glGetPixelMapfv, glGetPixelMapuiv, glGetPixelMapusv}
Return the specified pixel map
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getpixelmap.html}
@type map: Enumerated constant
@param map: Specifies the name of the pixel map to return.
@type values: Buffer object. Depends on function prototype.
@param values: Returns the pixel map contents.
"""
def glGetPolygonStipple(mask):
"""
Return the polygon stipple pattern
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getpolygonstipple.html}
@type mask: Buffer object I{type GL_BYTE}
@param mask: Returns the stipple pattern. The initial value is all 1's.
"""
def glGetString(name):
"""
Return a string describing the current GL connection
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getstring.html}
@type name: Enumerated constant
@param name: Specifies a symbolic constant.
"""
def glGetTexEnv (target, pname, params):
"""
B{glGetTexEnvfv, glGetTexEnviv}
Return texture environment parameters
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/gettexenv.html}
@type target: Enumerated constant
@param target: Specifies a texture environment. Must be GL_TEXTURE_ENV.
@type pname: Enumerated constant
@param pname: Specifies the symbolic name of a texture environment parameter.
@type params: Buffer object. Depends on function prototype.
@param params: Returns the requested data.
"""
def glGetTexGen (coord, pname, params):
"""
B{glGetTexGendv, glGetTexGenfv, glGetTexGeniv}
Return texture coordinate generation parameters
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/gettexgen.html}
@type coord: Enumerated constant
@param coord: Specifies a texture coordinate.
@type pname: Enumerated constant
@param pname: Specifies the symbolic name of the value(s) to be returned.
@type params: Buffer object. Depends on function prototype.
@param params: Returns the requested data.
"""
def glGetTexImage(target, level, format, type, pixels):
"""
Return a texture image
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getteximage.html}
@type target: Enumerated constant
@param target: Specifies which texture is to be obtained.
@type level: int
@param level: Specifies the level-of-detail number of the desired image.
Level 0 is the base image level. Level n is the nth mipmap reduction image.
@type format: Enumerated constant
@param format: Specifies a pixel format for the returned data.
@type type: Enumerated constant
@param type: Specifies a pixel type for the returned data.
@type pixels: Buffer object.
@param pixels: Returns the texture image. Should be a pointer to an array of the
type specified by type
"""
def glGetTexLevelParameter (target, level, pname, params):
"""
B{glGetTexLevelParameterfv, glGetTexLevelParameteriv}
return texture parameter values for a specific level of detail
@see: U{opengl.org/developers/documentation/man_pages/hardcopy/GL/html/gl/gettexlevelparameter.html}
@type target: Enumerated constant
@param target: Specifies the symbolic name of the target texture.
@type level: int
@param level: Specifies the level-of-detail number of the desired image.
Level 0 is the base image level. Level n is the nth mipmap reduction image.
@type pname: Enumerated constant
@param pname: Specifies the symbolic name of a texture parameter.
@type params: Buffer object. Depends on function prototype.
@param params: Returns the requested data.
"""
def glGetTexParameter (target, pname, params):
"""
B{glGetTexParameterfv, glGetTexParameteriv}
Return texture parameter values
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/gettexparameter.html}
@type target: Enumerated constant
@param target: Specifies the symbolic name of the target texture.
@type pname: Enumerated constant
@param pname: Specifies the symbolic name the target texture.
@type params: Buffer object. Depends on function prototype.
@param params: Returns the texture parameters.
"""
def glHint(target, mode):
"""
Specify implementation-specific hints
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/hint.html}
@type target: Enumerated constant
@param target: Specifies a symbolic constant indicating the behavior to be
controlled.
@type mode: Enumerated constant
@param mode: Specifies a symbolic constant indicating the desired behavior.
"""
def glIndex (c):
"""
B{glIndexd, glIndexf, glIndexi, glIndexs, glIndexdv, glIndexfv, glIndexiv, glIndexsv}
Set the current color index
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/index_.html}
@type c: Buffer object. Depends on function prototype.
@param c: Specifies a pointer to a one element array that contains the new value for
the current color index.
"""
def glInitNames():
"""
Initialize the name stack
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/initnames.html}
"""
def glIsEnabled(cap):
"""
Test whether a capability is enabled
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/isenabled.html}
@type cap: Enumerated constant
@param cap: Specifies a constant representing a GL capability.
"""
def glIsList(list):
"""
Determine if a name corresponds to a display-list
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/islist.html}
@type list: unsigned int
@param list: Specifies a potential display-list name.
"""
def glIsTexture(texture):
"""
Determine if a name corresponds to a texture
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/istexture.html}
@type texture: unsigned int
@param texture: Specifies a value that may be the name of a texture.
"""
def glLight (light, pname, param):
"""
B{glLightf,glLighti, glLightfv, glLightiv}
Set the light source parameters
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/light.html}
@type light: Enumerated constant
@param light: Specifies a light. The number of lights depends on the implementation,
but at least eight lights are supported. They are identified by symbolic names of the
form GL_LIGHTi where 0 < i < GL_MAX_LIGHTS.
@type pname: Enumerated constant
@param pname: Specifies a single-valued light source parameter for light.
@type param: Depends on function prototype.
@param param: Specifies the value that parameter pname of light source light will be set to.
If function prototype ends in 'v' specifies a pointer to the value or values that
parameter pname of light source light will be set to.
"""
def glLightModel (pname, param):
"""
B{glLightModelf, glLightModeli, glLightModelfv, glLightModeliv}
Set the lighting model parameters
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/lightmodel.html}
@type pname: Enumerated constant
@param pname: Specifies a single-value light model parameter.
@type param: Depends on function prototype.
@param param: Specifies the value that param will be set to. If function prototype ends in 'v'
specifies a pointer to the value or values that param will be set to.
"""
def glLineStipple(factor, pattern):
"""
Specify the line stipple pattern
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/linestipple.html}
@type factor: int
@param factor: Specifies a multiplier for each bit in the line stipple pattern.
If factor is 3, for example, each bit in the pattern is used three times before
the next bit in the pattern is used. factor is clamped to the range [1, 256] and
defaults to 1.
@type pattern: unsigned short int
@param pattern: Specifies a 16-bit integer whose bit pattern determines which fragments
of a line will be drawn when the line is rasterized. Bit zero is used first; the default
pattern is all 1's.
"""
def glLineWidth(width):
"""
Specify the width of rasterized lines.
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/linewidth.html}
@type width: float
@param width: Specifies the width of rasterized lines. The initial value is 1.
"""
def glListBase(base):
"""
Set the display-list base for glCallLists
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/listbase.html}
@type base: unsigned int
@param base: Specifies an integer offset that will be added to glCallLists
offsets to generate display-list names. The initial value is 0.
"""
def glLoadIdentity():
"""
Replace the current matrix with the identity matrix
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/loadidentity.html}
"""
def glLoadMatrix (m):
"""
B{glLoadMatrixd, glLoadMatixf}
Replace the current matrix with the specified matrix
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/loadmatrix.html}
@type m: Buffer object. Depends on function prototype.
@param m: Specifies a pointer to 16 consecutive values, which are used as the elements
of a 4x4 column-major matrix.
"""
def glLoadName(name):
"""
Load a name onto the name stack.
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/loadname.html}
@type name: unsigned int
@param name: Specifies a name that will replace the top value on the name stack.
"""
def glLogicOp(opcode):
"""
Specify a logical pixel operation for color index rendering
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/logicop.html}
@type opcode: Enumerated constant
@param opcode: Specifies a symbolic constant that selects a logical operation.
"""
def glMap1 (target, u1, u2, stride, order, points):
"""
B{glMap1d, glMap1f}
Define a one-dimensional evaluator
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/map1.html}
@type target: Enumerated constant
@param target: Specifies the kind of values that are generated by the evaluator.
@type u1, u2: Depends on function prototype.
@param u1,u2: Specify a linear mapping of u, as presented to glEvalCoord1, to ^, t
he variable that is evaluated by the equations specified by this command.
@type stride: int
@param stride: Specifies the number of floats or float (double)s between the beginning
of one control point and the beginning of the next one in the data structure
referenced in points. This allows control points to be embedded in arbitrary data
structures. The only constraint is that the values for a particular control point must
occupy contiguous memory locations.
@type order: int
@param order: Specifies the number of control points. Must be positive.
@type points: Buffer object. Depends on function prototype.
@param points: Specifies a pointer to the array of control points.
"""
def glMap2 (target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points):
"""
B{glMap2d, glMap2f}
Define a two-dimensional evaluator
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/map2.html}
@type target: Enumerated constant
@param target: Specifies the kind of values that are generated by the evaluator.
@type u1, u2: Depends on function prototype.
@param u1,u2: Specify a linear mapping of u, as presented to glEvalCoord2, to ^, t
he variable that is evaluated by the equations specified by this command. Initially
u1 is 0 and u2 is 1.
@type ustride: int
@param ustride: Specifies the number of floats or float (double)s between the beginning
of control point R and the beginning of control point R ij, where i and j are the u
and v control point indices, respectively. This allows control points to be embedded
in arbitrary data structures. The only constraint is that the values for a particular
control point must occupy contiguous memory locations. The initial value of ustride is 0.
@type uorder: int
@param uorder: Specifies the dimension of the control point array in the u axis.
Must be positive. The initial value is 1.
@type v1, v2: Depends on function prototype.
@param v1, v2: Specify a linear mapping of v, as presented to glEvalCoord2, to ^,
one of the two variables that are evaluated by the equations specified by this command.
Initially, v1 is 0 and v2 is 1.
@type vstride: int
@param vstride: Specifies the number of floats or float (double)s between the beginning of control
point R and the beginning of control point R ij, where i and j are the u and v control
point(indices, respectively. This allows control points to be embedded in arbitrary data
structures. The only constraint is that the values for a particular control point must
occupy contiguous memory locations. The initial value of vstride is 0.
@type vorder: int
@param vorder: Specifies the dimension of the control point array in the v axis.
Must be positive. The initial value is 1.
@type points: Buffer object. Depends on function prototype.
@param points: Specifies a pointer to the array of control points.
"""
def glMapGrid (un, u1,u2 ,vn, v1, v2):
"""
B{glMapGrid1d, glMapGrid1f, glMapGrid2d, glMapGrid2f}
Define a one- or two-dimensional mesh
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/mapgrid.html}
@type un: int
@param un: Specifies the number of partitions in the grid range interval
[u1, u2]. Must be positive.
@type u1, u2: Depends on function prototype.
@param u1, u2: Specify the mappings for integer grid domain values i=0 and i=un.
@type vn: int
@param vn: Specifies the number of partitions in the grid range interval [v1, v2]
(glMapGrid2 only).
@type v1, v2: Depends on function prototype.
@param v1, v2: Specify the mappings for integer grid domain values j=0 and j=vn
(glMapGrid2 only).
"""
def glMaterial (face, pname, params):
"""
Specify material parameters for the lighting model.
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/material.html}
@type face: Enumerated constant
@param face: Specifies which face or faces are being updated. Must be one of:
@type pname: Enumerated constant
@param pname: Specifies the single-valued material parameter of the face
or faces that is being updated. Must be GL_SHININESS.
@type params: int
@param params: Specifies the value that parameter GL_SHININESS will be set to.
If function prototype ends in 'v' specifies a pointer to the value or values that
pname will be set to.
"""
def glMatrixMode(mode):
"""
Specify which matrix is the current matrix.
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/matrixmode.html}
@type mode: Enumerated constant
@param mode: Specifies which matrix stack is the target for subsequent matrix operations.
"""
def glMultMatrix (m):
"""
B{glMultMatrixd, glMultMatrixf}
Multiply the current matrix with the specified matrix
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/multmatrix.html}
@type m: Buffer object. Depends on function prototype.
@param m: Points to 16 consecutive values that are used as the elements of a 4x4 column
major matrix.
"""
def glNewList(list, mode):
"""
Create or replace a display list
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/newlist.html}
@type list: unsigned int
@param list: Specifies the display list name
@type mode: Enumerated constant
@param mode: Specifies the compilation mode.
"""
def glNormal3 (nx, ny, nz, v):
"""
B{Normal3b, Normal3bv, Normal3d, Normal3dv, Normal3f, Normal3fv, Normal3i, Normal3iv,
Normal3s, Normal3sv}
Set the current normal vector
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/normal.html}
@type nx, ny, nz: Depends on function prototype. (non - 'v' prototypes only)
@param nx, ny, nz: Specify the x, y, and z coordinates of the new current normal.
The initial value of the current normal is the unit vector, (0, 0, 1).
@type v: Buffer object. Depends on function prototype. ('v' prototypes)
@param v: Specifies a pointer to an array of three elements: the x, y, and z coordinates
of the new current normal.
"""
def glOrtho(left, right, bottom, top, zNear, zFar):
"""
Multiply the current matrix with an orthographic matrix
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/ortho.html}
@type left, right: double (float)
@param left, right: Specify the coordinates for the left and
right vertical clipping planes.
@type bottom, top: double (float)
@param bottom, top: Specify the coordinates for the bottom and top
horizontal clipping planes.
@type zNear, zFar: double (float)
@param zNear, zFar: Specify the distances to the nearer and farther
depth clipping planes. These values are negative if the plane is to be behind the viewer.
"""
def glPassThrough(token):
"""
Place a marker in the feedback buffer
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/passthrough.html}
@type token: float
@param token: Specifies a marker value to be placed in the feedback
buffer following a GL_PASS_THROUGH_TOKEN.
"""
def glPixelMap (map, mapsize, values):
"""
B{glPixelMapfv, glPixelMapuiv, glPixelMapusv}
Set up pixel transfer maps
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pixelmap.html}
@type map: Enumerated constant
@param map: Specifies a symbolic map name.
@type mapsize: int
@param mapsize: Specifies the size of the map being defined.
@type values: Buffer object. Depends on function prototype.
@param values: Specifies an array of mapsize values.
"""
def glPixelStore (pname, param):
"""
B{glPixelStoref, glPixelStorei}
Set pixel storage modes
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pixelstore.html}
@type pname: Enumerated constant
@param pname: Specifies the symbolic name of the parameter to be set.
Six values affect the packing of pixel data into memory.
Six more affect the unpacking of pixel data from memory.
@type param: Depends on function prototype.
@param param: Specifies the value that pname is set to.
"""
def glPixelTransfer (pname, param):
"""
B{glPixelTransferf, glPixelTransferi}
Set pixel transfer modes
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pixeltransfer.html}
@type pname: Enumerated constant
@param pname: Specifies the symbolic name of the pixel transfer parameter to be set.
@type param: Depends on function prototype.
@param param: Specifies the value that pname is set to.
"""
def glPixelZoom(xfactor, yfactor):
"""
Specify the pixel zoom factors
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pixelzoom.html}
@type xfactor, yfactor: float
@param xfactor, yfactor: Specify the x and y zoom factors for pixel write operations.
"""
def glPointSize(size):
"""
Specify the diameter of rasterized points
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pointsize.html}
@type size: float
@param size: Specifies the diameter of rasterized points. The initial value is 1.
"""
def glPolygonMode(face, mode):
"""
Select a polygon rasterization mode
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/polygonmode.html}
@type face: Enumerated constant
@param face: Specifies the polygons that mode applies to.
Must be GL_FRONT for front-facing polygons, GL_BACK for back- facing polygons,
or GL_FRONT_AND_BACK for front- and back-facing polygons.
@type mode: Enumerated constant
@param mode: Specifies how polygons will be rasterized.
The initial value is GL_FILL for both front- and back- facing polygons.
"""
def glPolygonOffset(factor, units):
"""
Set the scale and units used to calculate depth values
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/polygonoffset.html}
@type factor: float
@param factor: Specifies a scale factor that is used to create a variable depth
offset for each polygon. The initial value is 0.
@type units: float
@param units: Is multiplied by an implementation-specific value to create a constant
depth offset. The initial value is 0.
"""
def glPolygonStipple(mask):
"""
Set the polygon stippling pattern
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/polygonstipple.html}
@type mask: Buffer object I{type GL_BYTE}
@param mask: Specifies a pointer to a 32x32 stipple pattern that will be unpacked
from memory in the same way that glDrawPixels unpacks pixels.
"""
def glPopAttrib():
"""
Pop the server attribute stack
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushattrib.html}
"""
def glPopClientAttrib():
"""
Pop the client attribute stack
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushclientattrib.html}
"""
def glPopMatrix():
"""
Pop the current matrix stack
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushmatrix.html}
"""
def glPopName():
"""
Pop the name stack
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushname.html}
"""
def glPrioritizeTextures(n, textures, priorities):
"""
Set texture residence priority
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/prioritizetextures.html}
@type n: int
@param n:Specifies the number of textures to be prioritized.
@type textures: Buffer I{type GL_INT}
@param textures: Specifies an array containing the names of the textures to be prioritized.
@type priorities: Buffer I{type GL_FLOAT}
@param priorities: Specifies an array containing the texture priorities. A priority given
in an element of priorities applies to the texture named by the corresponding element of textures.
"""
def glPushAttrib(mask):
"""
Push the server attribute stack
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushattrib.html}
@type mask: Enumerated constant(s)
@param mask: Specifies a mask that indicates which attributes to save.
"""
def glPushClientAttrib(mask):
"""
Push the client attribute stack
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushclientattrib.html}
@type mask: Enumerated constant(s)
@param mask: Specifies a mask that indicates which attributes to save.
"""
def glPushMatrix():
"""
Push the current matrix stack
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushmatrix.html}
"""
def glPushName(name):
"""
Push the name stack
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushname.html}
@type name: unsigned int
@param name: Specifies a name that will be pushed onto the name stack.
"""
def glRasterPos (x,y,z,w):
"""
B{glRasterPos2d, glRasterPos2f, glRasterPos2i, glRasterPos2s, glRasterPos3d,
glRasterPos3f, glRasterPos3i, glRasterPos3s, glRasterPos4d, glRasterPos4f,
glRasterPos4i, glRasterPos4s, glRasterPos2dv, glRasterPos2fv, glRasterPos2iv,
glRasterPos2sv, glRasterPos3dv, glRasterPos3fv, glRasterPos3iv, glRasterPos3sv,
glRasterPos4dv, glRasterPos4fv, glRasterPos4iv, glRasterPos4sv}
Specify the raster position for pixel operations
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/rasterpos.html}
@type x, y, z, w: Depends on function prototype. (z and w for '3' and '4' prototypes only)
@param x, y, z, w: Specify the x,y,z, and w object coordinates (if present) for the
raster position. If function prototype ends in 'v' specifies a pointer to an array of two,
three, or four elements, specifying x, y, z, and w coordinates, respectively.
@note:
If you are drawing to the 3d view with a Scriptlink of a space handler
the zoom level of the panels will scale the glRasterPos by the view matrix.
so a X of 10 will not always offset 10 pixels as you would expect.
To work around this get the scale value of the view matrix and use it to scale your pixel values.
Workaround::
import Blender
from Blender.BGL import *
xval, yval= 100, 40
# Get the scale of the view matrix
viewMatrix = Buffer(GL_FLOAT, 16)
glGetFloatv(GL_MODELVIEW_MATRIX, viewMatrix)
f = 1/viewMatrix[0]
glRasterPos2f(xval*f, yval*f) # Instead of the usual glRasterPos2i(xval, yval)
"""
def glReadBuffer(mode):
"""
Select a color buffer source for pixels.
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/readbuffer.html}
@type mode: Enumerated constant
@param mode: Specifies a color buffer.
"""
def glReadPixels(x, y, width, height, format, type, pixels):
"""
Read a block of pixels from the frame buffer
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/readpixels.html}
@type x, y: int
@param x, y:Specify the window coordinates of the first pixel that is read
from the frame buffer. This location is the lower left corner of a rectangular
block of pixels.
@type width, height: int
@param width, height: Specify the dimensions of the pixel rectangle. width and
height of one correspond to a single pixel.
@type format: Enumerated constant
@param format: Specifies the format of the pixel data.
@type type: Enumerated constant
@param type: Specifies the data type of the pixel data.
@type pixels: Buffer object
@param pixels: Returns the pixel data.
"""
def glRect (x1,y1,x2,y2,v1,v2):
"""
B{glRectd, glRectf, glRecti, glRects, glRectdv, glRectfv, glRectiv, glRectsv}
Draw a rectangle
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/rect.html}
@type x1, y1: Depends on function prototype. (for non 'v' prototypes only)
@param x1, y1: Specify one vertex of a rectangle
@type x2, y2: Depends on function prototype. (for non 'v' prototypes only)
@param x2, y2: Specify the opposite vertex of the rectangle
@type v1, v2: Depends on function prototype. (for 'v' prototypes only)
@param v1, v2: Specifies a pointer to one vertex of a rectangle and the pointer
to the opposite vertex of the rectangle
"""
def glRenderMode(mode):
"""
Set rasterization mode
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/rendermode.html}
@type mode: Enumerated constant
@param mode: Specifies the rasterization mode.
"""
def glRotate (angle, x, y, z):
"""
B{glRotated, glRotatef}
Multiply the current matrix by a rotation matrix
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/rotate.html}
@type angle: Depends on function prototype.
@param angle: Specifies the angle of rotation in degrees.
@type x, y, z: Depends on function prototype.
@param x, y, z: Specify the x, y, and z coordinates of a vector respectively.
"""
def glScale (x,y,z):
"""
B{glScaled, glScalef}
Multiply the current matrix by a general scaling matrix
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/scale.html}
@type x, y, z: Depends on function prototype.
@param x, y, z: Specify scale factors along the x, y, and z axes, respectively.
"""
def glScissor(x,y,width,height):
"""
Define the scissor box
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/scissor.html}
@type x, y: int
@param x, y: Specify the lower left corner of the scissor box. Initially (0, 0).
@type width, height: int
@param width height: Specify the width and height of the scissor box. When a
GL context is first attached to a window, width and height are set to the
dimensions of that window.
"""
def glSelectBuffer(size, buffer):
"""
Establish a buffer for selection mode values
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/selectbuffer.html}
@type size: int
@param size: Specifies the size of buffer
@type buffer: Buffer I{type GL_INT}
@param buffer: Returns the selection data
"""
def glShadeModel(mode):
"""
Select flat or smooth shading
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/shademodel.html}
@type mode: Enumerated constant
@param mode: Specifies a symbolic value representing a shading technique.
"""
def glStencilFuc(func, ref, mask):
"""
Set function and reference value for stencil testing
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/stencilfunc.html}
@type func: Enumerated constant
@param func:Specifies the test function.
@type ref: int
@param ref:Specifies the reference value for the stencil test. ref is clamped to
the range [0,2n-1], where n is the number of bitplanes in the stencil buffer.
The initial value is 0.
@type mask: unsigned int
@param mask:Specifies a mask that is ANDed with both the reference value and
the stored stencil value when the test is done. The initial value is all 1's.
"""
def glStencilMask(mask):
"""
Control the writing of individual bits in the stencil planes
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/stencilmask.html}
@type mask: unsigned int
@param mask: Specifies a bit mask to enable and disable writing of individual bits
in the stencil planes. Initially, the mask is all 1's.
"""
def glStencilOp(fail, zfail, zpass):
"""
Set stencil test actions
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/stencilop.html}
@type fail: Enumerated constant
@param fail: Specifies the action to take when the stencil test fails.
The initial value is GL_KEEP.
@type zfail: Enumerated constant
@param zfail: Specifies the stencil action when the stencil test passes, but the
depth test fails. zfail accepts the same symbolic constants as fail.
The initial value is GL_KEEP.
@type zpass: Enumerated constant
@param zpass: Specifies the stencil action when both the stencil test and the
depth test pass, or when the stencil test passes and either there is no depth
buffer or depth testing is not enabled. zpass accepts the same symbolic constants
as fail. The initial value is GL_KEEP.
"""
def glTexCoord (s,t,r,q,v):
"""
B{glTexCoord1d, glTexCoord1f, glTexCoord1i, glTexCoord1s, glTexCoord2d, glTexCoord2f,
glTexCoord2i, glTexCoord2s, glTexCoord3d, glTexCoord3f, glTexCoord3i, glTexCoord3s,
glTexCoord4d, glTexCoord4f, glTexCoord4i, glTexCoord4s, glTexCoord1dv, glTexCoord1fv,
glTexCoord1iv, glTexCoord1sv, glTexCoord2dv, glTexCoord2fv, glTexCoord2iv,
glTexCoord2sv, glTexCoord3dv, glTexCoord3fv, glTexCoord3iv, glTexCoord3sv,
glTexCoord4dv, glTexCoord4fv, glTexCoord4iv, glTexCoord4sv}
Set the current texture coordinates
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/texcoord.html}
@type s, t, r, q: Depends on function prototype. (r and q for '3' and '4' prototypes only)
@param s, t, r, q: Specify s, t, r, and q texture coordinates. Not all parameters are
present in all forms of the command.
@type v: Buffer object. Depends on function prototype. (for 'v' prototypes only)
@param v: Specifies a pointer to an array of one, two, three, or four elements,
which in turn specify the s, t, r, and q texture coordinates.
"""
def glTexEnv (target, pname, param):
"""
B{glTextEnvf, glTextEnvi, glTextEnvfv, glTextEnviv}
Set texture environment parameters
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/texenv.html}
@type target: Enumerated constant
@param target: Specifies a texture environment. Must be GL_TEXTURE_ENV.
@type pname: Enumerated constant
@param pname: Specifies the symbolic name of a single-valued texture environment
parameter. Must be GL_TEXTURE_ENV_MODE.
@type param: Depends on function prototype.
@param param: Specifies a single symbolic constant. If function prototype ends in 'v'
specifies a pointer to a parameter array that contains either a single symbolic
constant or an RGBA color
"""
def glTexGen (coord, pname, param):
"""
B{glTexGend, glTexGenf, glTexGeni, glTexGendv, glTexGenfv, glTexGeniv}
Control the generation of texture coordinates
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/texgen.html}
@type coord: Enumerated constant
@param coord: Specifies a texture coordinate.
@type pname: Enumerated constant
@param pname: Specifies the symbolic name of the texture- coordinate generation function.
@type param: Depends on function prototype.
@param param: Specifies a single-valued texture generation parameter.
If function prototype ends in 'v' specifies a pointer to an array of texture
generation parameters. If pname is GL_TEXTURE_GEN_MODE, then the array must
contain a single symbolic constant. Otherwise, params holds the coefficients
for the texture-coordinate generation function specified by pname.
"""
def glTexImage1D(target, level, internalformat, width, border, format, type, pixels):
"""
Specify a one-dimensional texture image
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/teximage1d.html}
@type target: Enumerated constant
@param target: Specifies the target texture.
@type level: int
@param level: Specifies the level-of-detail number. Level 0 is the base image level.
Level n is the nth mipmap reduction image.
@type internalformat: int
@param internalformat: Specifies the number of color components in the texture.
@type width: int
@param width: Specifies the width of the texture image. Must be 2n+2(border) for
some integer n. All implementations support texture images that are at least 64
texels wide. The height of the 1D texture image is 1.
@type border: int
@param border: Specifies the width of the border. Must be either 0 or 1.
@type format: Enumerated constant
@param format: Specifies the format of the pixel data.
@type type: Enumerated constant
@param type: Specifies the data type of the pixel data.
@type pixels: Buffer object.
@param pixels: Specifies a pointer to the image data in memory.
"""
def glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels):
"""
Specify a two-dimensional texture image
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/teximage2d.html}
@type target: Enumerated constant
@param target: Specifies the target texture.
@type level: int
@param level: Specifies the level-of-detail number. Level 0 is the base image level.
Level n is the nth mipmap reduction image.
@type internalformat: int
@param internalformat: Specifies the number of color components in the texture.
@type width: int
@param width: Specifies the width of the texture image. Must be 2n+2(border) for
some integer n. All implementations support texture images that are at least 64
texels wide.
@type height: int
@param height: Specifies the height of the texture image. Must be 2m+2(border) for
some integer m. All implementations support texture images that are at least 64
texels high.
@type border: int
@param border: Specifies the width of the border. Must be either 0 or 1.
@type format: Enumerated constant
@param format: Specifies the format of the pixel data.
@type type: Enumerated constant
@param type: Specifies the data type of the pixel data.
@type pixels: Buffer object.
@param pixels: Specifies a pointer to the image data in memory.
"""
def glTexParameter (target, pname, param):
"""
B{glTexParameterf, glTexParameteri, glTexParameterfv, glTexParameteriv}
Set texture parameters
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/texparameter.html}
@type target: Enumerated constant
@param target: Specifies the target texture.
@type pname: Enumerated constant
@param pname: Specifies the symbolic name of a single-valued texture parameter.
@type param: Depends on function prototype.
@param param: Specifies the value of pname. If function prototype ends in 'v' specifies
a pointer to an array where the value or values of pname are stored.
"""
def glTranslate (x, y, z):
"""
B{glTranslatef, glTranslated}
Multiply the current matrix by a translation matrix
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/translate.html}
@type x, y, z: Depends on function prototype.
@param x, y, z: Specify the x, y, and z coordinates of a translation vector.
"""
def glVertex (x,y,z,w,v):
"""
B{glVertex2d, glVertex2f, glVertex2i, glVertex2s, glVertex3d, glVertex3f, glVertex3i,
glVertex3s, glVertex4d, glVertex4f, glVertex4i, glVertex4s, glVertex2dv, glVertex2fv,
glVertex2iv, glVertex2sv, glVertex3dv, glVertex3fv, glVertex3iv, glVertex3sv, glVertex4dv,
glVertex4fv, glVertex4iv, glVertex4sv}
Specify a vertex
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/vertex.html}
@type x, y, z, w: Depends on function prototype (z and w for '3' and '4' prototypes only)
@param x, y, z, w: Specify x, y, z, and w coordinates of a vertex. Not all parameters
are present in all forms of the command.
@type v: Buffer object. Depends of function prototype (for 'v' prototypes only)
@param v: Specifies a pointer to an array of two, three, or four elements. The
elements of a two-element array are x and y; of a three-element array, x, y, and z;
and of a four-element array, x, y, z, and w.
"""
def glViewport(x,y,width,height):
"""
Set the viewport
@see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/viewport.html}
@type x, y: int
@param x, y: Specify the lower left corner of the viewport rectangle,
in pixels. The initial value is (0,0).
@type width, height: int
@param width, height: Specify the width and height of the viewport. When a GL context
is first attached to a window, width and height are set to the dimensions of that window.
"""
def gluPerspective(fovY, aspect, zNear, zFar):
"""
Set up a perspective projection matrix.
@see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5577288}
@type fovY: double
@param fovY: Specifies the field of view angle, in degrees, in the y direction.
@type aspect: double
@param aspect: Specifies the aspect ratio that determines the field of view in the x direction.
The aspect ratio is the ratio of x (width) to y (height).
@type zNear: double
@param zNear: Specifies the distance from the viewer to the near clipping plane (always positive).
@type zFar: double
@param zFar: Specifies the distance from the viewer to the far clipping plane (always positive).
"""
def gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz):
"""
Define a viewing transformation
@see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5573042}
@type eyex, eyey, eyez: double
@param eyex, eyey, eyez: Specifies the position of the eye point.
@type centerx, centery, centerz: double
@param centerx, centery, centerz: Specifies the position of the reference point.
@type upx, upy, upz: double
@param upx, upy, upz: Specifies the direction of the up vector.
"""
def gluOrtho2D(left, right, bottom, top):
"""
Define a 2-D orthographic projection matrix
@see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074}
@type left, right: double
@param left, right: Specify the coordinates for the left and right vertical clipping planes.
@type bottom, top: double
@param bottom, top: Specify the coordinates for the bottom and top horizontal clipping planes.
"""
def gluPickMatrix(x, y, width, height, viewport):
"""
Define a picking region
@see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074}
@type x, y: double
@param x, y: Specify the center of a picking region in window coordinates.
@type width, height: double
@param width, height: Specify the width and height, respectively, of the picking region in window coordinates.
@type viewport: Buffer object. [int]
@param viewport: Specifies the current viewport.
"""
def gluProject(objx, objy, objz, modelMatrix, projMatrix, viewport, winx, winy, winz):
"""
Map object coordinates to window coordinates.
@see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074}
@type objx, objy, objz: double
@param objx, objy, objz: Specify the object coordinates.
@type modelMatrix: Buffer object. [double]
@param modelMatrix: Specifies the current modelview matrix (as from a glGetDoublev call).
@type projMatrix: Buffer object. [double]
@param projMatrix: Specifies the current projection matrix (as from a glGetDoublev call).
@type viewport: Buffer object. [int]
@param viewport: Specifies the current viewport (as from a glGetIntegerv call).
@type winx, winy, winz: Buffer object. [double]
@param winx, winy, winz: Return the computed window coordinates.
"""
def gluUnProject(winx, winy, winz, modelMatrix, projMatrix, viewport, objx, objy, objz):
"""
Map object coordinates to window
coordinates.
@see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5582204}
@type winx, winy, winz: double
@param winx, winy, winz: Specify the window coordinates to be mapped.
@type modelMatrix: Buffer object. [double]
@param modelMatrix: Specifies the current modelview matrix (as from a glGetDoublev call).
@type projMatrix: Buffer object. [double]
@param projMatrix: Specifies the current projection matrix (as from a glGetDoublev call).
@type viewport: Buffer object. [int]
@param viewport: Specifies the current viewport (as from a glGetIntegerv call).
@type objx, objy, objz: Buffer object. [double]
@param objx, objy, objz: Return the computed object coordinates.
"""
class Buffer:
"""
The Buffer object is simply a block of memory that is delineated and initialized by the
user. Many OpenGL functions return data to a C-style pointer, however, because this
is not possible in python the Buffer object can be used to this end. Wherever pointer
notation is used in the OpenGL functions the Buffer object can be used in it's BGL
wrapper. In some instances the Buffer object will need to be initialized with the template
parameter, while in other instances the user will want to create just a blank buffer
which will be zeroed by default.
Example with Buffer::
import Blender
from Blender import BGL
myByteBuffer = BGL.Buffer(BGL.GL_BYTE, [32,32])
BGL.glGetPolygonStipple(myByteBuffer)
print myByteBuffer.dimensions
print myByteBuffer.list
sliceBuffer = myByteBuffer[0:16]
print sliceBuffer
@ivar list: The contents of the Buffer.
@ivar dimensions: The size of the Buffer.
"""
def __init__(type, dimensions, template = None):
"""
This will create a new Buffer object for use with other BGL OpenGL commands.
Only the type of argument to store in the buffer and the dimensions of the buffer
are necessary. Buffers are zeroed by default unless a template is supplied, in
which case the buffer is initialized to the template.
@type type: int
@param type: The format to store data in. The type should be one of
GL_BYTE, GL_SHORT, GL_INT, or GL_FLOAT.
@type dimensions: An int or sequence object specifying the dimensions of the buffer.
@param dimensions: If the dimensions are specified as an int a linear array will
be created for the buffer. If a sequence is passed for the dimensions, the buffer
becomes n-Dimensional, where n is equal to the number of parameters passed in the
sequence. Example: [256,2] is a two- dimensional buffer while [256,256,4] creates
a three- dimensional buffer. You can think of each additional dimension as a sub-item
of the dimension to the left. i.e. [10,2] is a 10 element array each with 2 sub-items.
[(0,0), (0,1), (1,0), (1,1), (2,0), ...] etc.
@type template: A python sequence object (optional)
@param template: A sequence of matching dimensions which will be used to initialize
the Buffer. If a template is not passed in all fields will be initialized to 0.
@rtype: Buffer object
@return: The newly created buffer as a PyObject.
"""

View File

@@ -0,0 +1,189 @@
# Blender.Geometry module and its subtypes
"""
The Blender.Geometry submodule.
Geometry
========
(when accessing it from the Game Engine use Geometry instead of Blender.Geometry)
This new module provides access to a geometry function.
"""
def Intersect(vec1, vec2, vec3, ray, orig, clip=1):
"""
Return the intersection between a ray and a triangle, if possible, return None otherwise.
@type vec1: Vector object.
@param vec1: A 3d vector, one corner of the triangle.
@type vec2: Vector object.
@param vec2: A 3d vector, one corner of the triangle.
@type vec3: Vector object.
@param vec3: A 3d vector, one corner of the triangle.
@type ray: Vector object.
@param ray: A 3d vector, the orientation of the ray. the length of the ray is not used, only the direction.
@type orig: Vector object.
@param orig: A 3d vector, the origin of the ray.
@type clip: integer
@param clip: if 0, don't restrict the intersection to the area of the triangle, use the infinite plane defined by the triangle.
@rtype: Vector object
@return: The intersection between a ray and a triangle, if possible, None otherwise.
"""
def TriangleArea(vec1, vec2, vec3):
"""
Return the area size of the 2D or 3D triangle defined.
@type vec1: Vector object.
@param vec1: A 2d or 3d vector, one corner of the triangle.
@type vec2: Vector object.
@param vec2: A 2d or 3d vector, one corner of the triangle.
@type vec3: Vector object.
@param vec3: A 2d or 3d vector, one corner of the triangle.
@rtype: float
@return: The area size of the 2D or 3D triangle defined.
"""
def TriangleNormal(vec1, vec2, vec3):
"""
Return the normal of the 3D triangle defined.
@type vec1: Vector object.
@param vec1: A 3d vector, one corner of the triangle.
@type vec2: Vector object.
@param vec2: A 3d vector, one corner of the triangle.
@type vec3: Vector object.
@param vec3: A 3d vector, one corner of the triangle.
@rtype: float
@return: The normal of the 3D triangle defined.
"""
def QuadNormal(vec1, vec2, vec3, vec4):
"""
Return the normal of the 3D quad defined.
@type vec1: Vector object.
@param vec1: A 3d vector, the first vertex of the quad.
@type vec2: Vector object.
@param vec2: A 3d vector, the second vertex of the quad.
@type vec3: Vector object.
@param vec3: A 3d vector, the third vertex of the quad.
@type vec4: Vector object.
@param vec4: A 3d vector, the fourth vertex of the quad.
@rtype: float
@return: The normal of the 3D quad defined.
"""
def LineIntersect(vec1, vec2, vec3, vec4):
"""
Return a tuple with the points on each line respectively closest to the other
(when both lines intersect, both vector hold the same value).
The lines are evaluated as infinite lines in space, the values returned may not be between the 2 points given for each line.
@type vec1: Vector object.
@param vec1: A 3d vector, one point on the first line.
@type vec2: Vector object.
@param vec2: A 3d vector, another point on the first line.
@type vec3: Vector object.
@param vec3: A 3d vector, one point on the second line.
@type vec4: Vector object.
@param vec4: A 3d vector, another point on the second line.
@rtype: (Vector object, Vector object)
@return: A tuple with the points on each line respectively closest to the other.
"""
def PolyFill(polylines):
"""
Takes a list of polylines and calculates triangles that would fill in the polylines.
Multiple lines can be used to make holes inside a polyline, or fill in 2 seperate lines at once.
@type polylines: List of lists containing vectors, each representing a closed polyline.
@rtype: list
@return: a list if tuples each a tuple of 3 ints representing a triangle indexing the points given.
@note: 2D Vectors will have an assumed Z axis of zero, 4D Vectors W axis is ignored.
@note: The order of points in a polyline effect the direction returned triangles face, reverse the order of a polyline to flip the normal of returned faces.
I{B{Example:}}
The example below creates 2 polylines and fills them in with faces, then makes a mesh in the current scene::
import Blender
Vector= Blender.Mathutils.Vector
# Outline of 5 points
polyline1= [Vector(-2.0, 1.0, 1.0), Vector(-1.0, 2.0, 1.0), Vector(1.0, 2.0, 1.0), Vector(1.0, -1.0, 1.0), Vector(-1.0, -1.0, 1.0)]
polyline2= [Vector(-1, 1, 1.0), Vector(0, 1, 1.0), Vector(0, 0, 1.0), Vector(-1.0, 0.0, 1.0)]
fill= Blender.Geometry.PolyFill([polyline1, polyline2])
# Make a new mesh and add the truangles into it
me= Blender.Mesh.New()
me.verts.extend(polyline1)
me.verts.extend(polyline2)
me.faces.extend(fill) # Add the faces, they reference the verts in polyline 1 and 2
scn = Blender.Scene.GetCurrent()
ob = scn.objects.new(me)
Blender.Redraw()
"""
def LineIntersect2D(vec1, vec2, vec3, vec4):
"""
Takes 2 lines vec1, vec2 for the 2 points of the first line and vec2, vec3 for the 2 points of the second line.
@rtype: Vector
@return: a 2D Vector for the intersection or None where there is no intersection.
"""
def ClosestPointOnLine(pt, vec1, vec2):
"""
Takes 2 lines vec1, vec2 for the 2 points of the first line and vec2, vec3 for the 2 points of the second line.
@rtype: tuple
@return: a tuple containing a vector and a float, the vector is the closest point on the line, the float is the position on the line, between 0 and 1 the point is on the line.
"""
def PointInTriangle2D(pt, tri_pt1, tri_pt2, tri_pt3):
"""
Takes 4 vectors (one for the test point and 3 for the triangle)
This is a 2d function so only X and Y are used, Z and W will be ignored.
@rtype: int
@return: 1 for a clockwise intersection, -1 for counter clockwise intersection, 0 when there is no intersection.
"""
def PointInQuad2D(pt, quad_pt1, quad_pt2, quad_pt3):
"""
Takes 5 vectors (one for the test point and 5 for the quad)
This is a 2d function so only X and Y are used, Z and W will be ignored.
@rtype: int
@return: 1 for a clockwise intersection, -1 for counter clockwise intersection, 0 when there is no intersection.
"""
def BoxPack2D(boxlist):
"""
Takes a list of 2D boxes and packs them into a square.
Each box in boxlist must be a list of at least 4 items - [x,y,w,h], after running this script,
the X and Y values in each box will be moved to packed, non overlapping locations.
Example::
# Make 500 random boxes, pack them and make a mesh from it
from Blender import Geometry, Scene, Mesh
import random
boxes = []
for i in xrange(500):
boxes.append( [0,0, random.random()+0.1, random.random()+0.1] )
boxsize = Geometry.BoxPack2D(boxes)
print 'BoxSize', boxsize
me = Mesh.New()
for x in boxes:
me.verts.extend([(x[0],x[1], 0), (x[0],x[1]+x[3], 0), (x[0]+x[2],x[1]+x[3], 0), (x[0]+x[2],x[1], 0) ])
v1= me.verts[-1]
v2= me.verts[-2]
v3= me.verts[-3]
v4= me.verts[-4]
me.faces.extend([(v1,v2,v3,v4)])
scn = Scene.GetCurrent()
scn.objects.new(me)
@note: Each boxlist item can be longer then 4, the extra items are ignored and stay untouched.
@rtype: tuple
@return: a tuple pair - (width, height) of all the packed boxes.
"""
def BezierInterp(vec_knot_1, vec_handle_1, vec_handle_2, vec_knot_2, resolution):
"""
Takes 4 vectors representing a bezier curve and returns a list of vector points.
@note: any vector size is supported, the largest dimension from the input will be used for all returned vectors/
@rtype: list
@return: a list of vectors the size of resolution including the start and end points (vec_knot_1 and vec_knot_2)
"""

View File

@@ -0,0 +1,132 @@
class IDGroup:
"""
The IDGroup Type
================
This type supports both iteration and the []
operator to get child ID properties.
You can also add new properties using the [] operator.
For example::
group['a float!'] = 0.0
group['an int!'] = 0
group['a string!'] = "hi!"
group['an array!'] = [0, 0, 1.0, 0]
group['a subgroup!] = {"float": 0.0, "an int": 1.0, "an array": [1, 2],
"another subgroup": {"a": 0.0, "str": "bleh"}}
Note that for arrays, the array type defaults to int unless a float is found
while scanning the template list; if any floats are found, then the whole
array is float. Note that double-precision floating point numbers are used for
python-created float ID properties and arrays (though the internal C api does
support single-precision floats, and the python code will read them).
You can also delete properties with the del operator. For example:
del group['property']
To get the type of a property, use the type() operator, for example::
if type(group['bleh']) == str: pass
To tell if the property is a group or array type, import the Blender.Types module and test
against IDGroupType and IDArrayType, like so::
from Blender.Types import IDGroupType, IDArrayType.
if type(group['bleghr']) == IDGroupType:
(do something)
@ivar name: The name of the property
@type name: string
"""
def pop(item):
"""
Pop an item from the group property.
@type item: string
@param item: The item name.
@rtype: can be dict, list, int, float or string.
@return: The removed property.
"""
def update(updatedict):
"""
Updates items in the dict, similar to normal python
dictionary method .update().
@type updatedict: dict
@param updatedict: A dict of simple types to derive updated/new IDProperties from.
@rtype: None
@return: None
"""
def keys():
"""
Returns a list of the keys in this property group.
@rtype: list of strings.
@return: a list of the keys in this property group.
"""
def values():
"""
Returns a list of the values in this property group.
Note that unless a value is itself a property group or an array, you
cannot change it by changing the values in this list, you must change them
in the parent property group.
For example,
group['some_property'] = new_value
. . .is correct, while,
values = group.values()
values[0] = new_value
. . .is wrong.
@rtype: list of strings.
@return: a list of the values in this property group.
"""
def iteritems():
"""
Implements the python dictionary iteritmes method.
For example::
for k, v in group.iteritems():
print "Property name: " + k
print "Property value: " + str(v)
@rtype: an iterator that spits out items of the form [key, value]
@return: an iterator.
"""
def convert_to_pyobject():
"""
Converts the entire property group to a purely python form.
@rtype: dict
@return: A python dictionary representing the property group
"""
class IDArray:
"""
The IDArray Type
================
@ivar type: returns the type of the array, can be either IDP_Int or IDP_Float
"""
def __getitem__(index):
pass
def __setitem__(index, value):
pass
def __len__():
pass

View File

@@ -0,0 +1,271 @@
# Blender.Mathutils module and its subtypes
"""
The Blender.Mathutils submodule.
Mathutils
=========
(when accessing it from the Game Engine use Mathutils instead of Blender.Mathutils)
This module provides access to matrices, eulers, quaternions and vectors.
Example::
import Blender
from Blender import Mathutils
from Blender.Mathutils import *
vec = Vector([1,2,3])
mat = RotationMatrix(90, 4, 'x')
matT = TranslationMatrix(vec)
matTotal = mat * matT
matTotal.invert()
mat3 = matTotal.rotationPart
quat1 = mat.to_quat()
quat2 = mat3.to_quat()
angle = DifferenceQuats(quat1, quat2)
print angle
"""
class Vector:
"""
The Vector object
=================
This object gives access to Vectors in Blender.
@group Axises: x, y, z, w
@ivar x: The x value.
@ivar y: The y value.
@ivar z: The z value (if any).
@ivar w: The w value (if any).
@ivar length: The magnitude of the vector.
@ivar magnitude: This is a synonym for length.
@ivar wrapped: Whether or not this item is wrapped data
@note: Comparison operators can be done on Vector classes:
- >, >=, <, <= test the vector magnitude
- ==, != test vector values e.g. 1,2,3 != 1,2,4 even if they are the same length
@note: Math can be performed on Vector classes
- vec + vec
- vec - vec
- vec * float/int
- vec * matrix
- vec * vec
- vec * quat
- -vec
@note: You can access a vector object like a sequence
- x = vector[0]
- vec_a[:] vec_b
- vec2d[:] vec3d[:2]
@note: Vectors support 'swizzle' operations
- vec.xyz = vec.zyx
- vec.xy = vec.zw
- vec.xxy = vec.wzz
- vec.yzyz = vec.yxyx
See U{http://en.wikipedia.org/wiki/Swizzling_(computer_graphics)}
@attention: Vector data can be wrapped or non-wrapped. When a object is wrapped it
means that the object will give you direct access to the data inside of blender. Modification
of this object will directly change the data inside of blender. To copy a wrapped object
you need to use the object's constructor. If you copy and object by assignment you will not get
a second copy but a second reference to the same data. Only certain functions will return
wrapped data. This will be indicated in the method description.
Example::
wrappedObject = Object.getAttribute() #this is wrapped data
print wrappedObject.wrapped #prints 'True'
copyOfObject = wrappedObject.copy() #creates a copy of the object
secondPointer = wrappedObject #creates a second pointer to the same data
print wrappedObject.attribute #prints '5'
secondPointer.attribute = 10
print wrappedObject.attribute #prints '10'
print copyOfObject.attribute #prints '5'
"""
def __init__(list = None):
"""
Create a new 2d, 3d, or 4d Vector object from a list of floating point numbers.
@note: that python uses higher precission floating point numbers, so values assigned to a vector may have some rounding error.
Example::
v = Vector(1,0,0)
v = Vector(myVec)
v = Vector(list)
@type list: PyList of float or int
@param list: The list of values for the Vector object. Can be a sequence or raw numbers.
Must be 2, 3, or 4 values. The list is mapped to the parameters as [x,y,z,w].
@rtype: Vector object.
@return: It depends wheter a parameter was passed:
- (list): Vector object initialized with the given values;
- (): An empty 3 dimensional vector.
"""
class Euler:
"""
The Euler object
================
This object gives access to Eulers in Blender.
@group Axises: x, y, z
@ivar x: The heading value in degrees.
@ivar y: The pitch value in degrees.
@ivar z: The roll value in degrees.
@ivar wrapped: Whether or not this object is wrapping data directly
@note: You can access a euler object like a sequence
- x = euler[0]
@note: Comparison operators can be done:
- ==, != test numeric values within epsilon
@attention: Euler data can be wrapped or non-wrapped. When a object is wrapped it
means that the object will give you direct access to the data inside of blender. Modification
of this object will directly change the data inside of blender. To copy a wrapped object
you need to use the object's constructor. If you copy and object by assignment you will not get
a second copy but a second reference to the same data. Only certain functions will return
wrapped data. This will be indicated in the method description.
Example::
wrappedObject = Object.getAttribute() #this is wrapped data
print wrappedObject.wrapped #prints 'True'
copyOfObject = wrappedObject.copy() #creates a copy of the object
secondPointer = wrappedObject #creates a second pointer to the same data
print wrappedObject.attribute #prints '5'
secondPointer.attribute = 10
print wrappedObject.attribute #prints '10'
print copyOfObject.attribute #prints '5'
"""
def __init__(list = None):
"""
Create a new euler object.
Example::
euler = Euler(45,0,0)
euler = Euler(myEuler)
euler = Euler(sequence)
@type list: PyList of float/int
@param list: 3d list to initialize euler
@rtype: Euler object
@return: Euler representing heading, pitch, bank.
@note: Values are in degrees.
"""
class Quaternion:
"""
The Quaternion object
=====================
This object gives access to Quaternions in Blender.
@group Axises: x, y, z, w
@ivar w: The w value.
@ivar x: The x value.
@ivar y: The y value.
@ivar z: The z value.
@ivar wrapped: Wether or not this object wraps data directly
@ivar magnitude: The magnitude of the quaternion.
@ivar axis: Vector representing the axis of rotation.
@ivar angle: A scalar representing the amount of rotation
in degrees.
@note: Comparison operators can be done:
- ==, != test numeric values within epsilon
@note: Math can be performed on Quaternion classes
- quat + quat
- quat - quat
- quat * float/int
- quat * vec
- quat * quat
@note: You can access a quaternion object like a sequence
- x = quat[0]
@attention: Quaternion data can be wrapped or non-wrapped. When a object is wrapped it
means that the object will give you direct access to the data inside of blender. Modification
of this object will directly change the data inside of blender. To copy a wrapped object
you need to use the object's constructor. If you copy and object by assignment you will not get
a second copy but a second reference to the same data. Only certain functions will return
wrapped data. This will be indicated in the method description.
Example::
wrappedObject = Object.getAttribute() #this is wrapped data
print wrappedObject.wrapped #prints 'True'
copyOfObject = wrappedObject.copy() #creates a copy of the object
secondPointer = wrappedObject #creates a second pointer to the same data
print wrappedObject.attribute #prints '5'
secondPointer.attribute = 10
print wrappedObject.attribute #prints '10'
print copyOfObject.attribute #prints '5'
"""
def __init__(list, angle = None):
"""
Create a new quaternion object from initialized values.
Example::
quat = Quaternion(1,2,3,4)
quat = Quaternion(axis, angle)
quat = Quaternion()
quat = Quaternion(180, list)
@type list: PyList of int/float
@param list: A 3d or 4d list to initialize quaternion.
4d if intializing [w,x,y,z], 3d if used as an axis of rotation.
@type angle: float (optional)
@param angle: An arbitrary rotation amount around 'list'.
List is used as an axis of rotation in this case.
@rtype: New quaternion object.
@return: It depends wheter a parameter was passed:
- (list/angle): Quaternion object initialized with the given values;
- (): An identity 4 dimensional quaternion.
"""
class Matrix:
"""
The Matrix Object
=================
This object gives access to Matrices in Blender.
@ivar rowSize: The row size of the matrix.
@ivar colSize: The column size of the matrix.
@ivar wrapped: Whether or not this object wrapps internal data
@note: Math can be performed on Matrix classes
- mat + mat
- mat - mat
- mat * float/int
- mat * vec
- mat * mat
@note: Comparison operators can be done:
- ==, != test numeric values within epsilon
@note: You can access a quaternion object like a 2d sequence
- x = matrix[0][1]
- vector = matrix[2]
@attention: Quaternion data can be wrapped or non-wrapped. When a object is wrapped it
means that the object will give you direct access to the data inside of blender. Modification
of this object will directly change the data inside of blender. To copy a wrapped object
you need to use the object's constructor. If you copy and object by assignment you will not get
a second copy but a second reference to the same data. Only certain functions will return
wrapped data. This will be indicated in the method description.
Example::
wrappedObject = Object.getAttribute() #this is wrapped data
print wrappedObject.wrapped #prints 'True'
copyOfObject = wrappedObject.copy() #creates a copy of the object
secondPointer = wrappedObject #creates a second pointer to the same data
print wrappedObject.attribute #prints '5'
secondPointer.attribute = 10
print wrappedObject.attribute #prints '10'
print copyOfObject.attribute #prints '5'
"""
def __init__(list1 = None, list2 = None, list3 = None, list4 = None):
"""
Create a new matrix object from initialized values.
Example::
matrix = Matrix([1,1,1],[0,1,0],[1,0,0])
matrix = Matrix(mat)
matrix = Matrix(seq1, seq2, vector)
@type list1: PyList of int/float
@param list1: A 2d,3d or 4d list.
@type list2: PyList of int/float
@param list2: A 2d,3d or 4d list.
@type list3: PyList of int/float
@param list3: A 2d,3d or 4d list.
@type list4: PyList of int/float
@param list4: A 2d,3d or 4d list.
@rtype: New matrix object.
@return: It depends wheter a parameter was passed:
- (list1, etc.): Matrix object initialized with the given values;
- (): An empty 3 dimensional matrix.
"""

View File

@@ -0,0 +1,45 @@
# Testing the BGL module
import Blender
from Blender.BGL import *
from Blender import Draw
R = G = B = 0
A = 1
instructions = "Hold mouse buttons to change the background color."
quitting = " Press ESC or q to quit."
def show_win():
glClearColor(R,G,B,A) # define color used to clear buffers
glClear(GL_COLOR_BUFFER_BIT) # use it to clear the color buffer
glColor3f(1,1,1) # change default color
glRasterPos2i(50,100) # move cursor to x = 50, y = 100
Draw.Text("Testing BGL + Draw") # draw this text there
glRasterPos2i(350,20) # move cursor again
Draw.Text(instructions + quitting) # draw another msg
glBegin(GL_LINE_LOOP) # begin a vertex-data list
glVertex2i(46,92)
glVertex2i(120,92)
glVertex2i(120,115)
glVertex2i(46,115)
glEnd() # close this list
glColor3f(0.35,0.18,0.92) # change default color again
glBegin(GL_POLYGON) # another list, for a polygon
glVertex2i(315, 292)
glVertex2i(412, 200)
glVertex2i(264, 256)
glEnd()
Draw.Redraw(1) # make changes visible.
def ev(evt, val): # this is a callback for Draw.Register()
global R,G,B,A # it handles input events
if evt == Draw.ESCKEY or evt == Draw.QKEY:
Draw.Exit() # this quits the script
elif evt == Draw.LEFTMOUSE: R = 1 - R
elif evt == Draw.MIDDLEMOUSE: G = 1 - G
elif evt == Draw.RIGHTMOUSE: B = 1 - B
else:
Draw.Register(show_win, ev, None)
Draw.Register(show_win, ev, None) # start the main loop

View File

@@ -47,19 +47,14 @@
#define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp
#define eps 0.000001
/*-- forward declarations -- */
static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq );
static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args );
static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args );
static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args );
static PyObject *M_Geometry_PointInQuad2D( PyObject * self, PyObject * args );
static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * args );
static PyObject *M_Geometry_BezierInterp( PyObject * self, PyObject * args );
static PyObject *M_Geometry_BarycentricTransform( PyObject * self, PyObject * args );
/*-------------------------DOC STRINGS ---------------------------*/
static char M_Geometry_doc[] = "The Blender Geometry module\n\n";
static char M_Geometry_Intersect_doc[] = "(v1, v2, v3, ray, orig, clip=1) - returns the intersection between a ray and a triangle, if possible, returns None otherwise";
static char M_Geometry_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined";
static char M_Geometry_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined";
static char M_Geometry_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined";
static char M_Geometry_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other";
static char M_Geometry_PolyFill_doc[] = "(veclist_list) - takes a list of polylines (each point a vector) and returns the point indicies for a polyline filled with triangles";
static char M_Geometry_LineIntersect2D_doc[] = "(lineA_p1, lineA_p2, lineB_p1, lineB_p2) - takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None";
static char M_Geometry_ClosestPointOnLine_doc[] = "(pt, line_p1, line_p2) - takes a point and a line and returns a (Vector, float) for the point on the line, and the bool so you can know if the point was between the 2 points";
@@ -67,40 +62,280 @@ static char M_Geometry_PointInTriangle2D_doc[] = "(pt, tri_p1, tri_p2, tri_p3) -
static char M_Geometry_PointInQuad2D_doc[] = "(pt, quad_p1, quad_p2, quad_p3, quad_p4) - takes 5 vectors, one is the point and the next 4 define the quad, only the x and y are used from the vectors";
static char M_Geometry_BoxPack2D_doc[] = "";
static char M_Geometry_BezierInterp_doc[] = "";
/*-----------------------METHOD DEFINITIONS ----------------------*/
struct PyMethodDef M_Geometry_methods[] = {
{"PolyFill", ( PyCFunction ) M_Geometry_PolyFill, METH_O, M_Geometry_PolyFill_doc},
{"LineIntersect2D", ( PyCFunction ) M_Geometry_LineIntersect2D, METH_VARARGS, M_Geometry_LineIntersect2D_doc},
{"ClosestPointOnLine", ( PyCFunction ) M_Geometry_ClosestPointOnLine, METH_VARARGS, M_Geometry_ClosestPointOnLine_doc},
{"PointInTriangle2D", ( PyCFunction ) M_Geometry_PointInTriangle2D, METH_VARARGS, M_Geometry_PointInTriangle2D_doc},
{"PointInQuad2D", ( PyCFunction ) M_Geometry_PointInQuad2D, METH_VARARGS, M_Geometry_PointInQuad2D_doc},
{"BoxPack2D", ( PyCFunction ) M_Geometry_BoxPack2D, METH_O, M_Geometry_BoxPack2D_doc},
{"BezierInterp", ( PyCFunction ) M_Geometry_BezierInterp, METH_VARARGS, M_Geometry_BezierInterp_doc},
{"BarycentricTransform", ( PyCFunction ) M_Geometry_BarycentricTransform, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef M_Geometry_module_def = {
PyModuleDef_HEAD_INIT,
"Geometry", /* m_name */
M_Geometry_doc, /* m_doc */
0, /* m_size */
M_Geometry_methods, /* m_methods */
0, /* m_reload */
0, /* m_traverse */
0, /* m_clear */
0, /* m_free */
};
/*----------------------------MODULE INIT-------------------------*/
PyObject *Geometry_Init(void)
//---------------------------------INTERSECTION FUNCTIONS--------------------
//----------------------------------Mathutils.Intersect() -------------------
static PyObject *M_Geometry_Intersect( PyObject * self, PyObject * args )
{
PyObject *submodule;
submodule = PyModule_Create(&M_Geometry_module_def);
PyDict_SetItemString(PySys_GetObject("modules"), M_Geometry_module_def.m_name, submodule);
return (submodule);
VectorObject *ray, *ray_off, *vec1, *vec2, *vec3;
float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
float det, inv_det, u, v, t;
int clip = 1;
if(!PyArg_ParseTuple(args, "O!O!O!O!O!|i", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off , &clip)) {
PyErr_SetString( PyExc_TypeError, "expected 5 vector types\n" );
return NULL;
}
if(vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) {
PyErr_SetString( PyExc_TypeError, "only 3D vectors for all parameters\n");
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(ray) || !BaseMath_ReadCallback(ray_off))
return NULL;
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec);
VECCOPY(dir, ray->vec);
normalize_v3(dir);
VECCOPY(orig, ray_off->vec);
/* find vectors for two edges sharing v1 */
sub_v3_v3v3(e1, v2, v1);
sub_v3_v3v3(e2, v3, v1);
/* begin calculating determinant - also used to calculated U parameter */
cross_v3_v3v3(pvec, dir, e2);
/* if determinant is near zero, ray lies in plane of triangle */
det = dot_v3v3(e1, pvec);
if (det > -0.000001 && det < 0.000001) {
Py_RETURN_NONE;
}
inv_det = 1.0f / det;
/* calculate distance from v1 to ray origin */
sub_v3_v3v3(tvec, orig, v1);
/* calculate U parameter and test bounds */
u = dot_v3v3(tvec, pvec) * inv_det;
if (clip && (u < 0.0f || u > 1.0f)) {
Py_RETURN_NONE;
}
/* prepare to test the V parameter */
cross_v3_v3v3(qvec, tvec, e1);
/* calculate V parameter and test bounds */
v = dot_v3v3(dir, qvec) * inv_det;
if (clip && (v < 0.0f || u + v > 1.0f)) {
Py_RETURN_NONE;
}
/* calculate t, ray intersects triangle */
t = dot_v3v3(e2, qvec) * inv_det;
mul_v3_fl(dir, t);
add_v3_v3v3(pvec, orig, dir);
return newVectorObject(pvec, 3, Py_NEW, NULL);
}
//----------------------------------Mathutils.LineIntersect() -------------------
/* Line-Line intersection using algorithm from mathworld.wolfram.com */
static PyObject *M_Geometry_LineIntersect( PyObject * self, PyObject * args )
{
PyObject * tuple;
VectorObject *vec1, *vec2, *vec3, *vec4;
float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3];
if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) {
PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
return NULL;
}
if( vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) {
PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" );
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4))
return NULL;
if( vec1->size == 3 || vec1->size == 2) {
int result;
if (vec1->size == 3) {
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec);
VECCOPY(v4, vec4->vec);
}
else {
v1[0] = vec1->vec[0];
v1[1] = vec1->vec[1];
v1[2] = 0.0f;
v2[0] = vec2->vec[0];
v2[1] = vec2->vec[1];
v2[2] = 0.0f;
v3[0] = vec3->vec[0];
v3[1] = vec3->vec[1];
v3[2] = 0.0f;
v4[0] = vec4->vec[0];
v4[1] = vec4->vec[1];
v4[2] = 0.0f;
}
result = isect_line_line_v3(v1, v2, v3, v4, i1, i2);
if (result == 0) {
/* colinear */
Py_RETURN_NONE;
}
else {
tuple = PyTuple_New( 2 );
PyTuple_SetItem( tuple, 0, newVectorObject(i1, vec1->size, Py_NEW, NULL) );
PyTuple_SetItem( tuple, 1, newVectorObject(i2, vec1->size, Py_NEW, NULL) );
return tuple;
}
}
else {
PyErr_SetString( PyExc_TypeError, "2D/3D vectors only\n" );
return NULL;
}
}
//---------------------------------NORMALS FUNCTIONS--------------------
//----------------------------------Mathutils.QuadNormal() -------------------
static PyObject *M_Geometry_QuadNormal( PyObject * self, PyObject * args )
{
VectorObject *vec1;
VectorObject *vec2;
VectorObject *vec3;
VectorObject *vec4;
float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3], n1[3], n2[3];
if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) {
PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
return NULL;
}
if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) {
PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" );
return NULL;
}
if( vec1->size != 3 ) {
PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4))
return NULL;
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec);
VECCOPY(v4, vec4->vec);
/* find vectors for two edges sharing v2 */
sub_v3_v3v3(e1, v1, v2);
sub_v3_v3v3(e2, v3, v2);
cross_v3_v3v3(n1, e2, e1);
normalize_v3(n1);
/* find vectors for two edges sharing v4 */
sub_v3_v3v3(e1, v3, v4);
sub_v3_v3v3(e2, v1, v4);
cross_v3_v3v3(n2, e2, e1);
normalize_v3(n2);
/* adding and averaging the normals of both triangles */
add_v3_v3v3(n1, n2, n1);
normalize_v3(n1);
return newVectorObject(n1, 3, Py_NEW, NULL);
}
//----------------------------Mathutils.TriangleNormal() -------------------
static PyObject *M_Geometry_TriangleNormal( PyObject * self, PyObject * args )
{
VectorObject *vec1, *vec2, *vec3;
float v1[3], v2[3], v3[3], e1[3], e2[3], n[3];
if( !PyArg_ParseTuple( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3 ) ) {
PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" );
return NULL;
}
if( vec1->size != vec2->size || vec1->size != vec3->size ) {
PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" );
return NULL;
}
if( vec1->size != 3 ) {
PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3))
return NULL;
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec);
/* find vectors for two edges sharing v2 */
sub_v3_v3v3(e1, v1, v2);
sub_v3_v3v3(e2, v3, v2);
cross_v3_v3v3(n, e2, e1);
normalize_v3(n);
return newVectorObject(n, 3, Py_NEW, NULL);
}
//--------------------------------- AREA FUNCTIONS--------------------
//----------------------------------Mathutils.TriangleArea() -------------------
static PyObject *M_Geometry_TriangleArea( PyObject * self, PyObject * args )
{
VectorObject *vec1, *vec2, *vec3;
float v1[3], v2[3], v3[3];
if( !PyArg_ParseTuple
( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
, &vector_Type, &vec3 ) ) {
PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n");
return NULL;
}
if( vec1->size != vec2->size || vec1->size != vec3->size ) {
PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" );
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3))
return NULL;
if (vec1->size == 3) {
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec);
return PyFloat_FromDouble( area_tri_v3(v1, v2, v3) );
}
else if (vec1->size == 2) {
v1[0] = vec1->vec[0];
v1[1] = vec1->vec[1];
v2[0] = vec2->vec[0];
v2[1] = vec2->vec[1];
v3[0] = vec3->vec[0];
v3[1] = vec3->vec[1];
return PyFloat_FromDouble( area_tri_v2(v1, v2, v3) );
}
else {
PyErr_SetString( PyExc_TypeError, "only 2D,3D vectors are supported\n" );
return NULL;
}
}
/*----------------------------------Geometry.PolyFill() -------------------*/
@@ -569,3 +804,43 @@ static PyObject *M_Geometry_BarycentricTransform(PyObject * self, PyObject * arg
return newVectorObject(vec, 3, Py_NEW, NULL);
}
struct PyMethodDef M_Geometry_methods[] = {
{"Intersect", ( PyCFunction ) M_Geometry_Intersect, METH_VARARGS, M_Geometry_Intersect_doc},
{"TriangleArea", ( PyCFunction ) M_Geometry_TriangleArea, METH_VARARGS, M_Geometry_TriangleArea_doc},
{"TriangleNormal", ( PyCFunction ) M_Geometry_TriangleNormal, METH_VARARGS, M_Geometry_TriangleNormal_doc},
{"QuadNormal", ( PyCFunction ) M_Geometry_QuadNormal, METH_VARARGS, M_Geometry_QuadNormal_doc},
{"LineIntersect", ( PyCFunction ) M_Geometry_LineIntersect, METH_VARARGS, M_Geometry_LineIntersect_doc},
{"PolyFill", ( PyCFunction ) M_Geometry_PolyFill, METH_O, M_Geometry_PolyFill_doc},
{"LineIntersect2D", ( PyCFunction ) M_Geometry_LineIntersect2D, METH_VARARGS, M_Geometry_LineIntersect2D_doc},
{"ClosestPointOnLine", ( PyCFunction ) M_Geometry_ClosestPointOnLine, METH_VARARGS, M_Geometry_ClosestPointOnLine_doc},
{"PointInTriangle2D", ( PyCFunction ) M_Geometry_PointInTriangle2D, METH_VARARGS, M_Geometry_PointInTriangle2D_doc},
{"PointInQuad2D", ( PyCFunction ) M_Geometry_PointInQuad2D, METH_VARARGS, M_Geometry_PointInQuad2D_doc},
{"BoxPack2D", ( PyCFunction ) M_Geometry_BoxPack2D, METH_O, M_Geometry_BoxPack2D_doc},
{"BezierInterp", ( PyCFunction ) M_Geometry_BezierInterp, METH_VARARGS, M_Geometry_BezierInterp_doc},
{"BarycentricTransform", ( PyCFunction ) M_Geometry_BarycentricTransform, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef M_Geometry_module_def = {
PyModuleDef_HEAD_INIT,
"Geometry", /* m_name */
M_Geometry_doc, /* m_doc */
0, /* m_size */
M_Geometry_methods, /* m_methods */
0, /* m_reload */
0, /* m_traverse */
0, /* m_clear */
0, /* m_free */
};
/*----------------------------MODULE INIT-------------------------*/
PyObject *Geometry_Init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&M_Geometry_module_def);
PyDict_SetItemString(PySys_GetObject("modules"), M_Geometry_module_def.m_name, submodule);
return (submodule);
}

View File

@@ -27,114 +27,34 @@
* ***** END GPL LICENSE BLOCK *****
*/
/* Note: Changes to Mathutils since 2.4x
* use radians rather then degrees
* - Mathutils.MidpointVecs --> vector.lerp(other, fac)
* - Mathutils.AngleBetweenVecs --> vector.angle(other)
* - Mathutils.ProjectVecs --> vector.project(other)
* - Mathutils.DifferenceQuats --> quat.difference(other)
* - Mathutils.Slerp --> quat.slerp(other, fac)
* - Mathutils.Rand: removed, use pythons random module
* - Mathutils.RotationMatrix(angle, size, axis_flag, axis) --> Mathutils.RotationMatrix(angle, size, axis); merge axis & axis_flag args
* - Matrix.scalePart --> Matrix.scale_part
* - Matrix.translationPart --> Matrix.translation_part
* - Matrix.rotationPart --> Matrix.rotation_part
* - toMatrix --> to_matrix
* - toEuler --> to_euler
* - toQuat --> to_quat
* - Vector.toTrackQuat --> Vector.to_track_quat
*
* Moved to Geometry module: Intersect, TriangleArea, TriangleNormal, QuadNormal, LineIntersect
*/
#include "Mathutils.h"
#include "BLI_math.h"
#include "PIL_time.h"
#include "BLI_rand.h"
#include "BKE_utildefines.h"
//-------------------------DOC STRINGS ---------------------------
static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n";
static char M_Mathutils_Rand_doc[] = "() - return a random number";
static char M_Mathutils_AngleBetweenVecs_doc[] = "() - returns the angle between two vectors in degrees";
static char M_Mathutils_MidpointVecs_doc[] = "() - return the vector to the midpoint between two vectors";
static char M_Mathutils_ProjectVecs_doc[] = "() - returns the projection vector from the projection of vecA onto vecB";
static char M_Mathutils_RotationMatrix_doc[] = "() - construct a rotation matrix from an angle and axis of rotation";
static char M_Mathutils_ScaleMatrix_doc[] = "() - construct a scaling matrix from a scaling factor";
static char M_Mathutils_OrthoProjectionMatrix_doc[] = "() - construct a orthographic projection matrix from a selected plane";
static char M_Mathutils_ShearMatrix_doc[] = "() - construct a shearing matrix from a plane of shear and a shear factor";
static char M_Mathutils_TranslationMatrix_doc[] = "(vec) - create a translation matrix from a vector";
static char M_Mathutils_Slerp_doc[] = "() - returns the interpolation between two quaternions";
static char M_Mathutils_DifferenceQuats_doc[] = "() - return the angular displacment difference between two quats";
static char M_Mathutils_Intersect_doc[] = "(v1, v2, v3, ray, orig, clip=1) - returns the intersection between a ray and a triangle, if possible, returns None otherwise";
static char M_Mathutils_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined";
static char M_Mathutils_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined";
static char M_Mathutils_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined";
static char M_Mathutils_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other";
//-----------------------METHOD DEFINITIONS ----------------------
static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args);
static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args);
static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args);
static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args);
static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args);
static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * value);
static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args);
static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args);
static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args);
static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args);
static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args);
static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args );
struct PyMethodDef M_Mathutils_methods[] = {
{"Rand", (PyCFunction) M_Mathutils_Rand, METH_VARARGS, M_Mathutils_Rand_doc},
{"AngleBetweenVecs", (PyCFunction) M_Mathutils_AngleBetweenVecs, METH_VARARGS, M_Mathutils_AngleBetweenVecs_doc},
{"MidpointVecs", (PyCFunction) M_Mathutils_MidpointVecs, METH_VARARGS, M_Mathutils_MidpointVecs_doc},
{"ProjectVecs", (PyCFunction) M_Mathutils_ProjectVecs, METH_VARARGS, M_Mathutils_ProjectVecs_doc},
{"RotationMatrix", (PyCFunction) M_Mathutils_RotationMatrix, METH_VARARGS, M_Mathutils_RotationMatrix_doc},
{"ScaleMatrix", (PyCFunction) M_Mathutils_ScaleMatrix, METH_VARARGS, M_Mathutils_ScaleMatrix_doc},
{"ShearMatrix", (PyCFunction) M_Mathutils_ShearMatrix, METH_VARARGS, M_Mathutils_ShearMatrix_doc},
{"TranslationMatrix", (PyCFunction) M_Mathutils_TranslationMatrix, METH_O, M_Mathutils_TranslationMatrix_doc},
{"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc},
{"DifferenceQuats", (PyCFunction) M_Mathutils_DifferenceQuats, METH_VARARGS,M_Mathutils_DifferenceQuats_doc},
{"Slerp", (PyCFunction) M_Mathutils_Slerp, METH_VARARGS, M_Mathutils_Slerp_doc},
{"Intersect", ( PyCFunction ) M_Mathutils_Intersect, METH_VARARGS, M_Mathutils_Intersect_doc},
{"TriangleArea", ( PyCFunction ) M_Mathutils_TriangleArea, METH_VARARGS, M_Mathutils_TriangleArea_doc},
{"TriangleNormal", ( PyCFunction ) M_Mathutils_TriangleNormal, METH_VARARGS, M_Mathutils_TriangleNormal_doc},
{"QuadNormal", ( PyCFunction ) M_Mathutils_QuadNormal, METH_VARARGS, M_Mathutils_QuadNormal_doc},
{"LineIntersect", ( PyCFunction ) M_Mathutils_LineIntersect, METH_VARARGS, M_Mathutils_LineIntersect_doc},
{NULL, NULL, 0, NULL}
};
/*----------------------------MODULE INIT-------------------------*/
/* from can be Blender.Mathutils or GameLogic.Mathutils for the BGE */
static struct PyModuleDef M_Mathutils_module_def = {
PyModuleDef_HEAD_INIT,
"Mathutils", /* m_name */
M_Mathutils_doc, /* m_doc */
0, /* m_size */
M_Mathutils_methods, /* m_methods */
0, /* m_reload */
0, /* m_traverse */
0, /* m_clear */
0, /* m_free */
};
PyObject *Mathutils_Init(void)
{
PyObject *submodule;
//seed the generator for the rand function
BLI_srand((unsigned int) (PIL_check_seconds_timer() * 0x7FFFFFFF));
if( PyType_Ready( &vector_Type ) < 0 )
return NULL;
if( PyType_Ready( &matrix_Type ) < 0 )
return NULL;
if( PyType_Ready( &euler_Type ) < 0 )
return NULL;
if( PyType_Ready( &quaternion_Type ) < 0 )
return NULL;
submodule = PyModule_Create(&M_Mathutils_module_def);
PyDict_SetItemString(PySys_GetObject("modules"), M_Mathutils_module_def.m_name, submodule);
/* each type has its own new() function */
PyModule_AddObject( submodule, "Vector", (PyObject *)&vector_Type );
PyModule_AddObject( submodule, "Matrix", (PyObject *)&matrix_Type );
PyModule_AddObject( submodule, "Euler", (PyObject *)&euler_Type );
PyModule_AddObject( submodule, "Quaternion", (PyObject *)&quaternion_Type );
mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb);
return (submodule);
}
static char M_Mathutils_doc[] = "This module provides access to matrices, eulers, quaternions and vectors.";
//-----------------------------METHODS----------------------------
//-----------------quat_rotation (internal)-----------
@@ -204,164 +124,49 @@ PyObject *quat_rotation(PyObject *arg1, PyObject *arg2)
}
//----------------------------------Mathutils.Rand() --------------------
//returns a random number between a high and low value
static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args)
{
float high, low, range;
double drand;
//initializers
high = 1.0;
low = 0.0;
if(!PyArg_ParseTuple(args, "|ff", &low, &high)) {
PyErr_SetString(PyExc_TypeError, "Mathutils.Rand(): expected nothing or optional (float, float)\n");
return NULL;
}
if((high < low) || (high < 0 && low > 0)) {
PyErr_SetString(PyExc_ValueError, "Mathutils.Rand(): high value should be larger than low value\n");
return NULL;
}
//get the random number 0 - 1
drand = BLI_drand();
//set it to range
range = high - low;
drand = drand * range;
drand = drand + low;
return PyFloat_FromDouble(drand);
}
//----------------------------------VECTOR FUNCTIONS---------------------
//----------------------------------Mathutils.AngleBetweenVecs() ---------
//calculates the angle between 2 vectors
static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f;
int x, size;
if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
goto AttributeError1; //not vectors
if(vec1->size != vec2->size)
goto AttributeError1; //bad sizes
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
return NULL;
//since size is the same....
size = vec1->size;
for(x = 0; x < size; x++) {
test_v1 += vec1->vec[x] * vec1->vec[x];
test_v2 += vec2->vec[x] * vec2->vec[x];
}
if (!test_v1 || !test_v2){
goto AttributeError2; //zero-length vector
}
//dot product
for(x = 0; x < size; x++) {
dot += vec1->vec[x] * vec2->vec[x];
}
dot /= (sqrt(test_v1) * sqrt(test_v2));
angleRads = (double)saacos(dot);
#ifdef USE_MATHUTILS_DEG
return PyFloat_FromDouble(angleRads * (180/ Py_PI));
#else
return PyFloat_FromDouble(angleRads);
#endif
AttributeError1:
PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n");
return NULL;
AttributeError2:
PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): zero length vectors are not acceptable arguments\n");
return NULL;
}
//----------------------------------Mathutils.MidpointVecs() -------------
//calculates the midpoint between 2 vectors
static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
float vec[4];
int x;
if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) {
PyErr_SetString(PyExc_TypeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
return NULL;
}
if(vec1->size != vec2->size) {
PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
return NULL;
for(x = 0; x < vec1->size; x++) {
vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]);
}
return newVectorObject(vec, vec1->size, Py_NEW, NULL);
}
//----------------------------------Mathutils.ProjectVecs() -------------
//projects vector 1 onto vector 2
static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
float vec[4];
double dot = 0.0f, dot2 = 0.0f;
int x, size;
if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) {
PyErr_SetString(PyExc_TypeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n");
return NULL;
}
if(vec1->size != vec2->size) {
PyErr_SetString(PyExc_AttributeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n");
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
return NULL;
//since they are the same size...
size = vec1->size;
//get dot products
for(x = 0; x < size; x++) {
dot += vec1->vec[x] * vec2->vec[x];
dot2 += vec2->vec[x] * vec2->vec[x];
}
//projection
dot /= dot2;
for(x = 0; x < size; x++) {
vec[x] = (float)(dot * vec2->vec[x]);
}
return newVectorObject(vec, size, Py_NEW, NULL);
}
//----------------------------------MATRIX FUNCTIONS--------------------
//----------------------------------Mathutils.RotationMatrix() ----------
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
//creates a rotation matrix
static char M_Mathutils_RotationMatrix_doc[] =
".. function:: RotationMatrix(angle, size, axis)\n"
"\n"
" Create a matrix representing a rotation.\n"
"\n"
" :arg angle: The angle of rotation desired.\n"
" :type angle: float\n"
" :arg size: The size of the rotation matrix to construct [2, 4].\n"
" :type size: int\n"
" :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object (optional when size is 2).\n"
" :type axis: string or vector\n"
" :return: A new rotation matrix.\n"
" :rtype: Matrix\n";
static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
{
VectorObject *vec = NULL;
char *axis = NULL;
VectorObject *vec= NULL;
char *axis= NULL;
int matSize;
float angle = 0.0f;
float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
if(!PyArg_ParseTuple(args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec)) {
PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(): expected float int and optional string and vector\n");
if(!PyArg_ParseTuple(args, "fi|O", &angle, &matSize, &vec)) {
PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(angle, size, axis): expected float int and a string or vector\n");
return NULL;
}
if(vec && !VectorObject_Check(vec)) {
axis= _PyUnicode_AsString((PyObject *)vec);
if(axis==NULL || axis[0]=='\0' || axis[1]!='\0' || axis[0] < 'X' || axis[0] > 'Z') {
PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(): 3rd argument axis value must be a 3D vector or a string in 'X', 'Y', 'Z'\n");
return NULL;
}
else {
/* use the string */
vec= NULL;
}
}
#ifdef USE_MATHUTILS_DEG
/* Clamp to -360:360 */
while (angle<-360.0f)
@@ -379,23 +184,17 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
return NULL;
}
if(matSize == 2 && (axis != NULL || vec != NULL)) {
if(matSize == 2 && (vec != NULL)) {
PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n");
return NULL;
}
if((matSize == 3 || matSize == 4) && axis == NULL) {
if((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) {
PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n");
return NULL;
}
if(axis) {
if(((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) && vec == NULL) {
PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please define the arbitrary axis of rotation\n");
return NULL;
}
}
if(vec) {
if(vec->size != 3) {
PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n");
PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): the vector axis must be a 3D vector\n");
return NULL;
}
@@ -414,35 +213,32 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
mat[1] = (float) sin (angle);
mat[2] = -((float) sin(angle));
mat[3] = (float) cos(angle);
} else if((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0)) {
} else if(strcmp(axis, "X") == 0) {
//rotation around X
mat[0] = 1.0f;
mat[4] = (float) cos(angle);
mat[5] = (float) sin(angle);
mat[7] = -((float) sin(angle));
mat[8] = (float) cos(angle);
} else if((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0)) {
} else if(strcmp(axis, "Y") == 0) {
//rotation around Y
mat[0] = (float) cos(angle);
mat[2] = -((float) sin(angle));
mat[4] = 1.0f;
mat[6] = (float) sin(angle);
mat[8] = (float) cos(angle);
} else if((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0)) {
} else if(strcmp(axis, "Z") == 0) {
//rotation around Z
mat[0] = (float) cos(angle);
mat[1] = (float) sin(angle);
mat[3] = -((float) sin(angle));
mat[4] = (float) cos(angle);
mat[8] = 1.0f;
} else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) {
//arbitrary rotation
axis_angle_to_mat3( (float (*)[3])mat,vec->vec, angle);
} else {
PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n");
return NULL;
/* check for valid vector/axis above */
axis_angle_to_mat3( (float (*)[3])mat,vec->vec, angle);
}
if(matSize == 4) {
//resize matrix
mat[10] = mat[8];
@@ -457,8 +253,17 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
//pass to matrix creation
return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL);
}
//----------------------------------Mathutils.TranslationMatrix() -------
//creates a translation matrix
static char M_Mathutils_TranslationMatrix_doc[] =
".. function:: TranslationMatrix(vector)\n"
"\n"
" Create a matrix representing a translation.\n"
"\n"
" :arg vector: The translation vector.\n"
" :type vector: Vector\n"
" :return: An identity matrix with a translation.\n"
" :rtype: Matrix\n";
static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * vec)
{
float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
@@ -486,7 +291,20 @@ static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * v
}
//----------------------------------Mathutils.ScaleMatrix() -------------
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
//creates a scaling matrix
static char M_Mathutils_ScaleMatrix_doc[] =
".. function:: ScaleMatrix(factor, size, axis)\n"
"\n"
" Create a matrix representing a scaling.\n"
"\n"
" :arg factor: The factor of scaling to apply.\n"
" :type factor: float\n"
" :arg size: The size of the scale matrix to construct [2, 4].\n"
" :type size: int\n"
" :arg axis: Direction to influence scale. (optional).\n"
" :type axis: Vector\n"
" :return: A new scale matrix.\n"
" :rtype: Matrix\n";
static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args)
{
VectorObject *vec = NULL;
@@ -564,7 +382,19 @@ static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args)
}
//----------------------------------Mathutils.OrthoProjectionMatrix() ---
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
//creates an ortho projection matrix
static char M_Mathutils_OrthoProjectionMatrix_doc[] =
".. function:: OrthoProjectionMatrix(plane, size, axis)\n"
"\n"
" Create a matrix to represent an orthographic projection.\n"
"\n"
" :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ', 'R'], where a single axis is for a 2D matrix and 'R' requires axis is given.\n"
" :type plane: string\n"
" :arg size: The size of the projection matrix to construct [2, 4].\n"
" :type size: int\n"
" :arg axis: Arbitrary perpendicular plane vector.\n"
" :type axis: vector (optional)\n"
" :return: A new projection matrix.\n"
" :rtype: Matrix\n";
static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args)
{
VectorObject *vec = NULL;
@@ -593,30 +423,21 @@ static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * a
}
if(vec == NULL) { //ortho projection onto cardinal plane
if(((strcmp(plane, "x") == 0)
|| (strcmp(plane, "X") == 0)) && matSize == 2) {
if((strcmp(plane, "X") == 0) && matSize == 2) {
mat[0] = 1.0f;
} else if(((strcmp(plane, "y") == 0)
|| (strcmp(plane, "Y") == 0))
&& matSize == 2) {
} else if((strcmp(plane, "Y") == 0) && matSize == 2) {
mat[3] = 1.0f;
} else if(((strcmp(plane, "xy") == 0)
|| (strcmp(plane, "XY") == 0))
&& matSize > 2) {
} else if((strcmp(plane, "XY") == 0) && matSize > 2) {
mat[0] = 1.0f;
mat[4] = 1.0f;
} else if(((strcmp(plane, "xz") == 0)
|| (strcmp(plane, "XZ") == 0))
&& matSize > 2) {
} else if((strcmp(plane, "XZ") == 0) && matSize > 2) {
mat[0] = 1.0f;
mat[8] = 1.0f;
} else if(((strcmp(plane, "yz") == 0)
|| (strcmp(plane, "YZ") == 0))
&& matSize > 2) {
} else if((strcmp(plane, "YZ") == 0) && matSize > 2) {
mat[4] = 1.0f;
mat[8] = 1.0f;
} else {
PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: x, y, xy, xz, yz\n");
PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: X, Y, XY, XZ, YZ\n");
return NULL;
}
} else { //arbitrary plane
@@ -628,15 +449,12 @@ static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * a
for(x = 0; x < vec->size; x++) {
vec->vec[x] /= norm;
}
if(((strcmp(plane, "r") == 0)
|| (strcmp(plane, "R") == 0)) && matSize == 2) {
if((strcmp(plane, "R") == 0) && matSize == 2) {
mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
mat[1] = -(vec->vec[0] * vec->vec[1]);
mat[2] = -(vec->vec[0] * vec->vec[1]);
mat[3] = 1 - (vec->vec[1] * vec->vec[1]);
} else if(((strcmp(plane, "r") == 0)
|| (strcmp(plane, "R") == 0))
&& matSize > 2) {
} else if((strcmp(plane, "R") == 0) && matSize > 2) {
mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
mat[1] = -(vec->vec[0] * vec->vec[1]);
mat[2] = -(vec->vec[0] * vec->vec[2]);
@@ -665,8 +483,21 @@ static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * a
//pass to matrix creation
return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL);
}
//----------------------------------Mathutils.ShearMatrix() -------------
//creates a shear matrix
static char M_Mathutils_ShearMatrix_doc[] =
".. function:: ShearMatrix(plane, factor, size)\n"
"\n"
" Create a matrix to represent an shear transformation.\n"
"\n"
" :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'], where a single axis is for a 2D matrix.\n"
" :type plane: string\n"
" :arg factor: The factor of shear to apply.\n"
" :type factor: float\n"
" :arg size: The size of the shear matrix to construct [2, 4].\n"
" :type size: int\n"
" :return: A new shear matrix.\n"
" :rtype: Matrix\n";
static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args)
{
int matSize;
@@ -684,31 +515,27 @@ static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args)
return NULL;
}
if(((strcmp(plane, "x") == 0) || (strcmp(plane, "X") == 0))
if((strcmp(plane, "X") == 0)
&& matSize == 2) {
mat[0] = 1.0f;
mat[2] = factor;
mat[3] = 1.0f;
} else if(((strcmp(plane, "y") == 0)
|| (strcmp(plane, "Y") == 0)) && matSize == 2) {
} else if((strcmp(plane, "Y") == 0) && matSize == 2) {
mat[0] = 1.0f;
mat[1] = factor;
mat[3] = 1.0f;
} else if(((strcmp(plane, "xy") == 0)
|| (strcmp(plane, "XY") == 0)) && matSize > 2) {
} else if((strcmp(plane, "XY") == 0) && matSize > 2) {
mat[0] = 1.0f;
mat[4] = 1.0f;
mat[6] = factor;
mat[7] = factor;
} else if(((strcmp(plane, "xz") == 0)
|| (strcmp(plane, "XZ") == 0)) && matSize > 2) {
} else if((strcmp(plane, "XZ") == 0) && matSize > 2) {
mat[0] = 1.0f;
mat[3] = factor;
mat[4] = 1.0f;
mat[5] = factor;
mat[8] = 1.0f;
} else if(((strcmp(plane, "yz") == 0)
|| (strcmp(plane, "YZ") == 0)) && matSize > 2) {
} else if((strcmp(plane, "YZ") == 0) && matSize > 2) {
mat[0] = 1.0f;
mat[1] = factor;
mat[2] = factor;
@@ -732,375 +559,6 @@ static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args)
//pass to matrix creation
return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL);
}
//----------------------------------QUATERNION FUNCTIONS-----------------
//----------------------------------Mathutils.DifferenceQuats() ---------
//returns the difference between 2 quaternions
static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args)
{
QuaternionObject *quatU = NULL, *quatV = NULL;
float quat[4], tempQuat[4];
double dot = 0.0f;
int x;
if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU, &quaternion_Type, &quatV)) {
PyErr_SetString(PyExc_TypeError, "Mathutils.DifferenceQuats(): expected Quaternion types");
return NULL;
}
if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV))
return NULL;
tempQuat[0] = quatU->quat[0];
tempQuat[1] = -quatU->quat[1];
tempQuat[2] = -quatU->quat[2];
tempQuat[3] = -quatU->quat[3];
dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] +
tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]);
for(x = 0; x < 4; x++) {
tempQuat[x] /= (float)(dot * dot);
}
mul_qt_qtqt(quat, tempQuat, quatV->quat);
return newQuaternionObject(quat, Py_NEW, NULL);
}
//----------------------------------Mathutils.Slerp() ------------------
//attemps to interpolate 2 quaternions and return the result
static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args)
{
QuaternionObject *quatU = NULL, *quatV = NULL;
float quat[4], quat_u[4], quat_v[4], param;
double x, y, dot, sinT, angle, IsinT;
int z;
if(!PyArg_ParseTuple(args, "O!O!f", &quaternion_Type, &quatU, &quaternion_Type, &quatV, &param)) {
PyErr_SetString(PyExc_TypeError, "Mathutils.Slerp(): expected Quaternion types and float");
return NULL;
}
if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV))
return NULL;
if(param > 1.0f || param < 0.0f) {
PyErr_SetString(PyExc_AttributeError, "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0");
return NULL;
}
//copy quats
for(z = 0; z < 4; z++){
quat_u[z] = quatU->quat[z];
quat_v[z] = quatV->quat[z];
}
//dot product
dot = quat_u[0] * quat_v[0] + quat_u[1] * quat_v[1] +
quat_u[2] * quat_v[2] + quat_u[3] * quat_v[3];
//if negative negate a quat (shortest arc)
if(dot < 0.0f) {
quat_v[0] = -quat_v[0];
quat_v[1] = -quat_v[1];
quat_v[2] = -quat_v[2];
quat_v[3] = -quat_v[3];
dot = -dot;
}
if(dot > .99999f) { //very close
x = 1.0f - param;
y = param;
} else {
//calculate sin of angle
sinT = sqrt(1.0f - (dot * dot));
//calculate angle
angle = atan2(sinT, dot);
//caluculate inverse of sin(theta)
IsinT = 1.0f / sinT;
x = sin((1.0f - param) * angle) * IsinT;
y = sin(param * angle) * IsinT;
}
//interpolate
quat[0] = (float)(quat_u[0] * x + quat_v[0] * y);
quat[1] = (float)(quat_u[1] * x + quat_v[1] * y);
quat[2] = (float)(quat_u[2] * x + quat_v[2] * y);
quat[3] = (float)(quat_u[3] * x + quat_v[3] * y);
return newQuaternionObject(quat, Py_NEW, NULL);
}
//----------------------------------EULER FUNCTIONS----------------------
//---------------------------------INTERSECTION FUNCTIONS--------------------
//----------------------------------Mathutils.Intersect() -------------------
static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args )
{
VectorObject *ray, *ray_off, *vec1, *vec2, *vec3;
float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
float det, inv_det, u, v, t;
int clip = 1;
if(!PyArg_ParseTuple(args, "O!O!O!O!O!|i", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off , &clip)) {
PyErr_SetString( PyExc_TypeError, "expected 5 vector types\n" );
return NULL;
}
if(vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) {
PyErr_SetString( PyExc_TypeError, "only 3D vectors for all parameters\n");
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(ray) || !BaseMath_ReadCallback(ray_off))
return NULL;
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec);
VECCOPY(dir, ray->vec);
normalize_v3(dir);
VECCOPY(orig, ray_off->vec);
/* find vectors for two edges sharing v1 */
sub_v3_v3v3(e1, v2, v1);
sub_v3_v3v3(e2, v3, v1);
/* begin calculating determinant - also used to calculated U parameter */
cross_v3_v3v3(pvec, dir, e2);
/* if determinant is near zero, ray lies in plane of triangle */
det = dot_v3v3(e1, pvec);
if (det > -0.000001 && det < 0.000001) {
Py_RETURN_NONE;
}
inv_det = 1.0f / det;
/* calculate distance from v1 to ray origin */
sub_v3_v3v3(tvec, orig, v1);
/* calculate U parameter and test bounds */
u = dot_v3v3(tvec, pvec) * inv_det;
if (clip && (u < 0.0f || u > 1.0f)) {
Py_RETURN_NONE;
}
/* prepare to test the V parameter */
cross_v3_v3v3(qvec, tvec, e1);
/* calculate V parameter and test bounds */
v = dot_v3v3(dir, qvec) * inv_det;
if (clip && (v < 0.0f || u + v > 1.0f)) {
Py_RETURN_NONE;
}
/* calculate t, ray intersects triangle */
t = dot_v3v3(e2, qvec) * inv_det;
mul_v3_fl(dir, t);
add_v3_v3v3(pvec, orig, dir);
return newVectorObject(pvec, 3, Py_NEW, NULL);
}
//----------------------------------Mathutils.LineIntersect() -------------------
/* Line-Line intersection using algorithm from mathworld.wolfram.com */
static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args )
{
PyObject * tuple;
VectorObject *vec1, *vec2, *vec3, *vec4;
float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3];
if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) {
PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
return NULL;
}
if( vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) {
PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" );
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4))
return NULL;
if( vec1->size == 3 || vec1->size == 2) {
int result;
if (vec1->size == 3) {
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec);
VECCOPY(v4, vec4->vec);
}
else {
v1[0] = vec1->vec[0];
v1[1] = vec1->vec[1];
v1[2] = 0.0f;
v2[0] = vec2->vec[0];
v2[1] = vec2->vec[1];
v2[2] = 0.0f;
v3[0] = vec3->vec[0];
v3[1] = vec3->vec[1];
v3[2] = 0.0f;
v4[0] = vec4->vec[0];
v4[1] = vec4->vec[1];
v4[2] = 0.0f;
}
result = isect_line_line_v3(v1, v2, v3, v4, i1, i2);
if (result == 0) {
/* colinear */
Py_RETURN_NONE;
}
else {
tuple = PyTuple_New( 2 );
PyTuple_SetItem( tuple, 0, newVectorObject(i1, vec1->size, Py_NEW, NULL) );
PyTuple_SetItem( tuple, 1, newVectorObject(i2, vec1->size, Py_NEW, NULL) );
return tuple;
}
}
else {
PyErr_SetString( PyExc_TypeError, "2D/3D vectors only\n" );
return NULL;
}
}
//---------------------------------NORMALS FUNCTIONS--------------------
//----------------------------------Mathutils.QuadNormal() -------------------
static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args )
{
VectorObject *vec1;
VectorObject *vec2;
VectorObject *vec3;
VectorObject *vec4;
float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3], n1[3], n2[3];
if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) {
PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
return NULL;
}
if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) {
PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" );
return NULL;
}
if( vec1->size != 3 ) {
PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4))
return NULL;
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec);
VECCOPY(v4, vec4->vec);
/* find vectors for two edges sharing v2 */
sub_v3_v3v3(e1, v1, v2);
sub_v3_v3v3(e2, v3, v2);
cross_v3_v3v3(n1, e2, e1);
normalize_v3(n1);
/* find vectors for two edges sharing v4 */
sub_v3_v3v3(e1, v3, v4);
sub_v3_v3v3(e2, v1, v4);
cross_v3_v3v3(n2, e2, e1);
normalize_v3(n2);
/* adding and averaging the normals of both triangles */
add_v3_v3v3(n1, n2, n1);
normalize_v3(n1);
return newVectorObject(n1, 3, Py_NEW, NULL);
}
//----------------------------Mathutils.TriangleNormal() -------------------
static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args )
{
VectorObject *vec1, *vec2, *vec3;
float v1[3], v2[3], v3[3], e1[3], e2[3], n[3];
if( !PyArg_ParseTuple( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3 ) ) {
PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" );
return NULL;
}
if( vec1->size != vec2->size || vec1->size != vec3->size ) {
PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" );
return NULL;
}
if( vec1->size != 3 ) {
PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3))
return NULL;
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec);
/* find vectors for two edges sharing v2 */
sub_v3_v3v3(e1, v1, v2);
sub_v3_v3v3(e2, v3, v2);
cross_v3_v3v3(n, e2, e1);
normalize_v3(n);
return newVectorObject(n, 3, Py_NEW, NULL);
}
//--------------------------------- AREA FUNCTIONS--------------------
//----------------------------------Mathutils.TriangleArea() -------------------
static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args )
{
VectorObject *vec1, *vec2, *vec3;
float v1[3], v2[3], v3[3];
if( !PyArg_ParseTuple
( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
, &vector_Type, &vec3 ) ) {
PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n");
return NULL;
}
if( vec1->size != vec2->size || vec1->size != vec3->size ) {
PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" );
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3))
return NULL;
if (vec1->size == 3) {
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec);
return PyFloat_FromDouble( area_tri_v3(v1, v2, v3) );
}
else if (vec1->size == 2) {
v1[0] = vec1->vec[0];
v1[1] = vec1->vec[1];
v2[0] = vec2->vec[0];
v2[1] = vec2->vec[1];
v3[0] = vec3->vec[0];
v3[1] = vec3->vec[1];
return PyFloat_FromDouble( area_tri_v2(v1, v2, v3) );
}
else {
PyErr_SetString( PyExc_TypeError, "only 2D,3D vectors are supported\n" );
return NULL;
}
}
/* Utility functions */
@@ -1219,3 +677,51 @@ void BaseMathObject_dealloc(BaseMathObject * self)
Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes
}
/*----------------------------MODULE INIT-------------------------*/
struct PyMethodDef M_Mathutils_methods[] = {
{"RotationMatrix", (PyCFunction) M_Mathutils_RotationMatrix, METH_VARARGS, M_Mathutils_RotationMatrix_doc},
{"ScaleMatrix", (PyCFunction) M_Mathutils_ScaleMatrix, METH_VARARGS, M_Mathutils_ScaleMatrix_doc},
{"ShearMatrix", (PyCFunction) M_Mathutils_ShearMatrix, METH_VARARGS, M_Mathutils_ShearMatrix_doc},
{"TranslationMatrix", (PyCFunction) M_Mathutils_TranslationMatrix, METH_O, M_Mathutils_TranslationMatrix_doc},
{"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef M_Mathutils_module_def = {
PyModuleDef_HEAD_INIT,
"Mathutils", /* m_name */
M_Mathutils_doc, /* m_doc */
0, /* m_size */
M_Mathutils_methods, /* m_methods */
0, /* m_reload */
0, /* m_traverse */
0, /* m_clear */
0, /* m_free */
};
PyObject *Mathutils_Init(void)
{
PyObject *submodule;
if( PyType_Ready( &vector_Type ) < 0 )
return NULL;
if( PyType_Ready( &matrix_Type ) < 0 )
return NULL;
if( PyType_Ready( &euler_Type ) < 0 )
return NULL;
if( PyType_Ready( &quaternion_Type ) < 0 )
return NULL;
submodule = PyModule_Create(&M_Mathutils_module_def);
PyDict_SetItemString(PySys_GetObject("modules"), M_Mathutils_module_def.m_name, submodule);
/* each type has its own new() function */
PyModule_AddObject( submodule, "Vector", (PyObject *)&vector_Type );
PyModule_AddObject( submodule, "Matrix", (PyObject *)&matrix_Type );
PyModule_AddObject( submodule, "Euler", (PyObject *)&euler_Type );
PyModule_AddObject( submodule, "Quaternion", (PyObject *)&quaternion_Type );
mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb);
return (submodule);
}

View File

@@ -33,29 +33,6 @@
#include "BLI_blenlib.h"
//-------------------------DOC STRINGS ---------------------------
static PyObject *Euler_Zero( EulerObject * self );
static PyObject *Euler_Unique( EulerObject * self );
static PyObject *Euler_ToMatrix( EulerObject * self );
static PyObject *Euler_ToQuat( EulerObject * self );
static PyObject *Euler_Rotate( EulerObject * self, PyObject *args );
static PyObject *Euler_MakeCompatible( EulerObject * self, EulerObject *value );
static PyObject *Euler_copy( EulerObject * self, PyObject *args );
//-----------------------METHOD DEFINITIONS ----------------------
static struct PyMethodDef Euler_methods[] = {
{"zero", (PyCFunction) Euler_Zero, METH_NOARGS, NULL},
{"unique", (PyCFunction) Euler_Unique, METH_NOARGS, NULL},
{"toMatrix", (PyCFunction) Euler_ToMatrix, METH_NOARGS, NULL},
{"toQuat", (PyCFunction) Euler_ToQuat, METH_NOARGS, NULL},
{"rotate", (PyCFunction) Euler_Rotate, METH_VARARGS, NULL},
{"makeCompatible", (PyCFunction) Euler_MakeCompatible, METH_O, NULL},
{"__copy__", (PyCFunction) Euler_copy, METH_VARARGS, NULL},
{"copy", (PyCFunction) Euler_copy, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
//----------------------------------Mathutils.Euler() -------------------
//makes a new euler for you to play with
static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwargs)
@@ -108,6 +85,15 @@ static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwar
//-----------------------------METHODS----------------------------
//----------------------------Euler.toQuat()----------------------
//return a quaternion representation of the euler
static char Euler_ToQuat_doc[] =
".. method:: to_quat()\n"
"\n"
" Return a quaternion representation of the euler.\n"
"\n"
" :return: Quaternion representation of the euler.\n"
" :rtype: Quaternion\n";
static PyObject *Euler_ToQuat(EulerObject * self)
{
float quat[4];
@@ -132,6 +118,14 @@ static PyObject *Euler_ToQuat(EulerObject * self)
}
//----------------------------Euler.toMatrix()---------------------
//return a matrix representation of the euler
static char Euler_ToMatrix_doc[] =
".. method:: to_matrix()\n"
"\n"
" Return a matrix representation of the euler.\n"
"\n"
" :return: A 3x3 roation matrix representation of the euler.\n"
" :rtype: Matrix\n";
static PyObject *Euler_ToMatrix(EulerObject * self)
{
float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
@@ -156,6 +150,14 @@ static PyObject *Euler_ToMatrix(EulerObject * self)
}
//----------------------------Euler.unique()-----------------------
//sets the x,y,z values to a unique euler rotation
static char Euler_Unique_doc[] =
".. method:: unique()\n"
"\n"
" Calculate a unique rotation for this euler. Avoids gimble lock.\n"
" :return: an instance of itself\n"
" :rtype: Euler\n";
static PyObject *Euler_Unique(EulerObject * self)
{
#define PI_2 (Py_PI * 2.0)
@@ -220,6 +222,13 @@ static PyObject *Euler_Unique(EulerObject * self)
}
//----------------------------Euler.zero()-------------------------
//sets the euler to 0,0,0
static char Euler_Zero_doc[] =
".. method:: zero()\n"
"\n"
" Set all values to zero.\n"
" :return: an instance of itself\n"
" :rtype: Euler\n";
static PyObject *Euler_Zero(EulerObject * self)
{
self->eul[0] = 0.0;
@@ -278,6 +287,16 @@ static PyObject *Euler_Rotate(EulerObject * self, PyObject *args)
return (PyObject *)self;
}
static char Euler_MakeCompatible_doc[] =
".. method:: make_compatible(other)\n"
"\n"
" Make this euler compatible with another, so interpolating between them works as intended.\n"
"\n"
" :arg other: make compatible with this rotation.\n"
" :type other: Euler\n"
" :return: an instance of itself.\n"
" :rtype: Euler\n";
static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value)
{
#ifdef USE_MATHUTILS_DEG
@@ -317,6 +336,17 @@ static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value)
//----------------------------Euler.rotate()-----------------------
// return a copy of the euler
static char Euler_copy_doc[] =
".. function:: copy()\n"
"\n"
" Returns a copy of this euler.\n"
"\n"
" :return: A copy of the euler.\n"
" :rtype: Euler\n"
"\n"
" .. note:: use this to get a copy of a wrapped euler with no reference to the original data.\n";
static PyObject *Euler_copy(EulerObject * self, PyObject *args)
{
if(!BaseMath_ReadCallback(self))
@@ -545,6 +575,20 @@ static PyGetSetDef Euler_getseters[] = {
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
//-----------------------METHOD DEFINITIONS ----------------------
static struct PyMethodDef Euler_methods[] = {
{"zero", (PyCFunction) Euler_Zero, METH_NOARGS, Euler_Zero_doc},
{"unique", (PyCFunction) Euler_Unique, METH_NOARGS, Euler_Unique_doc},
{"to_matrix", (PyCFunction) Euler_ToMatrix, METH_NOARGS, Euler_ToMatrix_doc},
{"to_quat", (PyCFunction) Euler_ToQuat, METH_NOARGS, Euler_ToQuat_doc},
{"rotate", (PyCFunction) Euler_Rotate, METH_VARARGS, NULL},
{"make_compatible", (PyCFunction) Euler_MakeCompatible, METH_O, Euler_MakeCompatible_doc},
{"__copy__", (PyCFunction) Euler_copy, METH_VARARGS, Euler_copy_doc},
{"copy", (PyCFunction) Euler_copy, METH_VARARGS, Euler_copy_doc},
{NULL, NULL, 0, NULL}
};
//------------------PY_OBECT DEFINITION--------------------------
PyTypeObject euler_Type = {
PyVarObject_HEAD_INIT(NULL, 0)

View File

@@ -105,39 +105,6 @@ Mathutils_Callback mathutils_matrix_vector_cb = {
};
/* matrix vector callbacks, this is so you can do matrix[i][j] = val */
/*-------------------------DOC STRINGS ---------------------------*/
static PyObject *Matrix_Zero( MatrixObject * self );
static PyObject *Matrix_Identity( MatrixObject * self );
static PyObject *Matrix_Transpose( MatrixObject * self );
static PyObject *Matrix_Determinant( MatrixObject * self );
static PyObject *Matrix_Invert( MatrixObject * self );
static PyObject *Matrix_TranslationPart( MatrixObject * self );
static PyObject *Matrix_RotationPart( MatrixObject * self );
static PyObject *Matrix_scalePart( MatrixObject * self );
static PyObject *Matrix_Resize4x4( MatrixObject * self );
static PyObject *Matrix_toEuler( MatrixObject * self, PyObject *args );
static PyObject *Matrix_toQuat( MatrixObject * self );
static PyObject *Matrix_copy( MatrixObject * self );
/*-----------------------METHOD DEFINITIONS ----------------------*/
static struct PyMethodDef Matrix_methods[] = {
{"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, NULL},
{"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, NULL},
{"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, NULL},
{"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, NULL},
{"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, NULL},
{"translationPart", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, NULL},
{"rotationPart", (PyCFunction) Matrix_RotationPart, METH_NOARGS, NULL},
{"scalePart", (PyCFunction) Matrix_scalePart, METH_NOARGS, NULL},
{"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, NULL},
{"toEuler", (PyCFunction) Matrix_toEuler, METH_VARARGS, NULL},
{"toQuat", (PyCFunction) Matrix_toQuat, METH_NOARGS, NULL},
{"copy", (PyCFunction) Matrix_copy, METH_NOARGS, NULL},
{"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
};
//----------------------------------Mathutils.Matrix() -----------------
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
//create a new matrix type
@@ -214,8 +181,33 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return newMatrixObject(matrix, argSize, seqSize, Py_NEW, NULL);
}
/* assumes rowsize == colsize is checked and the read callback has run */
static float matrix_determinant(MatrixObject * self)
{
if(self->rowSize == 2) {
return determinant_m2(self->matrix[0][0], self->matrix[0][1],
self->matrix[1][0], self->matrix[1][1]);
} else if(self->rowSize == 3) {
return determinant_m3(self->matrix[0][0], self->matrix[0][1],
self->matrix[0][2], self->matrix[1][0],
self->matrix[1][1], self->matrix[1][2],
self->matrix[2][0], self->matrix[2][1],
self->matrix[2][2]);
} else {
return determinant_m4((float (*)[4]) *self->matrix);
}
}
/*-----------------------------METHODS----------------------------*/
/*---------------------------Matrix.toQuat() ---------------------*/
static char Matrix_toQuat_doc[] =
".. method:: to_quat()\n"
"\n"
" Return a quaternion representation of the rotation matrix.\n"
"\n"
" :return: Quaternion representation of the rotation matrix.\n"
" :rtype: Quaternion\n";
static PyObject *Matrix_toQuat(MatrixObject * self)
{
float quat[4];
@@ -237,6 +229,16 @@ static PyObject *Matrix_toQuat(MatrixObject * self)
return newQuaternionObject(quat, Py_NEW, NULL);
}
/*---------------------------Matrix.toEuler() --------------------*/
static char Matrix_toEuler_doc[] =
".. method:: to_euler(euler_compat)\n"
"\n"
" Return an Euler representation of the rotation matrix (3x3 or 4x4 matrix only).\n"
"\n"
" :arg euler_compat: Optional euler argument the new euler will be made compatible with (no axis flipping between them). Useful for converting a series of matrices to animation curves.\n"
" :type euler_compat: Euler\n"
" :return: Euler representation of the matrix.\n"
" :rtype: Euler\n";
PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args)
{
float eul[3], eul_compatf[3];
@@ -288,6 +290,13 @@ PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args)
return newEulerObject(eul, Py_NEW, NULL);
}
/*---------------------------Matrix.resize4x4() ------------------*/
static char Matrix_Resize4x4_doc[] =
".. method:: resize4x4()\n"
"\n"
" Resize the matrix to 4x4.\n"
" :return: an instance of itself.\n"
" :rtype: Vector\n";
PyObject *Matrix_Resize4x4(MatrixObject * self)
{
int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index;
@@ -345,6 +354,15 @@ PyObject *Matrix_Resize4x4(MatrixObject * self)
return (PyObject *)self;
}
/*---------------------------Matrix.translationPart() ------------*/
static char Matrix_TranslationPart_doc[] =
".. method:: translation_part()\n"
"\n"
" Return a the translation part of a 4 row matrix.\n"
" :return: Return a the translation of a matrix.\n"
" :rtype: Matrix\n"
"\n"
" .. note:: Note that the (4,4) element of a matrix can be used for uniform scaling too.\n";
PyObject *Matrix_TranslationPart(MatrixObject * self)
{
float vec[4];
@@ -364,6 +382,15 @@ PyObject *Matrix_TranslationPart(MatrixObject * self)
return newVectorObject(vec, 3, Py_NEW, NULL);
}
/*---------------------------Matrix.rotationPart() ---------------*/
static char Matrix_RotationPart_doc[] =
".. method:: rotation_part()\n"
"\n"
" Return the 3d submatrix corresponding to the linear term of the embedded affine transformation in 3d. This matrix represents rotation and scale.\n"
" :return: Return the 3d matrix for rotation and scale.\n"
" :rtype: Matrix\n"
"\n"
" .. note:: Note that the (4,4) element of a matrix can be used for uniform scaling too.\n";
PyObject *Matrix_RotationPart(MatrixObject * self)
{
float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
@@ -390,6 +417,15 @@ PyObject *Matrix_RotationPart(MatrixObject * self)
return newMatrixObject(mat, 3, 3, Py_NEW, Py_TYPE(self));
}
/*---------------------------Matrix.scalePart() --------------------*/
static char Matrix_scalePart_doc[] =
".. method:: scale_part()\n"
"\n"
" Return a the scale part of a 3x3 or 4x4 matrix.\n"
" :return: Return a the scale of a matrix.\n"
" :rtype: Vector\n"
"\n"
" .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n";
PyObject *Matrix_scalePart(MatrixObject * self)
{
float scale[3], rot[3];
@@ -419,12 +455,22 @@ PyObject *Matrix_scalePart(MatrixObject * self)
return newVectorObject(scale, 3, Py_NEW, NULL);
}
/*---------------------------Matrix.invert() ---------------------*/
static char Matrix_Invert_doc[] =
".. method:: invert()\n"
"\n"
" Set the matrix to its inverse.\n"
" :return: an instance of itself.\n"
" :rtype: Matrix\n"
"\n"
" .. note:: :exc:`ValueError` exception is raised.\n"
"\n"
" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n";
PyObject *Matrix_Invert(MatrixObject * self)
{
int x, y, z = 0;
float det = 0.0f;
PyObject *f = NULL;
float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
@@ -437,9 +483,7 @@ PyObject *Matrix_Invert(MatrixObject * self)
}
/*calculate the determinant*/
f = Matrix_Determinant(self);
det = (float)PyFloat_AS_DOUBLE(f); /*Increfs, so we need to decref*/
Py_DECREF(f);
det = matrix_determinant(self);
if(det != 0) {
/*calculate the classical adjoint*/
@@ -478,10 +522,17 @@ PyObject *Matrix_Invert(MatrixObject * self)
/*---------------------------Matrix.determinant() ----------------*/
static char Matrix_Determinant_doc[] =
".. method:: determinant()\n"
"\n"
" Return the determinant of a matrix.\n"
" :return: Return a the determinant of a matrix.\n"
" :rtype: float\n"
"\n"
" .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n";
PyObject *Matrix_Determinant(MatrixObject * self)
{
float det = 0.0f;
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -490,22 +541,18 @@ PyObject *Matrix_Determinant(MatrixObject * self)
return NULL;
}
if(self->rowSize == 2) {
det = determinant_m2(self->matrix[0][0], self->matrix[0][1],
self->matrix[1][0], self->matrix[1][1]);
} else if(self->rowSize == 3) {
det = determinant_m3(self->matrix[0][0], self->matrix[0][1],
self->matrix[0][2], self->matrix[1][0],
self->matrix[1][1], self->matrix[1][2],
self->matrix[2][0], self->matrix[2][1],
self->matrix[2][2]);
} else {
det = determinant_m4((float (*)[4]) *self->matrix);
}
return PyFloat_FromDouble( (double) det );
return PyFloat_FromDouble((double)matrix_determinant(self));
}
/*---------------------------Matrix.transpose() ------------------*/
static char Matrix_Transpose_doc[] =
".. method:: transpose()\n"
"\n"
" Set the matrix to its transpose.\n"
" :return: an instance of itself\n"
" :rtype: Matrix\n"
"\n"
" .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n";
PyObject *Matrix_Transpose(MatrixObject * self)
{
float t = 0.0f;
@@ -535,6 +582,13 @@ PyObject *Matrix_Transpose(MatrixObject * self)
/*---------------------------Matrix.zero() -----------------------*/
static char Matrix_Zero_doc[] =
".. method:: zero()\n"
"\n"
" Set all the matrix values to zero.\n"
" :return: an instance of itself\n"
" :rtype: Matrix\n";
PyObject *Matrix_Zero(MatrixObject * self)
{
int row, col;
@@ -552,6 +606,17 @@ PyObject *Matrix_Zero(MatrixObject * self)
return (PyObject *)self;
}
/*---------------------------Matrix.identity(() ------------------*/
static char Matrix_Identity_doc[] =
".. method:: identity()\n"
"\n"
" Set the matrix to the identity matrix.\n"
" :return: an instance of itself\n"
" :rtype: Matrix\n"
"\n"
" .. note:: An object with zero location and rotation, a scale of one, will have an identity matrix.\n"
"\n"
" .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n";
PyObject *Matrix_Identity(MatrixObject * self)
{
if(!BaseMath_ReadCallback(self))
@@ -580,7 +645,14 @@ PyObject *Matrix_Identity(MatrixObject * self)
return (PyObject *)self;
}
/*---------------------------Matrix.inverted() ------------------*/
/*---------------------------Matrix.copy() ------------------*/
static char Matrix_copy_doc[] =
".. method:: copy()\n"
"\n"
" Returns a copy of this matrix.\n"
" :return: an instance of itself\n"
" :rtype: Matrix\n";
PyObject *Matrix_copy(MatrixObject * self)
{
if(!BaseMath_ReadCallback(self))
@@ -1162,6 +1234,24 @@ static PyGetSetDef Matrix_getseters[] = {
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
/*-----------------------METHOD DEFINITIONS ----------------------*/
static struct PyMethodDef Matrix_methods[] = {
{"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, Matrix_Zero_doc},
{"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, Matrix_Identity_doc},
{"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, Matrix_Transpose_doc},
{"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, Matrix_Determinant_doc},
{"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, Matrix_Invert_doc},
{"translation_part", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, Matrix_TranslationPart_doc},
{"rotation_part", (PyCFunction) Matrix_RotationPart, METH_NOARGS, Matrix_RotationPart_doc},
{"scale_part", (PyCFunction) Matrix_scalePart, METH_NOARGS, Matrix_scalePart_doc},
{"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, Matrix_Resize4x4_doc},
{"to_euler", (PyCFunction) Matrix_toEuler, METH_VARARGS, Matrix_toEuler_doc},
{"to_quat", (PyCFunction) Matrix_toQuat, METH_NOARGS, Matrix_toQuat_doc},
{"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
{"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
{NULL, NULL, 0, NULL}
};
/*------------------PY_OBECT DEFINITION--------------------------*/
PyTypeObject matrix_Type = {
PyVarObject_HEAD_INIT(NULL, 0)

View File

@@ -32,137 +32,17 @@
#include "BKE_utildefines.h"
#include "BLI_blenlib.h"
//-------------------------DOC STRINGS ---------------------------
static PyObject *Quaternion_Identity( QuaternionObject * self );
static PyObject *Quaternion_Negate( QuaternionObject * self );
static PyObject *Quaternion_Conjugate( QuaternionObject * self );
static PyObject *Quaternion_Inverse( QuaternionObject * self );
static PyObject *Quaternion_Normalize( QuaternionObject * self );
static PyObject *Quaternion_ToEuler( QuaternionObject * self, PyObject *args );
static PyObject *Quaternion_ToMatrix( QuaternionObject * self );
static PyObject *Quaternion_Cross( QuaternionObject * self, QuaternionObject * value );
static PyObject *Quaternion_Dot( QuaternionObject * self, QuaternionObject * value );
static PyObject *Quaternion_copy( QuaternionObject * self );
//-----------------------METHOD DEFINITIONS ----------------------
static struct PyMethodDef Quaternion_methods[] = {
{"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, NULL},
{"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, NULL},
{"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, NULL},
{"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, NULL},
{"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, NULL},
{"toEuler", (PyCFunction) Quaternion_ToEuler, METH_VARARGS, NULL},
{"toMatrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, NULL},
{"cross", (PyCFunction) Quaternion_Cross, METH_O, NULL},
{"dot", (PyCFunction) Quaternion_Dot, METH_O, NULL},
{"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, NULL},
{"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
};
//----------------------------------Mathutils.Quaternion() --------------
static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *listObject = NULL, *n, *q;
int size, i;
float quat[4];
double angle = 0.0f;
size = PyTuple_GET_SIZE(args);
if (size == 1 || size == 2) { //seq?
listObject = PyTuple_GET_ITEM(args, 0);
if (PySequence_Check(listObject)) {
size = PySequence_Length(listObject);
if ((size == 4 && PySequence_Length(args) !=1) ||
(size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) {
// invalid args/size
PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
if(size == 3){ //get angle in axis/angle
n = PySequence_GetItem(args, 1);
if(n == NULL) { // parsed item not a number or getItem fail
PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
angle = PyFloat_AsDouble(n);
Py_DECREF(n);
if (angle==-1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
}
}else{
listObject = PyTuple_GET_ITEM(args, 1);
if (size>1 && PySequence_Check(listObject)) {
size = PySequence_Length(listObject);
if (size != 3) {
// invalid args/size
PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
angle = PyFloat_AsDouble(PyTuple_GET_ITEM(args, 0));
if (angle==-1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
} else { // argument was not a sequence
PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
}
} else if (size == 0) { //returns a new empty quat
return newQuaternionObject(NULL, Py_NEW, NULL);
} else {
listObject = args;
}
if (size == 3) { // invalid quat size
if(PySequence_Length(args) != 2){
PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
}else{
if(size != 4){
PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
}
for (i=0; i<size; i++) { //parse
q = PySequence_GetItem(listObject, i);
if (q == NULL) { // Failed to read sequence
PyErr_SetString(PyExc_RuntimeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
quat[i] = PyFloat_AsDouble(q);
Py_DECREF(q);
if (quat[i]==-1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
}
if(size == 3) //calculate the quat based on axis/angle
#ifdef USE_MATHUTILS_DEG
axis_angle_to_quat(quat, quat, angle * (Py_PI / 180));
#else
axis_angle_to_quat(quat, quat, angle);
#endif
return newQuaternionObject(quat, Py_NEW, NULL);
}
//-----------------------------METHODS------------------------------
//----------------------------Quaternion.toEuler()------------------
//return the quat as a euler
static char Quaternion_ToEuler_doc[] =
".. method:: to_euler(euler_compat)\n"
"\n"
" Return Euler representation of the quaternion.\n"
"\n"
" :arg euler_compat: Optional euler argument the new euler will be made compatible with (no axis flipping between them). Useful for converting a series of matrices to animation curves.\n"
" :type euler_compat: Euler\n"
" :return: Euler representation of the quaternion.\n"
" :rtype: Euler\n";
static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
{
float eul[3];
@@ -212,7 +92,14 @@ static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
return newEulerObject(eul, Py_NEW, NULL);
}
//----------------------------Quaternion.toMatrix()------------------
//return the quat as a matrix
static char Quaternion_ToMatrix_doc[] =
".. method:: to_matrix(other)\n"
"\n"
" Return a matrix representation of the quaternion.\n"
"\n"
" :return: A 3x3 rotation matrix representation of the quaternion.\n"
" :rtype: Matrix\n";
static PyObject *Quaternion_ToMatrix(QuaternionObject * self)
{
float mat[9]; /* all values are set */
@@ -225,7 +112,16 @@ static PyObject *Quaternion_ToMatrix(QuaternionObject * self)
}
//----------------------------Quaternion.cross(other)------------------
//return the cross quat
static char Quaternion_Cross_doc[] =
".. method:: cross(other)\n"
"\n"
" Return the cross product of this quaternion and another.\n"
"\n"
" :arg other: The other quaternion to perform the cross product with.\n"
" :type other: Quaternion\n"
" :return: The cross product.\n"
" :rtype: Quaternion\n";
static PyObject *Quaternion_Cross(QuaternionObject * self, QuaternionObject * value)
{
float quat[4];
@@ -243,7 +139,16 @@ static PyObject *Quaternion_Cross(QuaternionObject * self, QuaternionObject * va
}
//----------------------------Quaternion.dot(other)------------------
//return the dot quat
static char Quaternion_Dot_doc[] =
".. method:: dot(other)\n"
"\n"
" Return the dot product of this quaternion and another.\n"
"\n"
" :arg other: The other quaternion to perform the dot product with.\n"
" :type other: Quaternion\n"
" :return: The dot product.\n"
" :rtype: Quaternion\n";
static PyObject *Quaternion_Dot(QuaternionObject * self, QuaternionObject * value)
{
if (!QuaternionObject_Check(value)) {
@@ -257,8 +162,90 @@ static PyObject *Quaternion_Dot(QuaternionObject * self, QuaternionObject * valu
return PyFloat_FromDouble(dot_qtqt(self->quat, value->quat));
}
static char Quaternion_Difference_doc[] =
".. function:: difference(other)\n"
"\n"
" Returns a quaternion representing the rotational difference.\n"
"\n"
" :arg other: second quaternion.\n"
" :type other: Quaternion\n"
" :return: the rotational difference between the two quat rotations.\n"
" :rtype: Quaternion\n";
static PyObject *Quaternion_Difference(QuaternionObject * self, QuaternionObject * value)
{
float quat[4], tempQuat[4];
double dot = 0.0f;
int x;
if (!QuaternionObject_Check(value)) {
PyErr_SetString( PyExc_TypeError, "quat.difference(value): expected a quaternion argument" );
return NULL;
}
if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
return NULL;
tempQuat[0] = self->quat[0];
tempQuat[1] = - self->quat[1];
tempQuat[2] = - self->quat[2];
tempQuat[3] = - self->quat[3];
dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] +
tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]);
for(x = 0; x < 4; x++) {
tempQuat[x] /= (float)(dot * dot);
}
mul_qt_qtqt(quat, tempQuat, value->quat);
return newQuaternionObject(quat, Py_NEW, NULL);
}
static char Quaternion_Slerp_doc[] =
".. function:: slerp(other, factor)\n"
"\n"
" Returns the interpolation of two quaternions.\n"
"\n"
" :arg other: value to interpolate with.\n"
" :type other: Quaternion\n"
" :arg factor: The interpolation value in [0.0, 1.0].\n"
" :type factor: float\n"
" :return: The interpolated rotation.\n"
" :rtype: Quaternion\n";
static PyObject *Quaternion_Slerp(QuaternionObject *self, PyObject *args)
{
QuaternionObject *value;
float quat[4], fac;
if(!PyArg_ParseTuple(args, "O!f", &quaternion_Type, &value, &fac)) {
PyErr_SetString(PyExc_TypeError, "Mathutils.Slerp(): expected Quaternion types and float");
return NULL;
}
if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
return NULL;
if(fac > 1.0f || fac < 0.0f) {
PyErr_SetString(PyExc_AttributeError, "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0");
return NULL;
}
interp_qt_qtqt(quat, self->quat, value->quat, fac);
return newQuaternionObject(quat, Py_NEW, NULL);
}
//----------------------------Quaternion.normalize()----------------
//normalize the axis of rotation of [theta,vector]
static char Quaternion_Normalize_doc[] =
".. function:: normalize()\n"
"\n"
" Normalize the quaternion.\n"
"\n"
" :return: an instance of itself.\n"
" :rtype: Quaternion\n";
static PyObject *Quaternion_Normalize(QuaternionObject * self)
{
if(!BaseMath_ReadCallback(self))
@@ -271,7 +258,14 @@ static PyObject *Quaternion_Normalize(QuaternionObject * self)
return (PyObject*)self;
}
//----------------------------Quaternion.inverse()------------------
//invert the quat
static char Quaternion_Inverse_doc[] =
".. function:: inverse()\n"
"\n"
" Set the quaternion to its inverse.\n"
"\n"
" :return: an instance of itself.\n"
" :rtype: Quaternion\n";
static PyObject *Quaternion_Inverse(QuaternionObject * self)
{
if(!BaseMath_ReadCallback(self))
@@ -284,7 +278,14 @@ static PyObject *Quaternion_Inverse(QuaternionObject * self)
return (PyObject*)self;
}
//----------------------------Quaternion.identity()-----------------
//generate the identity quaternion
static char Quaternion_Identity_doc[] =
".. function:: identity()\n"
"\n"
" Set the quaternion to an identity quaternion.\n"
"\n"
" :return: an instance of itself.\n"
" :rtype: Quaternion\n";
static PyObject *Quaternion_Identity(QuaternionObject * self)
{
if(!BaseMath_ReadCallback(self))
@@ -297,7 +298,14 @@ static PyObject *Quaternion_Identity(QuaternionObject * self)
return (PyObject*)self;
}
//----------------------------Quaternion.negate()-------------------
//negate the quat
static char Quaternion_Negate_doc[] =
".. function:: negate()\n"
"\n"
" Set the quaternion to its negative.\n"
"\n"
" :return: an instance of itself.\n"
" :rtype: Quaternion\n";
static PyObject *Quaternion_Negate(QuaternionObject * self)
{
if(!BaseMath_ReadCallback(self))
@@ -310,7 +318,14 @@ static PyObject *Quaternion_Negate(QuaternionObject * self)
return (PyObject*)self;
}
//----------------------------Quaternion.conjugate()----------------
//negate the vector part
static char Quaternion_Conjugate_doc[] =
".. function:: conjugate()\n"
"\n"
" Set the quaternion to its conjugate (negate x, y, z).\n"
"\n"
" :return: an instance of itself.\n"
" :rtype: Quaternion\n";
static PyObject *Quaternion_Conjugate(QuaternionObject * self)
{
if(!BaseMath_ReadCallback(self))
@@ -323,7 +338,16 @@ static PyObject *Quaternion_Conjugate(QuaternionObject * self)
return (PyObject*)self;
}
//----------------------------Quaternion.copy()----------------
//return a copy of the quat
static char Quaternion_copy_doc[] =
".. function:: copy()\n"
"\n"
" Returns a copy of this quaternion.\n"
"\n"
" :return: A copy of the quaternion.\n"
" :rtype: Quaternion\n"
"\n"
" .. note:: use this to get a copy of a wrapped quaternion with no reference to the original data.\n";
static PyObject *Quaternion_copy(QuaternionObject * self)
{
if(!BaseMath_ReadCallback(self))
@@ -702,52 +726,139 @@ static PyObject *Quaternion_getAxisVec( QuaternionObject * self, void *type )
return (PyObject *) newVectorObject(vec, 3, Py_NEW, NULL);
}
//----------------------------------Mathutils.Quaternion() --------------
static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *listObject = NULL, *n, *q;
int size, i;
float quat[4];
double angle = 0.0f;
size = PyTuple_GET_SIZE(args);
if (size == 1 || size == 2) { //seq?
listObject = PyTuple_GET_ITEM(args, 0);
if (PySequence_Check(listObject)) {
size = PySequence_Length(listObject);
if ((size == 4 && PySequence_Length(args) !=1) ||
(size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) {
// invalid args/size
PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
if(size == 3){ //get angle in axis/angle
n = PySequence_GetItem(args, 1);
if(n == NULL) { // parsed item not a number or getItem fail
PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
angle = PyFloat_AsDouble(n);
Py_DECREF(n);
if (angle==-1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
}
}else{
listObject = PyTuple_GET_ITEM(args, 1);
if (size>1 && PySequence_Check(listObject)) {
size = PySequence_Length(listObject);
if (size != 3) {
// invalid args/size
PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
angle = PyFloat_AsDouble(PyTuple_GET_ITEM(args, 0));
if (angle==-1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
} else { // argument was not a sequence
PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
}
} else if (size == 0) { //returns a new empty quat
return newQuaternionObject(NULL, Py_NEW, NULL);
} else {
listObject = args;
}
if (size == 3) { // invalid quat size
if(PySequence_Length(args) != 2){
PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
}else{
if(size != 4){
PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
}
for (i=0; i<size; i++) { //parse
q = PySequence_GetItem(listObject, i);
if (q == NULL) { // Failed to read sequence
PyErr_SetString(PyExc_RuntimeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
quat[i] = PyFloat_AsDouble(q);
Py_DECREF(q);
if (quat[i]==-1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
return NULL;
}
}
if(size == 3) //calculate the quat based on axis/angle
#ifdef USE_MATHUTILS_DEG
axis_angle_to_quat(quat, quat, angle * (Py_PI / 180));
#else
axis_angle_to_quat(quat, quat, angle);
#endif
return newQuaternionObject(quat, Py_NEW, NULL);
}
//-----------------------METHOD DEFINITIONS ----------------------
static struct PyMethodDef Quaternion_methods[] = {
{"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, Quaternion_Identity_doc},
{"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, Quaternion_Negate_doc},
{"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, Quaternion_Conjugate_doc},
{"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, Quaternion_Inverse_doc},
{"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, Quaternion_Normalize_doc},
{"to_euler", (PyCFunction) Quaternion_ToEuler, METH_VARARGS, Quaternion_ToEuler_doc},
{"to_matrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, Quaternion_ToMatrix_doc},
{"cross", (PyCFunction) Quaternion_Cross, METH_O, Quaternion_Cross_doc},
{"dot", (PyCFunction) Quaternion_Dot, METH_O, Quaternion_Dot_doc},
{"difference", (PyCFunction) Quaternion_Difference, METH_O, Quaternion_Difference_doc},
{"slerp", (PyCFunction) Quaternion_Slerp, METH_VARARGS, Quaternion_Slerp_doc},
{"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
{"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
{NULL, NULL, 0, NULL}
};
/*****************************************************************************/
/* Python attributes get/set structure: */
/*****************************************************************************/
static PyGetSetDef Quaternion_getseters[] = {
{"w",
(getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
"Quaternion W value",
(void *)0},
{"x",
(getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
"Quaternion X axis",
(void *)1},
{"y",
(getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
"Quaternion Y axis",
(void *)2},
{"z",
(getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
"Quaternion Z axis",
(void *)3},
{"magnitude",
(getter)Quaternion_getMagnitude, (setter)NULL,
"Size of the quaternion",
NULL},
{"angle",
(getter)Quaternion_getAngle, (setter)NULL,
"angle of the quaternion",
NULL},
{"axis",
(getter)Quaternion_getAxisVec, (setter)NULL,
"quaternion axis as a vector",
NULL},
{"wrapped",
(getter)BaseMathObject_getWrapped, (setter)NULL,
"True when this wraps blenders internal data",
NULL},
{"_owner",
(getter)BaseMathObject_getOwner, (setter)NULL,
"Read only owner for vectors that depend on another object",
NULL},
{"w", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion W value", (void *)0},
{"x", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion X axis", (void *)1},
{"y", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion Y axis", (void *)2},
{"z", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion Z axis", (void *)3},
{"magnitude", (getter)Quaternion_getMagnitude, (setter)NULL, "Size of the quaternion", NULL},
{"angle", (getter)Quaternion_getAngle, (setter)NULL, "angle of the quaternion", NULL},
{"axis",(getter)Quaternion_getAxisVec, (setter)NULL, "quaternion axis as a vector", NULL},
{"wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, "True when this wraps blenders internal data", NULL},
{"_owner", (getter)BaseMathObject_getOwner, (setter)NULL, "Read only owner for vectors that depend on another object", NULL},
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
//------------------PY_OBECT DEFINITION--------------------------
PyTypeObject quaternion_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -843,3 +954,4 @@ PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype)
return (PyObject *)self;
}

View File

@@ -41,37 +41,6 @@
static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat); /* utility func */
/*-----------------------METHOD DEFINITIONS ----------------------*/
static PyObject *Vector_Zero( VectorObject * self );
static PyObject *Vector_Normalize( VectorObject * self );
static PyObject *Vector_Negate( VectorObject * self );
static PyObject *Vector_Resize2D( VectorObject * self );
static PyObject *Vector_Resize3D( VectorObject * self );
static PyObject *Vector_Resize4D( VectorObject * self );
static PyObject *Vector_ToTuple( VectorObject * self, PyObject *value );
static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args );
static PyObject *Vector_Reflect( VectorObject *self, VectorObject *value );
static PyObject *Vector_Cross( VectorObject * self, VectorObject * value );
static PyObject *Vector_Dot( VectorObject * self, VectorObject * value );
static PyObject *Vector_copy( VectorObject * self );
static struct PyMethodDef Vector_methods[] = {
{"zero", (PyCFunction) Vector_Zero, METH_NOARGS, NULL},
{"normalize", (PyCFunction) Vector_Normalize, METH_NOARGS, NULL},
{"negate", (PyCFunction) Vector_Negate, METH_NOARGS, NULL},
{"resize2D", (PyCFunction) Vector_Resize2D, METH_NOARGS, NULL},
{"resize3D", (PyCFunction) Vector_Resize3D, METH_NOARGS, NULL},
{"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, NULL},
{"toTuple", (PyCFunction) Vector_ToTuple, METH_O, NULL},
{"toTrackQuat", ( PyCFunction ) Vector_ToTrackQuat, METH_VARARGS, NULL},
{"reflect", ( PyCFunction ) Vector_Reflect, METH_O, NULL},
{"cross", ( PyCFunction ) Vector_Cross, METH_O, NULL},
{"dot", ( PyCFunction ) Vector_Dot, METH_O, NULL},
{"copy", (PyCFunction) Vector_copy, METH_NOARGS, NULL},
{"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
};
//----------------------------------Mathutils.Vector() ------------------
// Supports 2D, 3D, and 4D vector objects both int and float values
// accepted. Mixed float and int values accepted. Ints are parsed to float
@@ -124,8 +93,13 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
/*-----------------------------METHODS---------------------------- */
/*----------------------------Vector.zero() ----------------------
set the vector data to 0,0,0 */
static char Vector_Zero_doc[] =
".. method:: zero()\n"
"\n"
" Set all values to zero.\n"
" :return: an instance of itself\n"
" :rtype: vector\n";
static PyObject *Vector_Zero(VectorObject * self)
{
int i;
@@ -137,8 +111,18 @@ static PyObject *Vector_Zero(VectorObject * self)
Py_INCREF(self);
return (PyObject*)self;
}
/*----------------------------Vector.normalize() -----------------
normalize the vector data to a unit vector */
/*----------------------------Vector.normalize() ----------------- */
static char Vector_Normalize_doc[] =
".. method:: normalize()\n"
"\n"
" Normalize the vector, making the length of the vector always 1.0.\n"
" :return: an instance of itself\n"
" :rtype: vector\n"
"\n"
" .. warning:: Normalizing a vector where all values are zero results in all axis having a nan value (not a number).\n"
"\n"
" .. note:: Normalize works for vectors of all sizes, however 4D Vectors w axis is left untouched.\n";
static PyObject *Vector_Normalize(VectorObject * self)
{
int i;
@@ -161,8 +145,14 @@ static PyObject *Vector_Normalize(VectorObject * self)
}
/*----------------------------Vector.resize2D() ------------------
resize the vector to x,y */
/*----------------------------Vector.resize2D() ------------------ */
static char Vector_Resize2D_doc[] =
".. method:: resize2D()\n"
"\n"
" Resize the vector to 2D (x, y).\n"
" :return: an instance of itself\n"
" :rtype: vector\n";
static PyObject *Vector_Resize2D(VectorObject * self)
{
if(self->wrapped==Py_WRAP) {
@@ -184,8 +174,14 @@ static PyObject *Vector_Resize2D(VectorObject * self)
Py_INCREF(self);
return (PyObject*)self;
}
/*----------------------------Vector.resize3D() ------------------
resize the vector to x,y,z */
/*----------------------------Vector.resize3D() ------------------ */
static char Vector_Resize3D_doc[] =
".. method:: resize3D()\n"
"\n"
" Resize the vector to 3D (x, y, z).\n"
" :return: an instance of itself\n"
" :rtype: vector\n";
static PyObject *Vector_Resize3D(VectorObject * self)
{
if (self->wrapped==Py_WRAP) {
@@ -210,8 +206,14 @@ static PyObject *Vector_Resize3D(VectorObject * self)
Py_INCREF(self);
return (PyObject*)self;
}
/*----------------------------Vector.resize4D() ------------------
resize the vector to x,y,z,w */
/*----------------------------Vector.resize4D() ------------------ */
static char Vector_Resize4D_doc[] =
".. method:: resize4D()\n"
"\n"
" Resize the vector to 4D (x, y, z, w).\n"
" :return: an instance of itself\n"
" :rtype: vector\n";
static PyObject *Vector_Resize4D(VectorObject * self)
{
if(self->wrapped==Py_WRAP) {
@@ -239,8 +241,17 @@ static PyObject *Vector_Resize4D(VectorObject * self)
return (PyObject*)self;
}
/*----------------------------Vector.resize4D() ------------------
resize the vector to x,y,z,w */
/*----------------------------Vector.toTuple() ------------------ */
static char Vector_ToTuple_doc[] =
".. method:: to_tuple(precision)\n"
"\n"
" Return this vector as a tuple with.\n"
"\n"
" :arg precision: The number to round the value to in [0, 21].\n"
" :type precision: int\n"
" :return: the values of the vector rounded by *precision*\n"
" :rtype: tuple\n";
static PyObject *Vector_ToTuple(VectorObject * self, PyObject *value)
{
int ndigits= PyLong_AsSsize_t(value);
@@ -265,8 +276,19 @@ static PyObject *Vector_ToTuple(VectorObject * self, PyObject *value)
return ret;
}
/*----------------------------Vector.toTrackQuat(track, up) ----------------------
extract a quaternion from the vector and the track and up axis */
/*----------------------------Vector.toTrackQuat(track, up) ---------------------- */
static char Vector_ToTrackQuat_doc[] =
".. method:: to_track_quat(track, up)\n"
"\n"
" Return a quaternion rotation from the vector and the track and up axis.\n"
"\n"
" :arg track: Track axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z'].\n"
" :type track: string\n"
" :arg up: Up axis in ['X', 'Y', 'Z'].\n"
" :type up: string\n"
" :return: rotation from the vector and the track and up axis."
" :rtype: Quaternion\n";
static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
{
float vec[3], quat[4];
@@ -290,14 +312,11 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
if (strack[0] == '-') {
switch(strack[1]) {
case 'X':
case 'x':
track = 3;
break;
case 'Y':
case 'y':
track = 4;
break;
case 'z':
case 'Z':
track = 5;
break;
@@ -315,14 +334,11 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
switch(strack[0]) {
case '-':
case 'X':
case 'x':
track = 0;
break;
case 'Y':
case 'y':
track = 1;
break;
case 'z':
case 'Z':
track = 2;
break;
@@ -341,14 +357,11 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
if (strlen(sup) == 1) {
switch(*sup) {
case 'X':
case 'x':
up = 0;
break;
case 'Y':
case 'y':
up = 1;
break;
case 'z':
case 'Z':
up = 2;
break;
@@ -385,6 +398,16 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
return a reflected vector on the mirror normal
vec - ((2 * DotVecs(vec, mirror)) * mirror)
*/
static char Vector_Reflect_doc[] =
".. method:: reflect(mirror)\n"
"\n"
" Return the reflection vector from the *mirror* argument.\n"
"\n"
" :arg mirror: This vector could be a normal from the reflecting surface.\n"
" :type mirror: vector\n"
" :return: The reflected vector.\n"
" :rtype: Vector object matching the size of this vector.\n";
static PyObject *Vector_Reflect( VectorObject * self, VectorObject * value )
{
float mirror[3], vec[3];
@@ -408,11 +431,24 @@ static PyObject *Vector_Reflect( VectorObject * self, VectorObject * value )
if (self->size > 2) vec[2] = self->vec[2];
else vec[2] = 0.0;
normalize_v3(mirror);
reflect_v3_v3v3(reflect, vec, mirror);
return newVectorObject(reflect, self->size, Py_NEW, NULL);
}
static char Vector_Cross_doc[] =
".. method:: cross(other)\n"
"\n"
" Return the cross product of this vector and another.\n"
"\n"
" :arg other: The other vector to perform the cross product with.\n"
" :type other: vector\n"
" :return: The cross product.\n"
" :rtype: Vector\n"
"\n"
" .. note:: both vectors must be 3D\n";
static PyObject *Vector_Cross( VectorObject * self, VectorObject * value )
{
VectorObject *vecCross = NULL;
@@ -435,13 +471,23 @@ static PyObject *Vector_Cross( VectorObject * self, VectorObject * value )
return (PyObject *)vecCross;
}
static char Vector_Dot_doc[] =
".. method:: dot(other)\n"
"\n"
" Return the dot product of this vector and another.\n"
"\n"
" :arg other: The other vector to perform the dot product with.\n"
" :type other: vector\n"
" :return: The dot product.\n"
" :rtype: Vector\n";
static PyObject *Vector_Dot( VectorObject * self, VectorObject * value )
{
double dot = 0.0;
int x;
if (!VectorObject_Check(value)) {
PyErr_SetString( PyExc_TypeError, "vec.cross(value): expected a vector argument" );
PyErr_SetString( PyExc_TypeError, "vec.dot(value): expected a vector argument" );
return NULL;
}
@@ -459,8 +505,156 @@ static PyObject *Vector_Dot( VectorObject * self, VectorObject * value )
return PyFloat_FromDouble(dot);
}
/*----------------------------Vector.copy() --------------------------------------
return a copy of the vector */
static char Vector_Angle_doc[] =
".. function:: angle(other)\n"
"\n"
" Return the angle between two vectors.\n"
"\n"
" :type other: vector\n"
" :return angle: angle in radians\n"
" :rtype: float\n"
"\n"
" .. note:: Zero length vectors raise an :exc:`AttributeError`.\n";
static PyObject *Vector_Angle(VectorObject * self, VectorObject * value)
{
double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f;
int x, size;
if (!VectorObject_Check(value)) {
PyErr_SetString( PyExc_TypeError, "vec.angle(value): expected a vector argument" );
return NULL;
}
if(self->size != value->size) {
PyErr_SetString(PyExc_AttributeError, "vec.angle(value): expects both vectors to have the same size\n");
return NULL;
}
if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
return NULL;
//since size is the same....
size = self->size;
for(x = 0; x < size; x++) {
test_v1 += self->vec[x] * self->vec[x];
test_v2 += value->vec[x] * value->vec[x];
}
if (!test_v1 || !test_v2){
PyErr_SetString(PyExc_AttributeError, "vector.angle(other): zero length vectors are not acceptable arguments\n");
return NULL;
}
//dot product
for(x = 0; x < size; x++) {
dot += self->vec[x] * value->vec[x];
}
dot /= (sqrt(test_v1) * sqrt(test_v2));
angleRads = (double)saacos(dot);
#ifdef USE_MATHUTILS_DEG
return PyFloat_FromDouble(angleRads * (180/ Py_PI));
#else
return PyFloat_FromDouble(angleRads);
#endif
}
static char Vector_Project_doc[] =
".. function:: project(other)\n"
"\n"
" Return the projection of this vector onto the *other*.\n"
"\n"
" :type other: vector\n"
" :return projection: the parallel projection vector\n"
" :rtype: vector\n";
static PyObject *Vector_Project(VectorObject * self, VectorObject * value)
{
float vec[4];
double dot = 0.0f, dot2 = 0.0f;
int x, size;
if (!VectorObject_Check(value)) {
PyErr_SetString( PyExc_TypeError, "vec.project(value): expected a vector argument" );
return NULL;
}
if(self->size != value->size) {
PyErr_SetString(PyExc_AttributeError, "vec.project(value): expects both vectors to have the same size\n");
return NULL;
}
if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
return NULL;
//since they are the same size...
size = self->size;
//get dot products
for(x = 0; x < size; x++) {
dot += self->vec[x] * value->vec[x];
dot2 += value->vec[x] * value->vec[x];
}
//projection
dot /= dot2;
for(x = 0; x < size; x++) {
vec[x] = (float)(dot * value->vec[x]);
}
return newVectorObject(vec, size, Py_NEW, NULL);
}
//----------------------------------Mathutils.MidpointVecs() -------------
static char Vector_Lerp_doc[] =
".. function:: lerp(other, factor)\n"
"\n"
" Returns the interpolation of two vectors.\n"
"\n"
" :arg other: value to interpolate with.\n"
" :type other: Vector\n"
" :arg factor: The interpolation value in [0.0, 1.0].\n"
" :type factor: float\n"
" :return: The interpolated rotation.\n"
" :rtype: Vector\n";
static PyObject *Vector_Lerp(VectorObject * self, PyObject * args)
{
VectorObject *vec2 = NULL;
float fac, ifac, vec[4];
int x;
if(!PyArg_ParseTuple(args, "O!f", &vector_Type, &vec2, &fac)) {
PyErr_SetString(PyExc_TypeError, "vector.lerp(): expects a vector of the same size and float");
return NULL;
}
if(self->size != vec2->size) {
PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size");
return NULL;
}
if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(vec2))
return NULL;
ifac= 1.0 - fac;
for(x = 0; x < self->size; x++) {
vec[x] = (ifac * self->vec[x]) + (fac * vec2->vec[x]);
}
return newVectorObject(vec, self->size, Py_NEW, NULL);
}
/*----------------------------Vector.copy() -------------------------------------- */
static char Vector_copy_doc[] =
".. function:: copy()\n"
"\n"
" Returns a copy of this vector.\n"
"\n"
" :return: A copy of the vector.\n"
" :rtype: Vector\n"
"\n"
" .. note:: use this to get a copy of a wrapped vector with no reference to the original data.\n";
static PyObject *Vector_copy(VectorObject * self)
{
if(!BaseMath_ReadCallback(self))
@@ -1807,7 +2001,87 @@ if len(unique) != len(items):
*/
//-----------------row_vector_multiplication (internal)-----------
//ROW VECTOR Multiplication - Vector X Matrix
//[x][y][z] * [1][4][7]
// [2][5][8]
// [3][6][9]
//vector/matrix multiplication IS NOT COMMUTATIVE!!!!
static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat)
{
float vecNew[4], vecCopy[4];
double dot = 0.0f;
int x, y, z = 0, vec_size = vec->size;
if(mat->colSize != vec_size){
if(mat->colSize == 4 && vec_size != 3){
PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same");
return NULL;
}else{
vecCopy[3] = 1.0f;
}
}
if(!BaseMath_ReadCallback(vec) || !BaseMath_ReadCallback(mat))
return NULL;
for(x = 0; x < vec_size; x++){
vecCopy[x] = vec->vec[x];
}
vecNew[3] = 1.0f;
//muliplication
for(x = 0; x < mat->rowSize; x++) {
for(y = 0; y < mat->colSize; y++) {
dot += mat->matrix[x][y] * vecCopy[y];
}
vecNew[z++] = (float)dot;
dot = 0.0f;
}
return newVectorObject(vecNew, vec_size, Py_NEW, NULL);
}
/*----------------------------Vector.negate() -------------------- */
static char Vector_Negate_doc[] =
".. method:: negate()\n"
"\n"
" Set all values to their negative.\n"
" :return: an instance of itself\n"
" :rtype: vector\n";
static PyObject *Vector_Negate(VectorObject * self)
{
int i;
if(!BaseMath_ReadCallback(self))
return NULL;
for(i = 0; i < self->size; i++)
self->vec[i] = -(self->vec[i]);
BaseMath_WriteCallback(self); // alredy checked for error
Py_INCREF(self);
return (PyObject*)self;
}
static struct PyMethodDef Vector_methods[] = {
{"zero", (PyCFunction) Vector_Zero, METH_NOARGS, Vector_Zero_doc},
{"normalize", (PyCFunction) Vector_Normalize, METH_NOARGS, Vector_Normalize_doc},
{"negate", (PyCFunction) Vector_Negate, METH_NOARGS, Vector_Negate_doc},
{"resize2D", (PyCFunction) Vector_Resize2D, METH_NOARGS, Vector_Resize2D_doc},
{"resize3D", (PyCFunction) Vector_Resize3D, METH_NOARGS, Vector_Resize3D_doc},
{"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, Vector_Resize4D_doc},
{"to_tuple", (PyCFunction) Vector_ToTuple, METH_O, Vector_ToTuple_doc},
{"to_track_quat", ( PyCFunction ) Vector_ToTrackQuat, METH_VARARGS, Vector_ToTrackQuat_doc},
{"reflect", ( PyCFunction ) Vector_Reflect, METH_O, Vector_Reflect_doc},
{"cross", ( PyCFunction ) Vector_Cross, METH_O, Vector_Cross_doc},
{"dot", ( PyCFunction ) Vector_Dot, METH_O, Vector_Dot_doc},
{"angle", ( PyCFunction ) Vector_Angle, METH_O, Vector_Angle_doc},
{"project", ( PyCFunction ) Vector_Project, METH_O, Vector_Project_doc},
{"lerp", ( PyCFunction ) Vector_Lerp, METH_VARARGS, Vector_Lerp_doc},
{"copy", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc},
{"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
};
/* Note
@@ -1816,6 +2090,8 @@ if len(unique) != len(items):
vec*mat and mat*vec both get sent to Vector_mul and it neesd to sort out the order
*/
static char vector_doc[] = "This object gives access to Vectors in Blender.";
PyTypeObject vector_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
/* For printing, in format "<module>.<name>" */
@@ -1851,7 +2127,7 @@ PyTypeObject vector_Type = {
/*** Flags to define presence of optional/expanded features ***/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
NULL, /* char *tp_doc; Documentation string */
vector_doc, /* char *tp_doc; Documentation string */
/*** Assigned meaning in release 2.0 ***/
/* call function for all accessible objects */
NULL, /* traverseproc tp_traverse; */
@@ -1896,7 +2172,6 @@ PyTypeObject vector_Type = {
NULL
};
/*------------------------newVectorObject (internal)-------------
creates a new vector object
pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
@@ -1955,59 +2230,3 @@ PyObject *newVectorObject_cb(PyObject *cb_user, int size, int cb_type, int cb_su
return (PyObject *)self;
}
//-----------------row_vector_multiplication (internal)-----------
//ROW VECTOR Multiplication - Vector X Matrix
//[x][y][z] * [1][4][7]
// [2][5][8]
// [3][6][9]
//vector/matrix multiplication IS NOT COMMUTATIVE!!!!
static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat)
{
float vecNew[4], vecCopy[4];
double dot = 0.0f;
int x, y, z = 0, vec_size = vec->size;
if(mat->colSize != vec_size){
if(mat->colSize == 4 && vec_size != 3){
PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same");
return NULL;
}else{
vecCopy[3] = 1.0f;
}
}
if(!BaseMath_ReadCallback(vec) || !BaseMath_ReadCallback(mat))
return NULL;
for(x = 0; x < vec_size; x++){
vecCopy[x] = vec->vec[x];
}
vecNew[3] = 1.0f;
//muliplication
for(x = 0; x < mat->rowSize; x++) {
for(y = 0; y < mat->colSize; y++) {
dot += mat->matrix[x][y] * vecCopy[y];
}
vecNew[z++] = (float)dot;
dot = 0.0f;
}
return newVectorObject(vecNew, vec_size, Py_NEW, NULL);
}
/*----------------------------Vector.negate() --------------------
set the vector to it's negative -x, -y, -z */
static PyObject *Vector_Negate(VectorObject * self)
{
int i;
if(!BaseMath_ReadCallback(self))
return NULL;
for(i = 0; i < self->size; i++)
self->vec[i] = -(self->vec[i]);
BaseMath_WriteCallback(self); // alredy checked for error
Py_INCREF(self);
return (PyObject*)self;
}

View File

@@ -242,7 +242,7 @@ static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, int
return data;
}
static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size, ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size, ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
{
int totdim, dim_size[MAX_ARRAY_DIMENSION];
int totitem;
@@ -266,6 +266,8 @@ static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *p
if (RNA_property_flag(prop) & PROP_DYNAMIC) {
/* not freeing allocated mem, RNA_parameter_list_free will do this */
*(char**)param_data= data;
RNA_parameter_length_set_data(parms, prop, param_data, totitem);
}
}
else {
@@ -358,18 +360,18 @@ static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *
RNA_property_boolean_set_index(ptr, prop, index, *(int*)value);
}
int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix)
int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, char *param_data, PyObject *py, const char *error_prefix)
{
int ret;
switch (RNA_property_type(prop)) {
case PROP_FLOAT:
ret= py_to_array(py, ptr, prop, param_data, py_float_check, "float", sizeof(float), py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix);
ret= py_to_array(py, ptr, prop, parms, param_data, py_float_check, "float", sizeof(float), py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix);
break;
case PROP_INT:
ret= py_to_array(py, ptr, prop, param_data, py_int_check, "int", sizeof(int), py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix);
ret= py_to_array(py, ptr, prop, parms, param_data, py_int_check, "int", sizeof(int), py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix);
break;
case PROP_BOOLEAN:
ret= py_to_array(py, ptr, prop, param_data, py_bool_check, "boolean", sizeof(int), py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
ret= py_to_array(py, ptr, prop, parms, param_data, py_bool_check, "boolean", sizeof(int), py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
break;
default:
PyErr_SetString(PyExc_TypeError, "not an array type");
@@ -457,14 +459,16 @@ static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop
}
#endif
PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, int index)
PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index)
{
int totdim, i, len;
int dimsize[MAX_ARRAY_DIMENSION];
int totdim, arraydim, arrayoffset, dimsize[MAX_ARRAY_DIMENSION], i, len;
BPy_PropertyRNA *ret= NULL;
arraydim= self ? self->arraydim : 0;
arrayoffset = self ? self->arrayoffset : 0;
/* just in case check */
len= RNA_property_multi_array_length(&self->ptr, self->prop, self->arraydim);
len= RNA_property_multi_array_length(ptr, prop, arraydim);
if (index >= len || index < 0) {
/* this shouldn't happen because higher level funcs must check for invalid index */
if (G.f & G_DEBUG) printf("pyrna_py_from_array_index: invalid index %d for array with length=%d\n", index, len);
@@ -473,11 +477,11 @@ PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, int index)
return NULL;
}
totdim= RNA_property_array_dimension(&self->ptr, self->prop, dimsize);
totdim= RNA_property_array_dimension(ptr, prop, dimsize);
if (self->arraydim + 1 < totdim) {
ret= (BPy_PropertyRNA*)pyrna_prop_CreatePyObject(&self->ptr, self->prop);
ret->arraydim= self->arraydim + 1;
if (arraydim + 1 < totdim) {
ret= (BPy_PropertyRNA*)pyrna_prop_CreatePyObject(ptr, prop);
ret->arraydim= arraydim + 1;
/* arr[3][4][5]
@@ -487,14 +491,14 @@ PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, int index)
x = arr[2][3]
index = offset + 3 * 5 */
for (i= self->arraydim + 1; i < totdim; i++)
for (i= arraydim + 1; i < totdim; i++)
index *= dimsize[i];
ret->arrayoffset= self->arrayoffset + index;
ret->arrayoffset= arrayoffset + index;
}
else {
index = self->arrayoffset + index;
ret= (BPy_PropertyRNA*)pyrna_array_item(&self->ptr, self->prop, index);
index = arrayoffset + index;
ret= (BPy_PropertyRNA*)pyrna_array_item(ptr, prop, index);
}
return (PyObject*)ret;

View File

@@ -39,6 +39,7 @@
#include "eval.h" /* for PyEval_EvalCode */
#include "bpy_rna.h"
#include "bpy_props.h"
#include "bpy_operator.h"
#include "bpy_ui.h"
#include "bpy_util.h"

View File

@@ -32,6 +32,8 @@
#include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
#include "bpy_util.h"
#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -45,6 +47,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
wmOperatorType *ot;
int error_val = 0;
PointerRNA ptr;
int operator_ret= OPERATOR_CANCELLED;
char *opname;
PyObject *kw= NULL; /* optional args */
@@ -63,7 +66,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
ot= WM_operatortype_exists(opname);
if (ot == NULL) {
PyErr_Format( PyExc_SystemError, "_bpy.ops.call: operator \"%s\" could not be found", opname);
PyErr_Format( PyExc_SystemError, "Calling operator \"bpy.ops.%s\" error, could not be found", opname);
return NULL;
}
@@ -76,7 +79,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
Py_XINCREF(context_dict); /* so we done loose it */
if(WM_operator_poll((bContext*)C, ot) == FALSE) {
PyErr_Format( PyExc_SystemError, "_bpy.ops.call: operator %.200s.poll() function failed, context is incorrect", opname);
PyErr_Format( PyExc_SystemError, "Operator bpy.ops.%.200s.poll() failed, context is incorrect", opname);
error_val= -1;
}
else {
@@ -94,7 +97,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
BKE_reports_init(reports, RPT_STORE);
WM_operator_call_py(C, ot, context, &ptr, reports);
operator_ret= WM_operator_call_py(C, ot, context, &ptr, reports);
if(BPy_reports_to_error(reports))
error_val = -1;
@@ -140,7 +143,9 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
return NULL;
}
Py_RETURN_NONE;
/* return operator_ret as a bpy enum */
return pyrna_enum_bitfield_to_py(operator_return_items, operator_ret);
}
static PyObject *pyop_as_string( PyObject * self, PyObject * args)

View File

@@ -31,6 +31,7 @@
#include "RNA_define.h"
#include "bpy_rna.h"
#include "bpy_props.h"
#include "bpy_util.h"
static void operator_properties_init(wmOperatorType *ot)

View File

@@ -0,0 +1,505 @@
/**
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Contributor(s): Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "bpy_props.h"
#include "bpy_rna.h"
#include "RNA_access.h"
#include "RNA_define.h" /* for defining our own rna */
#include "MEM_guardedalloc.h"
#include "float.h" /* FLT_MIN/MAX */
/* operators use this so it can store the args given but defer running
* it until the operator runs where these values are used to setup the
* default args for that operator instance */
static PyObject *bpy_prop_deferred_return(void *func, PyObject *kw)
{
PyObject *ret = PyTuple_New(2);
PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr(func, NULL));
PyTuple_SET_ITEM(ret, 1, kw);
Py_INCREF(kw);
return ret;
}
/* Function that sets RNA, NOTE - self is NULL when called from python, but being abused from C so we can pass the srna allong
* This isnt incorrect since its a python object - but be careful */
static char BPy_BoolProperty_doc[] =
".. function:: BoolProperty(name=\"\", description=\"\", default=False, hidden=False)\n"
"\n"
" Returns a new boolean property definition..";
PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "name", "description", "default", "hidden", NULL};
char *id=NULL, *name="", *description="";
int def=0, hidden=0;
PropertyRNA *prop;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssii:BoolProperty", kwlist, &id, &name, &description, &def, &hidden))
return NULL;
prop= RNA_def_boolean(srna, id, def, name, description);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_BoolProperty, kw);
}
}
static char BPy_IntProperty_doc[] =
".. function:: IntProperty(name=\"\", description=\"\", default=0, min=-sys.maxint, max=sys.maxint, soft_min=-sys.maxint, soft_max=sys.maxint, step=1, hidden=False)\n"
"\n"
" Returns a new int property definition.";
PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "hidden", NULL};
char *id=NULL, *name="", *description="";
int min=INT_MIN, max=INT_MAX, soft_min=INT_MIN, soft_max=INT_MAX, step=1, def=0;
int hidden=0;
PropertyRNA *prop;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssiiiiiii:IntProperty", kwlist, &id, &name, &description, &def, &min, &max, &soft_min, &soft_max, &step, &hidden))
return NULL;
prop= RNA_def_int(srna, id, def, min, max, name, description, soft_min, soft_max);
RNA_def_property_ui_range(prop, min, max, step, 0);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_IntProperty, kw);
}
}
static char BPy_FloatProperty_doc[] =
".. function:: FloatProperty(name=\"\", description=\"\", default=0.0, min=sys.float_info.min, max=sys.float_info.max, soft_min=sys.float_info.min, soft_max=sys.float_info.max, step=3, precision=2, hidden=False)\n"
"\n"
" Returns a new float property definition.";
PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "hidden", NULL};
char *id=NULL, *name="", *description="";
float min=-FLT_MAX, max=FLT_MAX, soft_min=-FLT_MAX, soft_max=FLT_MAX, step=3, def=0.0f;
int precision= 2, hidden=0;
PropertyRNA *prop;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssffffffii:FloatProperty", kwlist, &id, &name, &description, &def, &min, &max, &soft_min, &soft_max, &step, &precision, &hidden))
return NULL;
prop= RNA_def_float(srna, id, def, min, max, name, description, soft_min, soft_max);
RNA_def_property_ui_range(prop, min, max, step, precision);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_FloatProperty, kw);
}
}
static char BPy_FloatVectorProperty_doc[] =
".. function:: FloatVectorProperty(name=\"\", description=\"\", default=(0.0, 0.0, 0.0), min=sys.float_info.min, max=sys.float_info.max, soft_min=sys.float_info.min, soft_max=sys.float_info.max, step=3, precision=2, hidden=False, size=3)\n"
"\n"
" Returns a new vector float property definition.";
PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "hidden", "size", NULL};
char *id=NULL, *name="", *description="";
float min=-FLT_MAX, max=FLT_MAX, soft_min=-FLT_MAX, soft_max=FLT_MAX, step=3, def[PYRNA_STACK_ARRAY]={0.0f};
int precision= 2, hidden=0, size=3;
PropertyRNA *prop;
PyObject *pydef= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssOfffffiii:FloatVectorProperty", kwlist, &id, &name, &description, &pydef, &min, &max, &soft_min, &soft_max, &step, &precision, &hidden, &size))
return NULL;
if(size < 0 || size > PYRNA_STACK_ARRAY) {
PyErr_Format(PyExc_TypeError, "FloatVectorProperty(): size must be between 0 and %d, given %d.", PYRNA_STACK_ARRAY, size);
return NULL;
}
if(pydef) {
int i;
if(!PySequence_Check(pydef)) {
PyErr_Format(PyExc_TypeError, "FloatVectorProperty(): default value is not a sequence of size: %d.", size);
return NULL;
}
if(size != PySequence_Size(pydef)) {
PyErr_Format(PyExc_TypeError, "FloatVectorProperty(): size: %d, does not default: %d.", size, PySequence_Size(pydef));
return NULL;
}
for(i=0; i<size; i++) {
PyObject *item= PySequence_GetItem(pydef, i);
if(item) {
def[i]= PyFloat_AsDouble(item);
Py_DECREF(item);
}
}
if(PyErr_Occurred()) { /* error set above */
return NULL;
}
}
prop= RNA_def_float_vector(srna, id, size, pydef ? def:NULL, min, max, name, description, soft_min, soft_max);
RNA_def_property_ui_range(prop, min, max, step, precision);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_FloatVectorProperty, kw);
}
}
static char BPy_StringProperty_doc[] =
".. function:: StringProperty(name=\"\", description=\"\", default=\"\", maxlen=0, hidden=False)\n"
"\n"
" Returns a new string property definition.";
PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "name", "description", "default", "maxlen", "hidden", NULL};
char *id=NULL, *name="", *description="", *def="";
int maxlen=0, hidden=0;
PropertyRNA *prop;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|sssii:StringProperty", kwlist, &id, &name, &description, &def, &maxlen, &hidden))
return NULL;
prop= RNA_def_string(srna, id, def, maxlen, name, description);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_StringProperty, kw);
}
}
static EnumPropertyItem *enum_items_from_py(PyObject *value, const char *def, int *defvalue)
{
EnumPropertyItem *items= NULL;
PyObject *item;
int seq_len, i, totitem= 0;
if(!PySequence_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expected a sequence of tuples for the enum items");
return NULL;
}
seq_len = PySequence_Length(value);
for(i=0; i<seq_len; i++) {
EnumPropertyItem tmp= {0, "", 0, "", ""};
item= PySequence_GetItem(value, i);
if(item==NULL || PyTuple_Check(item)==0) {
PyErr_SetString(PyExc_TypeError, "expected a sequence of tuples for the enum items");
if(items) MEM_freeN(items);
Py_XDECREF(item);
return NULL;
}
if(!PyArg_ParseTuple(item, "sss", &tmp.identifier, &tmp.name, &tmp.description)) {
PyErr_SetString(PyExc_TypeError, "expected an identifier, name and description in the tuple");
Py_DECREF(item);
return NULL;
}
tmp.value= i;
RNA_enum_item_add(&items, &totitem, &tmp);
if(def[0] && strcmp(def, tmp.identifier) == 0)
*defvalue= tmp.value;
Py_DECREF(item);
}
if(!def[0])
*defvalue= 0;
RNA_enum_item_end(&items, &totitem);
return items;
}
static char BPy_EnumProperty_doc[] =
".. function:: EnumProperty(items, name=\"\", description=\"\", default=\"\", hidden=False)\n"
"\n"
" Returns a new enumerator property definition.\n"
"\n"
" :arg items: The items that make up this enumerator.\n"
" :type items: sequence of string triplets";
PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "items", "name", "description", "default", "hidden", NULL};
char *id=NULL, *name="", *description="", *def="";
int defvalue=0, hidden=0;
PyObject *items= Py_None;
EnumPropertyItem *eitems;
PropertyRNA *prop;
if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|sssi:EnumProperty", kwlist, &id, &items, &name, &description, &def, &hidden))
return NULL;
eitems= enum_items_from_py(items, def, &defvalue);
if(!eitems)
return NULL;
prop= RNA_def_enum(srna, id, eitems, defvalue, name, description);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
MEM_freeN(eitems);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_EnumProperty, kw);
}
}
static StructRNA *pointer_type_from_py(PyObject *value)
{
StructRNA *srna;
srna= srna_from_self(value);
if(!srna) {
PyErr_SetString(PyExc_SystemError, "expected an RNA type derived from IDPropertyGroup");
return NULL;
}
if(!RNA_struct_is_a(srna, &RNA_IDPropertyGroup)) {
PyErr_SetString(PyExc_SystemError, "expected an RNA type derived from IDPropertyGroup");
return NULL;
}
return srna;
}
static char BPy_PointerProperty_doc[] =
".. function:: PointerProperty(items, type=\"\", description=\"\", default=\"\", hidden=False)\n"
"\n"
" Returns a new pointer property definition.\n"
"\n"
" :arg type: Dynamic type from :mod:`bpy.types`.\n"
" :type type: class";
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "type", "name", "description", "hidden", NULL};
char *id=NULL, *name="", *description="";
int hidden= 0;
PropertyRNA *prop;
StructRNA *ptype;
PyObject *type= Py_None;
if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|ssi:PointerProperty", kwlist, &id, &type, &name, &description, &hidden))
return NULL;
ptype= pointer_type_from_py(type);
if(!ptype)
return NULL;
prop= RNA_def_pointer_runtime(srna, id, ptype, name, description);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_PointerProperty, kw);
}
return NULL;
}
static char BPy_CollectionProperty_doc[] =
".. function:: CollectionProperty(items, type=\"\", description=\"\", default=\"\", hidden=False)\n"
"\n"
" Returns a new collection property definition.\n"
"\n"
" :arg type: Dynamic type from :mod:`bpy.types`.\n"
" :type type: class";
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "type", "name", "description", "hidden", NULL};
char *id=NULL, *name="", *description="";
int hidden= 0;
PropertyRNA *prop;
StructRNA *ptype;
PyObject *type= Py_None;
if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|ssi:CollectionProperty", kwlist, &id, &type, &name, &description, &hidden))
return NULL;
ptype= pointer_type_from_py(type);
if(!ptype)
return NULL;
prop= RNA_def_collection_runtime(srna, id, ptype, name, description);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_CollectionProperty, kw);
}
return NULL;
}
static struct PyMethodDef props_methods[] = {
{"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, BPy_BoolProperty_doc},
{"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, BPy_IntProperty_doc},
{"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, BPy_FloatProperty_doc},
{"FloatVectorProperty", (PyCFunction)BPy_FloatVectorProperty, METH_VARARGS|METH_KEYWORDS, BPy_FloatVectorProperty_doc},
{"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, BPy_StringProperty_doc},
{"EnumProperty", (PyCFunction)BPy_EnumProperty, METH_VARARGS|METH_KEYWORDS, BPy_EnumProperty_doc},
{"PointerProperty", (PyCFunction)BPy_PointerProperty, METH_VARARGS|METH_KEYWORDS, BPy_PointerProperty_doc},
{"CollectionProperty", (PyCFunction)BPy_CollectionProperty, METH_VARARGS|METH_KEYWORDS, BPy_CollectionProperty_doc},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef props_module = {
PyModuleDef_HEAD_INIT,
"bpy.props",
"This module defines properties to extend blenders internal data, the result of these functions"
" is used to assign properties to classes registered with blender and can't be used directly.",
-1,/* multiple "initialization" just copies the module dict. */
props_methods,
NULL, NULL, NULL, NULL
};
PyObject *BPY_rna_props( void )
{
PyObject *submodule;
submodule= PyModule_Create(&props_module);
PyDict_SetItemString(PySys_GetObject("modules"), props_module.m_name, submodule);
/* INCREF since its its assumed that all these functions return the
* module with a new ref like PyDict_New, since they are passed to
* PyModule_AddObject which steals a ref */
Py_INCREF(submodule);
return submodule;
}

View File

@@ -0,0 +1,44 @@
/**
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Contributor(s): Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BPY_PROPS_H
#define BPY_PROPS_H
#include <Python.h>
PyObject *BPY_rna_props( void );
/* functions for setting up new props - experemental */
PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw);
#define PYRNA_STACK_ARRAY 32
#endif

View File

@@ -24,6 +24,7 @@
*/
#include "bpy_rna.h"
#include "bpy_props.h"
#include "bpy_util.h"
//#include "blendef.h"
#include "BLI_dynstr.h"
@@ -54,7 +55,7 @@
#include "../generic/Mathutils.h" /* so we can have mathutils callbacks */
#include "../generic/IDProp.h" /* for IDprop lookups */
static PyObject *prop_subscript_array_slice(PointerRNA *ptr, PropertyRNA *prop, int start, int stop, int length);
static PyObject *prop_subscript_array_slice(BPy_PropertyRNA *self, PointerRNA *ptr, PropertyRNA *prop, int start, int stop, int length);
/* bpyrna vector/euler/quat callbacks */
static int mathutils_rna_array_cb_index= -1; /* index for our callbacks */
@@ -239,7 +240,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
if(is_thick) {
/* this is an array we cant reference (since its not thin wrappable)
* and cannot be coerced into a mathutils type, so return as a list */
ret = prop_subscript_array_slice(ptr, prop, 0, len, len);
ret = prop_subscript_array_slice(NULL, ptr, prop, 0, len, len);
} else {
ret = pyrna_prop_CreatePyObject(ptr, prop); /* owned by the Mathutils PyObject */
}
@@ -423,6 +424,24 @@ static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *pr
return 1;
}
PyObject *pyrna_enum_bitfield_to_py(EnumPropertyItem *items, int value)
{
PyObject *ret= PySet_New(NULL);
const char *identifier[RNA_ENUM_BITFLAG_SIZE + 1];
if(RNA_enum_bitflag_identifiers(items, value, identifier)) {
PyObject *item;
int index;
for(index=0; identifier[index]; index++) {
item= PyUnicode_FromString(identifier[index]);
PySet_Add(ret, item);
Py_DECREF(item);
}
}
return ret;
}
static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
{
PyObject *item, *ret= NULL;
@@ -574,7 +593,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const cha
break;
}
} else {
if (pyrna_py_to_prop(ptr, prop, NULL, item, error_prefix)) {
if (pyrna_py_to_prop(ptr, prop, NULL, NULL, item, error_prefix)) {
error_val= -1;
break;
}
@@ -628,7 +647,7 @@ static PyObject *pyrna_func_to_py(BPy_DummyPointerRNA *pyrna, FunctionRNA *func)
int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value, const char *error_prefix)
int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, void *data, PyObject *value, const char *error_prefix)
{
/* XXX hard limits should be checked here */
int type = RNA_property_type(prop);
@@ -651,7 +670,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
return -1;
}
/* done getting the length */
ok= pyrna_py_to_array(ptr, prop, data, value, error_prefix);
ok= pyrna_py_to_array(ptr, prop, parms, data, value, error_prefix);
if (!ok) {
/* PyErr_Format(PyExc_AttributeError, "%.200s %s", error_prefix, error_str); */
@@ -669,7 +688,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
/* prefer not to have an exception here
* however so many poll functions return None or a valid Object.
* its a hassle to convert these into a bool before returning, */
if(RNA_property_flag(prop) & PROP_RETURN)
if(RNA_property_flag(prop) & PROP_OUTPUT)
param = PyObject_IsTrue( value );
else
param = PyLong_AsSsize_t( value );
@@ -877,7 +896,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
static PyObject * pyrna_prop_to_py_index(BPy_PropertyRNA *self, int index)
{
return pyrna_py_from_array_index(self, index);
return pyrna_py_from_array_index(self, &self->ptr, self->prop, index);
}
static int pyrna_py_to_prop_index(BPy_PropertyRNA *self, int index, PyObject *value)
@@ -1034,66 +1053,74 @@ static PyObject *prop_subscript_collection_slice(PointerRNA *ptr, PropertyRNA *p
* note: could also use pyrna_prop_to_py_index(self, count) in a loop but its a lot slower
* since at the moment it reads (and even allocates) the entire array for each index.
*/
#define PYRNA_STACK_ARRAY 32
static PyObject *prop_subscript_array_slice(PointerRNA *ptr, PropertyRNA *prop, int start, int stop, int length)
static PyObject *prop_subscript_array_slice(BPy_PropertyRNA *self, PointerRNA *ptr, PropertyRNA *prop, int start, int stop, int length)
{
int count, totdim;
PyObject *list = PyList_New(stop - start);
int count;
switch (RNA_property_type(prop)) {
totdim = RNA_property_array_dimension(ptr, prop, NULL);
if (totdim > 1) {
for (count = start; count < stop; count++)
PyList_SET_ITEM(list, count - start, pyrna_prop_to_py_index(self, count));
}
else {
switch (RNA_property_type(prop)) {
case PROP_FLOAT:
{
float values_stack[PYRNA_STACK_ARRAY];
float *values;
if(length > PYRNA_STACK_ARRAY) { values= PyMem_MALLOC(sizeof(float) * length); }
else { values= values_stack; }
RNA_property_float_get_array(ptr, prop, values);
{
float values_stack[PYRNA_STACK_ARRAY];
float *values;
if(length > PYRNA_STACK_ARRAY) { values= PyMem_MALLOC(sizeof(float) * length); }
else { values= values_stack; }
RNA_property_float_get_array(ptr, prop, values);
for(count=start; count<stop; count++)
PyList_SET_ITEM(list, count-start, PyFloat_FromDouble(values[count]));
for(count=start; count<stop; count++)
PyList_SET_ITEM(list, count-start, PyFloat_FromDouble(values[count]));
if(values != values_stack) {
PyMem_FREE(values);
if(values != values_stack) {
PyMem_FREE(values);
}
break;
}
break;
}
case PROP_BOOLEAN:
{
int values_stack[PYRNA_STACK_ARRAY];
int *values;
if(length > PYRNA_STACK_ARRAY) { values= PyMem_MALLOC(sizeof(int) * length); }
else { values= values_stack; }
{
int values_stack[PYRNA_STACK_ARRAY];
int *values;
if(length > PYRNA_STACK_ARRAY) { values= PyMem_MALLOC(sizeof(int) * length); }
else { values= values_stack; }
RNA_property_boolean_get_array(ptr, prop, values);
for(count=start; count<stop; count++)
PyList_SET_ITEM(list, count-start, PyBool_FromLong(values[count]));
RNA_property_boolean_get_array(ptr, prop, values);
for(count=start; count<stop; count++)
PyList_SET_ITEM(list, count-start, PyBool_FromLong(values[count]));
if(values != values_stack) {
PyMem_FREE(values);
if(values != values_stack) {
PyMem_FREE(values);
}
break;
}
break;
}
case PROP_INT:
{
int values_stack[PYRNA_STACK_ARRAY];
int *values;
if(length > PYRNA_STACK_ARRAY) { values= PyMem_MALLOC(sizeof(int) * length); }
else { values= values_stack; }
{
int values_stack[PYRNA_STACK_ARRAY];
int *values;
if(length > PYRNA_STACK_ARRAY) { values= PyMem_MALLOC(sizeof(int) * length); }
else { values= values_stack; }
RNA_property_int_get_array(ptr, prop, values);
for(count=start; count<stop; count++)
PyList_SET_ITEM(list, count-start, PyLong_FromSsize_t(values[count]));
RNA_property_int_get_array(ptr, prop, values);
for(count=start; count<stop; count++)
PyList_SET_ITEM(list, count-start, PyLong_FromSsize_t(values[count]));
if(values != values_stack) {
PyMem_FREE(values);
if(values != values_stack) {
PyMem_FREE(values);
}
break;
}
break;
}
default:
/* probably will never happen */
PyErr_SetString(PyExc_TypeError, "not an array type");
Py_DECREF(list);
list= NULL;
}
}
return list;
}
@@ -1156,7 +1183,7 @@ static PyObject *prop_subscript_array(BPy_PropertyRNA *self, PyObject *key)
return PyList_New(0);
}
else if (step == 1) {
return prop_subscript_array_slice(&self->ptr, self->prop, start, stop, len);
return prop_subscript_array_slice(self, &self->ptr, self->prop, start, stop, len);
}
else {
PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna");
@@ -1963,7 +1990,7 @@ static int pyrna_struct_setattro( BPy_StructRNA *self, PyObject *pyname, PyObjec
}
/* pyrna_py_to_prop sets its own exceptions */
return pyrna_py_to_prop(&self->ptr, prop, NULL, value, "StructRNA - item.attr = val:");
return pyrna_py_to_prop(&self->ptr, prop, NULL, NULL, value, "StructRNA - item.attr = val:");
}
static PyObject *pyrna_prop_dir(BPy_PropertyRNA *self)
@@ -2039,7 +2066,7 @@ static int pyrna_prop_setattro( BPy_PropertyRNA *self, PyObject *pyname, PyObjec
if(RNA_property_collection_type_get(&self->ptr, self->prop, &r_ptr)) {
if ((prop = RNA_struct_find_property(&r_ptr, name))) {
/* pyrna_py_to_prop sets its own exceptions */
return pyrna_py_to_prop(&r_ptr, prop, NULL, value, "BPy_PropertyRNA - Attribute (setattr):");
return pyrna_py_to_prop(&r_ptr, prop, NULL, NULL, value, "BPy_PropertyRNA - Attribute (setattr):");
}
}
}
@@ -2511,7 +2538,7 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self)
if(RNA_property_array_check(&self->ptr, self->prop)) {
int len= pyrna_prop_array_length(self);
ret = prop_subscript_array_slice(&self->ptr, self->prop, 0, len, len);
ret = prop_subscript_array_slice(self, &self->ptr, self->prop, 0, len, len);
}
else if ((ret = pyrna_prop_values(self))) {
/* do nothing */
@@ -2607,7 +2634,7 @@ static PyObject * pyrna_prop_new(PyTypeObject *type, PyObject *args, PyObject *k
}
}
PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
PyObject *pyrna_param_to_py(PointerRNA *ptr, ParameterList *parms, PropertyRNA *prop, void *data)
{
PyObject *ret;
int type = RNA_property_type(prop);
@@ -2615,7 +2642,15 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
int a;
if(RNA_property_array_check(ptr, prop)) {
int len = RNA_property_array_length(ptr, prop);
int len;
if (flag & PROP_DYNAMIC) {
len= RNA_parameter_length_get_data(parms, prop, data);
data= *((void **)data);
}
else
len= RNA_property_array_length(ptr, prop);
/* resolve the array from a new pytype */
@@ -2792,7 +2827,7 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
flag= RNA_property_flag(parm);
/* only useful for single argument returns, we'll need another list loop for multiple */
if (flag & PROP_RETURN) {
if (flag & PROP_OUTPUT) {
ret_len++;
if (pret_single==NULL) {
pret_single= parm;
@@ -2829,7 +2864,7 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
continue;
}
err= pyrna_py_to_prop(&funcptr, parm, iter.data, item, "");
err= pyrna_py_to_prop(&funcptr, parm, &parms, iter.data, item, "");
if(err!=0) {
/* the error generated isnt that useful, so generate it again with a useful prefix
@@ -2842,7 +2877,7 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
else
snprintf(error_prefix, sizeof(error_prefix), "%s.%s(): error with argument %d, \"%s\" - ", RNA_struct_identifier(self_ptr->type), RNA_function_identifier(self_func), i, parm_id);
pyrna_py_to_prop(&funcptr, parm, iter.data, item, error_prefix);
pyrna_py_to_prop(&funcptr, parm, &parms, iter.data, item, error_prefix);
break;
}
@@ -2900,7 +2935,7 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
RNA_parameter_list_begin(&parms, &iter);
for(; iter.valid; RNA_parameter_list_next(&iter)) {
parm= iter.parm;
if(RNA_property_flag(parm) & PROP_RETURN)
if(RNA_property_flag(parm) & PROP_OUTPUT)
continue;
BLI_dynstr_appendf(good_args, first ? "%s" : ", %s", RNA_property_identifier(parm));
@@ -2947,14 +2982,14 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
parm= iter.parm;
flag= RNA_property_flag(parm);
if (flag & PROP_RETURN)
PyTuple_SET_ITEM(ret, i++, pyrna_param_to_py(&funcptr, parm, iter.data));
if (flag & PROP_OUTPUT)
PyTuple_SET_ITEM(ret, i++, pyrna_param_to_py(&funcptr, &parms, parm, iter.data));
}
RNA_parameter_list_end(&iter);
}
else
ret= pyrna_param_to_py(&funcptr, pret_single, retdata_single);
ret= pyrna_param_to_py(&funcptr, &parms, pret_single, retdata_single);
/* possible there is an error in conversion */
if(ret==NULL)
@@ -3140,6 +3175,7 @@ static struct PyMethodDef pyrna_struct_subtype_methods[] = {
{"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"FloatVectorProperty", (PyCFunction)BPy_FloatVectorProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"EnumProperty", (PyCFunction)BPy_EnumProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"PointerProperty", (PyCFunction)BPy_PointerProperty, METH_VARARGS|METH_KEYWORDS, ""},
@@ -3462,8 +3498,13 @@ static PyObject *pyrna_basetype_getattro( BPy_BaseTypeRNA *self, PyObject *pynam
{
PointerRNA newptr;
PyObject *ret;
char *name= _PyUnicode_AsString(pyname);
if (RNA_property_collection_lookup_string(&self->ptr, self->prop, _PyUnicode_AsString(pyname), &newptr)) {
if(strcmp(name, "register")==0) {
/* this is called so often, make an exception and save a full lookup on all types */
ret= PyObject_GenericGetAttr((PyObject *)self, pyname);
}
else if (RNA_property_collection_lookup_string(&self->ptr, self->prop, name, &newptr)) {
ret= pyrna_struct_Subtype(&newptr);
if (ret==NULL) {
PyErr_Format(PyExc_SystemError, "bpy.types.%.200s subtype could not be generated, this is a bug!", _PyUnicode_AsString(pyname));
@@ -3531,40 +3572,6 @@ PyObject *BPY_rna_types(void)
return (PyObject *)self;
}
static struct PyMethodDef props_methods[] = {
{"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"EnumProperty", (PyCFunction)BPy_EnumProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"PointerProperty", (PyCFunction)BPy_PointerProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"CollectionProperty", (PyCFunction)BPy_CollectionProperty, METH_VARARGS|METH_KEYWORDS, ""},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef props_module = {
PyModuleDef_HEAD_INIT,
"bpy.props",
"",
-1,/* multiple "initialization" just copies the module dict. */
props_methods,
NULL, NULL, NULL, NULL
};
PyObject *BPY_rna_props( void )
{
PyObject *submodule;
submodule= PyModule_Create(&props_module);
PyDict_SetItemString(PySys_GetObject("modules"), props_module.m_name, submodule);
/* INCREF since its its assumed that all these functions return the
* module with a new ref like PyDict_New, since they are passed to
* PyModule_AddObject which steals a ref */
Py_INCREF(submodule);
return submodule;
}
StructRNA *pyrna_struct_as_srna(PyObject *self)
{
BPy_StructRNA *py_srna = NULL;
@@ -3602,7 +3609,6 @@ StructRNA *pyrna_struct_as_srna(PyObject *self)
return srna;
}
/* Orphan functions, not sure where they should go */
/* get the srna for methods attached to types */
/* */
@@ -3611,7 +3617,7 @@ StructRNA *srna_from_self(PyObject *self)
/* a bit sloppy but would cause a very confusing bug if
* an error happened to be set here */
PyErr_Clear();
if(self==NULL) {
return NULL;
}
@@ -3627,336 +3633,6 @@ StructRNA *srna_from_self(PyObject *self)
return pyrna_struct_as_srna(self);
}
/* operators use this so it can store the args given but defer running
* it until the operator runs where these values are used to setup the
* default args for that operator instance */
static PyObject *bpy_prop_deferred_return(void *func, PyObject *kw)
{
PyObject *ret = PyTuple_New(2);
PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr(func, NULL));
PyTuple_SET_ITEM(ret, 1, kw);
Py_INCREF(kw);
return ret;
}
/* Function that sets RNA, NOTE - self is NULL when called from python, but being abused from C so we can pass the srna allong
* This isnt incorrect since its a python object - but be careful */
PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "name", "description", "default", "hidden", NULL};
char *id=NULL, *name="", *description="";
int def=0, hidden=0;
PropertyRNA *prop;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssii:BoolProperty", kwlist, &id, &name, &description, &def, &hidden))
return NULL;
prop= RNA_def_boolean(srna, id, def, name, description);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_BoolProperty, kw);
}
}
PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "hidden", NULL};
char *id=NULL, *name="", *description="";
int min=INT_MIN, max=INT_MAX, soft_min=INT_MIN, soft_max=INT_MAX, step=1, def=0;
int hidden=0;
PropertyRNA *prop;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssiiiiiii:IntProperty", kwlist, &id, &name, &description, &def, &min, &max, &soft_min, &soft_max, &step, &hidden))
return NULL;
prop= RNA_def_int(srna, id, def, min, max, name, description, soft_min, soft_max);
RNA_def_property_ui_range(prop, min, max, step, 0);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_IntProperty, kw);
}
}
PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "hidden", NULL};
char *id=NULL, *name="", *description="";
float min=-FLT_MAX, max=FLT_MAX, soft_min=-FLT_MAX, soft_max=FLT_MAX, step=3, def=0.0f;
int precision= 1, hidden=0;
PropertyRNA *prop;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssffffffii:FloatProperty", kwlist, &id, &name, &description, &def, &min, &max, &soft_min, &soft_max, &step, &precision, &hidden))
return NULL;
prop= RNA_def_float(srna, id, def, min, max, name, description, soft_min, soft_max);
RNA_def_property_ui_range(prop, min, max, step, precision);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_FloatProperty, kw);
}
}
PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "name", "description", "default", "maxlen", "hidden", NULL};
char *id=NULL, *name="", *description="", *def="";
int maxlen=0, hidden=0;
PropertyRNA *prop;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|sssii:StringProperty", kwlist, &id, &name, &description, &def, &maxlen, &hidden))
return NULL;
prop= RNA_def_string(srna, id, def, maxlen, name, description);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_StringProperty, kw);
}
}
static EnumPropertyItem *enum_items_from_py(PyObject *value, const char *def, int *defvalue)
{
EnumPropertyItem *items= NULL;
PyObject *item;
int seq_len, i, totitem= 0;
if(!PySequence_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expected a sequence of tuples for the enum items");
return NULL;
}
seq_len = PySequence_Length(value);
for(i=0; i<seq_len; i++) {
EnumPropertyItem tmp= {0, "", 0, "", ""};
item= PySequence_GetItem(value, i);
if(item==NULL || PyTuple_Check(item)==0) {
PyErr_SetString(PyExc_TypeError, "expected a sequence of tuples for the enum items");
if(items) MEM_freeN(items);
Py_XDECREF(item);
return NULL;
}
if(!PyArg_ParseTuple(item, "sss", &tmp.identifier, &tmp.name, &tmp.description)) {
PyErr_SetString(PyExc_TypeError, "expected an identifier, name and description in the tuple");
Py_DECREF(item);
return NULL;
}
tmp.value= i;
RNA_enum_item_add(&items, &totitem, &tmp);
if(def[0] && strcmp(def, tmp.identifier) == 0)
*defvalue= tmp.value;
Py_DECREF(item);
}
if(!def[0])
*defvalue= 0;
RNA_enum_item_end(&items, &totitem);
return items;
}
PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "items", "name", "description", "default", "hidden", NULL};
char *id=NULL, *name="", *description="", *def="";
int defvalue=0, hidden=0;
PyObject *items= Py_None;
EnumPropertyItem *eitems;
PropertyRNA *prop;
if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|sssi:EnumProperty", kwlist, &id, &items, &name, &description, &def, &hidden))
return NULL;
eitems= enum_items_from_py(items, def, &defvalue);
if(!eitems)
return NULL;
prop= RNA_def_enum(srna, id, eitems, defvalue, name, description);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
MEM_freeN(eitems);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_EnumProperty, kw);
}
}
static StructRNA *pointer_type_from_py(PyObject *value)
{
StructRNA *srna;
srna= srna_from_self(value);
if(!srna) {
PyErr_SetString(PyExc_SystemError, "expected an RNA type derived from IDPropertyGroup");
return NULL;
}
if(!RNA_struct_is_a(srna, &RNA_IDPropertyGroup)) {
PyErr_SetString(PyExc_SystemError, "expected an RNA type derived from IDPropertyGroup");
return NULL;
}
return srna;
}
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "type", "name", "description", "hidden", NULL};
char *id=NULL, *name="", *description="";
int hidden= 0;
PropertyRNA *prop;
StructRNA *ptype;
PyObject *type= Py_None;
if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|ssi:PointerProperty", kwlist, &id, &type, &name, &description, &hidden))
return NULL;
ptype= pointer_type_from_py(type);
if(!ptype)
return NULL;
prop= RNA_def_pointer_runtime(srna, id, ptype, name, description);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_PointerProperty, kw);
}
return NULL;
}
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
srna= srna_from_self(self);
if(srna==NULL && PyErr_Occurred()) {
return NULL; /* self's type was compatible but error getting the srna */
}
else if(srna) {
static char *kwlist[] = {"attr", "type", "name", "description", "hidden", NULL};
char *id=NULL, *name="", *description="";
int hidden= 0;
PropertyRNA *prop;
StructRNA *ptype;
PyObject *type= Py_None;
if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|ssi:CollectionProperty", kwlist, &id, &type, &name, &description, &hidden))
return NULL;
ptype= pointer_type_from_py(type);
if(!ptype)
return NULL;
prop= RNA_def_collection_runtime(srna, id, ptype, name, description);
if(hidden) RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_duplicate_pointers(prop);
Py_RETURN_NONE;
}
else { /* operators defer running this function */
return bpy_prop_deferred_return((void *)BPy_CollectionProperty, kw);
}
return NULL;
}
static int deferred_register_prop(StructRNA *srna, PyObject *item, PyObject *key, PyObject *dummy_args)
{
/* We only care about results from C which
@@ -4056,7 +3732,7 @@ static int rna_function_arg_count(FunctionRNA *func)
for(link=lb->first; link; link=link->next) {
parm= (PropertyRNA*)link;
if(!(RNA_property_flag(parm) & PROP_RETURN))
if(!(RNA_property_flag(parm) & PROP_OUTPUT))
count++;
}
@@ -4157,7 +3833,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
if(strcmp(identifier, rna_attr) == 0) { \
item= PyObject_GetAttrString(py_class, py_attr); \
if(item && item != Py_None) { \
if(pyrna_py_to_prop(dummyptr, prop, NULL, item, "validating class error:") != 0) { \
if(pyrna_py_to_prop(dummyptr, prop, NULL, NULL, item, "validating class error:") != 0) { \
Py_DECREF(item); \
return -1; \
} \
@@ -4181,7 +3857,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
else {
Py_DECREF(item); /* no need to keep a ref, the class owns it */
if(pyrna_py_to_prop(dummyptr, prop, NULL, item, "validating class error:") != 0)
if(pyrna_py_to_prop(dummyptr, prop, NULL, NULL, item, "validating class error:") != 0)
return -1;
}
}
@@ -4244,7 +3920,7 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par
flag= RNA_property_flag(parm);
/* only useful for single argument returns, we'll need another list loop for multiple */
if (flag & PROP_RETURN) {
if (flag & PROP_OUTPUT) {
ret_len++;
if (pret_single==NULL) {
pret_single= parm;
@@ -4254,7 +3930,7 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par
continue;
}
parmitem= pyrna_param_to_py(&funcptr, parm, iter.data);
parmitem= pyrna_param_to_py(&funcptr, parms, parm, iter.data);
PyTuple_SET_ITEM(args, i, parmitem);
i++;
}
@@ -4282,7 +3958,7 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par
}
else {
if(ret_len==1) {
err= pyrna_py_to_prop(&funcptr, pret_single, retdata_single, ret, "calling class function:");
err= pyrna_py_to_prop(&funcptr, pret_single, parms, retdata_single, ret, "calling class function:");
}
else if (ret_len > 1) {
@@ -4304,8 +3980,8 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par
flag= RNA_property_flag(parm);
/* only useful for single argument returns, we'll need another list loop for multiple */
if (flag & PROP_RETURN) {
err= pyrna_py_to_prop(&funcptr, parm, iter.data, PyTuple_GET_ITEM(ret, i++), "calling class function:");
if (flag & PROP_OUTPUT) {
err= pyrna_py_to_prop(&funcptr, parm, parms, iter.data, PyTuple_GET_ITEM(ret, i++), "calling class function:");
if(err)
break;
}

View File

@@ -70,24 +70,16 @@ PyObject *BPY_rna_module( void );
void BPY_update_rna_module( void );
/*PyObject *BPY_rna_doc( void );*/
PyObject *BPY_rna_types( void );
PyObject *BPY_rna_props( void );
PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr );
PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop );
/* operators also need this to set args */
int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value, const char *error_prefix);
int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, void *data, PyObject *value, const char *error_prefix);
int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const char *error_prefix);
PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);
/* functions for setting up new props - experemental */
PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *pyrna_enum_bitfield_to_py(struct EnumPropertyItem *items, int value);
/* function for registering types */
PyObject *pyrna_basetype_register(PyObject *self, PyObject *args);
@@ -100,11 +92,11 @@ void pyrna_alloc_types(void);
void pyrna_free_types(void);
/* primitive type conversion */
int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix);
int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, char *param_data, PyObject *py, const char *error_prefix);
int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix);
PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop);
PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, int index);
PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index);
PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop);
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value);

View File

@@ -29,6 +29,7 @@ Generate html docs by running...
sphinx-build source/blender/python/doc/sphinx-in source/blender/python/doc/sphinx-out
'''
import os
import inspect
import bpy
@@ -49,6 +50,142 @@ def write_indented_lines(ident, fn, text):
for l in text.split("\n"):
fn(ident + l.strip() + "\n")
def pymethod2sphinx(ident, fw, identifier, py_func):
'''
class method to sphinx
'''
arg_str = inspect.formatargspec(*inspect.getargspec(py_func))
if arg_str.startswith("(self, "):
arg_str = "(" + arg_str[7:]
func_type = "method"
elif arg_str.startswith("(cls, "):
arg_str = "(" + arg_str[6:]
func_type = "classmethod"
else:
func_type = "staticmethod"
fw(ident + ".. %s:: %s%s\n\n" % (func_type, identifier, arg_str))
if py_func.__doc__:
write_indented_lines(ident + " ", fw, py_func.__doc__)
fw("\n")
def pyfunc2sphinx(ident, fw, identifier, py_func, is_class=True):
'''
function or class method to sphinx
'''
arg_str = inspect.formatargspec(*inspect.getargspec(py_func))
if not is_class:
func_type = "function"
# ther rest are class methods
elif arg_str.startswith("(self, "):
arg_str = "(" + arg_str[7:]
func_type = "method"
elif arg_str.startswith("(cls, "):
arg_str = "(" + arg_str[6:]
func_type = "classmethod"
else:
func_type = "staticmethod"
fw(ident + ".. %s:: %s%s\n\n" % (func_type, identifier, arg_str))
if py_func.__doc__:
write_indented_lines(ident + " ", fw, py_func.__doc__.strip())
fw("\n")
def py_c_func2sphinx(ident, fw, identifier, py_func, is_class=True):
'''
c defined function to sphinx.
'''
# dump the docstring, assume its formatted correctly
if py_func.__doc__:
for l in py_func.__doc__.split("\n"):
fw(ident + l + "\n")
fw("\n")
else:
fw(ident + ".. function:: %s()\n\n" % identifier)
fw(ident + " Undocumented function.\n\n" % identifier)
def pyprop2sphinx(ident, fw, identifier, py_prop):
'''
python property to sphinx
'''
fw(ident + ".. attribute:: %s\n\n" % identifier)
write_indented_lines(ident + " ", fw, py_prop.__doc__)
if py_prop.fset is None:
fw(ident + " (readonly)\n\n")
def pymodule2sphinx(BASEPATH, module_name, module, title):
import types
# lame, python wont give some access
MethodDescriptorType = type(dict.get)
GetSetDescriptorType = type(int.real)
filepath = os.path.join(BASEPATH, module_name + ".rst")
file = open(filepath, "w")
print(filepath)
print(filepath)
fw = file.write
fw(title + "\n")
fw(("=" * len(title)) + "\n\n")
fw(".. module:: %s\n\n" % module_name)
if module.__doc__:
# Note, may contain sphinx syntax, dont mangle!
fw(module.__doc__.strip())
fw("\n\n")
classes = []
for attribute in dir(module):
if not attribute.startswith("_"):
value = getattr(module, attribute)
value_type = type(value)
if value_type == types.FunctionType:
pyfunc2sphinx("", fw, attribute, value, is_class=False)
elif value_type in (types.BuiltinMethodType, types.BuiltinFunctionType): # both the same at the moment but to be future proof
# note: can't get args from these, so dump the string as is
# this means any module used like this must have fully formatted docstrings.
py_c_func2sphinx("", fw, attribute, value, is_class=False)
elif value_type == type:
classes.append((attribute, value))
# TODO, more types...
# write collected classes now
for (attribute, value) in classes:
# May need to be its own function
fw(".. class:: %s\n\n" % attribute)
if value.__doc__:
for l in value.__doc__.split("\n"):
fw(" %s\n" % l)
fw("\n")
for key, descr in value.__dict__.items():
if key.startswith("__"):
continue
descr_type = type(descr)
if descr_type in (MethodDescriptorType, ): # GetSetDescriptorType, GetSetDescriptorType's are not documented yet
if descr.__doc__:
for l in descr.__doc__.split("\n"):
fw(" %s\n" % l)
fw("\n")
fw("\n\n")
file.close()
def rna2sphinx(BASEPATH):
structs, funcs, ops, props = rna_info.BuildRNAInfo()
@@ -78,10 +215,34 @@ def rna2sphinx(BASEPATH):
fw("\n")
fw(".. toctree::\n")
fw(" :glob:\n\n")
fw(" bpy.ops.*\n\n")
fw(" bpy.types.*\n\n")
#fw(" bpy.ops.*\n\n")
#fw(" bpy.types.*\n\n")
# py modules
fw(" bpy.utils\n\n")
fw(" bpy.app\n\n")
# C modules
fw(" bpy.props\n\n")
fw(" Mathutils\n\n")
file.close()
# python modules
from bpy import utils as module
pymodule2sphinx(BASEPATH, "bpy.utils", module, "Blender Python Utilities")
from bpy import app as module
pymodule2sphinx(BASEPATH, "bpy.app", module, "Blender Python Application Constants")
from bpy import props as module
pymodule2sphinx(BASEPATH, "bpy.props", module, "Blender Python Property Definitions")
import Mathutils as module
pymodule2sphinx(BASEPATH, "Mathutils", module, "Module Mathutils")
del module
if 0:
filepath = os.path.join(BASEPATH, "bpy.rst")
file = open(filepath, "w")
@@ -167,10 +328,7 @@ def rna2sphinx(BASEPATH):
py_properties = struct.get_py_properties()
py_prop = None
for identifier, py_prop in py_properties:
fw(" .. attribute:: %s\n\n" % identifier)
write_indented_lines(" ", fw, py_prop.__doc__)
if py_prop.fset is None:
fw(" (readonly)\n\n")
pyprop2sphinx(" ", fw, identifier, py_prop)
del py_properties, py_prop
for func in struct.functions:
@@ -201,20 +359,7 @@ def rna2sphinx(BASEPATH):
py_func = None
for identifier, py_func in py_funcs:
arg_str = inspect.formatargspec(*inspect.getargspec(py_func))
if arg_str.startswith("(self, "):
arg_str = "(" + arg_str[7:]
func_type = "method"
elif arg_str.startswith("(cls, "):
arg_str = "(" + arg_str[6:]
func_type = "classmethod"
else:
func_type = "staticmethod"
fw(" .. %s:: %s%s\n\n" % (func_type, identifier, arg_str))
if py_func.__doc__:
write_indented_lines(" ", fw, py_func.__doc__)
fw("\n")
pyfunc2sphinx(" ", fw, identifier, py_func, is_class=True)
del py_funcs, py_func
if struct.references: