merge with/from trunk at r35190

This commit is contained in:
2011-02-27 06:19:40 +00:00
3230 changed files with 145269 additions and 212767 deletions

View File

@@ -27,11 +27,16 @@
* ***** END GPL LICENSE BLOCK *****
*/
/** \file BPY_extern.h
* \ingroup python
*/
#ifndef BPY_EXTERN_H
#define BPY_EXTERN_H
extern char bprogname[]; /* holds a copy of argv[0], from creator.c */
extern char btempdir[]; /* use this to store a valid temp directory */
struct Text; /* defined in DNA_text_types.h */
struct ID; /* DNA_ID.h */
@@ -39,14 +44,12 @@ struct Object; /* DNA_object_types.h */
struct ChannelDriver; /* DNA_anim_types.h */
struct ListBase; /* DNA_listBase.h */
struct SpaceText; /* DNA_space_types.h */
struct SpaceScript; /* DNA_space_types.h */
struct ScrArea; /* DNA_screen_types.h */
struct bScreen; /* DNA_screen_types.h */
struct bConstraint; /* DNA_constraint_types.h */
struct bPythonConstraint; /* DNA_constraint_types.h */
struct bConstraintOb; /* DNA_constraint_types.h */
struct bConstraintTarget; /* DNA_constraint_types.h*/
struct Script; /* DNA_screen_types.h */
struct BPyMenu;
struct bContext;
struct bContextDataResult;
@@ -56,34 +59,15 @@ struct ReportList;
extern "C" {
#endif
/*These two next functions are important for making sure the Draw module
works correctly. Before calling any gui callback using the Draw module,
the following code must be executed:
if (some_drawspace_pylist) {
BPy_Set_DrawButtonsList(some_drawspace_pylist->but_refs);
BPy_Free_DrawButtonsList();
}
some_drawspace_pylist = PyList_New(0);
BPy_Set_DrawButtonsList(some_drawspace_pylist);
Also, BPy_Free_DrawButtonsList() must be called as necassary when a drawspace
with python callbacks is destroyed.
This is necassary to avoid blender buttons storing invalid pointers to freed
python data.*/
// void BPy_Set_DrawButtonsList(void *list);
// void BPy_Free_DrawButtonsList(void);
//
void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
void BPY_pyconstraint_exec(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
// void BPY_pyconstraint_settings(void *arg1, void *arg2);
void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct);
void BPY_pyconstraint_update(struct Object *owner, struct bConstraint *con);
int BPY_is_pyconstraint(struct Text *text);
void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct);
void BPY_pyconstraint_update(struct Object *owner, struct bConstraint *con);
int BPY_is_pyconstraint(struct Text *text);
// void BPY_free_pyconstraint_links(struct Text *text);
//
void BPY_start_python( int argc, char **argv );
void BPY_end_python( void );
void BPY_python_start(int argc, const char **argv);
void BPY_python_end( void );
// void init_syspath( int first_time );
// void syspath_append( char *dir );
// void BPY_rebuild_syspath( void );
@@ -91,55 +75,23 @@ extern "C" {
//
// int BPY_Err_getLinenumber( void );
// const char *BPY_Err_getFilename( void );
//
// int BPY_txt_do_python_Text( struct Text *text );
// int BPY_menu_do_python( short menutype, int event );
// int BPY_menu_do_shortcut( short menutype, unsigned short key, unsigned short modifiers );
// int BPY_menu_invoke( struct BPyMenu *pym, short menutype );
/* 2.5 UI Scripts */
int BPY_run_python_script( struct bContext *C, const char *filename, struct Text *text, struct ReportList *reports ); // 2.5 working
int BPY_run_script_space_draw(const struct bContext *C, struct SpaceScript * sc); // 2.5 working
// int BPY_run_script_space_listener(struct bContext *C, struct SpaceScript * sc, struct ARegion *ar, struct wmNotifier *wmn); // 2.5 working
void BPY_update_modules( void ); // XXX - annoying, need this for pointers that get out of date
//
int BPY_context_get(struct bContext *C, const char *member, struct bContextDataResult *result);
//
// int BPY_run_script(struct Script *script);
void BPY_free_compiled_text( struct Text *text );
//
// int BPY_has_onload_script( void );
//
// int BPY_is_spacehandler(struct Text *text, char spacetype);
// int BPY_del_spacehandler(struct Text *text, struct ScrArea *sa);
// int BPY_add_spacehandler(struct Text *txt, struct ScrArea *sa,char spacetype);
// int BPY_has_spacehandler(struct Text *text, struct ScrArea *sa);
// void BPY_screen_free_spacehandlers(struct bScreen *sc);
// int BPY_do_spacehandlers(struct ScrArea *sa, unsigned short event,
// short eventValue, unsigned short space_event);
//
// void BPY_pydriver_update(void);
float BPY_eval_driver(struct ChannelDriver *driver);
//
int BPY_eval_button(struct bContext *C, const char *expr, double *value);
int BPY_eval_string(struct bContext *C, const char *expr);
/* 2.5 UI Scripts */
int BPY_filepath_exec(struct bContext *C, const char *filepath, struct ReportList *reports);
int BPY_text_exec(struct bContext *C, struct Text *text, struct ReportList *reports);
void BPY_text_free_code(struct Text *text);
void BPY_modules_update(struct bContext *C); // XXX - annoying, need this for pointers that get out of date
void BPY_modules_load_user(struct bContext *C);
/* format importer hook */
int BPY_call_importloader( char *name );
//
// void BPY_spacescript_do_pywin_draw( struct SpaceScript *sc );
// void BPY_spacescript_do_pywin_event( struct SpaceScript *sc,
// unsigned short event, short val, char ascii );
// void BPY_free_finished_script( struct Script *script );
// void BPY_scripts_clear_pyobjects( void );
//
// void error_pyscript( void );
void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */
void BPY_set_context(struct bContext *C);
/* void BPY_Err_Handle(struct Text *text); */
/* int BPY_spacetext_is_pywin(struct SpaceText *st); */
void BPY_load_user_modules(struct bContext *C);
void BPY_driver_reset(void);
float BPY_driver_exec(struct ChannelDriver *driver);
int BPY_button_exec(struct bContext *C, const char *expr, double *value);
int BPY_string_exec(struct bContext *C, const char *expr);
void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */
int BPY_context_member_get(struct bContext *C, const char *member, struct bContextDataResult *result);
void BPY_context_set(struct bContext *C);
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -14,36 +14,7 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2006, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Jacques Beaurainm, Campbell Barton
#
# ***** END GPL LICENSE BLOCK *****
ADD_SUBDIRECTORY(generic)
FILE(GLOB SRC intern/*.c)
SET(INC
.
../blenlib
../makesdna
../makesrna
../blenkernel
../windowmanager
../editors/include
../../../intern/guardedalloc
../../../intern/audaspace/intern
${PYTHON_INC}
)
# only to check if buildinfo is available
IF(WITH_BUILDINFO)
ADD_DEFINITIONS(-DBUILD_DATE)
ENDIF(WITH_BUILDINFO)
BLENDERLIB(bf_python "${SRC}" "${INC}")
add_subdirectory(intern)
add_subdirectory(generic)

View File

@@ -11,10 +11,10 @@ incs += ' #intern/audaspace/intern ' + env['BF_PYTHON_INC']
defs = []
if env['BF_BUILDINFO']:
defs.append('BUILD_DATE')
defs.append('BUILD_DATE')
if env['OURPLATFORM'] in ('win32-mingw', 'win32-vc','win64-vc') and env['BF_DEBUG']:
defs.append('_DEBUG')
defs.append('_DEBUG')
env.BlenderLib( libname = 'bf_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [361,160])

File diff suppressed because it is too large Load Diff

View File

@@ -1,189 +0,0 @@
# 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 separate 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

@@ -1,132 +0,0 @@
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

@@ -1,156 +0,0 @@
# Blender.mathutils module and its subtypes
class Vector:
"""
@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.
"""
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.
@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.
"""
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.
@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.
"""
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
=================
@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.
"""
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

@@ -1,45 +0,0 @@
# 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

@@ -1,29 +0,0 @@
import bpy
# print all objects
for obj in bpy.data.objects:
print(obj.name)
# print all scene names in a list
print(bpy.data.scenes.keys())
# remove mesh Cube
if "Cube" in bpy.data.meshes:
mesh = bpy.data.meshes["Cube"]
print("removing mesh", mesh)
bpy.data.meshes.unlink(mesh)
# write images into a file next to the blend
import os
file = open(os.path.splitext(bpy.data.filepath)[0] + ".txt", 'w')
for image in bpy.data.images:
file.write("%s %dx%d\n" % (image.filepath, image.size[0], image.size[1]))
file.close()

View File

@@ -1,3 +0,0 @@
import mathutils
# todo

View File

@@ -1,3 +0,0 @@
import mathutils
# todo

View File

@@ -1,3 +0,0 @@
import mathutils
# todo

View File

@@ -1,55 +0,0 @@
import mathutils
# zero length vector
vec = mathutils.Vector((0, 0, 1))
# unit length vector
vec_a = vec.copy().normalize()
vec_b = mathutils.Vector((0, 1, 2))
vec2d = mathutils.Vector((1, 2))
vec3d = mathutils.Vector((1, 0, 0))
vec4d = vec_a.copy().resize4D()
# other mathutuls types
quat = mathutils.Quaternion()
matrix = mathutils.Matrix()
# Comparison operators can be done on Vector classes:
# greater and less then test vector length.
vec_a > vec_b
vec_a >= vec_b
vec_a < vec_b
vec_a <= vec_b
# ==, != test vector values e.g. 1,2,3 != 3,2,1 even if they are the same length
vec_a == vec_b
vec_a != vec_b
# Math can be performed on Vector classes
vec_a + vec_b
vec_a - vec_b
vec_a * vec_b
vec_a * 10.0
vec_a * matrix
vec_a * vec_b
vec_a * quat
-vec_a
# You can access a vector object like a sequence
x = vec_a[0]
len(vec)
vec_a[:] = vec_b
vec2d[:] = vec3d[:2]
# Vectors support 'swizzle' operations
# See http://en.wikipedia.org/wiki/Swizzling_(computer_graphics)
vec.xyz = vec.zyx
vec.xy = vec4d.zw
vec.xyz = vec4d.wzz
vec4d.wxyz = vec.yxyx

View File

@@ -1,18 +0,0 @@
import mathutils
from math import radians
vec = mathutils.Vector((1.0, 2.0, 3.0))
mat_rot = mathutils.Matrix.Rotation(radians(90), 4, 'X')
mat_trans = mathutils.Matrix.Translation(vec)
mat = mat_trans * mat_rot
mat.invert()
mat3 = mat.rotation_part()
quat1 = mat.to_quat()
quat2 = mat3.to_quat()
angle = quat1.difference(quat2)
print(angle)

View File

@@ -1,862 +0,0 @@
# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Contributor(s): Campbell Barton
#
# #**** END GPL LICENSE BLOCK #****
script_help_msg = '''
Usage,
run this script from blenders root path once you have compiled blender
./blender.bin -b -P /b/source/blender/python/doc/sphinx_doc_gen.py
This will generate python files in "./source/blender/python/doc/sphinx-in"
Generate html docs by running...
sphinx-build source/blender/python/doc/sphinx-in source/blender/python/doc/sphinx-out
For PDF generation
sphinx-build -b latex source/blender/python/doc/sphinx-in source/blender/python/doc/sphinx-out
cd source/blender/python/doc/sphinx-out
make
'''
# import rpdb2; rpdb2.start_embedded_debugger('test')
import os
import inspect
import bpy
import rna_info
reload(rna_info)
# lame, python wont give some access
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
MethodDescriptorType = type(dict.get)
GetSetDescriptorType = type(int.real)
EXAMPLE_SET = set()
EXAMPLE_SET_USED = set()
_BPY_STRUCT_FAKE = "bpy_struct"
_BPY_FULL_REBUILD = False
def undocumented_message(module_name, type_name, identifier):
message = "Undocumented (`contribute " \
"<http://wiki.blender.org/index.php/Dev:2.5/Py/API/Documentation/Contribute" \
"?action=edit&section=new&preload=Dev:2.5/Py/API/Documentation/Contribute/Howto-message" \
"&preloadtitle=%s.%s.%s>`_)\n\n" % (module_name, type_name, identifier)
return message
def range_str(val):
'''
Converts values to strings for the range directive.
(unused function it seems)
'''
if val < -10000000: return '-inf'
if val > 10000000: return 'inf'
if type(val)==float:
return '%g' % val
else:
return str(val)
def write_example_ref(ident, fw, example_id, ext="py"):
if example_id in EXAMPLE_SET:
fw("%s.. literalinclude:: ../examples/%s.%s\n\n" % (ident, example_id, ext))
EXAMPLE_SET_USED.add(example_id)
else:
if bpy.app.debug:
print("\tskipping example:", example_id)
def write_indented_lines(ident, fn, text, strip=True):
'''
Apply same indentation to all lines in a multilines text.
'''
if text is None:
return
for l in text.split("\n"):
if strip:
fn(ident + l.strip() + "\n")
else:
fn(ident + l + "\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_descr2sphinx(ident, fw, descr, module_name, type_name, identifier):
if identifier.startswith("_"):
return
doc = descr.__doc__
if not doc:
doc = undocumented_message(module_name, type_name, identifier)
if type(descr) == GetSetDescriptorType:
fw(ident + ".. attribute:: %s\n\n" % identifier)
write_indented_lines(ident + " ", fw, doc, False)
elif type(descr) in (MethodDescriptorType, ClassMethodDescriptorType):
write_indented_lines(ident, fw, doc, False)
else:
raise TypeError("type was not GetSetDescriptorType, MethodDescriptorType or ClassMethodDescriptorType")
write_example_ref(ident, fw, module_name + "." + type_name + "." + identifier)
fw("\n")
def py_c_func2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_class=True):
'''
c defined function to sphinx.
'''
# dump the docstring, assume its formatted correctly
if py_func.__doc__:
write_indented_lines(ident, fw, py_func.__doc__, False)
fw("\n")
else:
fw(ident + ".. function:: %s()\n\n" % identifier)
fw(ident + " " + undocumented_message(module_name, type_name, identifier))
def pyprop2sphinx(ident, fw, identifier, py_prop):
'''
python property to sphinx
'''
# readonly properties use "data" directive, variables use "attribute" directive
if py_prop.fset is None:
fw(ident + ".. data:: %s\n\n" % identifier)
else:
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
attribute_set = set()
filepath = os.path.join(BASEPATH, module_name + ".rst")
file = open(filepath, "w")
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")
write_example_ref("", fw, module_name)
# write members of the module
# only tested with PyStructs which are not exactly modules
for key, descr in sorted(type(module).__dict__.items()):
if type(descr) == types.MemberDescriptorType:
if descr.__doc__:
fw(".. data:: %s\n\n" % key)
write_indented_lines(" ", fw, descr.__doc__, False)
attribute_set.add(key)
fw("\n")
del key, descr
classes = []
for attribute in sorted(dir(module)):
if not attribute.startswith("_"):
if attribute in attribute_set:
continue
if attribute.startswith("n_"): # annoying exception, needed for bpy.app
continue
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, module_name, module, attribute, value, is_class=False)
elif value_type == type:
classes.append((attribute, value))
elif value_type in (bool, int, float, str, tuple):
# constant, not much fun we can do here except to list it.
# TODO, figure out some way to document these!
fw(".. data:: %s\n\n" % attribute)
write_indented_lines(" ", fw, "constant value %s" % repr(value), False)
fw("\n")
else:
print("\tnot documenting %s.%s" % (module_name, attribute))
continue
attribute_set.add(attribute)
# TODO, more types...
# write collected classes now
for (type_name, value) in classes:
# May need to be its own function
fw(".. class:: %s\n\n" % type_name)
if value.__doc__:
write_indented_lines(" ", fw, value.__doc__, False)
fw("\n")
write_example_ref(" ", fw, module_name + "." + type_name)
descr_items = [(key, descr) for key, descr in sorted(value.__dict__.items()) if not key.startswith("__")]
for key, descr in descr_items:
if type(descr) == ClassMethodDescriptorType:
py_descr2sphinx(" ", fw, descr, module_name, type_name, key)
for key, descr in descr_items:
if type(descr) == MethodDescriptorType:
py_descr2sphinx(" ", fw, descr, module_name, type_name, key)
for key, descr in descr_items:
if type(descr) == GetSetDescriptorType:
py_descr2sphinx(" ", fw, descr, module_name, type_name, key)
fw("\n\n")
file.close()
def rna2sphinx(BASEPATH):
structs, funcs, ops, props = rna_info.BuildRNAInfo()
try:
os.mkdir(BASEPATH)
except:
pass
# conf.py - empty for now
filepath = os.path.join(BASEPATH, "conf.py")
file = open(filepath, "w")
fw = file.write
version_string = bpy.app.version_string.split("(")[0]
if bpy.app.build_revision != "Unknown":
version_string = version_string + " r" + bpy.app.build_revision
# for use with files
version_string_fp = "_".join(str(v) for v in bpy.app.version)
fw("project = 'Blender'\n")
# fw("master_doc = 'index'\n")
fw("copyright = u'Blender Foundation'\n")
fw("version = '%s - UNSTABLE API'\n" % version_string)
fw("release = '%s - UNSTABLE API'\n" % version_string)
fw("html_theme = 'blender-org'\n")
fw("html_theme_path = ['../']\n")
fw("html_favicon = 'favicon.ico'\n")
# not helpful since the source us generated, adds to upload size.
fw("html_copy_source = False\n")
fw("\n")
# needed for latex, pdf gen
fw("latex_documents = [ ('contents', 'contents.tex', 'Blender Index', 'Blender Foundation', 'manual'), ]\n")
fw("latex_paper_size = 'a4paper'\n")
file.close()
filepath = os.path.join(BASEPATH, "contents.rst")
file = open(filepath, "w")
fw = file.write
fw("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n")
fw(" Blender Documentation contents\n")
fw("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n")
fw("\n")
fw("This document is an API reference for Blender %s. built %s.\n" % (version_string, bpy.app.build_date))
fw("\n")
fw("An introduction to Blender and Python can be found at <http://wiki.blender.org/index.php/Dev:2.5/Py/API/Intro>\n")
fw("\n")
fw("`A PDF version of this document is also available <blender_python_reference_%s.pdf>`__\n" % version_string_fp)
fw("\n")
fw(".. warning:: The Python API in Blender is **UNSTABLE**, It should only be used for testing, any script written now may break in future releases.\n")
fw(" \n")
fw(" The following areas are subject to change.\n")
fw(" * operator names and arguments\n")
fw(" * render api\n")
fw(" * function calls with the data api (any function calls with values accessed from bpy.data), including functions for importing and exporting meshes\n")
fw(" * class registration (Operator, Panels, Menus, Headers)\n")
fw(" * modules: bpy.props, blf)\n")
fw(" * members in the bpy.context have to be reviewed\n")
fw(" * python defined modal operators, especially drawing callbacks are highly experemental\n")
fw(" \n")
fw(" These parts of the API are relatively stable and are unlikely to change significantly\n")
fw(" * data API, access to attributes of blender data such as mesh verts, material color, timeline frames and scene objects\n")
fw(" * user interface functions for defining buttons, creation of menus, headers, panels\n")
fw(" * modules: bgl, mathutils and geometry\n")
fw(" * game engine modules\n")
fw("\n")
fw("===================\n")
fw("Application Modules\n")
fw("===================\n")
fw("\n")
fw(".. toctree::\n")
fw(" :maxdepth: 1\n\n")
fw(" bpy.data.rst\n\n") # note: not actually a module
fw(" bpy.ops.rst\n\n")
fw(" bpy.types.rst\n\n")
# py modules
fw(" bpy.utils.rst\n\n")
fw(" bpy.path.rst\n\n")
fw(" bpy.app.rst\n\n")
# C modules
fw(" bpy.props.rst\n\n")
fw("==================\n")
fw("Standalone Modules\n")
fw("==================\n")
fw("\n")
fw(".. toctree::\n")
fw(" :maxdepth: 1\n\n")
fw(" mathutils.rst\n\n")
fw(" blf.rst\n\n")
fw(" aud.rst\n\n")
# game engine
fw("===================\n")
fw("Game Engine Modules\n")
fw("===================\n")
fw("\n")
fw(".. toctree::\n")
fw(" :maxdepth: 1\n\n")
fw(" bge.types.rst\n\n")
fw(" bge.logic.rst\n\n")
fw(" bge.render.rst\n\n")
fw(" bge.events.rst\n\n")
file.close()
# internal modules
filepath = os.path.join(BASEPATH, "bpy.ops.rst")
file = open(filepath, "w")
fw = file.write
fw("Operators (bpy.ops)\n")
fw("===================\n\n")
fw(".. toctree::\n")
fw(" :glob:\n\n")
fw(" bpy.ops.*\n\n")
file.close()
filepath = os.path.join(BASEPATH, "bpy.types.rst")
file = open(filepath, "w")
fw = file.write
fw("Types (bpy.types)\n")
fw("=================\n\n")
fw(".. toctree::\n")
fw(" :glob:\n\n")
fw(" bpy.types.*\n\n")
file.close()
# not actually a module, only write this file so we
# can reference in the TOC
filepath = os.path.join(BASEPATH, "bpy.data.rst")
file = open(filepath, "w")
fw = file.write
fw("Data Access (bpy.data)\n")
fw("======================\n\n")
fw(".. module:: bpy\n")
fw("\n")
fw("This module is used for all blender/python access.\n")
fw("\n")
fw(".. literalinclude:: ../examples/bpy.data.py\n")
fw("\n")
fw(".. data:: data\n")
fw("\n")
fw(" Access to blenders internal data\n")
fw("\n")
fw(" :type: :class:`bpy.types.BlendData`\n")
file.close()
EXAMPLE_SET_USED.add("bpy.data")
# python modules
from bpy import utils as module
pymodule2sphinx(BASEPATH, "bpy.utils", module, "Utilities (bpy.utils)")
from bpy import path as module
pymodule2sphinx(BASEPATH, "bpy.path", module, "Path Utilities (bpy.path)")
# C modules
from bpy import app as module
pymodule2sphinx(BASEPATH, "bpy.app", module, "Application Data (bpy.app)")
from bpy import props as module
pymodule2sphinx(BASEPATH, "bpy.props", module, "Property Definitions (bpy.props)")
import mathutils as module
pymodule2sphinx(BASEPATH, "mathutils", module, "Math Types & Utilities (mathutils)")
del module
import blf as module
pymodule2sphinx(BASEPATH, "blf", module, "Font Drawing (blf)")
del module
import aud as module
pymodule2sphinx(BASEPATH, "aud", module, "Audio System (aud)")
del module
# game engine
import shutil
# copy2 keeps time/date stamps
shutil.copy2(os.path.join(BASEPATH, "../../../../gameengine/PyDoc/bge.types.rst"), BASEPATH)
shutil.copy2(os.path.join(BASEPATH, "../../../../gameengine/PyDoc/bge.logic.rst"), BASEPATH)
shutil.copy2(os.path.join(BASEPATH, "../../../../gameengine/PyDoc/bge.render.rst"), BASEPATH)
shutil.copy2(os.path.join(BASEPATH, "../../../../gameengine/PyDoc/bge.events.rst"), BASEPATH)
if 0:
filepath = os.path.join(BASEPATH, "bpy.rst")
file = open(filepath, "w")
fw = file.write
fw("\n")
title = ":mod:`bpy` --- Blender Python Module"
fw("%s\n%s\n\n" % (title, "=" * len(title)))
fw(".. module:: bpy.types\n\n")
file.close()
def write_param(ident, fw, prop, is_return=False):
if is_return:
id_name = "return"
id_type = "rtype"
kwargs = {"as_ret": True, "class_fmt": ":class:`%s`"}
identifier = ""
else:
id_name = "arg"
id_type = "type"
kwargs = {"as_arg": True, "class_fmt": ":class:`%s`"}
identifier = " %s" % prop.identifier
type_descr = prop.get_type_description(**kwargs)
if prop.name or prop.description:
fw(ident + ":%s%s: %s\n" % (id_name, identifier, ", ".join([val for val in (prop.name, prop.description) if val])))
fw(ident + ":%s%s: %s\n" % (id_type, identifier, type_descr))
def write_struct(struct):
#if not struct.identifier.startswith("Sc") and not struct.identifier.startswith("I"):
# return
#if not struct.identifier == "Object":
# return
filepath = os.path.join(BASEPATH, "bpy.types.%s.rst" % struct.identifier)
file = open(filepath, "w")
fw = file.write
base_id = getattr(struct.base, "identifier", "")
if _BPY_STRUCT_FAKE:
if not base_id:
base_id = _BPY_STRUCT_FAKE
if base_id:
title = "%s(%s)" % (struct.identifier, base_id)
else:
title = struct.identifier
fw("%s\n%s\n\n" % (title, "=" * len(title)))
fw(".. module:: bpy.types\n\n")
base_ids = [base.identifier for base in struct.get_bases()]
if _BPY_STRUCT_FAKE:
base_ids.append(_BPY_STRUCT_FAKE)
base_ids.reverse()
if base_ids:
if len(base_ids) > 1:
fw("base classes --- ")
else:
fw("base class --- ")
fw(", ".join([(":class:`%s`" % base_id) for base_id in base_ids]))
fw("\n\n")
subclass_ids = [s.identifier for s in structs.values() if s.base is struct if not rna_info.rna_id_ignore(s.identifier)]
if subclass_ids:
fw("subclasses --- \n" + ", ".join([(":class:`%s`" % s) for s in subclass_ids]) + "\n\n")
base_id = getattr(struct.base, "identifier", "")
if _BPY_STRUCT_FAKE:
if not base_id:
base_id = _BPY_STRUCT_FAKE
if base_id:
fw(".. class:: %s(%s)\n\n" % (struct.identifier, base_id))
else:
fw(".. class:: %s\n\n" % struct.identifier)
fw(" %s\n\n" % struct.description)
# properties sorted in alphabetical order
sorted_struct_properties = struct.properties[:]
sorted_struct_properties.sort(key=lambda prop: prop.identifier)
for prop in sorted_struct_properties:
type_descr = prop.get_type_description(class_fmt=":class:`%s`")
# readonly properties use "data" directive, variables properties use "attribute" directive
if 'readonly' in type_descr:
fw(" .. data:: %s\n\n" % prop.identifier)
else:
fw(" .. attribute:: %s\n\n" % prop.identifier)
if prop.description:
fw(" %s\n\n" % prop.description)
fw(" :type: %s\n\n" % type_descr)
# python attributes
py_properties = struct.get_py_properties()
py_prop = None
for identifier, py_prop in py_properties:
pyprop2sphinx(" ", fw, identifier, py_prop)
del py_properties, py_prop
for func in struct.functions:
args_str = ", ".join([prop.get_arg_default(force=False) for prop in func.args])
fw(" .. %s:: %s(%s)\n\n" % ("classmethod" if func.is_classmethod else "method", func.identifier, args_str))
fw(" %s\n\n" % func.description)
for prop in func.args:
write_param(" ", fw, prop)
if len(func.return_values) == 1:
write_param(" ", fw, func.return_values[0], is_return=True)
elif func.return_values: # multiple return values
fw(" :return (%s):\n" % ", ".join([prop.identifier for prop in func.return_values]))
for prop in func.return_values:
type_descr = prop.get_type_description(as_ret=True, class_fmt=":class:`%s`")
descr = prop.description
if not descr:
descr = prop.name
fw(" `%s`, %s, %s\n\n" % (prop.identifier, descr, type_descr))
fw("\n")
# python methods
py_funcs = struct.get_py_functions()
py_func = None
for identifier, py_func in py_funcs:
pyfunc2sphinx(" ", fw, identifier, py_func, is_class=True)
del py_funcs, py_func
lines = []
if struct.base or _BPY_STRUCT_FAKE:
bases = list(reversed(struct.get_bases()))
# props
lines[:] = []
if _BPY_STRUCT_FAKE:
descr_items = [(key, descr) for key, descr in sorted(bpy.types.Struct.__bases__[0].__dict__.items()) if not key.startswith("__")]
if _BPY_STRUCT_FAKE:
for key, descr in descr_items:
if type(descr) == GetSetDescriptorType:
lines.append("* :class:`%s.%s`\n" % (_BPY_STRUCT_FAKE, key))
for base in bases:
for prop in base.properties:
lines.append("* :class:`%s.%s`\n" % (base.identifier, prop.identifier))
for identifier, py_prop in base.get_py_properties():
lines.append("* :class:`%s.%s`\n" % (base.identifier, identifier))
for identifier, py_prop in base.get_py_properties():
lines.append("* :class:`%s.%s`\n" % (base.identifier, identifier))
if lines:
fw(".. rubric:: Inherited Properties\n\n")
fw(".. hlist::\n")
fw(" :columns: 2\n\n")
for line in lines:
fw(line)
fw("\n")
# funcs
lines[:] = []
if _BPY_STRUCT_FAKE:
for key, descr in descr_items:
if type(descr) == MethodDescriptorType:
lines.append("* :class:`%s.%s`\n" % (_BPY_STRUCT_FAKE, key))
for base in bases:
for func in base.functions:
lines.append("* :class:`%s.%s`\n" % (base.identifier, func.identifier))
for identifier, py_func in base.get_py_functions():
lines.append("* :class:`%s.%s`\n" % (base.identifier, identifier))
if lines:
fw(".. rubric:: Inherited Functions\n\n")
fw(".. hlist::\n")
fw(" :columns: 2\n\n")
for line in lines:
fw(line)
fw("\n")
lines[:] = []
if struct.references:
# use this otherwise it gets in the index for a normal heading.
fw(".. rubric:: References\n\n")
fw(".. hlist::\n")
fw(" :columns: 2\n\n")
for ref in struct.references:
ref_split = ref.split(".")
if len(ref_split) > 2:
ref = ref_split[-2] + "." + ref_split[-1]
fw("* :class:`%s`\n" % ref)
fw("\n")
for struct in structs.values():
# TODO, rna_info should filter these out!
if "_OT_" in struct.identifier:
continue
write_struct(struct)
# special case, bpy_struct
if _BPY_STRUCT_FAKE:
filepath = os.path.join(BASEPATH, "bpy.types.%s.rst" % _BPY_STRUCT_FAKE)
file = open(filepath, "w")
fw = file.write
fw("%s\n" % _BPY_STRUCT_FAKE)
fw("=" * len(_BPY_STRUCT_FAKE) + "\n")
fw("\n")
fw(".. module:: bpy.types\n")
fw("\n")
subclass_ids = [s.identifier for s in structs.values() if s.base is None if not rna_info.rna_id_ignore(s.identifier)]
if subclass_ids:
fw("subclasses --- \n" + ", ".join([(":class:`%s`" % s) for s in sorted(subclass_ids)]) + "\n\n")
fw(".. class:: %s\n\n" % _BPY_STRUCT_FAKE)
fw(" built-in base class for all classes in bpy.types.\n\n")
fw(" .. note::\n\n")
fw(" Note that bpy.types.%s is not actually available from within blender, it only exists for the purpose of documentation.\n\n" % _BPY_STRUCT_FAKE)
descr_items = [(key, descr) for key, descr in sorted(bpy.types.Struct.__bases__[0].__dict__.items()) if not key.startswith("__")]
for key, descr in descr_items:
if type(descr) == MethodDescriptorType: # GetSetDescriptorType, GetSetDescriptorType's are not documented yet
py_descr2sphinx(" ", fw, descr, "bpy.types", _BPY_STRUCT_FAKE, key)
for key, descr in descr_items:
if type(descr) == GetSetDescriptorType:
py_descr2sphinx(" ", fw, descr, "bpy.types", _BPY_STRUCT_FAKE, key)
# operators
def write_ops():
API_BASEURL='https://svn.blender.org/svnroot/bf-blender/trunk/blender/release/scripts'
fw = None
last_mod = ''
for op_key in sorted(ops.keys()):
op = ops[op_key]
if last_mod != op.module_name:
filepath = os.path.join(BASEPATH, "bpy.ops.%s.rst" % op.module_name)
file = open(filepath, "w")
fw = file.write
title = "%s Operators" % (op.module_name[0].upper() + op.module_name[1:])
fw("%s\n%s\n\n" % (title, "=" * len(title)))
fw(".. module:: bpy.ops.%s\n\n" % op.module_name)
last_mod = op.module_name
args_str = ", ".join([prop.get_arg_default(force=True) for prop in op.args])
fw(".. function:: %s(%s)\n\n" % (op.func_name, args_str))
# if the description isn't valid, we output the standard warning
# with a link to the wiki so that people can help
if not op.description or op.description == "(undocumented operator)":
operator_description = undocumented_message('bpy.ops',op.module_name,op.func_name)
else:
operator_description = op.description
fw(" %s\n\n" % operator_description)
for prop in op.args:
write_param(" ", fw, prop)
if op.args:
fw("\n")
location = op.get_location()
if location != (None, None):
fw(" :file: `%s <%s/%s>`_:%d\n\n" % (location[0],API_BASEURL,location[0],location[1]))
write_ops()
file.close()
def main():
import bpy
if 'bpy' not in dir():
print("\nError, this script must run from inside blender2.5")
print(script_help_msg)
else:
import shutil
path_in = 'source/blender/python/doc/sphinx-in'
path_out = 'source/blender/python/doc/sphinx-out'
path_examples = 'source/blender/python/doc/examples'
# only for partial updates
path_in_tmp = path_in + "-tmp"
if not os.path.exists(path_in):
os.mkdir(path_in)
for f in os.listdir(path_examples):
if f.endswith(".py"):
EXAMPLE_SET.add(os.path.splitext(f)[0])
# only for full updates
if _BPY_FULL_REBUILD:
shutil.rmtree(path_in, True)
shutil.rmtree(path_out, True)
else:
# write here, then move
shutil.rmtree(path_in_tmp, True)
rna2sphinx(path_in_tmp)
if not _BPY_FULL_REBUILD:
import filecmp
# now move changed files from 'path_in_tmp' --> 'path_in'
file_list_path_in = set(os.listdir(path_in))
file_list_path_in_tmp = set(os.listdir(path_in_tmp))
# remove deprecated files that have been removed.
for f in sorted(file_list_path_in):
if f not in file_list_path_in_tmp:
print("\tdeprecated: %s" % f)
os.remove(os.path.join(path_in, f))
# freshen with new files.
for f in sorted(file_list_path_in_tmp):
f_from = os.path.join(path_in_tmp, f)
f_to = os.path.join(path_in, f)
do_copy = True
if f in file_list_path_in:
if filecmp.cmp(f_from, f_to):
do_copy = False
if do_copy:
print("\tupdating: %s" % f)
shutil.copy(f_from, f_to)
'''else:
print("\tkeeping: %s" % f) # eh, not that useful'''
EXAMPLE_SET_UNUSED = EXAMPLE_SET - EXAMPLE_SET_USED
if EXAMPLE_SET_UNUSED:
print("\nUnused examples found in '%s'..." % path_examples)
for f in EXAMPLE_SET_UNUSED:
print(" %s.py" % f)
print(" %d total\n" % len(EXAMPLE_SET_UNUSED))
import sys
sys.exit()
if __name__ == '__main__':
main()

View File

@@ -1,29 +0,0 @@
#!/bin/sh
# run from the blender source dir
# bash source/blender/python/doc/sphinx_doc_gen.sh
# ssh upload means you need an account on the server
BLENDER="./blender.bin"
SSH_HOST="ideasman42@emo.blender.org"
SSH_UPLOAD="/data/www/vhosts/www.blender.org/documentation" # blender_python_api_VERSION, added after
# sed string from hell, 'Blender 2.53 (sub 1) Build' --> '2_53_1'
# "_".join(str(v) for v in bpy.app.version)
BLENDER_VERSION=`$BLENDER --version | cut -f2-4 -d" " | sed 's/(//g' | sed 's/)//g' | sed 's/ sub /./g' | sed 's/\./_/g'`
SSH_UPLOAD_FULL=$SSH_UPLOAD/"blender_python_api_"$BLENDER_VERSION
# dont delete existing docs, now partial updates are used for quick builds.
$BLENDER --background --python ./source/blender/python/doc/sphinx_doc_gen.py
# html
sphinx-build source/blender/python/doc/sphinx-in source/blender/python/doc/sphinx-out
cp source/blender/python/doc/sphinx-out/contents.html source/blender/python/doc/sphinx-out/index.html
ssh ideasman42@emo.blender.org 'rm -rf '$SSH_UPLOAD_FULL'/*'
rsync --progress -avze "ssh -p 22" /b/source/blender/python/doc/sphinx-out/* $SSH_HOST:$SSH_UPLOAD_FULL/
# pdf
sphinx-build -b latex source/blender/python/doc/sphinx-in source/blender/python/doc/sphinx-out
cd source/blender/python/doc/sphinx-out
make
cd ../../../../../
rsync --progress -avze "ssh -p 22" source/blender/python/doc/sphinx-out/contents.pdf $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.pdf

View File

@@ -18,17 +18,46 @@
#
# ***** END GPL LICENSE BLOCK *****
FILE(GLOB SRC *.c)
SET(INC
set(INC
.
../../blenlib
../../makesdna
../../blenkernel
../../editors/include
../../blenloader
../../../../intern/guardedalloc
../../../../extern/glew/include
${PYTHON_INC}
${PYTHON_INCLUDE_DIRS}
)
BLENDERLIB(bf_python_ext "${SRC}" "${INC}")
set(SRC
IDProp.c
bgl.c
blf_py_api.c
bpy_internal_import.c
mathutils.c
mathutils_Color.c
mathutils_Euler.c
mathutils_Matrix.c
mathutils_Quaternion.c
mathutils_Vector.c
mathutils_geometry.c
noise_py_api.c
py_capi_utils.c
IDProp.h
bgl.h
blf_py_api.h
bpy_internal_import.h
mathutils.h
mathutils_Color.h
mathutils_Euler.h
mathutils_Matrix.h
mathutils_Quaternion.h
mathutils_Vector.h
mathutils_geometry.h
noise_py_api.h
py_capi_utils.h
)
blender_add_lib(bf_python_ext "${SRC}" "${INC}")

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -23,10 +23,17 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include "BKE_idprop.h"
#include <Python.h>
#include "IDProp.h"
#include "MEM_guardedalloc.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_idprop.h"
#define USE_STRING_COERCE
#ifdef USE_STRING_COERCE
@@ -34,7 +41,7 @@
#endif
PyObject * PyC_UnicodeFromByte(const char *str);
const char * PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
const char * PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
/*** Function to wrap ID properties ***/
PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent);
@@ -44,7 +51,7 @@ extern PyTypeObject IDGroup_Iter_Type;
/*********************** ID Property Main Wrapper Stuff ***************/
PyObject *IDGroup_repr( BPy_IDProperty *self )
static PyObject *IDGroup_repr( BPy_IDProperty *self )
{
return PyUnicode_FromFormat( "<bpy ID property from \"%s\">", self->id->name);
}
@@ -58,7 +65,7 @@ PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop )
#ifdef USE_STRING_COERCE
return PyC_UnicodeFromByte(prop->data.pointer);
#else
return PyUnicode_FromString( prop->data.pointer );
return PyUnicode_FromString(prop->data.pointer);
#endif
case IDP_INT:
return PyLong_FromLong( (long)prop->data.val );
@@ -88,7 +95,7 @@ PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop )
int i;
if (!seq) {
PyErr_Format( PyExc_RuntimeError, "BPy_IDGroup_MapDataToPy, IDP_IDPARRAY: PyList_New(%d) failed", prop->len);
PyErr_Format(PyExc_RuntimeError, "BPy_IDGroup_MapDataToPy, IDP_IDPARRAY: PyList_New(%d) failed", prop->len);
return NULL;
}
@@ -108,7 +115,8 @@ PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop )
Py_RETURN_NONE;
}
int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
#if 0 /* UNUSED, currenly assignment overwrites into new properties, rather then setting in-place */
static int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
{
switch (prop->type) {
case IDP_STRING:
@@ -123,10 +131,10 @@ int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
int alloc_len;
PyObject *value_coerce= NULL;
st= (char *)PuC_UnicodeAsByte(value, &value_coerce);
st= (char *)PyC_UnicodeAsByte(value, &value_coerce);
alloc_len= strlen(st) + 1;
st = _PyUnicode_AsString(value);
st = _PyUnicode_AsString(value);
IDP_ResizeArray(prop, alloc_len);
memcpy(prop->data.pointer, st, alloc_len);
Py_XDECREF(value_coerce);
@@ -176,13 +184,14 @@ int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
}
return 0;
}
#endif
PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *bleh)
static PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *UNUSED(closure))
{
return PyUnicode_FromString(self->prop->name);
}
static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *bleh)
static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *UNUSED(closure))
{
char *st;
if (!PyUnicode_Check(value)) {
@@ -191,12 +200,12 @@ static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *bleh
}
st = _PyUnicode_AsString(value);
if (strlen(st) >= MAX_IDPROP_NAME) {
if (BLI_strnlen(st, MAX_IDPROP_NAME) == MAX_IDPROP_NAME) {
PyErr_SetString(PyExc_TypeError, "string length cannot exceed 31 characters!");
return -1;
}
strcpy(self->prop->name, st);
BLI_strncpy(self->prop->name, st, sizeof(self->prop->name));
return 0;
}
@@ -208,17 +217,14 @@ static PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self)
#endif
static PyGetSetDef BPy_IDGroup_getseters[] = {
{"name",
(getter)BPy_IDGroup_GetName, (setter)BPy_IDGroup_SetName,
"The name of this Group.",
NULL},
{(char *)"name", (getter)BPy_IDGroup_GetName, (setter)BPy_IDGroup_SetName, (char *)"The name of this Group.", NULL},
{NULL, NULL, NULL, NULL, NULL}
};
static Py_ssize_t BPy_IDGroup_Map_Len(BPy_IDProperty *self)
{
if (self->prop->type != IDP_GROUP) {
PyErr_SetString( PyExc_TypeError, "len() of unsized object");
PyErr_SetString(PyExc_TypeError, "len() of unsized object");
return -1;
}
@@ -231,21 +237,21 @@ static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
char *name;
if (self->prop->type != IDP_GROUP) {
PyErr_SetString( PyExc_TypeError, "unsubscriptable object");
PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
return NULL;
}
name= _PyUnicode_AsString(item);
if (name == NULL) {
PyErr_SetString( PyExc_TypeError, "only strings are allowed as keys of ID properties");
PyErr_SetString(PyExc_TypeError, "only strings are allowed as keys of ID properties");
return NULL;
}
idprop= IDP_GetPropertyFromGroup(self->prop, name);
if(idprop==NULL) {
PyErr_SetString( PyExc_KeyError, "key not in subgroup dict");
PyErr_SetString(PyExc_KeyError, "key not in subgroup dict");
return NULL;
}
@@ -259,7 +265,7 @@ static int idp_sequence_type(PyObject *seq)
PyObject *item;
int type= IDP_INT;
int i, len = PySequence_Length(seq);
int i, len = PySequence_Size(seq);
for (i=0; i < len; i++) {
item = PySequence_GetItem(seq, i);
if (PyFloat_Check(item)) {
@@ -294,7 +300,7 @@ static int idp_sequence_type(PyObject *seq)
}
/* note: group can be a pointer array or a group */
char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObject *ob)
const char *BPy_IDProperty_Map_ValidateAndCreate(const char *name, IDProperty *group, PyObject *ob)
{
IDProperty *prop = NULL;
IDPropertyTemplate val = {0};
@@ -311,7 +317,7 @@ char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObje
} else if (PyUnicode_Check(ob)) {
#ifdef USE_STRING_COERCE
PyObject *value_coerce= NULL;
val.str = (char *)PuC_UnicodeAsByte(ob, &value_coerce);
val.str = (char *)PyC_UnicodeAsByte(ob, &value_coerce);
prop = IDP_New(IDP_STRING, val, name);
Py_XDECREF(value_coerce);
#else
@@ -329,7 +335,7 @@ char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObje
we assume IDP_INT unless we hit a float
number; then we assume it's */
val.array.len = PySequence_Length(ob);
val.array.len = PySequence_Size(ob);
switch(val.array.type) {
case IDP_DOUBLE:
@@ -351,7 +357,7 @@ char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObje
case IDP_IDPARRAY:
prop= IDP_NewIDPArray(name);
for (i=0; i<val.array.len; i++) {
char *error;
const char *error;
item = PySequence_GetItem(ob, i);
error= BPy_IDProperty_Map_ValidateAndCreate("", prop, item);
Py_DECREF(item);
@@ -414,7 +420,7 @@ char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObje
int BPy_Wrap_SetMapItem(IDProperty *prop, PyObject *key, PyObject *val)
{
if (prop->type != IDP_GROUP) {
PyErr_SetString( PyExc_TypeError, "unsubscriptable object");
PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
return -1;
}
@@ -426,21 +432,21 @@ int BPy_Wrap_SetMapItem(IDProperty *prop, PyObject *key, PyObject *val)
MEM_freeN(pkey);
return 0;
} else {
PyErr_SetString( PyExc_KeyError, "property not found in group" );
PyErr_SetString(PyExc_KeyError, "property not found in group");
return -1;
}
}
else {
char *err;
const char *err;
if (!PyUnicode_Check(key)) {
PyErr_SetString( PyExc_TypeError, "only strings are allowed as subgroup keys" );
PyErr_SetString(PyExc_TypeError, "only strings are allowed as subgroup keys");
return -1;
}
err = BPy_IDProperty_Map_ValidateAndCreate(_PyUnicode_AsString(key), prop, val);
if (err) {
PyErr_SetString( PyExc_KeyError, err );
PyErr_SetString(PyExc_KeyError, err );
return -1;
}
@@ -488,7 +494,7 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
int i;
if (!seq) {
PyErr_Format( PyExc_RuntimeError, "BPy_IDGroup_MapDataToPy, IDP_ARRAY: PyList_New(%d) failed", prop->len);
PyErr_Format(PyExc_RuntimeError, "BPy_IDGroup_MapDataToPy, IDP_ARRAY: PyList_New(%d) failed", prop->len);
return NULL;
}
@@ -513,7 +519,7 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
int i;
if (!seq) {
PyErr_Format( PyExc_RuntimeError, "BPy_IDGroup_MapDataToPy, IDP_IDPARRAY: PyList_New(%d) failed", prop->len);
PyErr_Format(PyExc_RuntimeError, "BPy_IDGroup_MapDataToPy, IDP_IDPARRAY: PyList_New(%d) failed", prop->len);
return NULL;
}
@@ -555,7 +561,7 @@ static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
char *name = _PyUnicode_AsString(value);
if (!name) {
PyErr_SetString( PyExc_TypeError, "pop expected at least 1 argument, got 0" );
PyErr_SetString(PyExc_TypeError, "pop expected at least 1 argument, got 0");
return NULL;
}
@@ -575,7 +581,7 @@ static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
return pyform;
}
PyErr_SetString( PyExc_KeyError, "item not in group" );
PyErr_SetString(PyExc_KeyError, "item not in group");
return NULL;
}
@@ -692,7 +698,7 @@ static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
char *name = _PyUnicode_AsString(value);
if (!name) {
PyErr_SetString( PyExc_TypeError, "expected a string");
PyErr_SetString(PyExc_TypeError, "expected a string");
return -1;
}
@@ -705,7 +711,7 @@ static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *value)
Py_ssize_t i=0;
if (!PyDict_Check(value)) {
PyErr_SetString( PyExc_TypeError, "expected an object derived from dict.");
PyErr_SetString(PyExc_TypeError, "expected an object derived from dict");
return NULL;
}
@@ -724,7 +730,7 @@ static PyObject *BPy_IDGroup_ConvertToPy(BPy_IDProperty *self)
/* Matches python dict.get(key, [default]) */
PyObject* BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
static PyObject* BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
{
IDProperty *idprop;
char *key;
@@ -761,23 +767,23 @@ static struct PyMethodDef BPy_IDGroup_methods[] = {
"idprop.get(k[,d]) -> idprop[k] if k in idprop, else d. d defaults to None"},
{"convert_to_pyobject", (PyCFunction)BPy_IDGroup_ConvertToPy, METH_NOARGS,
"return a purely python version of the group"},
{0, NULL, 0, NULL}
{NULL, NULL, 0, NULL}
};
static PySequenceMethods BPy_IDGroup_Seq = {
(lenfunc) BPy_IDGroup_Map_Len, /* lenfunc sq_length */
0, /* binaryfunc sq_concat */
0, /* ssizeargfunc sq_repeat */
0, /* ssizeargfunc sq_item */ /* TODO - setting this will allow PySequence_Check to return True */
0, /* intintargfunc ***was_sq_slice*** */
0, /* intobjargproc sq_ass_item */
0, /* ssizeobjargproc ***was_sq_ass_slice*** */
(lenfunc) BPy_IDGroup_Map_Len, /* lenfunc sq_length */
NULL, /* binaryfunc sq_concat */
NULL, /* ssizeargfunc sq_repeat */
NULL, /* ssizeargfunc sq_item */ /* TODO - setting this will allow PySequence_Check to return True */
NULL, /* intintargfunc ***was_sq_slice*** */
NULL, /* intobjargproc sq_ass_item */
NULL, /* ssizeobjargproc ***was_sq_ass_slice*** */
(objobjproc) BPy_IDGroup_Contains, /* objobjproc sq_contains */
0, /* binaryfunc sq_inplace_concat */
0, /* ssizeargfunc sq_inplace_repeat */
NULL, /* binaryfunc sq_inplace_concat */
NULL, /* ssizeargfunc sq_inplace_repeat */
};
PyMappingMethods BPy_IDGroup_Mapping = {
static PyMappingMethods BPy_IDGroup_Mapping = {
(lenfunc)BPy_IDGroup_Map_Len, /*inquiry mp_length */
(binaryfunc)BPy_IDGroup_Map_GetItem, /*binaryfunc mp_subscript */
(objobjargproc)BPy_IDGroup_Map_SetItem, /*objobjargproc mp_ass_subscript */
@@ -860,7 +866,7 @@ PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent)
static PyObject *IDArray_repr(BPy_IDArray *self)
{
return PyUnicode_FromString("(ID Array)");
return PyUnicode_FromFormat("(ID Array [%d])", self->prop->len);
}
@@ -875,14 +881,8 @@ static PyObject *BPy_IDArray_GetLen(BPy_IDArray *self)
}
static PyGetSetDef BPy_IDArray_getseters[] = {
{"len",
(getter)BPy_IDArray_GetLen, (setter)NULL,
"The length of the array, can also be gotten with len(array).",
NULL},
{"type",
(getter)BPy_IDArray_GetType, (setter)NULL,
"The type of the data in the array, is an ant.",
NULL},
{(char *)"len", (getter)BPy_IDArray_GetLen, (setter)NULL, (char *)"The length of the array, can also be gotten with len(array).", NULL},
{(char *)"type", (getter)BPy_IDArray_GetType, (setter)NULL, (char *)"The type of the data in the array, is an ant.", NULL},
{NULL, NULL, NULL, NULL, NULL},
};
@@ -894,7 +894,7 @@ static PyObject *BPy_IDArray_ConvertToPy(BPy_IDArray *self)
static PyMethodDef BPy_IDArray_methods[] = {
{"convert_to_pyobject", (PyCFunction)BPy_IDArray_ConvertToPy, METH_NOARGS,
"return a purely python version of the group"},
{0, NULL, 0, NULL}
{NULL, NULL, 0, NULL}
};
static int BPy_IDArray_Len(BPy_IDArray *self)
@@ -905,7 +905,7 @@ static int BPy_IDArray_Len(BPy_IDArray *self)
static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
{
if (index < 0 || index >= self->prop->len) {
PyErr_SetString( PyExc_IndexError, "index out of range!");
PyErr_SetString(PyExc_IndexError, "index out of range!");
return NULL;
}
@@ -921,7 +921,7 @@ static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
break;
}
PyErr_SetString( PyExc_RuntimeError, "invalid/corrupt array type!");
PyErr_SetString(PyExc_RuntimeError, "invalid/corrupt array type!");
return NULL;
}
@@ -932,7 +932,7 @@ static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
double d;
if (index < 0 || index >= self->prop->len) {
PyErr_SetString( PyExc_RuntimeError, "index out of range!");
PyErr_SetString(PyExc_RuntimeError, "index out of range!");
return -1;
}
@@ -968,16 +968,16 @@ static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
static PySequenceMethods BPy_IDArray_Seq = {
(lenfunc) BPy_IDArray_Len, /* inquiry sq_length */
0, /* binaryfunc sq_concat */
0, /* intargfunc sq_repeat */
NULL, /* binaryfunc sq_concat */
NULL, /* intargfunc sq_repeat */
(ssizeargfunc)BPy_IDArray_GetItem, /* intargfunc sq_item */
0, /* intintargfunc sq_slice */
(ssizeobjargproc)BPy_IDArray_SetItem, /* intobjargproc sq_ass_item */
0, /* intintobjargproc sq_ass_slice */
0, /* objobjproc sq_contains */
NULL, /* intintargfunc sq_slice */
(ssizeobjargproc)BPy_IDArray_SetItem,/* intobjargproc sq_ass_item */
NULL, /* intintobjargproc sq_ass_slice */
NULL, /* objobjproc sq_contains */
/* Added in release 2.0 */
0, /* binaryfunc sq_inplace_concat */
0, /* intargfunc sq_inplace_repeat */
NULL, /* binaryfunc sq_inplace_concat */
NULL, /* intargfunc sq_inplace_repeat */
};
PyTypeObject IDArray_Type = {
@@ -1071,7 +1071,7 @@ static PyObject *IDGroup_Iter_iterself(PyObject *self)
static PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
{
return PyUnicode_FromString("(ID Property Group)");
return PyUnicode_FromFormat("(ID Property Group Iter \"%s\")", self->group->prop->name);
}
static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
@@ -1091,7 +1091,7 @@ static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
return PyUnicode_FromString(cur->name);
}
} else {
PyErr_SetString( PyExc_StopIteration, "iterator at end" );
PyErr_SetString(PyExc_StopIteration, "iterator at end");
return NULL;
}
}

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -22,7 +22,8 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#ifndef IDPROP_H
#define IDPROP_H
struct ID;
struct IDProperty;
@@ -56,9 +57,11 @@ int BPy_Wrap_SetMapItem(struct IDProperty *prop, PyObject *key, PyObject *val);
PyObject *BPy_IDGroup_WrapData(struct ID *id, struct IDProperty *prop );
char *BPy_IDProperty_Map_ValidateAndCreate(char *name, struct IDProperty *group, PyObject *ob);
const char *BPy_IDProperty_Map_ValidateAndCreate(const char *name, struct IDProperty *group, PyObject *ob);
void IDProp_Init_Types(void);
#define IDPROP_ITER_KEYS 0
#define IDPROP_ITER_ITEMS 1
#endif /* IDPROP_H */

View File

@@ -1,66 +0,0 @@
#
# $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): none yet.
#
# ***** END GPL LICENSE BLOCK *****
#
#
LIBNAME = gen_python
DIR = $(OCGDIR)/blender/$(LIBNAME)
include nan_compile.mk
CFLAGS += $(LEVEL_1_C_WARNINGS)
# OpenGL and Python
CPPFLAGS += -I$(NAN_GLEW)/include
CPPFLAGS += $(OGL_CPPFLAGS)
CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
# PreProcessor stuff
CPPFLAGS += -I$(NAN_GHOST)/include
CPPFLAGS += $(NAN_SDLCFLAGS)
# modules
CPPFLAGS += -I../../editors/include
CPPFLAGS += -I../../python
CPPFLAGS += -I../../makesdna
CPPFLAGS += -I../../makesrna
CPPFLAGS += -I../../blenlib
CPPFLAGS += -I../../blenkernel
CPPFLAGS += -I../../nodes
CPPFLAGS += -I../../imbuf
CPPFLAGS += -I../../blenloader
CPPFLAGS += -I../../windowmanager
CPPFLAGS += -I../../render/extern/include
# path to the guarded memory allocator
CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
CPPFLAGS += -I$(NAN_MEMUTIL)/include
# path to our own headerfiles
CPPFLAGS += -I..

View File

@@ -31,10 +31,15 @@
* The BGL submodule "wraps" OpenGL functions and constants,
* allowing script writers to make OpenGL calls in their Python scripts. */
#include <Python.h>
#include "bgl.h" /*This must come first */
#include <GL/glew.h>
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
static char Method_Buffer_doc[] =
"(type, dimensions, [template]) - Create a new Buffer object\n\n\
(type) - The format to store data in\n\
@@ -51,7 +56,7 @@ For example, passing [100, 100] will create a 2 dimensional\n\
square buffer. Passing [16, 16, 32] will create a 3 dimensional\n\
buffer which is twice as deep as it is wide or high.";
static PyObject *Method_Buffer( PyObject * self, PyObject * args );
static PyObject *Method_Buffer( PyObject * self, PyObject *args );
/* Buffer sequence methods */
@@ -90,16 +95,16 @@ PyTypeObject BGL_bufferType = {
( printfunc ) 0, /*tp_print */
( getattrfunc ) Buffer_getattr, /*tp_getattr */
( setattrfunc ) 0, /*tp_setattr */
0, /*tp_compare */
NULL, /*tp_compare */
( reprfunc ) Buffer_repr, /*tp_repr */
0, /*tp_as_number */
NULL, /*tp_as_number */
&Buffer_SeqMethods, /*tp_as_sequence */
};
/* #ifndef __APPLE__ */
#define BGL_Wrap(nargs, funcname, ret, arg_list) \
static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\
static PyObject *Method_##funcname (PyObject *UNUSED(self), PyObject *args) {\
arg_def##nargs arg_list; \
ret_def_##ret; \
if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\
@@ -108,7 +113,7 @@ static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\
}
#define BGLU_Wrap(nargs, funcname, ret, arg_list) \
static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\
static PyObject *Method_##funcname (PyObject *UNUSED(self), PyObject *args) {\
arg_def##nargs arg_list; \
ret_def_##ret; \
if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\
@@ -181,45 +186,62 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf
}
#define MAX_DIMENSIONS 256
static PyObject *Method_Buffer (PyObject *self, PyObject *args)
static PyObject *Method_Buffer (PyObject *UNUSED(self), PyObject *args)
{
PyObject *length_ob= NULL, *template= NULL;
PyObject *length_ob= NULL, *init= NULL;
Buffer *buffer;
int dimensions[MAX_DIMENSIONS];
int i, type;
int ndimensions = 0;
if (!PyArg_ParseTuple(args, "iO|O", &type, &length_ob, &template)) {
if (!PyArg_ParseTuple(args, "iO|O", &type, &length_ob, &init)) {
PyErr_SetString(PyExc_AttributeError, "expected an int and one or two PyObjects");
return NULL;
}
if (type!=GL_BYTE && type!=GL_SHORT && type!=GL_INT && type!=GL_FLOAT && type!=GL_DOUBLE) {
if (!ELEM5(type, GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE)) {
PyErr_SetString(PyExc_AttributeError, "invalid first argument type, should be one of GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT or GL_DOUBLE");
return NULL;
}
if (PyNumber_Check(length_ob)) {
if (PyLong_Check(length_ob)) {
ndimensions= 1;
dimensions[0]= PyLong_AsLong(length_ob);
} else if (PySequence_Check(length_ob)) {
ndimensions= PySequence_Length(length_ob);
if(((dimensions[0]= PyLong_AsLong(length_ob)) < 1)) {
PyErr_SetString(PyExc_AttributeError, "dimensions must be between 1 and "STRINGIFY(MAX_DIMENSIONS));
return NULL;
}
}
else if (PySequence_Check(length_ob)) {
ndimensions= PySequence_Size(length_ob);
if (ndimensions > MAX_DIMENSIONS) {
PyErr_SetString(PyExc_AttributeError, "too many dimensions, max is 256");
PyErr_SetString(PyExc_AttributeError, "too many dimensions, max is "STRINGIFY(MAX_DIMENSIONS));
return NULL;
}
else if (ndimensions < 1) {
PyErr_SetString(PyExc_AttributeError, "sequence must have at least one dimension");
return NULL;
}
for (i=0; i<ndimensions; i++) {
PyObject *ob= PySequence_GetItem(length_ob, i);
if (!PyNumber_Check(ob)) dimensions[i]= 1;
if (!PyLong_Check(ob)) dimensions[i]= 1;
else dimensions[i]= PyLong_AsLong(ob);
Py_DECREF(ob);
if(dimensions[i] < 1) {
PyErr_SetString(PyExc_AttributeError, "dimensions must be between 1 and "STRINGIFY(MAX_DIMENSIONS));
return NULL;
}
}
}
else {
PyErr_Format(PyExc_TypeError, "invalid second argument argument expected a sequence or an int, not a %.200s", Py_TYPE(length_ob)->tp_name);
return NULL;
}
buffer= BGL_MakeBuffer(type, ndimensions, dimensions, NULL);
if (template && ndimensions) {
if (Buffer_ass_slice((PyObject *) buffer, 0, dimensions[0], template)) {
if (init && ndimensions) {
if (Buffer_ass_slice((PyObject *) buffer, 0, dimensions[0], init)) {
Py_DECREF(buffer);
return NULL;
}
@@ -295,9 +317,9 @@ static PyObject *Buffer_slice(PyObject *self, int begin, int end)
list= PyList_New(end-begin);
for (count= begin; count<end; count++)
PyList_SetItem(list, count-begin, Buffer_item(self, count));
for (count= begin; count<end; count++) {
PyList_SET_ITEM(list, count-begin, Buffer_item(self, count));
}
return list;
}
@@ -356,8 +378,8 @@ static int Buffer_ass_slice(PyObject *self, int begin, int end, PyObject *seq)
return -1;
}
if (PySequence_Length(seq)!=(end-begin)) {
int seq_len = PySequence_Length(seq);
if (PySequence_Size(seq)!=(end-begin)) {
int seq_len = PySequence_Size(seq);
char err_str[128];
sprintf(err_str, "size mismatch in assignment. Expected size: %d (size provided: %d)", seq_len, (end-begin));
PyErr_SetString(PyExc_TypeError, err_str);
@@ -389,11 +411,11 @@ static PyObject *Buffer_tolist(PyObject *self)
{
int i, len= ((Buffer *)self)->dimensions[0];
PyObject *list= PyList_New(len);
for (i=0; i<len; i++) {
PyList_SetItem(list, i, Buffer_item(self, i));
PyList_SET_ITEM(list, i, Buffer_item(self, i));
}
return list;
}
@@ -402,11 +424,11 @@ static PyObject *Buffer_dimensions(PyObject *self)
Buffer *buffer= (Buffer *) self;
PyObject *list= PyList_New(buffer->ndimensions);
int i;
for (i= 0; i<buffer->ndimensions; i++) {
PyList_SetItem(list, i, PyLong_FromLong(buffer->dimensions[i]));
PyList_SET_ITEM(list, i, PyLong_FromLong(buffer->dimensions[i]));
}
return list;
}
@@ -1103,22 +1125,21 @@ static struct PyMethodDef BGL_methods[] = {
static struct PyModuleDef BGL_module_def = {
PyModuleDef_HEAD_INIT,
"bgl", /* m_name */
0, /* m_doc */
NULL, /* m_doc */
0, /* m_size */
BGL_methods, /* m_methods */
0, /* m_reload */
0, /* m_traverse */
0, /* m_clear */
0, /* m_free */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
PyObject *BGL_Init(void)
PyObject *BPyInit_bgl(void)
{
PyObject *mod, *dict, *item;
mod = PyModule_Create(&BGL_module_def);
PyDict_SetItemString(PyImport_GetModuleDict(), BGL_module_def.m_name, mod);
dict= PyModule_GetDict(mod);
PyObject *submodule, *dict, *item;
submodule= PyModule_Create(&BGL_module_def);
dict= PyModule_GetDict(submodule);
if( PyType_Ready( &BGL_bufferType) < 0)
return NULL; /* should never happen */
@@ -1610,6 +1631,6 @@ PyObject *BGL_Init(void)
EXPP_ADDCONST(GL_TEXTURE_BINDING_1D);
EXPP_ADDCONST(GL_TEXTURE_BINDING_2D);
return mod;
return submodule;
}

View File

@@ -33,12 +33,10 @@
* writers to make OpenGL calls in their Python scripts for Blender. The
* more important original comments are marked with an @ symbol. */
#ifndef EXPP_BGL_H
#define EXPP_BGL_H
#ifndef BGL_H
#define BGL_H
#include <Python.h>
PyObject *BGL_Init(void);
PyObject *BPyInit_bgl(void);
/*@ Create a buffer object */
/*@ dimensions is an array of ndimensions integers representing the size of each dimension */
@@ -215,19 +213,19 @@ extern PyTypeObject BGL_bufferType;
#define GLsizei_def(num) int GLsizei_var(num)
/* typedef unsigned char GLubyte; */
#define GLubyte_str "b"
#define GLubyte_str "B"
#define GLubyte_var(num) bgl_var##num
#define GLubyte_ref(num) &bgl_var##num
#define GLubyte_def(num) /* unsigned */ char GLubyte_var(num)
/* typedef unsigned short GLushort; */
#define GLushort_str "h"
#define GLushort_str "H"
#define GLushort_var(num) bgl_var##num
#define GLushort_ref(num) &bgl_var##num
#define GLushort_def(num) /* unsigned */ short GLushort_var(num)
/* typedef unsigned int GLuint; */
#define GLuint_str "i"
#define GLuint_str "I"
#define GLuint_var(num) bgl_var##num
#define GLuint_ref(num) &bgl_var##num
#define GLuint_def(num) /* unsigned */ int GLuint_var(num)
@@ -337,4 +335,4 @@ extern PyTypeObject BGL_bufferType;
return NULL;\
}
#endif /* EXPP_BGL_H */
#endif /* BGL_H */

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -23,10 +23,14 @@
*/
#include <Python.h>
#include "blf_api.h"
#include "blf_py_api.h"
#include "../../blenfont/BLF_api.h"
#include "BLI_utildefines.h"
static char py_blf_position_doc[] =
".. function:: position(fontid, x, y, z)\n"
"\n"
@@ -41,7 +45,7 @@ static char py_blf_position_doc[] =
" :arg z: Z axis position to draw the text.\n"
" :type z: float\n";
static PyObject *py_blf_position(PyObject *self, PyObject *args)
static PyObject *py_blf_position(PyObject *UNUSED(self), PyObject *args)
{
int fontid;
float x, y, z;
@@ -67,7 +71,7 @@ static char py_blf_size_doc[] =
" :arg dpi: dots per inch value to use for drawing.\n"
" :type dpi: int\n";
static PyObject *py_blf_size(PyObject *self, PyObject *args)
static PyObject *py_blf_size(PyObject *UNUSED(self), PyObject *args)
{
int fontid, size, dpi;
@@ -90,7 +94,7 @@ static char py_blf_aspect_doc[] =
" :arg aspect: The aspect ratio for text drawing to use.\n"
" :type aspect: float\n";
static PyObject *py_blf_aspect(PyObject *self, PyObject *args)
static PyObject *py_blf_aspect(PyObject *UNUSED(self), PyObject *args)
{
float aspect;
int fontid;
@@ -98,7 +102,7 @@ static PyObject *py_blf_aspect(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "if:blf.aspect", &fontid, &aspect))
return NULL;
BLF_aspect(fontid, aspect);
BLF_aspect(fontid, aspect, aspect, 1.0);
Py_RETURN_NONE;
}
@@ -114,7 +118,7 @@ static char py_blf_blur_doc[] =
" :arg radius: The radius for blurring text (in pixels).\n"
" :type radius: int\n";
static PyObject *py_blf_blur(PyObject *self, PyObject *args)
static PyObject *py_blf_blur(PyObject *UNUSED(self), PyObject *args)
{
int blur, fontid;
@@ -137,15 +141,16 @@ static char py_blf_draw_doc[] =
" :arg text: the text to draw.\n"
" :type text: string\n";
static PyObject *py_blf_draw(PyObject *self, PyObject *args)
static PyObject *py_blf_draw(PyObject *UNUSED(self), PyObject *args)
{
char *text;
int text_length;
int fontid;
if (!PyArg_ParseTuple(args, "is:blf.draw", &fontid, &text))
if (!PyArg_ParseTuple(args, "is#:blf.draw", &fontid, &text, &text_length))
return NULL;
BLF_draw(fontid, text);
BLF_draw(fontid, text, (unsigned int)text_length);
Py_RETURN_NONE;
}
@@ -162,7 +167,7 @@ static char py_blf_dimensions_doc[] =
" :return: the width and height of the text.\n"
" :rtype: tuple of 2 floats\n";
static PyObject *py_blf_dimensions(PyObject *self, PyObject *args)
static PyObject *py_blf_dimensions(PyObject *UNUSED(self), PyObject *args)
{
char *text;
float r_width, r_height;
@@ -196,7 +201,7 @@ static char py_blf_clipping_doc[] =
" :arg ymax: Clip the drawing area by these bounds.\n"
" :type ymax: float\n";
static PyObject *py_blf_clipping(PyObject *self, PyObject *args)
static PyObject *py_blf_clipping(PyObject *UNUSED(self), PyObject *args)
{
float xmin, ymin, xmax, ymax;
int fontid;
@@ -219,7 +224,7 @@ static char py_blf_disable_doc[] =
" :arg option: One of ROTATION, CLIPPING, SHADOW or KERNING_DEFAULT.\n"
" :type option: int\n";
static PyObject *py_blf_disable(PyObject *self, PyObject *args)
static PyObject *py_blf_disable(PyObject *UNUSED(self), PyObject *args)
{
int option, fontid;
@@ -241,7 +246,7 @@ static char py_blf_enable_doc[] =
" :arg option: One of ROTATION, CLIPPING, SHADOW or KERNING_DEFAULT.\n"
" :type option: int\n";
static PyObject *py_blf_enable(PyObject *self, PyObject *args)
static PyObject *py_blf_enable(PyObject *UNUSED(self), PyObject *args)
{
int option, fontid;
@@ -263,7 +268,7 @@ static char py_blf_rotation_doc[] =
" :arg angle: The angle for text drawing to use.\n"
" :type angle: float\n";
static PyObject *py_blf_rotation(PyObject *self, PyObject *args)
static PyObject *py_blf_rotation(PyObject *UNUSED(self), PyObject *args)
{
float angle;
int fontid;
@@ -294,7 +299,7 @@ static char py_blf_shadow_doc[] =
" :arg a: Shadow color (alpha channel 0.0 - 1.0).\n"
" :type a: float\n";
static PyObject *py_blf_shadow(PyObject *self, PyObject *args)
static PyObject *py_blf_shadow(PyObject *UNUSED(self), PyObject *args)
{
int level, fontid;
float r, g, b, a;
@@ -324,7 +329,7 @@ static char py_blf_shadow_offset_doc[] =
" :arg y: Horizontal shadow offset value in pixels.\n"
" :type y: float\n";
static PyObject *py_blf_shadow_offset(PyObject *self, PyObject *args)
static PyObject *py_blf_shadow_offset(PyObject *UNUSED(self), PyObject *args)
{
int x, y, fontid;
@@ -346,7 +351,7 @@ static char py_blf_load_doc[] =
" :return: the new font's fontid or -1 if there was an error.\n"
" :rtype: integer\n";
static PyObject *py_blf_load(PyObject *self, PyObject *args)
static PyObject *py_blf_load(PyObject *UNUSED(self), PyObject *args)
{
char* filename;
@@ -357,7 +362,7 @@ static PyObject *py_blf_load(PyObject *self, PyObject *args)
}
/*----------------------------MODULE INIT-------------------------*/
struct PyMethodDef BLF_methods[] = {
static PyMethodDef BLF_methods[] = {
{"aspect", (PyCFunction) py_blf_aspect, METH_VARARGS, py_blf_aspect_doc},
{"blur", (PyCFunction) py_blf_blur, METH_VARARGS, py_blf_blur_doc},
{"clipping", (PyCFunction) py_blf_clipping, METH_VARARGS, py_blf_clipping_doc},
@@ -365,7 +370,7 @@ struct PyMethodDef BLF_methods[] = {
{"dimensions", (PyCFunction) py_blf_dimensions, METH_VARARGS, py_blf_dimensions_doc},
{"draw", (PyCFunction) py_blf_draw, METH_VARARGS, py_blf_draw_doc},
{"enable", (PyCFunction) py_blf_enable, METH_VARARGS, py_blf_enable_doc},
{"position", (PyCFunction)py_blf_position, METH_VARARGS, py_blf_position_doc},
{"position", (PyCFunction) py_blf_position, METH_VARARGS, py_blf_position_doc},
{"rotation", (PyCFunction) py_blf_rotation, METH_VARARGS, py_blf_rotation_doc},
{"shadow", (PyCFunction) py_blf_shadow, METH_VARARGS, py_blf_shadow_doc},
{"shadow_offset", (PyCFunction) py_blf_shadow_offset, METH_VARARGS, py_blf_shadow_offset_doc},
@@ -383,23 +388,22 @@ static struct PyModuleDef BLF_module_def = {
BLF_doc, /* m_doc */
0, /* m_size */
BLF_methods, /* m_methods */
0, /* m_reload */
0, /* m_traverse */
0, /* m_clear */
0, /* m_free */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
PyObject *BLF_Init(void)
PyObject *BPyInit_blf(void)
{
PyObject *submodule;
submodule = PyModule_Create(&BLF_module_def);
PyDict_SetItemString(PyImport_GetModuleDict(), BLF_module_def.m_name, submodule);
PyModule_AddIntConstant(submodule, "ROTATION", BLF_ROTATION);
PyModule_AddIntConstant(submodule, "CLIPPING", BLF_CLIPPING);
PyModule_AddIntConstant(submodule, "SHADOW", BLF_SHADOW);
PyModule_AddIntConstant(submodule, "KERNING_DEFAULT", BLF_KERNING_DEFAULT);
return (submodule);
return submodule;
}

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -22,5 +22,4 @@
* ***** END GPL LICENSE BLOCK *****
*/
PyObject *BLF_Init(void);
PyObject *BPyInit_blf(void);

View File

@@ -1,5 +1,5 @@
/*
* $Id: bpy_internal_import.c 21094 2009-06-23 00:09:26Z gsrb3d $
* $Id$
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -26,17 +26,27 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#include <stddef.h>
#include "compile.h" /* for the PyCodeObject */
#include "eval.h" /* for PyEval_EvalCode */
#include "bpy_internal_import.h"
#include "DNA_text_types.h"
#include "MEM_guardedalloc.h"
#include "BKE_text.h" /* txt_to_buf */
#include "BKE_main.h"
#include "BKE_global.h" /* grr, only for G.sce */
#include "DNA_text_types.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include <stddef.h>
#include "BLI_utildefines.h"
/* UNUSED */
#include "BKE_text.h" /* txt_to_buf */
#include "BKE_main.h"
#include "BKE_global.h" /* grr, only for G.main->name */
static Main *bpy_import_main= NULL;
@@ -61,16 +71,17 @@ void bpy_import_main_set(struct Main *maggie)
/* returns a dummy filename for a textblock so we can tell what file a text block comes from */
void bpy_text_filename_get(char *fn, Text *text)
{
sprintf(fn, "%s/%s", text->id.lib ? text->id.lib->filepath : G.sce, text->id.name+2);
/* XXX, this is a bug in python's Py_CompileString()!
#if PY_VERSION_HEX >= 0x03020000
sprintf(fn, "%s%c%s", text->id.lib ? text->id.lib->filepath : G.main->name, SEP, text->id.name+2);
#else
/* this is a bug in python's Py_CompileString()!, fixed for python 3.2.
the string encoding should not be required to be utf-8
reported: http://bugs.python.org/msg115202
*/
BLI_utf8_invalid_strip(fn, strlen(fn));
reported: http://bugs.python.org/msg115202 */
strcpy(fn, text->id.name+2);
#endif
}
PyObject *bpy_text_import( Text *text )
PyObject *bpy_text_import(Text *text)
{
char *buf = NULL;
char modulename[24];
@@ -191,24 +202,24 @@ PyObject *bpy_text_reimport( PyObject *module, int *found )
}
static PyObject *blender_import( PyObject * self, PyObject * args, PyObject * kw)
static PyObject *blender_import(PyObject *UNUSED(self), PyObject *args, PyObject * kw)
{
PyObject *exception, *err, *tb;
char *name;
int found= 0;
PyObject *globals = NULL, *locals = NULL, *fromlist = NULL;
int level= -1; /* relative imports */
PyObject *newmodule;
//PyObject_Print(args, stderr, 0);
int dummy_val; /* what does this do?*/
static char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", 0};
static const char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", NULL};
if( !PyArg_ParseTupleAndKeywords( args, kw, "s|OOOi:bpy_import_meth", kwlist,
&name, &globals, &locals, &fromlist, &dummy_val) )
if( !PyArg_ParseTupleAndKeywords(args, kw, "s|OOOi:bpy_import_meth", (char **)kwlist,
&name, &globals, &locals, &fromlist, &level) )
return NULL;
/* import existing builtin modules or modules that have been imported already */
newmodule = PyImport_ImportModuleEx( name, globals, locals, fromlist );
newmodule= PyImport_ImportModuleLevel(name, globals, locals, fromlist, level);
if(newmodule)
return newmodule;
@@ -244,7 +255,7 @@ static PyObject *blender_import( PyObject * self, PyObject * args, PyObject * k
* our reload() module, to handle reloading in-memory scripts
*/
static PyObject *blender_reload( PyObject * self, PyObject * module )
static PyObject *blender_reload(PyObject *UNUSED(self), PyObject * module)
{
PyObject *exception, *err, *tb;
PyObject *newmodule = NULL;
@@ -281,8 +292,8 @@ static PyObject *blender_reload( PyObject * self, PyObject * module )
return newmodule;
}
PyMethodDef bpy_import_meth[] = { {"bpy_import_meth", (PyCFunction)blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"} };
PyMethodDef bpy_reload_meth[] = { {"bpy_reload_meth", (PyCFunction)blender_reload, METH_O, "blenders reload"} };
PyMethodDef bpy_import_meth = {"bpy_import_meth", (PyCFunction)blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"};
PyMethodDef bpy_reload_meth = {"bpy_reload_meth", (PyCFunction)blender_reload, METH_O, "blenders reload"};
/* Clear user modules.
@@ -357,26 +368,3 @@ void bpy_text_clear_modules(int clear_all)
Py_DECREF(list); /* removes all references from append */
}
#endif
/*****************************************************************************
* Description: This function creates a new Python dictionary object.
* note: dict is owned by sys.modules["__main__"] module, reference is borrowed
* note: important we use the dict from __main__, this is what python expects
for 'pickle' to work as well as strings like this...
>> foo = 10
>> print(__import__("__main__").foo)
*****************************************************************************/
PyObject *bpy_namespace_dict_new(const char *filename)
{
PyInterpreterState *interp= PyThreadState_GET()->interp;
PyObject *mod_main= PyModule_New("__main__");
PyDict_SetItemString(interp->modules, "__main__", mod_main);
Py_DECREF(mod_main); /* sys.modules owns now */
PyModule_AddStringConstant(mod_main, "__name__", "__main__");
if(filename)
PyModule_AddStringConstant(mod_main, "__file__", filename); /* __file__ only for nice UI'ness */
PyModule_AddObject(mod_main, "__builtins__", interp->builtins);
Py_INCREF(interp->builtins); /* AddObject steals a reference */
return PyModule_GetDict(mod_main);
}

View File

@@ -28,8 +28,8 @@
/* Note, the BGE needs to use this too, keep it minimal */
#ifndef EXPP_bpy_import_h
#define EXPP_bpy_import_h
#ifndef BPY_INTERNAL_IMPORT_H
#define BPY_INTERNAL_IMPORT_H
/* python redefines :/ */
#ifdef _POSIX_C_SOURCE
@@ -40,27 +40,20 @@
#undef _XOPEN_SOURCE
#endif
#include <Python.h>
#include "compile.h" /* for the PyCodeObject */
#include "eval.h" /* for PyEval_EvalCode */
struct Text;
PyObject* bpy_text_import( struct Text *text );
PyObject* bpy_text_import_name( char *name, int *found );
PyObject* bpy_text_reimport( PyObject *module, int *found );
/* void bpy_text_clear_modules( int clear_all );*/ /* Clear user modules */
PyObject* bpy_text_import(struct Text *text);
PyObject* bpy_text_import_name(char *name, int *found);
PyObject* bpy_text_reimport(PyObject *module, int *found);
/* void bpy_text_clear_modules(int clear_all);*/ /* Clear user modules */
void bpy_text_filename_get(char *fn, struct Text *text);
extern PyMethodDef bpy_import_meth[];
extern PyMethodDef bpy_reload_meth[];
extern PyMethodDef bpy_import_meth;
extern PyMethodDef bpy_reload_meth;
/* The game engine has its own Main struct, if this is set search this rather then G.main */
struct Main *bpy_import_main_get(void);
void bpy_import_main_set(struct Main *maggie);
/* name namespace function for bpy & bge */
PyObject *bpy_namespace_dict_new(const char *filename);
#endif /* EXPP_bpy_import_h */
#endif /* BPY_INTERNAL_IMPORT_H */

View File

@@ -1,841 +0,0 @@
/*
* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* This is a new part of Blender.
*
* Contributor(s): Joseph Gilbert, Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "geometry.h"
/* Used for PolyFill */
#include "BKE_displist.h"
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BKE_utildefines.h"
#include "BKE_curve.h"
#include "BLI_boxpack2d.h"
#include "BLI_math.h"
#define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp
#define eps 0.000001
/*-------------------------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";
static char M_Geometry_PointInTriangle2D_doc[] = "(pt, tri_p1, tri_p2, tri_p3) - takes 4 vectors, one is the point and the next 3 define the triangle, only the x and y are used from the vectors";
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[] = "";
//---------------------------------INTERSECTION FUNCTIONS--------------------
//----------------------------------geometry.Intersect() -------------------
static PyObject *M_Geometry_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);
}
//----------------------------------geometry.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--------------------
//----------------------------------geometry.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);
}
//----------------------------geometry.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--------------------
//----------------------------------geometry.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() -------------------*/
/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */
static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq )
{
PyObject *tri_list; /*return this list of tri's */
PyObject *polyLine, *polyVec;
int i, len_polylines, len_polypoints, ls_error = 0;
/* display listbase */
ListBase dispbase={NULL, NULL};
DispList *dl;
float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */
int index, *dl_face, totpoints=0;
dispbase.first= dispbase.last= NULL;
if(!PySequence_Check(polyLineSeq)) {
PyErr_SetString( PyExc_TypeError, "expected a sequence of poly lines" );
return NULL;
}
len_polylines = PySequence_Size( polyLineSeq );
for( i = 0; i < len_polylines; ++i ) {
polyLine= PySequence_GetItem( polyLineSeq, i );
if (!PySequence_Check(polyLine)) {
freedisplist(&dispbase);
Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/
PyErr_SetString( PyExc_TypeError, "One or more of the polylines is not a sequence of mathutils.Vector's" );
return NULL;
}
len_polypoints= PySequence_Size( polyLine );
if (len_polypoints>0) { /* dont bother adding edges as polylines */
#if 0
if (EXPP_check_sequence_consistency( polyLine, &vector_Type ) != 1) {
freedisplist(&dispbase);
Py_DECREF(polyLine);
PyErr_SetString( PyExc_TypeError, "A point in one of the polylines is not a mathutils.Vector type" );
return NULL;
}
#endif
dl= MEM_callocN(sizeof(DispList), "poly disp");
BLI_addtail(&dispbase, dl);
dl->type= DL_INDEX3;
dl->nr= len_polypoints;
dl->type= DL_POLY;
dl->parts= 1; /* no faces, 1 edge loop */
dl->col= 0; /* no material */
dl->verts= fp= MEM_callocN( sizeof(float)*3*len_polypoints, "dl verts");
dl->index= MEM_callocN(sizeof(int)*3*len_polypoints, "dl index");
for( index = 0; index<len_polypoints; ++index, fp+=3) {
polyVec= PySequence_GetItem( polyLine, index );
if(VectorObject_Check(polyVec)) {
if(!BaseMath_ReadCallback((VectorObject *)polyVec))
ls_error= 1;
fp[0] = ((VectorObject *)polyVec)->vec[0];
fp[1] = ((VectorObject *)polyVec)->vec[1];
if( ((VectorObject *)polyVec)->size > 2 )
fp[2] = ((VectorObject *)polyVec)->vec[2];
else
fp[2]= 0.0f; /* if its a 2d vector then set the z to be zero */
}
else {
ls_error= 1;
}
totpoints++;
Py_DECREF(polyVec);
}
}
Py_DECREF(polyLine);
}
if(ls_error) {
freedisplist(&dispbase); /* possible some dl was allocated */
PyErr_SetString( PyExc_TypeError, "A point in one of the polylines is not a mathutils.Vector type" );
return NULL;
}
else if (totpoints) {
/* now make the list to return */
filldisplist(&dispbase, &dispbase, 0);
/* The faces are stored in a new DisplayList
thats added to the head of the listbase */
dl= dispbase.first;
tri_list= PyList_New(dl->parts);
if( !tri_list ) {
freedisplist(&dispbase);
PyErr_SetString( PyExc_RuntimeError, "geometry.PolyFill failed to make a new list" );
return NULL;
}
index= 0;
dl_face= dl->index;
while(index < dl->parts) {
PyList_SetItem(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2]) );
dl_face+= 3;
index++;
}
freedisplist(&dispbase);
} else {
/* no points, do this so scripts dont barf */
freedisplist(&dispbase); /* possible some dl was allocated */
tri_list= PyList_New(0);
}
return tri_list;
}
static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args )
{
VectorObject *line_a1, *line_a2, *line_b1, *line_b2;
float a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, xi, yi, a1,a2,b1,b2, newvec[2];
if( !PyArg_ParseTuple ( args, "O!O!O!O!",
&vector_Type, &line_a1,
&vector_Type, &line_a2,
&vector_Type, &line_b1,
&vector_Type, &line_b2)
) {
PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
return NULL;
}
if(!BaseMath_ReadCallback(line_a1) || !BaseMath_ReadCallback(line_a2) || !BaseMath_ReadCallback(line_b1) || !BaseMath_ReadCallback(line_b2))
return NULL;
a1x= line_a1->vec[0];
a1y= line_a1->vec[1];
a2x= line_a2->vec[0];
a2y= line_a2->vec[1];
b1x= line_b1->vec[0];
b1y= line_b1->vec[1];
b2x= line_b2->vec[0];
b2y= line_b2->vec[1];
if((MIN2(a1x, a2x) > MAX2(b1x, b2x)) ||
(MAX2(a1x, a2x) < MIN2(b1x, b2x)) ||
(MIN2(a1y, a2y) > MAX2(b1y, b2y)) ||
(MAX2(a1y, a2y) < MIN2(b1y, b2y)) ) {
Py_RETURN_NONE;
}
/* Make sure the hoz/vert line comes first. */
if (fabs(b1x - b2x) < eps || fabs(b1y - b2y) < eps) {
SWAP_FLOAT(a1x, b1x, xi); /*abuse xi*/
SWAP_FLOAT(a1y, b1y, xi);
SWAP_FLOAT(a2x, b2x, xi);
SWAP_FLOAT(a2y, b2y, xi);
}
if (fabs(a1x-a2x) < eps) { /* verticle line */
if (fabs(b1x-b2x) < eps){ /*verticle second line */
Py_RETURN_NONE; /* 2 verticle lines dont intersect. */
}
else if (fabs(b1y-b2y) < eps) {
/*X of vert, Y of hoz. no calculation needed */
newvec[0]= a1x;
newvec[1]= b1y;
return newVectorObject(newvec, 2, Py_NEW, NULL);
}
yi = (float)(((b1y / fabs(b1x - b2x)) * fabs(b2x - a1x)) + ((b2y / fabs(b1x - b2x)) * fabs(b1x - a1x)));
if (yi > MAX2(a1y, a2y)) {/* New point above seg1's vert line */
Py_RETURN_NONE;
} else if (yi < MIN2(a1y, a2y)) { /* New point below seg1's vert line */
Py_RETURN_NONE;
}
newvec[0]= a1x;
newvec[1]= yi;
return newVectorObject(newvec, 2, Py_NEW, NULL);
} else if (fabs(a2y-a1y) < eps) { /* hoz line1 */
if (fabs(b2y-b1y) < eps) { /*hoz line2*/
Py_RETURN_NONE; /*2 hoz lines dont intersect*/
}
/* Can skip vert line check for seg 2 since its covered above. */
xi = (float)(((b1x / fabs(b1y - b2y)) * fabs(b2y - a1y)) + ((b2x / fabs(b1y - b2y)) * fabs(b1y - a1y)));
if (xi > MAX2(a1x, a2x)) { /* New point right of hoz line1's */
Py_RETURN_NONE;
} else if (xi < MIN2(a1x, a2x)) { /*New point left of seg1's hoz line */
Py_RETURN_NONE;
}
newvec[0]= xi;
newvec[1]= a1y;
return newVectorObject(newvec, 2, Py_NEW, NULL);
}
b1 = (a2y-a1y)/(a2x-a1x);
b2 = (b2y-b1y)/(b2x-b1x);
a1 = a1y-b1*a1x;
a2 = b1y-b2*b1x;
if (b1 - b2 == 0.0) {
Py_RETURN_NONE;
}
xi = - (a1-a2)/(b1-b2);
yi = a1+b1*xi;
if ((a1x-xi)*(xi-a2x) >= 0 && (b1x-xi)*(xi-b2x) >= 0 && (a1y-yi)*(yi-a2y) >= 0 && (b1y-yi)*(yi-b2y)>=0) {
newvec[0]= xi;
newvec[1]= yi;
return newVectorObject(newvec, 2, Py_NEW, NULL);
}
Py_RETURN_NONE;
}
static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args )
{
VectorObject *pt, *line_1, *line_2;
float pt_in[3], pt_out[3], l1[3], l2[3];
float lambda;
PyObject *ret;
if( !PyArg_ParseTuple ( args, "O!O!O!",
&vector_Type, &pt,
&vector_Type, &line_1,
&vector_Type, &line_2)
) {
PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" );
return NULL;
}
if(!BaseMath_ReadCallback(pt) || !BaseMath_ReadCallback(line_1) || !BaseMath_ReadCallback(line_2))
return NULL;
/* accept 2d verts */
if (pt->size==3) { VECCOPY(pt_in, pt->vec);}
else { pt_in[2]=0.0; VECCOPY2D(pt_in, pt->vec) }
if (line_1->size==3) { VECCOPY(l1, line_1->vec);}
else { l1[2]=0.0; VECCOPY2D(l1, line_1->vec) }
if (line_2->size==3) { VECCOPY(l2, line_2->vec);}
else { l2[2]=0.0; VECCOPY2D(l2, line_2->vec) }
/* do the calculation */
lambda = closest_to_line_v3( pt_out,pt_in, l1, l2);
ret = PyTuple_New(2);
PyTuple_SET_ITEM( ret, 0, newVectorObject(pt_out, 3, Py_NEW, NULL) );
PyTuple_SET_ITEM( ret, 1, PyFloat_FromDouble(lambda) );
return ret;
}
static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args )
{
VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3;
if( !PyArg_ParseTuple ( args, "O!O!O!O!",
&vector_Type, &pt_vec,
&vector_Type, &tri_p1,
&vector_Type, &tri_p2,
&vector_Type, &tri_p3)
) {
PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
return NULL;
}
if(!BaseMath_ReadCallback(pt_vec) || !BaseMath_ReadCallback(tri_p1) || !BaseMath_ReadCallback(tri_p2) || !BaseMath_ReadCallback(tri_p3))
return NULL;
return PyLong_FromLong(isect_point_tri_v2(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec));
}
static PyObject *M_Geometry_PointInQuad2D( PyObject * self, PyObject * args )
{
VectorObject *pt_vec, *quad_p1, *quad_p2, *quad_p3, *quad_p4;
if( !PyArg_ParseTuple ( args, "O!O!O!O!O!",
&vector_Type, &pt_vec,
&vector_Type, &quad_p1,
&vector_Type, &quad_p2,
&vector_Type, &quad_p3,
&vector_Type, &quad_p4)
) {
PyErr_SetString( PyExc_TypeError, "expected 5 vector types\n" );
return NULL;
}
if(!BaseMath_ReadCallback(pt_vec) || !BaseMath_ReadCallback(quad_p1) || !BaseMath_ReadCallback(quad_p2) || !BaseMath_ReadCallback(quad_p3) || !BaseMath_ReadCallback(quad_p4))
return NULL;
return PyLong_FromLong(isect_point_quad_v2(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec));
}
static int boxPack_FromPyObject(PyObject * value, boxPack **boxarray )
{
int len, i;
PyObject *list_item, *item_1, *item_2;
boxPack *box;
/* Error checking must already be done */
if( !PyList_Check( value ) ) {
PyErr_SetString( PyExc_TypeError, "can only back a list of [x,y,x,w]" );
return -1;
}
len = PyList_Size( value );
(*boxarray) = MEM_mallocN( len*sizeof(boxPack), "boxPack box");
for( i = 0; i < len; i++ ) {
list_item = PyList_GET_ITEM( value, i );
if( !PyList_Check( list_item ) || PyList_Size( list_item ) < 4 ) {
MEM_freeN(*boxarray);
PyErr_SetString( PyExc_TypeError, "can only back a list of [x,y,x,w]" );
return -1;
}
box = (*boxarray)+i;
item_1 = PyList_GET_ITEM(list_item, 2);
item_2 = PyList_GET_ITEM(list_item, 3);
if (!PyNumber_Check(item_1) || !PyNumber_Check(item_2)) {
MEM_freeN(*boxarray);
PyErr_SetString( PyExc_TypeError, "can only back a list of 2d boxes [x,y,x,w]" );
return -1;
}
box->w = (float)PyFloat_AsDouble( item_1 );
box->h = (float)PyFloat_AsDouble( item_2 );
box->index = i;
/* verts will be added later */
}
return 0;
}
static void boxPack_ToPyObject(PyObject * value, boxPack **boxarray)
{
int len, i;
PyObject *list_item;
boxPack *box;
len = PyList_Size( value );
for( i = 0; i < len; i++ ) {
box = (*boxarray)+i;
list_item = PyList_GET_ITEM( value, box->index );
PyList_SET_ITEM( list_item, 0, PyFloat_FromDouble( box->x ));
PyList_SET_ITEM( list_item, 1, PyFloat_FromDouble( box->y ));
}
MEM_freeN(*boxarray);
}
static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * boxlist )
{
boxPack *boxarray = NULL;
float tot_width, tot_height;
int len;
int error;
if(!PyList_Check(boxlist)) {
PyErr_SetString( PyExc_TypeError, "expected a sequence of boxes [[x,y,w,h], ... ]" );
return NULL;
}
len = PyList_Size( boxlist );
if (!len)
return Py_BuildValue( "ff", 0.0, 0.0);
error = boxPack_FromPyObject(boxlist, &boxarray);
if (error!=0) return NULL;
/* Non Python function */
boxPack2D(boxarray, len, &tot_width, &tot_height);
boxPack_ToPyObject(boxlist, &boxarray);
return Py_BuildValue( "ff", tot_width, tot_height);
}
static PyObject *M_Geometry_BezierInterp( PyObject * self, PyObject * args )
{
VectorObject *vec_k1, *vec_h1, *vec_k2, *vec_h2;
int resolu;
int dims;
int i;
float *coord_array, *fp;
PyObject *list;
float k1[4] = {0.0, 0.0, 0.0, 0.0};
float h1[4] = {0.0, 0.0, 0.0, 0.0};
float k2[4] = {0.0, 0.0, 0.0, 0.0};
float h2[4] = {0.0, 0.0, 0.0, 0.0};
if( !PyArg_ParseTuple ( args, "O!O!O!O!i",
&vector_Type, &vec_k1,
&vector_Type, &vec_h1,
&vector_Type, &vec_h2,
&vector_Type, &vec_k2, &resolu) || (resolu<=1)
) {
PyErr_SetString( PyExc_TypeError, "expected 4 vector types and an int greater then 1\n" );
return NULL;
}
if(!BaseMath_ReadCallback(vec_k1) || !BaseMath_ReadCallback(vec_h1) || !BaseMath_ReadCallback(vec_k2) || !BaseMath_ReadCallback(vec_h2))
return NULL;
dims= MAX4(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size);
for(i=0; i < vec_k1->size; i++) k1[i]= vec_k1->vec[i];
for(i=0; i < vec_h1->size; i++) h1[i]= vec_h1->vec[i];
for(i=0; i < vec_k2->size; i++) k2[i]= vec_k2->vec[i];
for(i=0; i < vec_h2->size; i++) h2[i]= vec_h2->vec[i];
coord_array = MEM_callocN(dims * (resolu) * sizeof(float), "BezierInterp");
for(i=0; i<dims; i++) {
forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array+i, resolu-1, sizeof(float)*dims);
}
list= PyList_New(resolu);
fp= coord_array;
for(i=0; i<resolu; i++, fp= fp+dims) {
PyList_SET_ITEM(list, i, newVectorObject(fp, dims, Py_NEW, NULL));
}
MEM_freeN(coord_array);
return list;
}
static PyObject *M_Geometry_BarycentricTransform(PyObject * self, PyObject * args)
{
VectorObject *vec_pt;
VectorObject *vec_t1_tar, *vec_t2_tar, *vec_t3_tar;
VectorObject *vec_t1_src, *vec_t2_src, *vec_t3_src;
float vec[3];
if( !PyArg_ParseTuple ( args, "O!O!O!O!O!O!O!",
&vector_Type, &vec_pt,
&vector_Type, &vec_t1_src,
&vector_Type, &vec_t2_src,
&vector_Type, &vec_t3_src,
&vector_Type, &vec_t1_tar,
&vector_Type, &vec_t2_tar,
&vector_Type, &vec_t3_tar) || ( vec_pt->size != 3 ||
vec_t1_src->size != 3 ||
vec_t2_src->size != 3 ||
vec_t3_src->size != 3 ||
vec_t1_tar->size != 3 ||
vec_t2_tar->size != 3 ||
vec_t3_tar->size != 3)
) {
PyErr_SetString( PyExc_TypeError, "expected 7, 3D vector types\n" );
return NULL;
}
barycentric_transform(vec, vec_pt->vec,
vec_t1_tar->vec, vec_t2_tar->vec, vec_t3_tar->vec,
vec_t1_src->vec, vec_t2_src->vec, vec_t3_src->vec);
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(PyImport_GetModuleDict(), M_Geometry_module_def.m_name, submodule);
return (submodule);
}

View File

@@ -37,15 +37,34 @@
* - 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
* - Mathutils.OrthoProjectionMatrix(plane, size, axis) --> Mathutils.OrthoProjectionMatrix(axis, size); merge axis & plane args
* - Mathutils.ShearMatrix(plane, factor, size) --> Mathutils.ShearMatrix(plane, size, factor); swap size & factor args, match other constructors.
* - Matrix.scalePart --> Matrix.scale_part
* - Matrix.translationPart --> Matrix.translation_part
* - Matrix.rotationPart --> Matrix.rotation_part
* - mathutils.Matrix.Shear(plane, fac, size), now takes a pair of floats for 3x3 or 4x4 shear factor.
* - toMatrix --> to_matrix
* - toEuler --> to_euler
* - toQuat --> to_quat
* - Vector.toTrackQuat --> Vector.to_track_quat
* - Vector.rotate(axis, angle) --> rotate(other), where other can be Euler/Quaternion/Matrix.
* - Quaternion * Quaternion --> cross product (not dot product)
*
* - Euler.rotate(angle, axis) --> Euler.rotate_axis(axis, angle)
* - Euler.unique() *removed*, not a standard function only toggled different rotations.
* - Matrix.rotation_part() -> to_3x3()
* - Matrix.scale_part() -> to_scale()
* - Matrix.translation_part() -> to_translation()
* - Matrix.resize4x4() -> resize_4x4()
* - Euler.to_quat() -> to_quaternion()
* - Matrix.to_quat() -> to_quaternion()
* resizing nolonger returns the resized value.
* - Vector.resize2D -> resize_2d
* - Vector.resize3D -> resize_3d
* - Vector.resize4D -> resize_4d
* added new functions.
* - Vector.to_2d()
* - Vector.to_3d()
* - Vector.to_4d()
* moved into class functions.
* - Mathutils.RotationMatrix -> mathutils.Matrix.Rotation
* - Mathutils.ScaleMatrix -> mathutils.Matrix.Scale
@@ -54,20 +73,37 @@
* - Mathutils.OrthoProjectionMatrix -> mathutils.Matrix.OrthoProjection
*
* Moved to Geometry module: Intersect, TriangleArea, TriangleNormal, QuadNormal, LineIntersect
* - geometry.Intersect -> intersect_ray_tri
* - geometry.ClosestPointOnLine -> intersect_point_line
* - geometry.PointInTriangle2D -> intersect_point_tri_2d
* - geometry.PointInQuad2D -> intersect_point_quad_2d
* - geometry.LineIntersect -> intersect_line_line
* - geometry.LineIntersect2D -> intersect_line_line_2d
* - geometry.BezierInterp -> interpolate_bezier
* - geometry.TriangleArea -> area_tri
* - geometry.QuadNormal, TriangleNormal -> normal
* - geometry.PolyFill -> tesselate_polygon
* - geometry.BoxPack2D -> box_pack_2d
* - geometry.BarycentricTransform -> barycentric_transform
*/
#include <Python.h>
#include "mathutils.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
//-------------------------DOC STRINGS ---------------------------
static char M_Mathutils_doc[] =
"This module provides access to matrices, eulers, quaternions and vectors.";
/* helper functionm returns length of the 'value', -1 on error */
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
"This module provides access to matrices, eulers, quaternions and vectors."
;
static int mathutils_array_parse_fast(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
{
PyObject *value_fast= NULL;
PyObject *item;
int i, size;
@@ -89,8 +125,8 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
i= size;
do {
i--;
if(((array[i]= PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value_fast, i))) == -1.0) && PyErr_Occurred()) {
PyErr_Format(PyExc_ValueError, "%.200s: sequence index %d is not a float", error_prefix, i);
if(((array[i]= PyFloat_AsDouble((item= PySequence_Fast_GET_ITEM(value_fast, i)))) == -1.0) && PyErr_Occurred()) {
PyErr_Format(PyExc_ValueError, "%.200s: sequence index %d expected a number, found '%.200s' type, ", error_prefix, i, Py_TYPE(item)->tp_name);
Py_DECREF(value_fast);
return -1;
}
@@ -100,6 +136,80 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
return size;
}
/* helper functionm returns length of the 'value', -1 on error */
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
{
#if 1 /* approx 6x speedup for mathutils types */
int size;
if( (VectorObject_Check(value) && (size= ((VectorObject *)value)->size)) ||
(EulerObject_Check(value) && (size= 3)) ||
(QuaternionObject_Check(value) && (size= 4)) ||
(ColorObject_Check(value) && (size= 3))
) {
if(!BaseMath_ReadCallback((BaseMathObject *)value)) {
return -1;
}
if(size > array_max || size < array_min) {
if (array_max == array_min) PyErr_Format(PyExc_ValueError, "%.200s: sequence size is %d, expected %d", error_prefix, size, array_max);
else PyErr_Format(PyExc_ValueError, "%.200s: sequence size is %d, expected [%d - %d]", error_prefix, size, array_min, array_max);
return -1;
}
memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float));
return size;
}
else
#endif
{
return mathutils_array_parse_fast(array, array_min, array_max, value, error_prefix);
}
}
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
{
if(EulerObject_Check(value)) {
if(!BaseMath_ReadCallback((BaseMathObject *)value)) {
return -1;
}
else {
eulO_to_mat3(rmat, ((EulerObject *)value)->eul, ((EulerObject *)value)->order);
return 0;
}
}
else if (QuaternionObject_Check(value)) {
if(!BaseMath_ReadCallback((BaseMathObject *)value)) {
return -1;
}
else {
float tquat[4];
normalize_qt_qt(tquat, ((QuaternionObject *)value)->quat);
quat_to_mat3(rmat, tquat);
return 0;
}
}
else if (MatrixObject_Check(value)) {
if(!BaseMath_ReadCallback((BaseMathObject *)value)) {
return -1;
}
else if(((MatrixObject *)value)->col_size < 3 || ((MatrixObject *)value)->row_size < 3) {
PyErr_Format(PyExc_ValueError, "%.200s: matrix must have minimum 3x3 dimensions", error_prefix);
return -1;
}
else {
matrix_as_3x3(rmat, (MatrixObject *)value);
normalize_m3(rmat);
return 0;
}
}
else {
PyErr_Format(PyExc_TypeError, "%.200s: expected a Euler, Quaternion or Matrix type, found %.200s", error_prefix, Py_TYPE(value)->tp_name);
return -1;
}
}
//----------------------------------MATRIX FUNCTIONS--------------------
@@ -139,7 +249,7 @@ int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps)
/* Mathutils Callbacks */
/* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */
Mathutils_Callback *mathutils_callbacks[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
static Mathutils_Callback *mathutils_callbacks[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
int Mathutils_RegisterCallback(Mathutils_Callback *cb)
{
@@ -163,7 +273,7 @@ int _BaseMathObject_ReadCallback(BaseMathObject *self)
return 1;
if(!PyErr_Occurred())
PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
PyErr_Format(PyExc_RuntimeError, "%s user has become invalid", Py_TYPE(self)->tp_name);
return 0;
}
@@ -174,7 +284,7 @@ int _BaseMathObject_WriteCallback(BaseMathObject *self)
return 1;
if(!PyErr_Occurred())
PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
PyErr_Format(PyExc_RuntimeError, "%s user has become invalid", Py_TYPE(self)->tp_name);
return 0;
}
@@ -185,7 +295,7 @@ int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index)
return 1;
if(!PyErr_Occurred())
PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
PyErr_Format(PyExc_RuntimeError, "%s user has become invalid", Py_TYPE(self)->tp_name);
return 0;
}
@@ -196,13 +306,13 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index)
return 1;
if(!PyErr_Occurred())
PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
PyErr_Format(PyExc_RuntimeError, "%s user has become invalid", Py_TYPE(self)->tp_name);
return 0;
}
/* BaseMathObject generic functions for all mathutils types */
char BaseMathObject_Owner_doc[] = "The item this is wrapping or None (readonly).";
PyObject *BaseMathObject_getOwner( BaseMathObject * self, void *type )
PyObject *BaseMathObject_getOwner(BaseMathObject *self, void *UNUSED(closure))
{
PyObject *ret= self->cb_user ? self->cb_user : Py_None;
Py_INCREF(ret);
@@ -210,23 +320,37 @@ PyObject *BaseMathObject_getOwner( BaseMathObject * self, void *type )
}
char BaseMathObject_Wrapped_doc[] = "True when this object wraps external data (readonly).\n\n:type: boolean";
PyObject *BaseMathObject_getWrapped( BaseMathObject *self, void *type )
PyObject *BaseMathObject_getWrapped(BaseMathObject *self, void *UNUSED(closure))
{
return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1:0);
}
void BaseMathObject_dealloc(BaseMathObject * self)
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->cb_user);
return 0;
}
int BaseMathObject_clear(BaseMathObject *self)
{
Py_CLEAR(self->cb_user);
return 0;
}
void BaseMathObject_dealloc(BaseMathObject *self)
{
/* only free non wrapped */
if(self->wrapped != Py_WRAP)
if(self->wrapped != Py_WRAP) {
PyMem_Free(self->data);
}
BaseMathObject_clear(self);
Py_XDECREF(self->cb_user);
Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes
}
/*----------------------------MODULE INIT-------------------------*/
struct PyMethodDef M_Mathutils_methods[] = {
static struct PyMethodDef M_Mathutils_methods[] = {
{NULL, NULL, 0, NULL}
};
@@ -236,16 +360,17 @@ static struct PyModuleDef M_Mathutils_module_def = {
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 */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
PyObject *Mathutils_Init(void)
PyMODINIT_FUNC BPyInit_mathutils(void)
{
PyObject *submodule;
PyObject *item;
if( PyType_Ready( &vector_Type ) < 0 )
return NULL;
if( PyType_Ready( &matrix_Type ) < 0 )
@@ -258,7 +383,6 @@ PyObject *Mathutils_Init(void)
return NULL;
submodule = PyModule_Create(&M_Mathutils_module_def);
PyDict_SetItemString(PyImport_GetModuleDict(), M_Mathutils_module_def.m_name, submodule);
/* each type has its own new() function */
PyModule_AddObject( submodule, "Vector", (PyObject *)&vector_Type );
@@ -267,7 +391,15 @@ PyObject *Mathutils_Init(void)
PyModule_AddObject( submodule, "Quaternion", (PyObject *)&quaternion_Type );
PyModule_AddObject( submodule, "Color", (PyObject *)&color_Type );
/* submodule */
PyModule_AddObject( submodule, "geometry", (item=BPyInit_mathutils_geometry()));
/* XXX, python doesnt do imports with this usefully yet
* 'from mathutils.geometry import PolyFill'
* ...fails without this. */
PyDict_SetItemString(PyThreadState_GET()->interp->modules, "mathutils.geometry", item);
Py_INCREF(item);
mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb);
return (submodule);
return submodule;
}

View File

@@ -28,10 +28,8 @@
*/
//Include this file for access to vector, quat, matrix, euler, etc...
#ifndef EXPP_Mathutils_H
#define EXPP_Mathutils_H
#include <Python.h>
#ifndef MATHUTILS_H
#define MATHUTILS_H
/* Can cast different mathutils types to this, use for generic funcs */
@@ -50,25 +48,25 @@ typedef struct {
BASE_MATH_MEMBERS(data)
} BaseMathObject;
#include "mathutils_vector.h"
#include "mathutils_matrix.h"
#include "mathutils_quat.h"
#include "mathutils_euler.h"
#include "mathutils_color.h"
#include "mathutils_Vector.h"
#include "mathutils_Matrix.h"
#include "mathutils_Quaternion.h"
#include "mathutils_Euler.h"
#include "mathutils_Color.h"
#include "mathutils_geometry.h"
PyObject *BaseMathObject_getOwner( BaseMathObject * self, void * );
PyObject *BaseMathObject_getWrapped( BaseMathObject *self, void * );
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg);
int BaseMathObject_clear(BaseMathObject *self);
void BaseMathObject_dealloc(BaseMathObject * self);
PyObject *Mathutils_Init(void);
PyObject *Noise_Init(void); /* lazy, saves having own header */
PyMODINIT_FUNC BPyInit_mathutils(void);
int EXPP_FloatsAreEqual(float A, float B, int floatSteps);
int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps);
#define Py_PI 3.14159265358979323846
#define Py_NEW 1
#define Py_WRAP 2
@@ -103,5 +101,6 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index);
/* utility func */
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix);
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
#endif /* EXPP_Mathutils_H */
#endif /* MATHUTILS_H */

View File

@@ -22,19 +22,26 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#include "mathutils.h"
#include "BLI_math.h"
#include "BKE_utildefines.h"
#include "BLI_utildefines.h"
#define COLOR_SIZE 3
//----------------------------------mathutils.Color() -------------------
//makes a new color for you to play with
static PyObject *Color_new(PyTypeObject * type, PyObject * args, PyObject * kwargs)
static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
float col[3]= {0.0f, 0.0f, 0.0f};
if(kwds && PyDict_Size(kwds)) {
PyErr_SetString(PyExc_TypeError, "mathutils.Color(): takes no keyword args");
return NULL;
}
switch(PyTuple_GET_SIZE(args)) {
case 0:
break;
@@ -81,9 +88,9 @@ static char Color_copy_doc[] =
" :return: A copy of the color.\n"
" :rtype: :class:`Color`\n"
"\n"
" .. note:: use this to get a copy of a wrapped color with no reference to the original data.\n";
static PyObject *Color_copy(ColorObject * self, PyObject *args)
" .. note:: use this to get a copy of a wrapped color with no reference to the original data.\n"
;
static PyObject *Color_copy(ColorObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -111,54 +118,46 @@ static PyObject *Color_repr(ColorObject * self)
//------------------------tp_richcmpr
//returns -1 execption, 0 false, 1 true
static PyObject* Color_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
static PyObject* Color_richcmpr(PyObject *a, PyObject *b, int op)
{
ColorObject *colA = NULL, *colB = NULL;
int result = 0;
PyObject *res;
int ok= -1; /* zero is true */
if(ColorObject_Check(objectA)) {
colA = (ColorObject*)objectA;
if(!BaseMath_ReadCallback(colA))
return NULL;
}
if(ColorObject_Check(objectB)) {
colB = (ColorObject*)objectB;
if(!BaseMath_ReadCallback(colB))
if (ColorObject_Check(a) && ColorObject_Check(b)) {
ColorObject *colA= (ColorObject*)a;
ColorObject *colB= (ColorObject*)b;
if(!BaseMath_ReadCallback(colA) || !BaseMath_ReadCallback(colB))
return NULL;
ok= EXPP_VectorsAreEqual(colA->col, colB->col, COLOR_SIZE, 1) ? 0 : -1;
}
if (!colA || !colB){
if (comparison_type == Py_NE){
Py_RETURN_TRUE;
}else{
Py_RETURN_FALSE;
}
}
colA = (ColorObject*)objectA;
colB = (ColorObject*)objectB;
switch (op) {
case Py_NE:
ok = !ok; /* pass through */
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
switch (comparison_type){
case Py_EQ:
result = EXPP_VectorsAreEqual(colA->col, colB->col, COLOR_SIZE, 1);
break;
case Py_NE:
result = !EXPP_VectorsAreEqual(colA->col, colB->col, COLOR_SIZE, 1);
break;
default:
printf("The result of the comparison could not be evaluated");
break;
}
if (result == 1){
Py_RETURN_TRUE;
}else{
Py_RETURN_FALSE;
case Py_LT:
case Py_LE:
case Py_GT:
case Py_GE:
res = Py_NotImplemented;
break;
default:
PyErr_BadArgument();
return NULL;
}
return Py_INCREF(res), res;
}
//---------------------SEQUENCE PROTOCOLS------------------------
//----------------------------len(object)------------------------
//sequence length
static int Color_len(ColorObject * self)
static int Color_len(ColorObject *UNUSED(self))
{
return COLOR_SIZE;
}
@@ -193,7 +192,7 @@ static int Color_ass_item(ColorObject * self, int i, PyObject * value)
if(i<0) i= COLOR_SIZE-i;
if(i < 0 || i >= COLOR_SIZE){
PyErr_SetString(PyExc_IndexError, "color[attribute] = x: array assignment index out of range\n");
PyErr_SetString(PyExc_IndexError, "color[attribute] = x: array assignment index out of range");
return -1;
}
@@ -208,7 +207,7 @@ static int Color_ass_item(ColorObject * self, int i, PyObject * value)
//sequence slice (get)
static PyObject *Color_slice(ColorObject * self, int begin, int end)
{
PyObject *list = NULL;
PyObject *tuple;
int count;
if(!BaseMath_ReadCallback(self))
@@ -217,15 +216,14 @@ static PyObject *Color_slice(ColorObject * self, int begin, int end)
CLAMP(begin, 0, COLOR_SIZE);
if (end<0) end= (COLOR_SIZE + 1) + end;
CLAMP(end, 0, COLOR_SIZE);
begin = MIN2(begin,end);
begin= MIN2(begin, end);
list = PyList_New(end - begin);
for(count = begin; count < end; count++) {
PyList_SetItem(list, count - begin,
PyFloat_FromDouble(self->col[count]));
tuple= PyTuple_New(end - begin);
for(count= begin; count < end; count++) {
PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->col[count]));
}
return list;
return tuple;
}
//----------------------------object[z:y]------------------------
//sequence slice (set)
@@ -253,7 +251,7 @@ static int Color_ass_slice(ColorObject * self, int begin, int end, PyObject * se
for(i= 0; i < COLOR_SIZE; i++)
self->col[begin + i] = col[i];
BaseMath_WriteCallback(self);
(void)BaseMath_WriteCallback(self);
return 0;
}
@@ -270,11 +268,11 @@ static PyObject *Color_subscript(ColorObject *self, PyObject *item)
} else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength;
if (PySlice_GetIndicesEx((PySliceObject*)item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0)
if (PySlice_GetIndicesEx((void *)item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0)
return NULL;
if (slicelength <= 0) {
return PyList_New(0);
return PyTuple_New(0);
}
else if (step == 1) {
return Color_slice(self, start, stop);
@@ -285,9 +283,7 @@ static PyObject *Color_subscript(ColorObject *self, PyObject *item)
}
}
else {
PyErr_Format(PyExc_TypeError,
"color indices must be integers, not %.200s",
item->ob_type->tp_name);
PyErr_Format(PyExc_TypeError, "color indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
return NULL;
}
}
@@ -305,7 +301,7 @@ static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *valu
else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength;
if (PySlice_GetIndicesEx((PySliceObject*)item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0)
if (PySlice_GetIndicesEx((void *)item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0)
return -1;
if (step == 1)
@@ -316,9 +312,7 @@ static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *valu
}
}
else {
PyErr_Format(PyExc_TypeError,
"color indices must be integers, not %.200s",
item->ob_type->tp_name);
PyErr_Format(PyExc_TypeError, "color indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
return -1;
}
}
@@ -329,9 +323,9 @@ static PySequenceMethods Color_SeqMethods = {
(binaryfunc) NULL, /* sq_concat */
(ssizeargfunc) NULL, /* sq_repeat */
(ssizeargfunc) Color_item, /* sq_item */
(ssizessizeargfunc) NULL, /* sq_slice, deprecated */
NULL, /* sq_slice, deprecated */
(ssizeobjargproc) Color_ass_item, /* sq_ass_item */
(ssizessizeobjargproc) NULL, /* sq_ass_slice, deprecated */
NULL, /* sq_ass_slice, deprecated */
(objobjproc) NULL, /* sq_contains */
(binaryfunc) NULL, /* sq_inplace_concat */
(ssizeargfunc) NULL, /* sq_inplace_repeat */
@@ -394,7 +388,7 @@ static int Color_setChannelHSV(ColorObject * self, PyObject * value, void * type
}
/* color channel (HSV), color.h/s/v */
static PyObject *Color_getHSV(ColorObject * self, void *type)
static PyObject *Color_getHSV(ColorObject * self, void *UNUSED(closure))
{
float hsv[3];
PyObject *ret;
@@ -411,7 +405,7 @@ static PyObject *Color_getHSV(ColorObject * self, void *type)
return ret;
}
static int Color_setHSV(ColorObject * self, PyObject * value, void * type)
static int Color_setHSV(ColorObject * self, PyObject * value, void *UNUSED(closure))
{
float hsv[3];
@@ -434,80 +428,80 @@ static int Color_setHSV(ColorObject * self, PyObject * value, void * type)
/* Python attributes get/set structure: */
/*****************************************************************************/
static PyGetSetDef Color_getseters[] = {
{"r", (getter)Color_getChannel, (setter)Color_setChannel, "Red color channel.\n\n:type: float", (void *)0},
{"g", (getter)Color_getChannel, (setter)Color_setChannel, "Green color channel.\n\n:type: float", (void *)1},
{"b", (getter)Color_getChannel, (setter)Color_setChannel, "Blue color channel.\n\n:type: float", (void *)2},
{(char *)"r", (getter)Color_getChannel, (setter)Color_setChannel, (char *)"Red color channel.\n\n:type: float", (void *)0},
{(char *)"g", (getter)Color_getChannel, (setter)Color_setChannel, (char *)"Green color channel.\n\n:type: float", (void *)1},
{(char *)"b", (getter)Color_getChannel, (setter)Color_setChannel, (char *)"Blue color channel.\n\n:type: float", (void *)2},
{"h", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, "HSV Hue component in [0, 1].\n\n:type: float", (void *)0},
{"s", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, "HSV Saturation component in [0, 1].\n\n:type: float", (void *)1},
{"v", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, "HSV Value component in [0, 1].\n\n:type: float", (void *)2},
{(char *)"h", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, (char *)"HSV Hue component in [0, 1].\n\n:type: float", (void *)0},
{(char *)"s", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, (char *)"HSV Saturation component in [0, 1].\n\n:type: float", (void *)1},
{(char *)"v", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, (char *)"HSV Value component in [0, 1].\n\n:type: float", (void *)2},
{"hsv", (getter)Color_getHSV, (setter)Color_setHSV, "HSV Values in [0, 1].\n\n:type: float triplet", (void *)0},
{(char *)"hsv", (getter)Color_getHSV, (setter)Color_setHSV, (char *)"HSV Values in [0, 1].\n\n:type: float triplet", (void *)0},
{"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, BaseMathObject_Wrapped_doc, NULL},
{"owner", (getter)BaseMathObject_getOwner, (setter)NULL, BaseMathObject_Owner_doc, NULL},
{(char *)"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, BaseMathObject_Wrapped_doc, NULL},
{(char *)"owner", (getter)BaseMathObject_getOwner, (setter)NULL, BaseMathObject_Owner_doc, NULL},
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
//-----------------------METHOD DEFINITIONS ----------------------
static struct PyMethodDef Color_methods[] = {
{"__copy__", (PyCFunction) Color_copy, METH_VARARGS, Color_copy_doc},
{"copy", (PyCFunction) Color_copy, METH_VARARGS, Color_copy_doc},
{"__copy__", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
{"copy", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
{NULL, NULL, 0, NULL}
};
//------------------PY_OBECT DEFINITION--------------------------
static char color_doc[] =
"This object gives access to Colors in Blender.";
"This object gives access to Colors in Blender."
;
PyTypeObject color_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"color", //tp_name
"mathutils.Color", //tp_name
sizeof(ColorObject), //tp_basicsize
0, //tp_itemsize
(destructor)BaseMathObject_dealloc, //tp_dealloc
0, //tp_print
0, //tp_getattr
0, //tp_setattr
0, //tp_compare
NULL, //tp_print
NULL, //tp_getattr
NULL, //tp_setattr
NULL, //tp_compare
(reprfunc) Color_repr, //tp_repr
0, //tp_as_number
NULL, //tp_as_number
&Color_SeqMethods, //tp_as_sequence
&Color_AsMapping, //tp_as_mapping
0, //tp_hash
0, //tp_call
0, //tp_str
0, //tp_getattro
0, //tp_setattro
0, //tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
NULL, //tp_hash
NULL, //tp_call
NULL, //tp_str
NULL, //tp_getattro
NULL, //tp_setattro
NULL, //tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, //tp_flags
color_doc, //tp_doc
0, //tp_traverse
0, //tp_clear
(traverseproc)BaseMathObject_traverse, //tp_traverse
(inquiry)BaseMathObject_clear, //tp_clear
(richcmpfunc)Color_richcmpr, //tp_richcompare
0, //tp_weaklistoffset
0, //tp_iter
0, //tp_iternext
NULL, //tp_iter
NULL, //tp_iternext
Color_methods, //tp_methods
0, //tp_members
NULL, //tp_members
Color_getseters, //tp_getset
0, //tp_base
0, //tp_dict
0, //tp_descr_get
0, //tp_descr_set
NULL, //tp_base
NULL, //tp_dict
NULL, //tp_descr_get
NULL, //tp_descr_set
0, //tp_dictoffset
0, //tp_init
0, //tp_alloc
NULL, //tp_init
NULL, //tp_alloc
Color_new, //tp_new
0, //tp_free
0, //tp_is_gc
0, //tp_bases
0, //tp_mro
0, //tp_cache
0, //tp_subclasses
0, //tp_weaklist
0 //tp_del
NULL, //tp_free
NULL, //tp_is_gc
NULL, //tp_bases
NULL, //tp_mro
NULL, //tp_cache
NULL, //tp_subclasses
NULL, //tp_weaklist
NULL //tp_del
};
//------------------------newColorObject (internal)-------------
//creates a new color object
@@ -519,28 +513,31 @@ PyObject *newColorObject(float *col, int type, PyTypeObject *base_type)
{
ColorObject *self;
if(base_type) self = (ColorObject *)base_type->tp_alloc(base_type, 0);
else self = PyObject_NEW(ColorObject, &color_Type);
self= base_type ? (ColorObject *)base_type->tp_alloc(base_type, 0) :
(ColorObject *)PyObject_GC_New(ColorObject, &color_Type);
/* init callbacks as NULL */
self->cb_user= NULL;
self->cb_type= self->cb_subtype= 0;
if(self) {
/* init callbacks as NULL */
self->cb_user= NULL;
self->cb_type= self->cb_subtype= 0;
if(type == Py_WRAP){
self->col = col;
self->wrapped = Py_WRAP;
}
else if (type == Py_NEW){
self->col = PyMem_Malloc(COLOR_SIZE * sizeof(float));
if(col)
copy_v3_v3(self->col, col);
else
zero_v3(self->col);
if(type == Py_WRAP){
self->col = col;
self->wrapped = Py_WRAP;
}
else if (type == Py_NEW){
self->col = PyMem_Malloc(COLOR_SIZE * sizeof(float));
if(col)
copy_v3_v3(self->col, col);
else
zero_v3(self->col);
self->wrapped = Py_NEW;
}
else {
return NULL;
self->wrapped = Py_NEW;
}
else {
PyErr_SetString(PyExc_RuntimeError, "Color(): invalid type");
return NULL;
}
}
return (PyObject *)self;

View File

@@ -28,10 +28,8 @@
*
*/
#ifndef EXPP_color_h
#define EXPP_color_h
#include <Python.h>
#ifndef MATHUTILS_COLOR_H
#define MATHUTILS_COLOR_H
extern PyTypeObject color_Type;
#define ColorObject_Check(_v) PyObject_TypeCheck((_v), &color_Type)
@@ -49,4 +47,4 @@ blender (stored in blend_data). This is an either/or struct not both*/
PyObject *newColorObject( float *col, int type, PyTypeObject *base_type);
PyObject *newColorObject_cb(PyObject *cb_user, int cb_type, int cb_subtype);
#endif /* EXPP_color_h */
#endif /* MATHUTILS_COLOR_H */

View File

@@ -20,16 +20,18 @@
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
*
*
* Contributor(s): Joseph Gilbert
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#include "mathutils.h"
#include "BLI_math.h"
#include "BKE_utildefines.h"
#include "BLI_utildefines.h"
#ifndef int32_t
#include "BLO_sys_types.h"
@@ -39,14 +41,19 @@
//----------------------------------mathutils.Euler() -------------------
//makes a new euler for you to play with
static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwargs)
static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *seq= NULL;
char *order_str= NULL;
const char *order_str= NULL;
float eul[EULER_SIZE]= {0.0f, 0.0f, 0.0f};
short order= EULER_ORDER_XYZ;
if(kwds && PyDict_Size(kwds)) {
PyErr_SetString(PyExc_TypeError, "mathutils.Euler(): takes no keyword args");
return NULL;
}
if(!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str))
return NULL;
@@ -62,7 +69,14 @@ static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwar
return NULL;
break;
}
return newEulerObject(eul, order, Py_NEW, NULL);
return newEulerObject(eul, order, Py_NEW, type);
}
/* internal use, assuem read callback is done */
static const char *euler_order_str(EulerObject *self)
{
static const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
return order[self->order-EULER_ORDER_XYZ];
}
short euler_order_from_string(const char *str, const char *error_prefix)
@@ -107,146 +121,77 @@ static PyObject *Euler_ToTupleExt(EulerObject *self, int ndigits)
//-----------------------------METHODS----------------------------
//return a quaternion representation of the euler
static char Euler_ToQuat_doc[] =
".. method:: to_quat()\n"
static char Euler_to_quaternion_doc[] =
".. method:: to_quaternion()\n"
"\n"
" Return a quaternion representation of the euler.\n"
"\n"
" :return: Quaternion representation of the euler.\n"
" :rtype: :class:`Quaternion`\n";
static PyObject *Euler_ToQuat(EulerObject * self)
" :rtype: :class:`Quaternion`\n"
;
static PyObject *Euler_to_quaternion(EulerObject * self)
{
float quat[4];
if(!BaseMath_ReadCallback(self))
return NULL;
if(self->order==EULER_ORDER_XYZ) eul_to_quat(quat, self->eul);
else eulO_to_quat(quat, self->eul, self->order);
eulO_to_quat(quat, self->eul, self->order);
return newQuaternionObject(quat, Py_NEW, NULL);
}
//return a matrix representation of the euler
static char Euler_ToMatrix_doc[] =
static char Euler_to_matrix_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: :class:`Matrix`\n";
static PyObject *Euler_ToMatrix(EulerObject * self)
" :rtype: :class:`Matrix`\n"
;
static PyObject *Euler_to_matrix(EulerObject * self)
{
float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
float mat[9];
if(!BaseMath_ReadCallback(self))
return NULL;
if(self->order==EULER_ORDER_XYZ) eul_to_mat3((float (*)[3])mat, self->eul);
else eulO_to_mat3((float (*)[3])mat, self->eul, self->order);
eulO_to_mat3((float (*)[3])mat, self->eul, self->order);
return newMatrixObject(mat, 3, 3 , Py_NEW, NULL);
}
//sets the x,y,z values to a unique euler rotation
// TODO, check if this works with rotation order!!!
static char Euler_Unique_doc[] =
".. method:: unique()\n"
"\n"
" Calculate a unique rotation for this euler. Avoids gimble lock.\n"
"\n"
" :return: an instance of itself\n"
" :rtype: :class:`Euler`\n";
static PyObject *Euler_Unique(EulerObject * self)
{
#define PI_2 (Py_PI * 2.0)
#define PI_HALF (Py_PI / 2.0)
#define PI_INV (1.0 / Py_PI)
double heading, pitch, bank;
if(!BaseMath_ReadCallback(self))
return NULL;
heading = self->eul[0];
pitch = self->eul[1];
bank = self->eul[2];
//wrap heading in +180 / -180
pitch += Py_PI;
pitch -= floor(pitch * PI_INV) * PI_2;
pitch -= Py_PI;
if(pitch < -PI_HALF) {
pitch = -Py_PI - pitch;
heading += Py_PI;
bank += Py_PI;
} else if(pitch > PI_HALF) {
pitch = Py_PI - pitch;
heading += Py_PI;
bank += Py_PI;
}
//gimbal lock test
if(fabs(pitch) > PI_HALF - 1e-4) {
heading += bank;
bank = 0.0f;
} else {
bank += Py_PI;
bank -= (floor(bank * PI_INV)) * PI_2;
bank -= Py_PI;
}
heading += Py_PI;
heading -= (floor(heading * PI_INV)) * PI_2;
heading -= Py_PI;
BaseMath_WriteCallback(self);
Py_INCREF(self);
return (PyObject *)self;
}
//sets the euler to 0,0,0
static char Euler_Zero_doc[] =
static char Euler_zero_doc[] =
".. method:: zero()\n"
"\n"
" Set all values to zero.\n"
"\n"
" :return: an instance of itself\n"
" :rtype: :class:`Euler`\n";
static PyObject *Euler_Zero(EulerObject * self)
;
static PyObject *Euler_zero(EulerObject * self)
{
self->eul[0] = 0.0;
self->eul[1] = 0.0;
self->eul[2] = 0.0;
zero_v3(self->eul);
BaseMath_WriteCallback(self);
Py_INCREF(self);
return (PyObject *)self;
(void)BaseMath_WriteCallback(self);
Py_RETURN_NONE;
}
static char Euler_Rotate_doc[] =
".. method:: rotate(angle, axis)\n"
static char Euler_rotate_axis_doc[] =
".. method:: rotate_axis(axis, angle)\n"
"\n"
" Rotates the euler a certain amount and returning a unique euler rotation (no 720 degree pitches).\n"
"\n"
" :arg angle: angle in radians.\n"
" :type angle: float\n"
" :arg axis: single character in ['X, 'Y', 'Z'].\n"
" :type axis: string\n"
" :return: an instance of itself\n"
" :rtype: :class:`Euler`";
static PyObject *Euler_Rotate(EulerObject * self, PyObject *args)
" :arg angle: angle in radians.\n"
" :type angle: float\n"
;
static PyObject *Euler_rotate_axis(EulerObject * self, PyObject *args)
{
float angle = 0.0f;
char *axis;
const char *axis;
if(!PyArg_ParseTuple(args, "fs:rotate", &angle, &axis)){
if(!PyArg_ParseTuple(args, "sf:rotate", &axis, &angle)){
PyErr_SetString(PyExc_TypeError, "euler.rotate(): expected angle (float) and axis (x,y,z)");
return NULL;
}
@@ -258,46 +203,63 @@ static PyObject *Euler_Rotate(EulerObject * self, PyObject *args)
if(!BaseMath_ReadCallback(self))
return NULL;
if(self->order == EULER_ORDER_XYZ) rotate_eul(self->eul, *axis, angle);
else rotate_eulO(self->eul, self->order, *axis, angle);
BaseMath_WriteCallback(self);
Py_INCREF(self);
return (PyObject *)self;
rotate_eulO(self->eul, self->order, *axis, angle);
(void)BaseMath_WriteCallback(self);
Py_RETURN_NONE;
}
static char Euler_MakeCompatible_doc[] =
static char Euler_rotate_doc[] =
".. method:: rotate(other)\n"
"\n"
" Rotates the euler a by another mathutils value.\n"
"\n"
" :arg other: rotation component of mathutils value\n"
" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
;
static PyObject *Euler_rotate(EulerObject * self, PyObject *value)
{
float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
if(!BaseMath_ReadCallback(self))
return NULL;
if(mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1)
return NULL;
eulO_to_mat3(self_rmat, self->eul, self->order);
mul_m3_m3m3(rmat, self_rmat, other_rmat);
mat3_to_compatible_eulO(self->eul, self->eul, self->order, rmat);
(void)BaseMath_WriteCallback(self);
Py_RETURN_NONE;
}
static char Euler_make_compatible_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: :class:`Euler`\n"
" :return: an instance of itself.\n"
" :rtype: :class:`Euler`\n"
"\n"
" .. note:: the order of eulers must match or an exception is raised.\n";
static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value)
" .. note:: the rotation order is not taken into account for this function.\n"
;
static PyObject *Euler_make_compatible(EulerObject * self, PyObject *value)
{
if(!EulerObject_Check(value)) {
PyErr_SetString(PyExc_TypeError, "euler.make_compatible(euler): expected a single euler argument.");
return NULL;
}
if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
float teul[EULER_SIZE];
if(!BaseMath_ReadCallback(self))
return NULL;
if(self->order != value->order) {
PyErr_SetString(PyExc_ValueError, "euler.make_compatible(euler): rotation orders don't match\n");
if(mathutils_array_parse(teul, EULER_SIZE, EULER_SIZE, value, "euler.make_compatible(other), invalid 'other' arg") == -1)
return NULL;
}
compatible_eul(self->eul, value->eul);
compatible_eul(self->eul, teul);
BaseMath_WriteCallback(self);
Py_INCREF(self);
return (PyObject *)self;
(void)BaseMath_WriteCallback(self);
Py_RETURN_NONE;
}
//----------------------------Euler.rotate()-----------------------
@@ -311,9 +273,9 @@ static char Euler_copy_doc[] =
" :return: A copy of the euler.\n"
" :rtype: :class:`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)
" .. 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)
{
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -327,68 +289,58 @@ static PyObject *Euler_copy(EulerObject * self, PyObject *args)
static PyObject *Euler_repr(EulerObject * self)
{
PyObject *ret, *tuple;
if(!BaseMath_ReadCallback(self))
return NULL;
tuple= Euler_ToTupleExt(self, -1);
ret= PyUnicode_FromFormat("Euler(%R)", tuple);
ret= PyUnicode_FromFormat("Euler(%R, '%s')", tuple, euler_order_str(self));
Py_DECREF(tuple);
return ret;
}
//------------------------tp_richcmpr
//returns -1 execption, 0 false, 1 true
static PyObject* Euler_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
static PyObject* Euler_richcmpr(PyObject *a, PyObject *b, int op)
{
EulerObject *eulA = NULL, *eulB = NULL;
int result = 0;
PyObject *res;
int ok= -1; /* zero is true */
if(EulerObject_Check(objectA)) {
eulA = (EulerObject*)objectA;
if(!BaseMath_ReadCallback(eulA))
return NULL;
}
if(EulerObject_Check(objectB)) {
eulB = (EulerObject*)objectB;
if(!BaseMath_ReadCallback(eulB))
if (EulerObject_Check(a) && EulerObject_Check(b)) {
EulerObject *eulA= (EulerObject*)a;
EulerObject *eulB= (EulerObject*)b;
if(!BaseMath_ReadCallback(eulA) || !BaseMath_ReadCallback(eulB))
return NULL;
ok= ((eulA->order == eulB->order) && EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1)) ? 0 : -1;
}
if (!eulA || !eulB){
if (comparison_type == Py_NE){
Py_RETURN_TRUE;
}else{
Py_RETURN_FALSE;
}
}
eulA = (EulerObject*)objectA;
eulB = (EulerObject*)objectB;
switch (op) {
case Py_NE:
ok = !ok; /* pass through */
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
switch (comparison_type){
case Py_EQ:
result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1);
break;
case Py_NE:
result = !EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1);
break;
default:
printf("The result of the comparison could not be evaluated");
break;
}
if (result == 1){
Py_RETURN_TRUE;
}else{
Py_RETURN_FALSE;
case Py_LT:
case Py_LE:
case Py_GT:
case Py_GE:
res = Py_NotImplemented;
break;
default:
PyErr_BadArgument();
return NULL;
}
return Py_INCREF(res), res;
}
//---------------------SEQUENCE PROTOCOLS------------------------
//----------------------------len(object)------------------------
//sequence length
static int Euler_len(EulerObject * self)
static int Euler_len(EulerObject *UNUSED(self))
{
return EULER_SIZE;
}
@@ -397,7 +349,7 @@ static int Euler_len(EulerObject * self)
static PyObject *Euler_item(EulerObject * self, int i)
{
if(i<0) i= EULER_SIZE-i;
if(i < 0 || i >= EULER_SIZE) {
PyErr_SetString(PyExc_IndexError, "euler[attribute]: array index out of range");
return NULL;
@@ -411,7 +363,7 @@ static PyObject *Euler_item(EulerObject * self, int i)
}
//----------------------------object[]-------------------------
//sequence accessor (set)
static int Euler_ass_item(EulerObject * self, int i, PyObject * value)
static int Euler_ass_item(EulerObject * self, int i, PyObject *value)
{
float f = PyFloat_AsDouble(value);
@@ -421,12 +373,12 @@ static int Euler_ass_item(EulerObject * self, int i, PyObject * value)
}
if(i<0) i= EULER_SIZE-i;
if(i < 0 || i >= EULER_SIZE){
PyErr_SetString(PyExc_IndexError, "euler[attribute] = x: array assignment index out of range\n");
PyErr_SetString(PyExc_IndexError, "euler[attribute] = x: array assignment index out of range");
return -1;
}
self->eul[i] = f;
if(!BaseMath_WriteIndexCallback(self, i))
@@ -438,7 +390,7 @@ static int Euler_ass_item(EulerObject * self, int i, PyObject * value)
//sequence slice (get)
static PyObject *Euler_slice(EulerObject * self, int begin, int end)
{
PyObject *list = NULL;
PyObject *tuple;
int count;
if(!BaseMath_ReadCallback(self))
@@ -447,15 +399,14 @@ static PyObject *Euler_slice(EulerObject * self, int begin, int end)
CLAMP(begin, 0, EULER_SIZE);
if (end<0) end= (EULER_SIZE + 1) + end;
CLAMP(end, 0, EULER_SIZE);
begin = MIN2(begin,end);
begin= MIN2(begin, end);
list = PyList_New(end - begin);
tuple= PyTuple_New(end - begin);
for(count = begin; count < end; count++) {
PyList_SetItem(list, count - begin,
PyFloat_FromDouble(self->eul[count]));
PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->eul[count]));
}
return list;
return tuple;
}
//----------------------------object[z:y]------------------------
//sequence slice (set)
@@ -483,7 +434,7 @@ static int Euler_ass_slice(EulerObject * self, int begin, int end, PyObject * se
for(i= 0; i < EULER_SIZE; i++)
self->eul[begin + i] = eul[i];
BaseMath_WriteCallback(self);
(void)BaseMath_WriteCallback(self);
return 0;
}
@@ -500,11 +451,11 @@ static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
} else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength;
if (PySlice_GetIndicesEx((PySliceObject*)item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0)
if (PySlice_GetIndicesEx((void *)item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0)
return NULL;
if (slicelength <= 0) {
return PyList_New(0);
return PyTuple_New(0);
}
else if (step == 1) {
return Euler_slice(self, start, stop);
@@ -515,9 +466,7 @@ static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
}
}
else {
PyErr_Format(PyExc_TypeError,
"euler indices must be integers, not %.200s",
item->ob_type->tp_name);
PyErr_Format(PyExc_TypeError, "euler indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
return NULL;
}
}
@@ -536,7 +485,7 @@ static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *valu
else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength;
if (PySlice_GetIndicesEx((PySliceObject*)item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0)
if (PySlice_GetIndicesEx((void *)item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0)
return -1;
if (step == 1)
@@ -547,9 +496,7 @@ static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *valu
}
}
else {
PyErr_Format(PyExc_TypeError,
"euler indices must be integers, not %.200s",
item->ob_type->tp_name);
PyErr_Format(PyExc_TypeError, "euler indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
return -1;
}
}
@@ -577,37 +524,35 @@ static PyMappingMethods Euler_AsMapping = {
/*
* euler axis, euler.x/y/z
*/
static PyObject *Euler_getAxis( EulerObject * self, void *type )
static PyObject *Euler_getAxis(EulerObject *self, void *type )
{
return Euler_item(self, GET_INT_FROM_POINTER(type));
}
static int Euler_setAxis( EulerObject * self, PyObject * value, void * type )
static int Euler_setAxis(EulerObject *self, PyObject *value, void *type)
{
return Euler_ass_item(self, GET_INT_FROM_POINTER(type), value);
}
/* rotation order */
static PyObject *Euler_getOrder(EulerObject *self, void *type)
static PyObject *Euler_getOrder(EulerObject *self, void *UNUSED(closure))
{
const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
if(!BaseMath_ReadCallback(self)) /* can read order too */
return NULL;
return PyUnicode_FromString(order[self->order-EULER_ORDER_XYZ]);
return PyUnicode_FromString(euler_order_str(self));
}
static int Euler_setOrder( EulerObject * self, PyObject * value, void * type )
static int Euler_setOrder(EulerObject *self, PyObject *value, void *UNUSED(closure))
{
char *order_str= _PyUnicode_AsString(value);
const char *order_str= _PyUnicode_AsString(value);
short order= euler_order_from_string(order_str, "euler.order");
if(order == -1)
return -1;
self->order= order;
BaseMath_WriteCallback(self); /* order can be written back */
(void)BaseMath_WriteCallback(self); /* order can be written back */
return 0;
}
@@ -615,81 +560,81 @@ static int Euler_setOrder( EulerObject * self, PyObject * value, void * type )
/* Python attributes get/set structure: */
/*****************************************************************************/
static PyGetSetDef Euler_getseters[] = {
{"x", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler X axis in radians.\n\n:type: float", (void *)0},
{"y", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler Y axis in radians.\n\n:type: float", (void *)1},
{"z", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler Z axis in radians.\n\n:type: float", (void *)2},
{"order", (getter)Euler_getOrder, (setter)Euler_setOrder, "Euler rotation order.\n\n:type: string in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']", (void *)NULL},
{(char *)"x", (getter)Euler_getAxis, (setter)Euler_setAxis, (char *)"Euler X axis in radians.\n\n:type: float", (void *)0},
{(char *)"y", (getter)Euler_getAxis, (setter)Euler_setAxis, (char *)"Euler Y axis in radians.\n\n:type: float", (void *)1},
{(char *)"z", (getter)Euler_getAxis, (setter)Euler_setAxis, (char *)"Euler Z axis in radians.\n\n:type: float", (void *)2},
{(char *)"order", (getter)Euler_getOrder, (setter)Euler_setOrder, (char *)"Euler rotation order.\n\n:type: string in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']", (void *)NULL},
{"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, BaseMathObject_Wrapped_doc, NULL},
{"owner", (getter)BaseMathObject_getOwner, (setter)NULL, BaseMathObject_Owner_doc, NULL},
{(char *)"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, (char *)BaseMathObject_Wrapped_doc, NULL},
{(char *)"owner", (getter)BaseMathObject_getOwner, (setter)NULL, (char *)BaseMathObject_Owner_doc, NULL},
{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, Euler_Rotate_doc},
{"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},
{"zero", (PyCFunction) Euler_zero, METH_NOARGS, Euler_zero_doc},
{"to_matrix", (PyCFunction) Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc},
{"to_quaternion", (PyCFunction) Euler_to_quaternion, METH_NOARGS, Euler_to_quaternion_doc},
{"rotate_axis", (PyCFunction) Euler_rotate_axis, METH_VARARGS, Euler_rotate_axis_doc},
{"rotate", (PyCFunction) Euler_rotate, METH_O, Euler_rotate_doc},
{"make_compatible", (PyCFunction) Euler_make_compatible, METH_O, Euler_make_compatible_doc},
{"__copy__", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc},
{"copy", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc},
{NULL, NULL, 0, NULL}
};
//------------------PY_OBECT DEFINITION--------------------------
static char euler_doc[] =
"This object gives access to Eulers in Blender.";
"This object gives access to Eulers in Blender."
;
PyTypeObject euler_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"euler", //tp_name
"mathutils.Euler", //tp_name
sizeof(EulerObject), //tp_basicsize
0, //tp_itemsize
(destructor)BaseMathObject_dealloc, //tp_dealloc
0, //tp_print
0, //tp_getattr
0, //tp_setattr
0, //tp_compare
NULL, //tp_print
NULL, //tp_getattr
NULL, //tp_setattr
NULL, //tp_compare
(reprfunc) Euler_repr, //tp_repr
0, //tp_as_number
NULL, //tp_as_number
&Euler_SeqMethods, //tp_as_sequence
&Euler_AsMapping, //tp_as_mapping
0, //tp_hash
0, //tp_call
0, //tp_str
0, //tp_getattro
0, //tp_setattro
0, //tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
NULL, //tp_hash
NULL, //tp_call
NULL, //tp_str
NULL, //tp_getattro
NULL, //tp_setattro
NULL, //tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, //tp_flags
euler_doc, //tp_doc
0, //tp_traverse
0, //tp_clear
(traverseproc)BaseMathObject_traverse, //tp_traverse
(inquiry)BaseMathObject_clear, //tp_clear
(richcmpfunc)Euler_richcmpr, //tp_richcompare
0, //tp_weaklistoffset
0, //tp_iter
0, //tp_iternext
NULL, //tp_iter
NULL, //tp_iternext
Euler_methods, //tp_methods
0, //tp_members
NULL, //tp_members
Euler_getseters, //tp_getset
0, //tp_base
0, //tp_dict
0, //tp_descr_get
0, //tp_descr_set
NULL, //tp_base
NULL, //tp_dict
NULL, //tp_descr_get
NULL, //tp_descr_set
0, //tp_dictoffset
0, //tp_init
0, //tp_alloc
NULL, //tp_init
NULL, //tp_alloc
Euler_new, //tp_new
0, //tp_free
0, //tp_is_gc
0, //tp_bases
0, //tp_mro
0, //tp_cache
0, //tp_subclasses
0, //tp_weaklist
0 //tp_del
NULL, //tp_free
NULL, //tp_is_gc
NULL, //tp_bases
NULL, //tp_mro
NULL, //tp_cache
NULL, //tp_subclasses
NULL, //tp_weaklist
NULL //tp_del
};
//------------------------newEulerObject (internal)-------------
//creates a new euler object
@@ -701,31 +646,37 @@ PyObject *newEulerObject(float *eul, short order, int type, PyTypeObject *base_t
{
EulerObject *self;
if(base_type) self = (EulerObject *)base_type->tp_alloc(base_type, 0);
else self = PyObject_NEW(EulerObject, &euler_Type);
self= base_type ? (EulerObject *)base_type->tp_alloc(base_type, 0) :
(EulerObject *)PyObject_GC_New(EulerObject, &euler_Type);
/* init callbacks as NULL */
self->cb_user= NULL;
self->cb_type= self->cb_subtype= 0;
if(self) {
/* init callbacks as NULL */
self->cb_user= NULL;
self->cb_type= self->cb_subtype= 0;
if(type == Py_WRAP) {
self->eul = eul;
self->wrapped = Py_WRAP;
}
else if (type == Py_NEW){
self->eul = PyMem_Malloc(EULER_SIZE * sizeof(float));
if(eul)
copy_v3_v3(self->eul, eul);
else
zero_v3(self->eul);
if(type == Py_WRAP) {
self->eul = eul;
self->wrapped = Py_WRAP;
}
else if (type == Py_NEW) {
self->eul = PyMem_Malloc(EULER_SIZE * sizeof(float));
if(eul) {
copy_v3_v3(self->eul, eul);
}
else {
zero_v3(self->eul);
}
self->wrapped = Py_NEW;
}
else{
return NULL;
self->wrapped = Py_NEW;
}
else {
PyErr_SetString(PyExc_RuntimeError, "Euler(): invalid type");
return NULL;
}
self->order= order;
}
self->order= order;
return (PyObject *)self;
}

View File

@@ -28,10 +28,8 @@
*
*/
#ifndef EXPP_euler_h
#define EXPP_euler_h
#include <Python.h>
#ifndef MATHUTILS_EULER_H
#define MATHUTILS_EULER_H
extern PyTypeObject euler_Type;
#define EulerObject_Check(_v) PyObject_TypeCheck((_v), &euler_Type)
@@ -54,4 +52,4 @@ PyObject *newEulerObject_cb(PyObject *cb_user, short order, int cb_type, int cb_
short euler_order_from_string(const char *str, const char *error_prefix);
#endif /* EXPP_euler_h */
#endif /* MATHUTILS_EULER_H */

File diff suppressed because it is too large Load Diff

View File

@@ -27,10 +27,8 @@
*
*/
#ifndef EXPP_matrix_h
#define EXPP_matrix_h
#include <Python.h>
#ifndef MATHUTILS_MATRIX_H
#define MATHUTILS_MATRIX_H
extern PyTypeObject matrix_Type;
#define MatrixObject_Check(_v) PyObject_TypeCheck((_v), &matrix_Type)
@@ -38,10 +36,9 @@ extern PyTypeObject matrix_Type;
typedef struct {
BASE_MATH_MEMBERS(contigPtr)
unsigned char rowSize;
unsigned int colSize;
float *matrix[MATRIX_MAX_DIM]; /* ptr to the contigPtr (accessor) */
unsigned short row_size;
unsigned short col_size;
} MatrixObject;
/*struct data contains a pointer to the actual data that the
@@ -50,10 +47,12 @@ be stored in py_data) or be a wrapper for data allocated through
blender (stored in blend_data). This is an either/or struct not both*/
/*prototypes*/
PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type, PyTypeObject *base_type);
PyObject *newMatrixObject_cb(PyObject *user, int rowSize, int colSize, int cb_type, int cb_subtype);
PyObject *newMatrixObject(float *mat, const unsigned short row_size, const unsigned short col_size, int type, PyTypeObject *base_type);
PyObject *newMatrixObject_cb(PyObject *user, int row_size, int col_size, int cb_type, int cb_subtype);
extern int mathutils_matrix_vector_cb_index;
extern struct Mathutils_Callback mathutils_matrix_vector_cb;
#endif /* EXPP_matrix_H */
void matrix_as_3x3(float mat[3][3], MatrixObject *self);
#endif /* MATHUTILS_MATRIX_H */

View File

@@ -28,10 +28,8 @@
*
*/
#ifndef EXPP_quat_h
#define EXPP_quat_h
#include <Python.h>
#ifndef MATHUTILS_QUAT_H
#define MATHUTILS_QUAT_H
extern PyTypeObject quaternion_Type;
#define QuaternionObject_Check(_v) PyObject_TypeCheck((_v), &quaternion_Type)
@@ -49,4 +47,4 @@ blender (stored in blend_data). This is an either/or struct not both*/
PyObject *newQuaternionObject( float *quat, int type, PyTypeObject *base_type);
PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype);
#endif /* EXPP_quat_h */
#endif /* MATHUTILS_QUAT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -28,10 +28,8 @@
*
*/
#ifndef EXPP_vector_h
#define EXPP_vector_h
#include <Python.h>
#ifndef MATHUTILS_VECTOR_H
#define MATHUTILS_VECTOR_H
extern PyTypeObject vector_Type;
#define VectorObject_Check(_v) PyObject_TypeCheck((_v), &vector_Type)
@@ -43,7 +41,7 @@ typedef struct {
} VectorObject;
/*prototypes*/
PyObject *newVectorObject(float *vec, int size, int type, PyTypeObject *base_type);
PyObject *newVectorObject(float *vec, const int size, const int type, PyTypeObject *base_type);
PyObject *newVectorObject_cb(PyObject *user, int size, int callback_type, int subtype);
#endif /* EXPP_vector_h */
#endif /* MATHUTILS_VECTOR_H */

View File

@@ -0,0 +1,882 @@
/*
* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* This is a new part of Blender.
*
* Contributor(s): Joseph Gilbert, Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#include "mathutils_geometry.h"
/* Used for PolyFill */
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_boxpack2d.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_displist.h"
#include "BKE_curve.h"
#define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp
#define eps 0.000001
/*-------------------------DOC STRINGS ---------------------------*/
static char M_Geometry_doc[]= "The Blender geometry module\n\n";
//---------------------------------INTERSECTION FUNCTIONS--------------------
static char M_Geometry_intersect_ray_tri_doc[] =
".. function:: intersect_ray_tri(v1, v2, v3, ray, orig, clip=True)\n"
"\n"
" Returns the intersection between a ray and a triangle, if possible, returns None otherwise.\n"
"\n"
" :arg v1: Point1\n"
" :type v1: :class:`mathutils.Vector`\n"
" :arg v2: Point2\n"
" :type v2: :class:`mathutils.Vector`\n"
" :arg v3: Point3\n"
" :type v3: :class:`mathutils.Vector`\n"
" :arg ray: Direction of the projection\n"
" :type ray: :class:`mathutils.Vector`\n"
" :arg orig: Origin\n"
" :type orig: :class:`mathutils.Vector`\n"
" :arg clip: Clip by the ray length\n"
" :type clip: boolean\n"
" :return: The point of intersection or None if no intersection is found\n"
" :rtype: :class:`mathutils.Vector` or None\n"
;
static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(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:intersect_ray_tri", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off , &clip)) {
return NULL;
}
if(vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) {
PyErr_SetString(PyExc_ValueError, "only 3D vectors for all parameters");
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);
}
/* Line-Line intersection using algorithm from mathworld.wolfram.com */
static char M_Geometry_intersect_line_line_doc[] =
".. function:: intersect_line_line(v1, v2, v3, v4)\n"
"\n"
" Returns a tuple with the points on each line respectively closest to the other.\n"
"\n"
" :arg v1: First point of the first line\n"
" :type v1: :class:`mathutils.Vector`\n"
" :arg v2: Second point of the first line\n"
" :type v2: :class:`mathutils.Vector`\n"
" :arg v3: First point of the second line\n"
" :type v3: :class:`mathutils.Vector`\n"
" :arg v4: Second point of the second line\n"
" :type v4: :class:`mathutils.Vector`\n"
" :rtype: tuple of :class:`mathutils.Vector`'s\n"
;
static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(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!:intersect_line_line", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4)) {
return NULL;
}
if(vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) {
PyErr_SetString(PyExc_ValueError,"vectors must be of the same size");
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_SET_ITEM(tuple, 0, newVectorObject(i1, vec1->size, Py_NEW, NULL));
PyTuple_SET_ITEM(tuple, 1, newVectorObject(i2, vec1->size, Py_NEW, NULL));
return tuple;
}
}
else {
PyErr_SetString(PyExc_ValueError, "2D/3D vectors only");
return NULL;
}
}
//----------------------------geometry.normal() -------------------
static char M_Geometry_normal_doc[] =
".. function:: normal(v1, v2, v3, v4=None)\n"
"\n"
" Returns the normal of the 3D tri or quad.\n"
"\n"
" :arg v1: Point1\n"
" :type v1: :class:`mathutils.Vector`\n"
" :arg v2: Point2\n"
" :type v2: :class:`mathutils.Vector`\n"
" :arg v3: Point3\n"
" :type v3: :class:`mathutils.Vector`\n"
" :arg v4: Point4 (optional)\n"
" :type v4: :class:`mathutils.Vector`\n"
" :rtype: :class:`mathutils.Vector`\n"
;
static PyObject *M_Geometry_normal(PyObject *UNUSED(self), PyObject* args)
{
VectorObject *vec1, *vec2, *vec3, *vec4;
float n[3];
if(PyTuple_GET_SIZE(args) == 3) {
if(!PyArg_ParseTuple(args, "O!O!O!:normal", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3)) {
return NULL;
}
if(vec1->size != vec2->size || vec1->size != vec3->size) {
PyErr_SetString(PyExc_ValueError, "vectors must be of the same size");
return NULL;
}
if(vec1->size < 3) {
PyErr_SetString(PyExc_ValueError, "2D vectors unsupported");
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3))
return NULL;
normal_tri_v3(n, vec1->vec, vec2->vec, vec3->vec);
}
else {
if(!PyArg_ParseTuple(args, "O!O!O!O!:normal", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4)) {
return NULL;
}
if(vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) {
PyErr_SetString(PyExc_ValueError,"vectors must be of the same size");
return NULL;
}
if(vec1->size < 3) {
PyErr_SetString(PyExc_ValueError, "2D vectors unsupported");
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4))
return NULL;
normal_quad_v3(n, vec1->vec, vec2->vec, vec3->vec, vec4->vec);
}
return newVectorObject(n, 3, Py_NEW, NULL);
}
//--------------------------------- AREA FUNCTIONS--------------------
static char M_Geometry_area_tri_doc[] =
".. function:: area_tri(v1, v2, v3)\n"
"\n"
" Returns the area size of the 2D or 3D triangle defined.\n"
"\n"
" :arg v1: Point1\n"
" :type v1: :class:`mathutils.Vector`\n"
" :arg v2: Point2\n"
" :type v2: :class:`mathutils.Vector`\n"
" :arg v3: Point3\n"
" :type v3: :class:`mathutils.Vector`\n"
" :rtype: float\n"
;
static PyObject *M_Geometry_area_tri(PyObject *UNUSED(self), PyObject* args)
{
VectorObject *vec1, *vec2, *vec3;
if(!PyArg_ParseTuple(args, "O!O!O!:area_tri", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3)) {
return NULL;
}
if(vec1->size != vec2->size || vec1->size != vec3->size) {
PyErr_SetString(PyExc_ValueError, "vectors must be of the same size");
return NULL;
}
if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3))
return NULL;
if (vec1->size == 3) {
return PyFloat_FromDouble(area_tri_v3(vec1->vec, vec2->vec, vec3->vec));
}
else if (vec1->size == 2) {
return PyFloat_FromDouble(area_tri_v2(vec1->vec, vec2->vec, vec3->vec));
}
else {
PyErr_SetString(PyExc_ValueError, "only 2D,3D vectors are supported");
return NULL;
}
}
/*----------------------------------geometry.PolyFill() -------------------*/
static char M_Geometry_tesselate_polygon_doc[] =
".. function:: tesselate_polygon(veclist_list)\n"
"\n"
" Takes a list of polylines (each point a vector) and returns the point indices for a polyline filled with triangles.\n"
"\n"
" :arg veclist_list: list of polylines\n"
" :rtype: list\n"
;
/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */
static PyObject *M_Geometry_tesselate_polygon(PyObject *UNUSED(self), PyObject *polyLineSeq)
{
PyObject *tri_list; /*return this list of tri's */
PyObject *polyLine, *polyVec;
int i, len_polylines, len_polypoints, ls_error= 0;
/* display listbase */
ListBase dispbase={NULL, NULL};
DispList *dl;
float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */
int index, *dl_face, totpoints=0;
if(!PySequence_Check(polyLineSeq)) {
PyErr_SetString(PyExc_TypeError, "expected a sequence of poly lines");
return NULL;
}
len_polylines= PySequence_Size(polyLineSeq);
for(i= 0; i < len_polylines; ++i) {
polyLine= PySequence_GetItem(polyLineSeq, i);
if (!PySequence_Check(polyLine)) {
freedisplist(&dispbase);
Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/
PyErr_SetString(PyExc_TypeError, "One or more of the polylines is not a sequence of mathutils.Vector's");
return NULL;
}
len_polypoints= PySequence_Size(polyLine);
if (len_polypoints>0) { /* dont bother adding edges as polylines */
#if 0
if (EXPP_check_sequence_consistency(polyLine, &vector_Type) != 1) {
freedisplist(&dispbase);
Py_DECREF(polyLine);
PyErr_SetString(PyExc_TypeError, "A point in one of the polylines is not a mathutils.Vector type");
return NULL;
}
#endif
dl= MEM_callocN(sizeof(DispList), "poly disp");
BLI_addtail(&dispbase, dl);
dl->type= DL_INDEX3;
dl->nr= len_polypoints;
dl->type= DL_POLY;
dl->parts= 1; /* no faces, 1 edge loop */
dl->col= 0; /* no material */
dl->verts= fp= MEM_callocN(sizeof(float)*3*len_polypoints, "dl verts");
dl->index= MEM_callocN(sizeof(int)*3*len_polypoints, "dl index");
for(index= 0; index<len_polypoints; ++index, fp+=3) {
polyVec= PySequence_GetItem(polyLine, index);
if(VectorObject_Check(polyVec)) {
if(!BaseMath_ReadCallback((VectorObject *)polyVec))
ls_error= 1;
fp[0]= ((VectorObject *)polyVec)->vec[0];
fp[1]= ((VectorObject *)polyVec)->vec[1];
if(((VectorObject *)polyVec)->size > 2)
fp[2]= ((VectorObject *)polyVec)->vec[2];
else
fp[2]= 0.0f; /* if its a 2d vector then set the z to be zero */
}
else {
ls_error= 1;
}
totpoints++;
Py_DECREF(polyVec);
}
}
Py_DECREF(polyLine);
}
if(ls_error) {
freedisplist(&dispbase); /* possible some dl was allocated */
PyErr_SetString(PyExc_TypeError, "A point in one of the polylines is not a mathutils.Vector type");
return NULL;
}
else if (totpoints) {
/* now make the list to return */
filldisplist(&dispbase, &dispbase, 0);
/* The faces are stored in a new DisplayList
thats added to the head of the listbase */
dl= dispbase.first;
tri_list= PyList_New(dl->parts);
if(!tri_list) {
freedisplist(&dispbase);
PyErr_SetString(PyExc_RuntimeError, "geometry.PolyFill failed to make a new list");
return NULL;
}
index= 0;
dl_face= dl->index;
while(index < dl->parts) {
PyList_SET_ITEM(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2]));
dl_face+= 3;
index++;
}
freedisplist(&dispbase);
} else {
/* no points, do this so scripts dont barf */
freedisplist(&dispbase); /* possible some dl was allocated */
tri_list= PyList_New(0);
}
return tri_list;
}
static char M_Geometry_intersect_line_line_2d_doc[] =
".. function:: intersect_line_line_2d(lineA_p1, lineA_p2, lineB_p1, lineB_p2)\n"
"\n"
" Takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None.\n"
"\n"
" :arg lineA_p1: First point of the first line\n"
" :type lineA_p1: :class:`mathutils.Vector`\n"
" :arg lineA_p2: Second point of the first line\n"
" :type lineA_p2: :class:`mathutils.Vector`\n"
" :arg lineB_p1: First point of the second line\n"
" :type lineB_p1: :class:`mathutils.Vector`\n"
" :arg lineB_p2: Second point of the second line\n"
" :type lineB_p2: :class:`mathutils.Vector`\n"
" :return: The point of intersection or None when not found\n"
" :rtype: :class:`mathutils.Vector` or None\n"
;
static PyObject *M_Geometry_intersect_line_line_2d(PyObject *UNUSED(self), PyObject* args)
{
VectorObject *line_a1, *line_a2, *line_b1, *line_b2;
float vi[2];
if(!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line_2d",
&vector_Type, &line_a1,
&vector_Type, &line_a2,
&vector_Type, &line_b1,
&vector_Type, &line_b2)
) {
return NULL;
}
if(!BaseMath_ReadCallback(line_a1) || !BaseMath_ReadCallback(line_a2) || !BaseMath_ReadCallback(line_b1) || !BaseMath_ReadCallback(line_b2))
return NULL;
if(isect_seg_seg_v2_point(line_a1->vec, line_a2->vec, line_b1->vec, line_b2->vec, vi) == 1) {
return newVectorObject(vi, 2, Py_NEW, NULL);
} else {
Py_RETURN_NONE;
}
}
static char M_Geometry_intersect_point_line_doc[] =
".. function:: intersect_point_line(pt, line_p1, line_p2)\n"
"\n"
" Takes a point and a line and returns a tuple with the closest point on the line and its distance from the first point of the line as a percentage of the length of the line.\n"
"\n"
" :arg pt: Point\n"
" :type pt: :class:`mathutils.Vector`\n"
" :arg line_p1: First point of the line\n"
" :type line_p1: :class:`mathutils.Vector`\n"
" :arg line_p1: Second point of the line\n"
" :type line_p1: :class:`mathutils.Vector`\n"
" :rtype: (:class:`mathutils.Vector`, float)\n"
;
static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObject* args)
{
VectorObject *pt, *line_1, *line_2;
float pt_in[3], pt_out[3], l1[3], l2[3];
float lambda;
PyObject *ret;
if(!PyArg_ParseTuple(args, "O!O!O!:intersect_point_line",
&vector_Type, &pt,
&vector_Type, &line_1,
&vector_Type, &line_2)
) {
return NULL;
}
if(!BaseMath_ReadCallback(pt) || !BaseMath_ReadCallback(line_1) || !BaseMath_ReadCallback(line_2))
return NULL;
/* accept 2d verts */
if (pt->size==3) { VECCOPY(pt_in, pt->vec);}
else { pt_in[2]=0.0; VECCOPY2D(pt_in, pt->vec) }
if (line_1->size==3) { VECCOPY(l1, line_1->vec);}
else { l1[2]=0.0; VECCOPY2D(l1, line_1->vec) }
if (line_2->size==3) { VECCOPY(l2, line_2->vec);}
else { l2[2]=0.0; VECCOPY2D(l2, line_2->vec) }
/* do the calculation */
lambda= closest_to_line_v3(pt_out,pt_in, l1, l2);
ret= PyTuple_New(2);
PyTuple_SET_ITEM(ret, 0, newVectorObject(pt_out, 3, Py_NEW, NULL));
PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(lambda));
return ret;
}
static char M_Geometry_intersect_point_tri_2d_doc[] =
".. function:: intersect_point_tri_2d(pt, tri_p1, tri_p2, tri_p3)\n"
"\n"
" Takes 4 vectors (using only the x and y coordinates): one is the point and the next 3 define the triangle. Returns 1 if the point is within the triangle, otherwise 0.\n"
"\n"
" :arg pt: Point\n"
" :type v1: :class:`mathutils.Vector`\n"
" :arg tri_p1: First point of the triangle\n"
" :type tri_p1: :class:`mathutils.Vector`\n"
" :arg tri_p2: Second point of the triangle\n"
" :type tri_p2: :class:`mathutils.Vector`\n"
" :arg tri_p3: Third point of the triangle\n"
" :type tri_p3: :class:`mathutils.Vector`\n"
" :rtype: int\n"
;
static PyObject *M_Geometry_intersect_point_tri_2d(PyObject *UNUSED(self), PyObject* args)
{
VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3;
if(!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri_2d",
&vector_Type, &pt_vec,
&vector_Type, &tri_p1,
&vector_Type, &tri_p2,
&vector_Type, &tri_p3)
) {
return NULL;
}
if(!BaseMath_ReadCallback(pt_vec) || !BaseMath_ReadCallback(tri_p1) || !BaseMath_ReadCallback(tri_p2) || !BaseMath_ReadCallback(tri_p3))
return NULL;
return PyLong_FromLong(isect_point_tri_v2(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec));
}
static char M_Geometry_intersect_point_quad_2d_doc[] =
".. function:: intersect_point_quad_2d(pt, quad_p1, quad_p2, quad_p3, quad_p4)\n"
"\n"
" Takes 5 vectors (using only the x and y coordinates): one is the point and the next 4 define the quad, only the x and y are used from the vectors. Returns 1 if the point is within the quad, otherwise 0.\n"
"\n"
" :arg pt: Point\n"
" :type v1: :class:`mathutils.Vector`\n"
" :arg quad_p1: First point of the quad\n"
" :type quad_p1: :class:`mathutils.Vector`\n"
" :arg quad_p2: Second point of the quad\n"
" :type quad_p2: :class:`mathutils.Vector`\n"
" :arg quad_p3: Third point of the quad\n"
" :type quad_p3: :class:`mathutils.Vector`\n"
" :arg quad_p4: Forth point of the quad\n"
" :type quad_p4: :class:`mathutils.Vector`\n"
" :rtype: int\n"
;
static PyObject *M_Geometry_intersect_point_quad_2d(PyObject *UNUSED(self), PyObject* args)
{
VectorObject *pt_vec, *quad_p1, *quad_p2, *quad_p3, *quad_p4;
if(!PyArg_ParseTuple(args, "O!O!O!O!O!:intersect_point_quad_2d",
&vector_Type, &pt_vec,
&vector_Type, &quad_p1,
&vector_Type, &quad_p2,
&vector_Type, &quad_p3,
&vector_Type, &quad_p4)
) {
return NULL;
}
if(!BaseMath_ReadCallback(pt_vec) || !BaseMath_ReadCallback(quad_p1) || !BaseMath_ReadCallback(quad_p2) || !BaseMath_ReadCallback(quad_p3) || !BaseMath_ReadCallback(quad_p4))
return NULL;
return PyLong_FromLong(isect_point_quad_v2(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec));
}
static int boxPack_FromPyObject(PyObject *value, boxPack **boxarray)
{
int len, i;
PyObject *list_item, *item_1, *item_2;
boxPack *box;
/* Error checking must already be done */
if(!PyList_Check(value)) {
PyErr_SetString(PyExc_TypeError, "can only back a list of [x, y, w, h]");
return -1;
}
len= PyList_Size(value);
(*boxarray)= MEM_mallocN(len*sizeof(boxPack), "boxPack box");
for(i= 0; i < len; i++) {
list_item= PyList_GET_ITEM(value, i);
if(!PyList_Check(list_item) || PyList_Size(list_item) < 4) {
MEM_freeN(*boxarray);
PyErr_SetString(PyExc_TypeError, "can only pack a list of [x, y, w, h]");
return -1;
}
box= (*boxarray)+i;
item_1= PyList_GET_ITEM(list_item, 2);
item_2= PyList_GET_ITEM(list_item, 3);
box->w= (float)PyFloat_AsDouble(item_1);
box->h= (float)PyFloat_AsDouble(item_2);
box->index= i;
if (box->w < 0.0f || box->h < 0.0f) {
MEM_freeN(*boxarray);
PyErr_SetString(PyExc_TypeError, "error parsing width and height values from list: [x, y, w, h], not numbers or below zero");
return -1;
}
/* verts will be added later */
}
return 0;
}
static void boxPack_ToPyObject(PyObject * value, boxPack **boxarray)
{
int len, i;
PyObject *list_item;
boxPack *box;
len= PyList_Size(value);
for(i= 0; i < len; i++) {
box= (*boxarray)+i;
list_item= PyList_GET_ITEM(value, box->index);
PyList_SET_ITEM(list_item, 0, PyFloat_FromDouble(box->x));
PyList_SET_ITEM(list_item, 1, PyFloat_FromDouble(box->y));
}
MEM_freeN(*boxarray);
}
static char M_Geometry_box_pack_2d_doc[] =
".. function:: box_pack_2d(boxes)\n"
"\n"
" Returns the normal of the 3D tri or quad.\n"
"\n"
" :arg boxes: list of boxes, each box is a list where the first 4 items are [x,y, width, height, ...] other items are ignored.\n"
" :type boxes: list\n"
" :return: the width and height of the packed bounding box\n"
" :rtype: tuple, pair of floats\n"
;
static PyObject *M_Geometry_box_pack_2d(PyObject *UNUSED(self), PyObject *boxlist)
{
float tot_width= 0.0f, tot_height= 0.0f;
int len;
PyObject *ret;
if(!PyList_Check(boxlist)) {
PyErr_SetString(PyExc_TypeError, "expected a list of boxes [[x,y,w,h], ... ]");
return NULL;
}
len= PyList_GET_SIZE(boxlist);
if (len) {
boxPack *boxarray= NULL;
if(boxPack_FromPyObject(boxlist, &boxarray) == -1) {
return NULL; /* exception set */
}
/* Non Python function */
boxPack2D(boxarray, len, &tot_width, &tot_height);
boxPack_ToPyObject(boxlist, &boxarray);
}
ret= PyTuple_New(2);
PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(tot_width));
PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(tot_width));
return ret;
}
static char M_Geometry_interpolate_bezier_doc[] =
".. function:: interpolate_bezier(knot1, handle1, handle2, knot2, resolution)\n"
"\n"
" Interpolate a bezier spline segment.\n"
"\n"
" :arg knot1: First bezier spline point.\n"
" :type knot1: :class:`mathutils.Vector`\n"
" :arg handle1: First bezier spline handle.\n"
" :type handle1: :class:`mathutils.Vector`\n"
" :arg handle2: Second bezier spline handle.\n"
" :type handle2: :class:`mathutils.Vector`\n"
" :arg knot2: Second bezier spline point.\n"
" :type knot2: :class:`mathutils.Vector`\n"
" :arg resolution: Number of points to return.\n"
" :type resolution: int\n"
" :return: The interpolated points\n"
" :rtype: list of :class:`mathutils.Vector`'s\n"
;
static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject* args)
{
VectorObject *vec_k1, *vec_h1, *vec_k2, *vec_h2;
int resolu;
int dims;
int i;
float *coord_array, *fp;
PyObject *list;
float k1[4]= {0.0, 0.0, 0.0, 0.0};
float h1[4]= {0.0, 0.0, 0.0, 0.0};
float k2[4]= {0.0, 0.0, 0.0, 0.0};
float h2[4]= {0.0, 0.0, 0.0, 0.0};
if(!PyArg_ParseTuple(args, "O!O!O!O!i:interpolate_bezier",
&vector_Type, &vec_k1,
&vector_Type, &vec_h1,
&vector_Type, &vec_h2,
&vector_Type, &vec_k2, &resolu)
) {
return NULL;
}
if(resolu <= 1) {
PyErr_SetString(PyExc_ValueError, "resolution must be 2 or over");
return NULL;
}
if(!BaseMath_ReadCallback(vec_k1) || !BaseMath_ReadCallback(vec_h1) || !BaseMath_ReadCallback(vec_k2) || !BaseMath_ReadCallback(vec_h2))
return NULL;
dims= MAX4(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size);
for(i=0; i < vec_k1->size; i++) k1[i]= vec_k1->vec[i];
for(i=0; i < vec_h1->size; i++) h1[i]= vec_h1->vec[i];
for(i=0; i < vec_k2->size; i++) k2[i]= vec_k2->vec[i];
for(i=0; i < vec_h2->size; i++) h2[i]= vec_h2->vec[i];
coord_array= MEM_callocN(dims * (resolu) * sizeof(float), "interpolate_bezier");
for(i=0; i<dims; i++) {
forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array+i, resolu-1, sizeof(float)*dims);
}
list= PyList_New(resolu);
fp= coord_array;
for(i=0; i<resolu; i++, fp= fp+dims) {
PyList_SET_ITEM(list, i, newVectorObject(fp, dims, Py_NEW, NULL));
}
MEM_freeN(coord_array);
return list;
}
static char M_Geometry_barycentric_transform_doc[] =
".. function:: barycentric_transform(point, tri_a1, tri_a2, tri_a3, tri_b1, tri_b2, tri_b3)\n"
"\n"
" Return a transformed point, the transformation is defined by 2 triangles.\n"
"\n"
" :arg point: The point to transform.\n"
" :type point: :class:`mathutils.Vector`\n"
" :arg tri_a1: source triangle vertex.\n"
" :type tri_a1: :class:`mathutils.Vector`\n"
" :arg tri_a2: source triangle vertex.\n"
" :type tri_a2: :class:`mathutils.Vector`\n"
" :arg tri_a3: source triangle vertex.\n"
" :type tri_a3: :class:`mathutils.Vector`\n"
" :arg tri_a1: target triangle vertex.\n"
" :type tri_a1: :class:`mathutils.Vector`\n"
" :arg tri_a2: target triangle vertex.\n"
" :type tri_a2: :class:`mathutils.Vector`\n"
" :arg tri_a3: target triangle vertex.\n"
" :type tri_a3: :class:`mathutils.Vector`\n"
" :return: The transformed point\n"
" :rtype: :class:`mathutils.Vector`'s\n"
;
static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObject *args)
{
VectorObject *vec_pt;
VectorObject *vec_t1_tar, *vec_t2_tar, *vec_t3_tar;
VectorObject *vec_t1_src, *vec_t2_src, *vec_t3_src;
float vec[3];
if(!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!:barycentric_transform",
&vector_Type, &vec_pt,
&vector_Type, &vec_t1_src,
&vector_Type, &vec_t2_src,
&vector_Type, &vec_t3_src,
&vector_Type, &vec_t1_tar,
&vector_Type, &vec_t2_tar,
&vector_Type, &vec_t3_tar)
) {
return NULL;
}
if( vec_pt->size != 3 ||
vec_t1_src->size != 3 ||
vec_t2_src->size != 3 ||
vec_t3_src->size != 3 ||
vec_t1_tar->size != 3 ||
vec_t2_tar->size != 3 ||
vec_t3_tar->size != 3)
{
PyErr_SetString(PyExc_ValueError, "One of more of the vector arguments wasnt a 3D vector");
return NULL;
}
barycentric_transform(vec, vec_pt->vec,
vec_t1_tar->vec, vec_t2_tar->vec, vec_t3_tar->vec,
vec_t1_src->vec, vec_t2_src->vec, vec_t3_src->vec);
return newVectorObject(vec, 3, Py_NEW, NULL);
}
static PyMethodDef M_Geometry_methods[]= {
{"intersect_ray_tri", (PyCFunction) M_Geometry_intersect_ray_tri, METH_VARARGS, M_Geometry_intersect_ray_tri_doc},
{"intersect_point_line", (PyCFunction) M_Geometry_intersect_point_line, METH_VARARGS, M_Geometry_intersect_point_line_doc},
{"intersect_point_tri_2d", (PyCFunction) M_Geometry_intersect_point_tri_2d, METH_VARARGS, M_Geometry_intersect_point_tri_2d_doc},
{"intersect_point_quad_2d", (PyCFunction) M_Geometry_intersect_point_quad_2d, METH_VARARGS, M_Geometry_intersect_point_quad_2d_doc},
{"intersect_line_line", (PyCFunction) M_Geometry_intersect_line_line, METH_VARARGS, M_Geometry_intersect_line_line_doc},
{"intersect_line_line_2d", (PyCFunction) M_Geometry_intersect_line_line_2d, METH_VARARGS, M_Geometry_intersect_line_line_2d_doc},
{"interpolate_bezier", (PyCFunction) M_Geometry_interpolate_bezier, METH_VARARGS, M_Geometry_interpolate_bezier_doc},
{"area_tri", (PyCFunction) M_Geometry_area_tri, METH_VARARGS, M_Geometry_area_tri_doc},
{"normal", (PyCFunction) M_Geometry_normal, METH_VARARGS, M_Geometry_normal_doc},
{"tesselate_polygon", (PyCFunction) M_Geometry_tesselate_polygon, METH_O, M_Geometry_tesselate_polygon_doc},
{"box_pack_2d", (PyCFunction) M_Geometry_box_pack_2d, METH_O, M_Geometry_box_pack_2d_doc},
{"barycentric_transform", (PyCFunction) M_Geometry_barycentric_transform, METH_VARARGS, M_Geometry_barycentric_transform_doc},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef M_Geometry_module_def= {
PyModuleDef_HEAD_INIT,
"mathutils.geometry", /* m_name */
M_Geometry_doc, /* m_doc */
0, /* m_size */
M_Geometry_methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
/*----------------------------MODULE INIT-------------------------*/
PyMODINIT_FUNC BPyInit_mathutils_geometry(void)
{
PyObject *submodule= PyModule_Create(&M_Geometry_module_def);
return submodule;
}

View File

@@ -28,12 +28,11 @@
*/
/*Include this file for access to vector, quat, matrix, euler, etc...*/
#ifndef EXPP_Geometry_H
#define EXPP_Geometry_H
#ifndef MATHUTILS_GEOMETRY_H
#define MATHUTILS_GEOMETRY_H
#include <Python.h>
#include "mathutils.h"
PyObject *Geometry_Init(void);
PyMODINIT_FUNC BPyInit_mathutils_geometry(void);
#endif /* EXPP_Geometry_H */
#endif /* MATHUTILS_GEOMETRY_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/**
* $Id: noise.c 31332 2010-08-14 05:33:20Z campbellbarton $
/*
* $Id$
*
* Blender.Noise BPython module implementation.
* This submodule has functions to generate noise of various types.
@@ -35,10 +35,16 @@
/************************/
#include <Python.h>
#include "structseq.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "DNA_texture_types.h"
#include "noise_py_api.h"
/*-----------------------------------------*/
/* 'mersenne twister' random number generator */
@@ -120,8 +126,6 @@ static int left = 1;
static int initf = 0;
static unsigned long *next;
PyObject *Noise_Init(void);
/* initializes state[N] with a seed */
static void init_genrand(unsigned long s)
{
@@ -174,7 +178,7 @@ static void setRndSeed(int seed)
}
/* float number in range [0, 1) using the mersenne twister rng */
static float frand()
static float frand(void)
{
unsigned long y;
@@ -207,12 +211,12 @@ static void randuvec(float v[3])
v[2] = 1.f;
}
static PyObject *Noise_random(PyObject * self)
static PyObject *Noise_random(PyObject *UNUSED(self))
{
return PyFloat_FromDouble(frand());
}
static PyObject *Noise_random_unit_vector(PyObject * self)
static PyObject *Noise_random_unit_vector(PyObject *UNUSED(self))
{
float v[3] = {0.0f, 0.0f, 0.0f};
randuvec(v);
@@ -223,7 +227,7 @@ static PyObject *Noise_random_unit_vector(PyObject * self)
/* Random seed init. Only used for MT random() & randuvec() */
static PyObject *Noise_seed_set(PyObject * self, PyObject * args)
static PyObject *Noise_seed_set(PyObject *UNUSED(self), PyObject *args)
{
int s;
if(!PyArg_ParseTuple(args, "i:seed_set", &s))
@@ -236,7 +240,7 @@ static PyObject *Noise_seed_set(PyObject * self, PyObject * args)
/* General noise */
static PyObject *Noise_noise(PyObject * self, PyObject * args)
static PyObject *Noise_noise(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z;
int nb = 1;
@@ -260,7 +264,7 @@ static void noise_vector(float x, float y, float z, int nb, float v[3])
nb) - 1.0);
}
static PyObject *Noise_vector(PyObject * self, PyObject * args)
static PyObject *Noise_vector(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z, v[3];
int nb = 1;
@@ -296,7 +300,7 @@ static float turb(float x, float y, float z, int oct, int hard, int nb,
return out;
}
static PyObject *Noise_turbulence(PyObject * self, PyObject * args)
static PyObject *Noise_turbulence(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z;
int oct, hd, nb = 1;
@@ -340,7 +344,7 @@ static void vTurb(float x, float y, float z, int oct, int hard, int nb,
}
}
static PyObject *Noise_turbulence_vector(PyObject * self, PyObject * args)
static PyObject *Noise_turbulence_vector(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z, v[3];
int oct, hd, nb = 1;
@@ -355,7 +359,7 @@ static PyObject *Noise_turbulence_vector(PyObject * self, PyObject * args)
/* F. Kenton Musgrave's fractal functions */
static PyObject *Noise_fractal(PyObject * self, PyObject * args)
static PyObject *Noise_fractal(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z, H, lac, oct;
int nb = 1;
@@ -366,7 +370,7 @@ static PyObject *Noise_fractal(PyObject * self, PyObject * args)
/*------------------------------------------------------------------------*/
static PyObject *Noise_multi_fractal(PyObject * self, PyObject * args)
static PyObject *Noise_multi_fractal(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z, H, lac, oct;
int nb = 1;
@@ -378,7 +382,7 @@ static PyObject *Noise_multi_fractal(PyObject * self, PyObject * args)
/*------------------------------------------------------------------------*/
static PyObject *Noise_vl_vector(PyObject * self, PyObject * args)
static PyObject *Noise_vl_vector(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z, d;
int nt1 = 1, nt2 = 1;
@@ -389,7 +393,7 @@ static PyObject *Noise_vl_vector(PyObject * self, PyObject * args)
/*-------------------------------------------------------------------------*/
static PyObject *Noise_hetero_terrain(PyObject * self, PyObject * args)
static PyObject *Noise_hetero_terrain(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z, H, lac, oct, ofs;
int nb = 1;
@@ -401,7 +405,7 @@ static PyObject *Noise_hetero_terrain(PyObject * self, PyObject * args)
/*-------------------------------------------------------------------------*/
static PyObject *Noise_hybrid_multi_fractal(PyObject * self, PyObject * args)
static PyObject *Noise_hybrid_multi_fractal(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z, H, lac, oct, ofs, gn;
int nb = 1;
@@ -413,7 +417,7 @@ static PyObject *Noise_hybrid_multi_fractal(PyObject * self, PyObject * args)
/*------------------------------------------------------------------------*/
static PyObject *Noise_ridged_multi_fractal(PyObject * self, PyObject * args)
static PyObject *Noise_ridged_multi_fractal(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z, H, lac, oct, ofs, gn;
int nb = 1;
@@ -424,7 +428,7 @@ static PyObject *Noise_ridged_multi_fractal(PyObject * self, PyObject * args)
/*-------------------------------------------------------------------------*/
static PyObject *Noise_voronoi(PyObject * self, PyObject * args)
static PyObject *Noise_voronoi(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z, da[4], pa[12];
int dtype = 0;
@@ -441,7 +445,7 @@ static PyObject *Noise_voronoi(PyObject * self, PyObject * args)
/*-------------------------------------------------------------------------*/
static PyObject *Noise_cell(PyObject * self, PyObject * args)
static PyObject *Noise_cell(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z;
if(!PyArg_ParseTuple(args, "(fff):cell", &x, &y, &z))
@@ -452,7 +456,7 @@ static PyObject *Noise_cell(PyObject * self, PyObject * args)
/*--------------------------------------------------------------------------*/
static PyObject *Noise_cell_vector(PyObject * self, PyObject * args)
static PyObject *Noise_cell_vector(PyObject *UNUSED(self), PyObject *args)
{
float x, y, z, ca[3];
if(!PyArg_ParseTuple(args, "(fff):cell_vector", &x, &y, &z))
@@ -603,22 +607,22 @@ look like anything from an earthquake to a very nervous or maybe even drunk came
/* Just in case, declarations for a header file */
/*
static PyObject *Noise_random(PyObject *self);
static PyObject *Noise_random_unit_vector(PyObject *self);
static PyObject *Noise_seed_set(PyObject *self, PyObject *args);
static PyObject *Noise_noise(PyObject *self, PyObject *args);
static PyObject *Noise_vector(PyObject *self, PyObject *args);
static PyObject *Noise_turbulence(PyObject *self, PyObject *args);
static PyObject *Noise_turbulence_vector(PyObject *self, PyObject *args);
static PyObject *Noise_fractal(PyObject *self, PyObject *args);
static PyObject *Noise_multi_fractal(PyObject *self, PyObject *args);
static PyObject *Noise_vl_vector(PyObject *self, PyObject *args);
static PyObject *Noise_hetero_terrain(PyObject *self, PyObject *args);
static PyObject *Noise_hybrid_multi_fractal(PyObject *self, PyObject *args);
static PyObject *Noise_ridged_multi_fractal(PyObject *self, PyObject *args);
static PyObject *Noise_voronoi(PyObject *self, PyObject *args);
static PyObject *Noise_cell(PyObject *self, PyObject *args);
static PyObject *Noise_cell_vector(PyObject *self, PyObject *args);
static PyObject *Noise_random(PyObject *UNUSED(self));
static PyObject *Noise_random_unit_vector(PyObject *UNUSED(self));
static PyObject *Noise_seed_set(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_noise(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_vector(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_turbulence(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_turbulence_vector(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_fractal(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_multi_fractal(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_vl_vector(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_hetero_terrain(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_hybrid_multi_fractal(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_ridged_multi_fractal(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_voronoi(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_cell(PyObject *UNUSED(self), PyObject *args);
static PyObject *Noise_cell_vector(PyObject *UNUSED(self), PyObject *args);
*/
static PyMethodDef NoiseMethods[] = {
@@ -647,18 +651,17 @@ static struct PyModuleDef noise_module_def = {
PyModuleDef_HEAD_INIT,
"noise", /* m_name */
Noise__doc__, /* m_doc */
0, /* m_size */
0, /* m_size */
NoiseMethods, /* m_methods */
0, /* m_reload */
0, /* m_traverse */
0, /* m_clear */
0, /* m_free */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
PyObject *Noise_Init(void)
PyObject *BPyInit_noise(void)
{
PyObject *submodule = PyModule_Create(&noise_module_def);
PyDict_SetItemString(PyImport_GetModuleDict(), noise_module_def.m_name, submodule);
/* use current time as seed for random number generator by default */
setRndSeed(0);
@@ -666,22 +669,22 @@ PyObject *Noise_Init(void)
/* Constant noisetype dictionary */
if(submodule) {
static PyStructSequence_Field noise_types_fields[] = {
{"BLENDER", ""},
{"STDPERLIN", ""},
{"NEWPERLIN", ""},
{"VORONOI_F1", ""},
{"VORONOI_F2", ""},
{"VORONOI_F3", ""},
{"VORONOI_F4", ""},
{"VORONOI_F2F1", ""},
{"VORONOI_CRACKLE", ""},
{"CELLNOISE", ""},
{0}
{(char *)"BLENDER", NULL},
{(char *)"STDPERLIN", NULL},
{(char *)"NEWPERLIN", NULL},
{(char *)"VORONOI_F1", NULL},
{(char *)"VORONOI_F2", NULL},
{(char *)"VORONOI_F3", NULL},
{(char *)"VORONOI_F4", NULL},
{(char *)"VORONOI_F2F1", NULL},
{(char *)"VORONOI_CRACKLE", NULL},
{(char *)"CELLNOISE", NULL},
{NULL}
};
static PyStructSequence_Desc noise_types_info_desc = {
"noise.types", /* name */
"Noise type", /* doc */
(char *)"noise.types", /* name */
(char *)"Noise type", /* doc */
noise_types_fields, /* fields */
(sizeof(noise_types_fields)/sizeof(PyStructSequence_Field)) - 1
};
@@ -715,19 +718,19 @@ PyObject *Noise_Init(void)
if(submodule) {
static PyStructSequence_Field distance_metrics_fields[] = {
{"DISTANCE", ""},
{"DISTANCE_SQUARED", ""},
{"MANHATTAN", ""},
{"CHEBYCHEV", ""},
{"MINKOVSKY_HALF", ""},
{"MINKOVSKY_FOUR", ""},
{"MINKOVSKY", ""},
{0}
{(char *)"DISTANCE", NULL},
{(char *)"DISTANCE_SQUARED", NULL},
{(char *)"MANHATTAN", NULL},
{(char *)"CHEBYCHEV", NULL},
{(char *)"MINKOVSKY_HALF", NULL},
{(char *)"MINKOVSKY_FOUR", NULL},
{(char *)"MINKOVSKY", NULL},
{NULL}
};
static PyStructSequence_Desc noise_types_info_desc = {
"noise.distance_metrics", /* name */
"Distance Metrics for noise module.", /* doc */
(char *)"noise.distance_metrics", /* name */
(char *)"Distance Metrics for noise module.", /* doc */
distance_metrics_fields, /* fields */
(sizeof(distance_metrics_fields)/sizeof(PyStructSequence_Field)) - 1
};

View File

@@ -0,0 +1,29 @@
/*
* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef NOISE_PY_API_H
#define NOISE_PY_API_H
PyObject *BPyInit_noise(void);
#endif // NOISE_PY_API_H

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -21,10 +21,12 @@
*/
#include <Python.h>
#include <frameobject.h>
#include "py_capi_utils.h"
/* for debugging */
void PyC_ObSpit(char *name, PyObject *var) {
void PyC_ObSpit(const char *name, PyObject *var) {
fprintf(stderr, "<%s> : ", name);
if (var==NULL) {
fprintf(stderr, "<NIL>");
@@ -53,39 +55,34 @@ void PyC_LineSpit(void) {
fprintf(stderr, "%s:%d\n", filename, lineno);
}
/* python 3.2 only, copied from frameobjec.c */
#if PY_VERSION_HEX < 0x03020000
int
PyFrame_GetLineNumber(PyFrameObject *f)
{
if (f->f_trace)
return f->f_lineno;
else
return PyCode_Addr2Line(f->f_code, f->f_lasti);
}
#endif
void PyC_FileAndNum(const char **filename, int *lineno)
{
PyObject *getframe, *frame;
PyObject *f_lineno= NULL, *co_filename= NULL;
PyFrameObject *frame;
if (filename) *filename= NULL;
if (lineno) *lineno = -1;
getframe = PySys_GetObject("_getframe"); // borrowed
if (getframe==NULL) {
PyErr_Clear();
if (!(frame= PyThreadState_GET()->frame)) {
return;
}
frame = PyObject_CallObject(getframe, NULL);
if (frame==NULL) {
PyErr_Clear();
return;
}
/* when executing a script */
if (filename) {
co_filename= PyC_Object_GetAttrStringArgs(frame, 1, "f_code", "co_filename");
if (co_filename==NULL) {
PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_code.co_filename");
Py_DECREF(frame);
return;
}
*filename = _PyUnicode_AsString(co_filename);
Py_DECREF(co_filename);
*filename = _PyUnicode_AsString(frame->f_code->co_filename);
}
/* when executing a module */
if(filename && *filename == NULL) {
/* try an alternative method to get the filename - module based
@@ -103,21 +100,10 @@ void PyC_FileAndNum(const char **filename, int *lineno)
}
}
}
if (lineno) {
f_lineno= PyObject_GetAttrString(frame, "f_lineno");
if (f_lineno==NULL) {
PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_lineno");
Py_DECREF(frame);
return;
}
*lineno = (int)PyLong_AsSsize_t(f_lineno);
Py_DECREF(f_lineno);
}
Py_DECREF(frame);
if (lineno) {
*lineno = PyFrame_GetLineNumber(frame);
}
}
/* Would be nice if python had this built in */
@@ -171,7 +157,7 @@ PyObject *PyC_ExceptionBuffer(void)
if(! (string_io_mod= PyImport_ImportModule("io")) ) {
goto error_cleanup;
} else if (! (string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) {
} else if (! (string_io = PyObject_CallMethod(string_io_mod, (char *)"StringIO", NULL))) {
goto error_cleanup;
} else if (! (string_io_getvalue= PyObject_GetAttrString(string_io, "getvalue"))) {
goto error_cleanup;
@@ -217,7 +203,7 @@ error_cleanup:
/* string conversion, escape non-unicode chars, coerce must be set to NULL */
const char *PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
{
char *result;
@@ -228,6 +214,10 @@ const char *PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
* chars since blender doesnt limit this */
return result;
}
else if(PyBytes_Check(py_str)) {
PyErr_Clear();
return PyBytes_AS_STRING(py_str);
}
else {
/* mostly copied from fileio.c's, fileio_init */
PyObject *stringobj;
@@ -265,7 +255,193 @@ PyObject *PyC_UnicodeFromByte(const char *str)
}
else {
PyErr_Clear();
result= PyUnicode_DecodeUTF8(str, strlen(str), "surrogateescape");
/* this means paths will always be accessible once converted, on all OS's */
result= PyUnicode_DecodeFSDefault(str);
return result;
}
}
/*****************************************************************************
* Description: This function creates a new Python dictionary object.
* note: dict is owned by sys.modules["__main__"] module, reference is borrowed
* note: important we use the dict from __main__, this is what python expects
for 'pickle' to work as well as strings like this...
>> foo = 10
>> print(__import__("__main__").foo)
*
* note: this overwrites __main__ which gives problems with nested calles.
* be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is
* any chance that python is in the call stack.
*****************************************************************************/
PyObject *PyC_DefaultNameSpace(const char *filename)
{
PyInterpreterState *interp= PyThreadState_GET()->interp;
PyObject *mod_main= PyModule_New("__main__");
PyDict_SetItemString(interp->modules, "__main__", mod_main);
Py_DECREF(mod_main); /* sys.modules owns now */
PyModule_AddStringConstant(mod_main, "__name__", "__main__");
if(filename)
PyModule_AddStringConstant(mod_main, "__file__", filename); /* __file__ only for nice UI'ness */
PyModule_AddObject(mod_main, "__builtins__", interp->builtins);
Py_INCREF(interp->builtins); /* AddObject steals a reference */
return PyModule_GetDict(mod_main);
}
/* restore MUST be called after this */
void PyC_MainModule_Backup(PyObject **main_mod)
{
PyInterpreterState *interp= PyThreadState_GET()->interp;
*main_mod= PyDict_GetItemString(interp->modules, "__main__");
Py_XINCREF(*main_mod); /* dont free */
}
void PyC_MainModule_Restore(PyObject *main_mod)
{
PyInterpreterState *interp= PyThreadState_GET()->interp;
PyDict_SetItemString(interp->modules, "__main__", main_mod);
Py_XDECREF(main_mod);
}
/* Would be nice if python had this built in */
void PyC_RunQuicky(const char *filepath, int n, ...)
{
FILE *fp= fopen(filepath, "r");
if(fp) {
PyGILState_STATE gilstate= PyGILState_Ensure();
va_list vargs;
int *sizes= PyMem_MALLOC(sizeof(int) * (n / 2));
int i;
PyObject *py_dict = PyC_DefaultNameSpace(filepath);
PyObject *values= PyList_New(n / 2); /* namespace owns this, dont free */
PyObject *py_result, *ret;
PyObject *struct_mod= PyImport_ImportModule("struct");
PyObject *calcsize= PyObject_GetAttrString(struct_mod, "calcsize"); /* struct.calcsize */
PyObject *pack= PyObject_GetAttrString(struct_mod, "pack"); /* struct.pack */
PyObject *unpack= PyObject_GetAttrString(struct_mod, "unpack"); /* struct.unpack */
Py_DECREF(struct_mod);
va_start(vargs, n);
for (i=0; i * 2<n; i++) {
char *format = va_arg(vargs, char *);
void *ptr = va_arg(vargs, void *);
ret= PyObject_CallFunction(calcsize, (char *)"s", format);
if(ret) {
sizes[i]= PyLong_AsSsize_t(ret);
Py_DECREF(ret);
ret = PyObject_CallFunction(unpack, (char *)"sy#", format, (char *)ptr, sizes[i]);
}
if(ret == NULL) {
printf("PyC_InlineRun error, line:%d\n", __LINE__);
PyErr_Print();
PyErr_Clear();
PyList_SET_ITEM(values, i, Py_None); /* hold user */
Py_INCREF(Py_None);
sizes[i]= 0;
}
else {
if(PyTuple_GET_SIZE(ret) == 1) {
/* convenience, convert single tuples into single values */
PyObject *tmp= PyTuple_GET_ITEM(ret, 0);
Py_INCREF(tmp);
Py_DECREF(ret);
ret = tmp;
}
PyList_SET_ITEM(values, i, ret); /* hold user */
}
}
va_end(vargs);
/* set the value so we can access it */
PyDict_SetItemString(py_dict, "values", values);
py_result = PyRun_File(fp, filepath, Py_file_input, py_dict, py_dict);
fclose(fp);
if(py_result) {
/* we could skip this but then only slice assignment would work
* better not be so strict */
values= PyDict_GetItemString(py_dict, "values");
if(values && PyList_Check(values)) {
/* dont use the result */
Py_DECREF(py_result);
py_result= NULL;
/* now get the values back */
va_start(vargs, n);
for (i=0; i*2 <n; i++) {
char *format = va_arg(vargs, char *);
void *ptr = va_arg(vargs, void *);
PyObject *item;
PyObject *item_new;
/* prepend the string formatting and remake the tuple */
item= PyList_GET_ITEM(values, i);
if(PyTuple_CheckExact(item)) {
int ofs= PyTuple_GET_SIZE(item);
item_new= PyTuple_New(ofs + 1);
while(ofs--) {
PyObject *member= PyTuple_GET_ITEM(item, ofs);
PyTuple_SET_ITEM(item_new, ofs + 1, member);
Py_INCREF(member);
}
PyTuple_SET_ITEM(item_new, 0, PyUnicode_FromString(format));
}
else {
item_new= Py_BuildValue("sO", format, item);
}
ret = PyObject_Call(pack, item_new, NULL);
if(ret) {
/* copy the bytes back into memory */
memcpy(ptr, PyBytes_AS_STRING(ret), sizes[i]);
Py_DECREF(ret);
}
else {
printf("PyC_InlineRun error on arg '%d', line:%d\n", i, __LINE__);
PyC_ObSpit("failed converting:", item_new);
PyErr_Print();
PyErr_Clear();
}
Py_DECREF(item_new);
}
va_end(vargs);
}
else {
printf("PyC_InlineRun error, 'values' not a list, line:%d\n", __LINE__);
}
}
else {
printf("PyC_InlineRun error line:%d\n", __LINE__);
PyErr_Print();
PyErr_Clear();
}
Py_DECREF(calcsize);
Py_DECREF(pack);
Py_DECREF(unpack);
PyMem_FREE(sizes);
PyGILState_Release(gilstate);
}
}

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -25,17 +25,21 @@
#ifndef PY_CAPI_UTILS_H
#define PY_CAPI_UTILS_H
struct PyObject;
void PyC_ObSpit(char *name, PyObject *var);
void PyC_ObSpit(const char *name, PyObject *var);
void PyC_LineSpit(void);
PyObject * PyC_ExceptionBuffer(void);
PyObject * PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
void PyC_FileAndNum(const char **filename, int *lineno);
int PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, char *error_prefix);
int PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, const char *error_prefix);
/* follow http://www.python.org/dev/peps/pep-0383/ */
PyObject * PyC_UnicodeFromByte(const char *str);
const char * PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
const char * PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
/* name namespace function for bpy & bge */
PyObject * PyC_DefaultNameSpace(const char *filename);
void PyC_RunQuicky(const char *filepath, int n, ...);
void PyC_MainModule_Backup(PyObject **main_mod);
void PyC_MainModule_Restore(PyObject *main_mod);
#endif // PY_CAPI_UTILS_H

View File

@@ -0,0 +1,77 @@
# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2006, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Jacques Beaurainm, Campbell Barton
#
# ***** END GPL LICENSE BLOCK *****
set(INC
..
../../blenlib
../../makesdna
../../makesrna
../../blenkernel
../../blenloader
../../windowmanager
../../editors/include
../../../../intern/guardedalloc
../../../../intern/audaspace/intern
${PYTHON_INCLUDE_DIRS}
)
set(SRC
bpy.c
bpy_app.c
bpy_driver.c
bpy_interface.c
bpy_operator.c
bpy_operator_wrap.c
bpy_props.c
bpy_rna.c
bpy_rna_array.c
bpy_rna_callback.c
bpy_traceback.c
bpy_util.c
stubs.c
bpy.h
bpy_app.h
bpy_driver.h
bpy_operator.h
bpy_operator_wrap.h
bpy_props.h
bpy_rna.h
bpy_rna_callback.h
bpy_traceback.h
bpy_util.h
../BPY_extern.h
)
# only to check if buildinfo is available
if(WITH_BUILDINFO)
add_definitions(-DBUILD_DATE)
endif()
if(WITH_PYTHON_MODULE)
add_definitions(-DWITH_PYTHON_MODULE)
endif()
blender_add_lib(bf_python "${SRC}" "${INC}")

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -25,7 +25,11 @@
/* This file defines the '_bpy' module which is used by python's 'bpy' package.
* a script writer should never directly access this module */
#define WITH_PYTHON /* for AUD_PyInit.h, possibly others */
#include <Python.h>
#include "bpy.h"
#include "bpy_util.h"
#include "bpy_rna.h"
#include "bpy_app.h"
@@ -34,15 +38,23 @@
#include "BLI_path_util.h"
#include "BLI_bpath.h"
#include "BLI_utildefines.h"
#include "BKE_global.h" /* XXX, G.main only */
#include "MEM_guardedalloc.h"
/* external util modules */
#include "../generic/geometry.h"
#include "../generic/mathutils.h"
#include "../generic/bgl.h"
#include "../generic/blf_api.h"
#include "../generic/blf_py_api.h"
#include "../generic/IDProp.h"
//#include "AUD_PyInit.h"
PyObject *bpy_package_py= NULL;
static char bpy_script_paths_doc[] =
".. function:: script_paths()\n"
"\n"
@@ -51,7 +63,7 @@ static char bpy_script_paths_doc[] =
" :return: (system, user) strings will be empty when not found.\n"
" :rtype: tuple of strigs\n";
PyObject *bpy_script_paths(PyObject *self)
static PyObject *bpy_script_paths(PyObject *UNUSED(self))
{
PyObject *ret= PyTuple_New(2);
char *path;
@@ -73,58 +85,96 @@ static char bpy_blend_paths_doc[] =
" :type absolute: boolean\n"
" :return: path list.\n"
" :rtype: list of strigs\n";
static PyObject *bpy_blend_paths(PyObject * self, PyObject *args, PyObject *kw)
static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
struct BPathIterator bpi;
PyObject *list = PyList_New(0), *st; /* stupidly big string to be safe */
struct BPathIterator *bpi;
PyObject *list, *st; /* stupidly big string to be safe */
/* be sure there is low chance of the path being too short */
char filepath_expanded[1024];
char *lib;
const char *lib;
int absolute = 0;
static char *kwlist[] = {"absolute", NULL};
static const char *kwlist[] = {"absolute", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kw, "|i:blend_paths", kwlist, &absolute))
if (!PyArg_ParseTupleAndKeywords(args, kw, "|i:blend_paths", (char **)kwlist, &absolute))
return NULL;
for(BLI_bpathIterator_init(&bpi, NULL); !BLI_bpathIterator_isDone(&bpi); BLI_bpathIterator_step(&bpi)) {
list= PyList_New(0);
for(BLI_bpathIterator_init(&bpi, G.main, NULL, 0); !BLI_bpathIterator_isDone(bpi); BLI_bpathIterator_step(bpi)) {
/* build the list */
if (absolute) {
BLI_bpathIterator_getPathExpanded(&bpi, filepath_expanded);
BLI_bpathIterator_getPathExpanded(bpi, filepath_expanded);
}
else {
lib = BLI_bpathIterator_getLib(&bpi);
if (lib && (strcmp(lib, bpi.base_path))) { /* relative path to the library is NOT the same as our blendfile path, return an absolute path */
BLI_bpathIterator_getPathExpanded(&bpi, filepath_expanded);
lib = BLI_bpathIterator_getLib(bpi);
if (lib && (strcmp(lib, BLI_bpathIterator_getBasePath(bpi)))) { /* relative path to the library is NOT the same as our blendfile path, return an absolute path */
BLI_bpathIterator_getPathExpanded(bpi, filepath_expanded);
}
else {
BLI_bpathIterator_getPath(&bpi, filepath_expanded);
BLI_bpathIterator_getPath(bpi, filepath_expanded);
}
}
st = PyUnicode_FromString(filepath_expanded);
st= PyUnicode_DecodeFSDefault(filepath_expanded);
PyList_Append(list, st);
Py_DECREF(st);
}
BLI_bpathIterator_free(&bpi);
BLI_bpathIterator_free(bpi);
return list;
}
static PyMethodDef meth_bpy_script_paths[] = {{ "script_paths", (PyCFunction)bpy_script_paths, METH_NOARGS, bpy_script_paths_doc}};
static PyMethodDef meth_bpy_blend_paths[] = {{ "blend_paths", (PyCFunction)bpy_blend_paths, METH_VARARGS|METH_KEYWORDS, bpy_blend_paths_doc}};
static void bpy_import_test(char *modname)
// static char bpy_user_resource_doc[] = // now in bpy/utils.py
static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
PyObject *mod= PyImport_ImportModuleLevel(modname, NULL, NULL, NULL, 0);
char *type;
char *subdir= NULL;
int folder_id;
static const char *kwlist[] = {"type", "subdir", NULL};
char *path;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|s:user_resource", (char **)kwlist, &type, &subdir))
return NULL;
/* stupid string compare */
if (!strcmp(type, "DATAFILES")) folder_id= BLENDER_USER_DATAFILES;
else if(!strcmp(type, "CONFIG")) folder_id= BLENDER_USER_CONFIG;
else if(!strcmp(type, "SCRIPTS")) folder_id= BLENDER_USER_SCRIPTS;
else if(!strcmp(type, "AUTOSAVE")) folder_id= BLENDER_USER_AUTOSAVE;
else {
PyErr_SetString(PyExc_ValueError, "invalid resource argument");
return NULL;
}
/* same logic as BLI_get_folder_create(), but best leave it up to the script author to create */
path= BLI_get_folder(folder_id, subdir);
if (!path)
path = BLI_get_user_folder_notest(folder_id, subdir);
return PyUnicode_FromString(path ? path : "");
}
static PyMethodDef meth_bpy_script_paths = {"script_paths", (PyCFunction)bpy_script_paths, METH_NOARGS, bpy_script_paths_doc};
static PyMethodDef meth_bpy_blend_paths = {"blend_paths", (PyCFunction)bpy_blend_paths, METH_VARARGS|METH_KEYWORDS, bpy_blend_paths_doc};
static PyMethodDef meth_bpy_user_resource = {"user_resource", (PyCFunction)bpy_user_resource, METH_VARARGS|METH_KEYWORDS, NULL};
static PyObject *bpy_import_test(const char *modname)
{
PyObject *mod= PyImport_ImportModuleLevel((char *)modname, NULL, NULL, NULL, 0);
if(mod) {
Py_DECREF(mod);
}
else {
PyErr_Print();
PyErr_Clear();
}
}
return mod;
}
/*****************************************************************************
@@ -149,13 +199,7 @@ void BPy_init_modules( void )
printf("bpy: couldnt find 'scripts/modules', blender probably wont start.\n");
}
/* stand alone utility modules not related to blender directly */
Geometry_Init();
Mathutils_Init();
Noise_Init();
BGL_Init();
BLF_Init();
IDProp_Init_Types();
//AUD_initPython();
IDProp_Init_Types(); /* not actually a submodule, just types */
mod = PyModule_New("_bpy");
@@ -167,6 +211,8 @@ void BPy_init_modules( void )
BPY_rna_init();
PyModule_AddObject( mod, "types", BPY_rna_types() ); /* needs to be first so bpy_types can run */
PyModule_AddObject(mod, "StructMetaPropGroup", (PyObject *)&pyrna_struct_meta_idprop_Type); /* metaclass for idprop types, bpy_types.py needs access */
bpy_import_test("bpy_types");
PyModule_AddObject( mod, "data", BPY_rna_module() ); /* imports bpy_types by running this */
bpy_import_test("bpy_types");
@@ -175,7 +221,7 @@ void BPy_init_modules( void )
PyModule_AddObject( mod, "app", BPY_app_struct() );
/* bpy context */
RNA_pointer_create(NULL, &RNA_Context, BPy_GetContext(), &ctx_ptr);
RNA_pointer_create(NULL, &RNA_Context, (void *)BPy_GetContext(), &ctx_ptr);
bpy_context_module= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ctx_ptr);
/* odd that this is needed, 1 ref on creation and another for the module
* but without we get a crash on exit */
@@ -184,9 +230,14 @@ void BPy_init_modules( void )
PyModule_AddObject(mod, "context", (PyObject *)bpy_context_module);
/* utility func's that have nowhere else to go */
PyModule_AddObject(mod, meth_bpy_script_paths->ml_name, (PyObject *)PyCFunction_New(meth_bpy_script_paths, NULL));
PyModule_AddObject(mod, meth_bpy_blend_paths->ml_name, (PyObject *)PyCFunction_New(meth_bpy_blend_paths, NULL));
PyModule_AddObject(mod, meth_bpy_script_paths.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_script_paths, NULL));
PyModule_AddObject(mod, meth_bpy_blend_paths.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_blend_paths, NULL));
PyModule_AddObject(mod, meth_bpy_user_resource.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_user_resource, NULL));
/* register funcs (bpy_rna.c) */
PyModule_AddObject(mod, meth_bpy_register_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_register_class, NULL));
PyModule_AddObject(mod, meth_bpy_unregister_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_unregister_class, NULL));
/* add our own modules dir, this is a python package */
bpy_import_test("bpy");
bpy_package_py= bpy_import_test("bpy");
}

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -22,4 +22,4 @@
* ***** END GPL LICENSE BLOCK ***** */
void BPy_init_modules( void );
extern PyObject *bpy_package_py;

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -22,43 +22,57 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#include "bpy_app.h"
#include "bpy_driver.h"
#include "BLI_path_util.h"
#include "BLI_utildefines.h"
#include "BKE_blender.h"
#include "BKE_global.h"
#include "structseq.h"
#include "../generic/py_capi_utils.h"
#ifdef BUILD_DATE
extern char build_date[];
extern char build_time[];
extern char build_rev[];
extern char build_platform[];
extern char build_type[];
extern char build_cflags[];
extern char build_cxxflags[];
extern char build_linkflags[];
extern char build_system[];
#endif
static PyTypeObject BlenderAppType;
static PyStructSequence_Field app_info_fields[] = {
{"version", "The Blender version as a tuple of 3 numbers. eg. (2, 50, 11)"},
{"version_string", "The Blender version formatted as a string"},
{"binary_path", "The location of blenders executable, useful for utilities that spawn new instances"},
{"debug", "Boolean, set when blender is running in debug mode (started with -d)"},
{"background", "Boolean, True when blender is running without a user interface (started with -b)"},
{(char *)"version", (char *)"The Blender version as a tuple of 3 numbers. eg. (2, 50, 11)"},
{(char *)"version_string", (char *)"The Blender version formatted as a string"},
{(char *)"binary_path", (char *)"The location of blenders executable, useful for utilities that spawn new instances"},
{(char *)"background", (char *)"Boolean, True when blender is running without a user interface (started with -b)"},
/* buildinfo */
{"build_date", "The date this blender instance was built"},
{"build_time", "The time this blender instance was built"},
{"build_revision", "The subversion revision this blender instance was built with"},
{"build_platform", "The platform this blender instance was built for"},
{"build_type", "The type of build (Release, Debug)"},
{0}
{(char *)"build_date", (char *)"The date this blender instance was built"},
{(char *)"build_time", (char *)"The time this blender instance was built"},
{(char *)"build_revision", (char *)"The subversion revision this blender instance was built with"},
{(char *)"build_platform", (char *)"The platform this blender instance was built for"},
{(char *)"build_type", (char *)"The type of build (Release, Debug)"},
{(char *)"build_cflags", (char *)"C compiler flags"},
{(char *)"build_cxxflags", (char *)"C++ compiler flags"},
{(char *)"build_linkflags", (char *)"Binary linking flags"},
{(char *)"build_system", (char *)"Build system used"},
{NULL}
};
static PyStructSequence_Desc app_info_desc = {
"bpy.app", /* name */
"This module contains application values that remain unchanged during runtime.", /* doc */
(char *)"bpy.app", /* name */
(char *)"This module contains application values that remain unchanged during runtime.", /* doc */
app_info_fields, /* fields */
(sizeof(app_info_fields)/sizeof(PyStructSequence_Field)) - 1
};
@@ -85,7 +99,6 @@ static PyObject *make_app_info(void)
SetObjItem(Py_BuildValue("(iii)", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION));
SetObjItem(PyUnicode_FromFormat("%d.%02d (sub %d)", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION));
SetStrItem(bprogname);
SetObjItem(PyBool_FromLong(G.f & G_DEBUG));
SetObjItem(PyBool_FromLong(G.background));
/* build info */
@@ -95,12 +108,20 @@ static PyObject *make_app_info(void)
SetStrItem(build_rev);
SetStrItem(build_platform);
SetStrItem(build_type);
SetStrItem(build_cflags);
SetStrItem(build_cxxflags);
SetStrItem(build_linkflags);
SetStrItem(build_system);
#else
SetStrItem("Unknown");
SetStrItem("Unknown");
SetStrItem("Unknown");
SetStrItem("Unknown");
SetStrItem("Unknown");
SetStrItem("Unknown");
SetStrItem("Unknown");
SetStrItem("Unknown");
SetStrItem("Unknown");
#endif
#undef SetIntItem
@@ -114,10 +135,90 @@ static PyObject *make_app_info(void)
return app_info;
}
/* a few getsets because it makes sense for them to be in bpy.app even though
* they are not static */
static PyObject *bpy_app_debug_get(PyObject *UNUSED(self), void *UNUSED(closure))
{
return PyBool_FromLong(G.f & G_DEBUG);
}
static int bpy_app_debug_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure))
{
int param= PyObject_IsTrue(value);
if(param < 0) {
PyErr_SetString(PyExc_TypeError, "bpy.app.debug can only be True/False");
return -1;
}
if(param) G.f |= G_DEBUG;
else G.f &= ~G_DEBUG;
return 0;
}
static PyObject *bpy_app_debug_value_get(PyObject *UNUSED(self), void *UNUSED(closure))
{
return PyLong_FromSsize_t(G.rt);
}
static int bpy_app_debug_value_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure))
{
int param= PyLong_AsSsize_t(value);
if (param == -1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "bpy.app.debug_value can only be set to a whole number");
return -1;
}
G.rt= param;
return 0;
}
static PyObject *bpy_app_tempdir_get(PyObject *UNUSED(self), void *UNUSED(closure))
{
extern char btempdir[];
return PyC_UnicodeFromByte(btempdir);
}
static PyObject *bpy_app_driver_dict_get(PyObject *UNUSED(self), void *UNUSED(closure))
{
if (bpy_pydriver_Dict == NULL)
if (bpy_pydriver_create_dict() != 0) {
PyErr_SetString(PyExc_RuntimeError, "bpy.app.driver_namespace failed to create dictionary");
return NULL;
}
Py_INCREF(bpy_pydriver_Dict);
return bpy_pydriver_Dict;
}
static PyGetSetDef bpy_app_getsets[]= {
{(char *)"debug", bpy_app_debug_get, bpy_app_debug_set, (char *)"Boolean, set when blender is running in debug mode (started with -d)", NULL},
{(char *)"debug_value", bpy_app_debug_value_get, bpy_app_debug_value_set, (char *)"Int, number which can be set to non-zero values for testing purposes.", NULL},
{(char *)"tempdir", bpy_app_tempdir_get, NULL, (char *)"String, the temp directory used by blender (read-only)", NULL},
{(char *)"driver_namespace", bpy_app_driver_dict_get, NULL, (char *)"Dictionary for drivers namespace, editable in-place, reset on file load (read-only)", NULL},
{NULL, NULL, NULL, NULL, NULL}
};
static void py_struct_seq_getset_init(void)
{
/* tricky dynamic members, not to py-spec! */
PyGetSetDef *getset;
for(getset= bpy_app_getsets; getset->name; getset++) {
PyDict_SetItemString(BlenderAppType.tp_dict, getset->name, PyDescr_NewGetSet(&BlenderAppType, getset));
}
}
/* end dynamic bpy.app */
PyObject *BPY_app_struct(void)
{
PyObject *ret;
PyStructSequence_InitType(&BlenderAppType, &app_info_desc);
ret= make_app_info();
@@ -125,6 +226,10 @@ PyObject *BPY_app_struct(void)
/* prevent user from creating new instances */
BlenderAppType.tp_init = NULL;
BlenderAppType.tp_new = NULL;
/* kindof a hack ontop of PyStructSequence */
py_struct_seq_getset_init();
return ret;
}

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -21,11 +21,9 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BPY_APP_H__
#define BPY_APP_H__
#include <Python.h>
#ifndef BPY_APP_H
#define BPY_APP_H
PyObject *BPY_app_struct( void );
#endif
#endif // BPY_APP_H

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -34,13 +34,15 @@
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "bpy_driver.h"
/* for pydrivers (drivers using one-line Python expressions to express relationships between targets) */
PyObject *bpy_pydriver_Dict = NULL;
/* For faster execution we keep a special dictionary for pydrivers, with
* the needed modules and aliases.
*/
static int bpy_pydriver_create_dict(void)
int bpy_pydriver_create_dict(void)
{
PyObject *d, *mod;
@@ -63,47 +65,21 @@ static int bpy_pydriver_create_dict(void)
}
/* add bpy to global namespace */
mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
mod= PyImport_ImportModuleLevel((char *)"bpy", NULL, NULL, NULL, 0);
if (mod) {
PyDict_SetItemString(bpy_pydriver_Dict, "bpy", mod);
Py_DECREF(mod);
}
#if 0 // non existant yet
mod = PyImport_ImportModule("Blender.Noise");
if (mod) {
PyDict_SetItemString(d, "noise", mod);
PyDict_SetItemString(d, "n", mod);
Py_DECREF(mod);
} else {
PyErr_Clear();
}
/* If there's a Blender text called pydrivers.py, import it.
* Users can add their own functions to this module.
*/
if (G.f & G_SCRIPT_AUTOEXEC) {
mod = importText("pydrivers"); /* can also use PyImport_Import() */
if (mod) {
PyDict_SetItemString(d, "pydrivers", mod);
PyDict_SetItemString(d, "p", mod);
Py_DECREF(mod);
} else {
PyErr_Clear();
}
}
#endif // non existant yet
return 0;
}
/* Update function, it gets rid of pydrivers global dictionary, forcing
* BPY_eval_driver to recreate it. This function is used to force
* BPY_driver_exec to recreate it. This function is used to force
* reloading the Blender text module "pydrivers.py", if available, so
* updates in it reach pydriver evaluation.
*/
void BPY_pydriver_update(void)
void BPY_driver_reset(void)
{
PyGILState_STATE gilstate;
int use_gil= 1; // (PyThreadState_Get()==NULL);
@@ -124,22 +100,14 @@ void BPY_pydriver_update(void)
}
/* error return function for BPY_eval_pydriver */
static float pydriver_error(ChannelDriver *driver)
static void pydriver_error(ChannelDriver *driver)
{
if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
PyDict_Clear(bpy_pydriver_Dict);
Py_DECREF(bpy_pydriver_Dict);
bpy_pydriver_Dict = NULL;
}
driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */
fprintf(stderr, "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n", driver->expression);
// BPy_errors_to_report(NULL); // TODO - reports
PyErr_Print();
PyErr_Clear();
return 0.0f;
}
/* This evals py driver expressions, 'expr' is a Python expression that
@@ -149,7 +117,7 @@ static float pydriver_error(ChannelDriver *driver)
* bake operator which intern starts a thread which calls scene update which
* does a driver update. to avoid a deadlock check PyThreadState_Get() if PyGILState_Ensure() is needed.
*/
float BPY_eval_driver (ChannelDriver *driver)
float BPY_driver_exec(ChannelDriver *driver)
{
PyObject *driver_vars=NULL;
PyObject *retval= NULL;
@@ -238,15 +206,15 @@ float BPY_eval_driver (ChannelDriver *driver)
/* try to add to dictionary */
/* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */
if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg)) { /* use string interning for faster namespace creation */
if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) < 0) { /* use string interning for faster namespace creation */
/* this target failed - bad name */
if (targets_ok) {
/* first one - print some extra info for easier identification */
fprintf(stderr, "\nBPY_eval_driver() - Error while evaluating PyDriver:\n");
fprintf(stderr, "\nBPY_driver_eval() - Error while evaluating PyDriver:\n");
targets_ok= 0;
}
fprintf(stderr, "\tBPY_eval_driver() - couldn't add variable '%s' to namespace\n", dvar->name);
fprintf(stderr, "\tBPY_driver_eval() - couldn't add variable '%s' to namespace\n", dvar->name);
// BPy_errors_to_report(NULL); // TODO - reports
PyErr_Print();
PyErr_Clear();
@@ -259,7 +227,7 @@ float BPY_eval_driver (ChannelDriver *driver)
#else
/* evaluate the compiled expression */
if (expr_code)
retval= PyEval_EvalCode((PyCodeObject *)expr_code, bpy_pydriver_Dict, driver_vars);
retval= PyEval_EvalCode((void *)expr_code, bpy_pydriver_Dict, driver_vars);
#endif
/* decref the driver vars first... */
@@ -286,7 +254,7 @@ float BPY_eval_driver (ChannelDriver *driver)
return (float)result;
}
else {
fprintf(stderr, "\tBPY_eval_driver() - driver '%s' evaluates to '%f'\n", dvar->name, result);
fprintf(stderr, "\tBPY_driver_eval() - driver '%s' evaluates to '%f'\n", dvar->name, result);
return 0.0f;
}
}

View File

@@ -0,0 +1,36 @@
/*
* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BPY_DRIVER_H
#define BPY_DRIVER_H
struct ChannelDriver;
int bpy_pydriver_create_dict(void);
extern PyObject *bpy_pydriver_Dict;
/* externals */
float BPY_driver_exec(struct ChannelDriver *driver);
void BPY_driver_reset(void);
#endif // BPY_DRIVER_H

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -23,25 +23,28 @@
* ***** END GPL LICENSE BLOCK *****
*/
/* grr, python redefines */
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#include <Python.h>
#include "MEM_guardedalloc.h"
#include "bpy.h"
#include "bpy_rna.h"
#include "bpy_util.h"
#include "bpy_traceback.h"
#include "DNA_space_types.h"
#include "DNA_text_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_path_util.h"
#include "BLI_math_base.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
#include "BKE_text.h"
@@ -52,6 +55,13 @@
#include "BPY_extern.h"
#include "../generic/bpy_internal_import.h" // our own imports
#include "../generic/py_capi_utils.h"
/* inittab initialization functions */
#include "../generic/noise_py_api.h"
#include "../generic/mathutils.h"
#include "../generic/bgl.h"
#include "../generic/blf_py_api.h"
/* for internal use, when starting and ending python scripts */
@@ -59,8 +69,7 @@
static int py_call_level= 0;
BPy_StructRNA *bpy_context_module= NULL; /* for fast access */
// only for tests
#define TIME_PY_RUN
// #define TIME_PY_RUN // simple python tests. prints on exit.
#ifdef TIME_PY_RUN
#include "PIL_time.h"
@@ -87,7 +96,7 @@ void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
fprintf(stderr, "ERROR: Python context called with a NULL Context. this should not happen!\n");
}
BPY_update_modules(); /* can give really bad results if this isnt here */
BPY_modules_update(C); /* can give really bad results if this isnt here */
#ifdef TIME_PY_RUN
if(bpy_timer_count==0) {
@@ -103,7 +112,8 @@ void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
}
}
void bpy_context_clear(bContext *C, PyGILState_STATE *gilstate)
/* context should be used but not now because it causes some bugs */
void bpy_context_clear(bContext *UNUSED(C), PyGILState_STATE *gilstate)
{
py_call_level--;
@@ -126,7 +136,7 @@ void bpy_context_clear(bContext *C, PyGILState_STATE *gilstate)
}
}
void BPY_free_compiled_text( struct Text *text )
void BPY_text_free_code(Text *text)
{
if( text->compiled ) {
Py_DECREF( ( PyObject * ) text->compiled );
@@ -134,7 +144,7 @@ void BPY_free_compiled_text( struct Text *text )
}
}
void BPY_update_modules( void )
void BPY_modules_update(bContext *C)
{
#if 0 // slow, this runs all the time poll, draw etc 100's of time a sec.
PyObject *mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
@@ -144,11 +154,12 @@ void BPY_update_modules( void )
/* refreshes the main struct */
BPY_update_rna_module();
bpy_context_module->ptr.data= (void *)BPy_GetContext();
bpy_context_module->ptr.data= (void *)C;
}
/* must be called before Py_Initialize */
void BPY_start_python_path(void)
#ifndef WITH_PYTHON_MODULE
static void bpy_python_start_path(void)
{
char *py_path_bundle= BLI_get_folder(BLENDER_PYTHON, NULL);
@@ -170,15 +181,7 @@ void BPY_start_python_path(void)
/* cmake/MSVC debug build crashes without this, why only
in this case is unknown.. */
{
char *envpath = getenv("PYTHONPATH");
if(envpath && envpath[0]) {
char *newenvpath = BLI_sprintfN("%s;%s", py_path_bundle, envpath);
BLI_setenv("PYTHONPATH", newenvpath);
MEM_freeN(newenvpath);
}
else
BLI_setenv("PYTHONPATH", py_path_bundle);
BLI_setenv("PYTHONPATH", py_path_bundle);
}
#endif
@@ -194,25 +197,46 @@ void BPY_start_python_path(void)
// printf("found python (wchar_t) '%ls'\n", py_path_bundle_wchar);
}
}
#endif
void BPY_set_context(bContext *C)
void BPY_context_set(bContext *C)
{
BPy_SetContext(C);
}
/* call BPY_set_context first */
void BPY_start_python( int argc, char **argv )
/* defined in AUD_C-API.cpp */
extern PyObject *AUD_initPython(void);
static struct _inittab bpy_internal_modules[]= {
{(char *)"noise", BPyInit_noise},
{(char *)"mathutils", BPyInit_mathutils},
// {(char *)"mathutils.geometry", BPyInit_mathutils_geometry},
{(char *)"bgl", BPyInit_bgl},
{(char *)"blf", BPyInit_blf},
{(char *)"aud", AUD_initPython},
{NULL, NULL}
};
/* call BPY_context_set first */
void BPY_python_start(int argc, const char **argv)
{
#ifndef WITH_PYTHON_MODULE
PyThreadState *py_tstate = NULL;
/* not essential but nice to set our name */
static wchar_t bprogname_wchar[FILE_MAXDIR+FILE_MAXFILE]; /* python holds a reference */
utf8towchar(bprogname_wchar, bprogname);
Py_SetProgramName(bprogname_wchar);
BPY_start_python_path(); /* allow to use our own included python */
/* builtin modules */
PyImport_ExtendInittab(bpy_internal_modules);
bpy_python_start_path(); /* allow to use our own included python */
/* Python 3.2 now looks for '2.56/python/include/python3.2d/pyconfig.h' to parse
* from the 'sysconfig' module which is used by 'site', so for now disable site.
* alternatively we could copy the file. */
Py_NoSiteFlag= 1;
Py_Initialize( );
@@ -220,52 +244,57 @@ void BPY_start_python( int argc, char **argv )
/* sigh, why do python guys not have a char** version anymore? :( */
{
int i;
#if 0
PyObject *py_argv= PyList_New(argc);
for (i=0; i<argc; i++)
PyList_SET_ITEM(py_argv, i, PyUnicode_FromString(argv[i]));
PyList_SET_ITEM(py_argv, i, PyC_UnicodeFromByte(argv[i])); /* should fix bug #20021 - utf path name problems, by replacing PyUnicode_FromString */
#else // should fix bug #20021 - utf path name problems
PyObject *py_argv= PyList_New(0);
for (i=0; i<argc; i++) {
PyObject *item= PyUnicode_Decode(argv[i], strlen(argv[i]), Py_FileSystemDefaultEncoding, NULL);
if(item==NULL) { // should never happen
PyErr_Print();
PyErr_Clear();
}
else {
PyList_Append(py_argv, item);
Py_DECREF(item);
}
}
#endif
PySys_SetObject("argv", py_argv);
Py_DECREF(py_argv);
}
/* Initialize thread support (also acquires lock) */
PyEval_InitThreads();
#else
(void)argc;
(void)argv;
PyImport_ExtendInittab(bpy_internal_modules);
#endif
/* bpy.* and lets us import it */
BPy_init_modules();
{ /* our own import and reload functions */
PyObject *item;
PyObject *mod;
//PyObject *m = PyImport_AddModule("__builtin__");
//PyObject *d = PyModule_GetDict(m);
PyObject *d = PyEval_GetBuiltins( );
PyDict_SetItemString(d, "reload", item=PyCFunction_New(bpy_reload_meth, NULL)); Py_DECREF(item);
PyDict_SetItemString(d, "__import__", item=PyCFunction_New(bpy_import_meth, NULL)); Py_DECREF(item);
// PyDict_SetItemString(d, "reload", item=PyCFunction_New(&bpy_reload_meth, NULL)); Py_DECREF(item);
PyDict_SetItemString(d, "__import__", item=PyCFunction_New(&bpy_import_meth, NULL)); Py_DECREF(item);
/* move reload here
* XXX, use import hooks */
mod= PyImport_ImportModuleLevel((char *)"imp", NULL, NULL, NULL, 0);
if(mod) {
PyDict_SetItemString(PyModule_GetDict(mod), "reload", item=PyCFunction_New(&bpy_reload_meth, NULL)); Py_DECREF(item);
Py_DECREF(mod);
}
else {
BLI_assert(!"unable to load 'imp' module.");
}
}
pyrna_alloc_types();
#ifndef WITH_PYTHON_MODULE
py_tstate = PyGILState_GetThisThreadState();
PyEval_ReleaseThread(py_tstate);
#endif
}
void BPY_end_python( void )
void BPY_python_end(void)
{
// fprintf(stderr, "Ending Python!\n");
@@ -299,23 +328,55 @@ void BPY_end_python( void )
}
/* Can run a file or text block */
int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struct ReportList *reports)
static void python_script_error_jump_text(struct Text *text)
{
PyObject *py_dict, *py_result= NULL;
int lineno;
int offset;
python_script_error_jump(text->id.name+2, &lineno, &offset);
if(lineno != -1) {
/* select the line with the error */
txt_move_to(text, lineno - 1, INT_MAX, FALSE);
txt_move_to(text, lineno - 1, offset, TRUE);
}
}
/* super annoying, undo _PyModule_Clear(), bug [#23871] */
#define PYMODULE_CLEAR_WORKAROUND
#ifdef PYMODULE_CLEAR_WORKAROUND
/* bad!, we should never do this, but currently only safe way I could find to keep namespace.
* from being cleared. - campbell */
typedef struct {
PyObject_HEAD
PyObject *md_dict;
/* ommit other values, we only want the dict. */
} PyModuleObject;
#endif
int PyC_MainModule_Backup(PyObject **main_mod);
PyObject *PyC_DefaultNameSpace(const char *n);
int PyC_MainModule_Restore(PyObject *main_mod);
static int python_script_exec(bContext *C, const char *fn, struct Text *text, struct ReportList *reports)
{
PyObject *main_mod= NULL;
PyObject *py_dict= NULL, *py_result= NULL;
PyGILState_STATE gilstate;
BLI_assert(fn || text);
if (fn==NULL && text==NULL) {
return 0;
}
bpy_context_set(C, &gilstate);
PyC_MainModule_Backup(&main_mod);
if (text) {
char fn_dummy[FILE_MAXDIR];
bpy_text_filename_get(fn_dummy, text);
py_dict = bpy_namespace_dict_new(fn_dummy);
if( !text->compiled ) { /* if it wasn't already compiled, do it now */
char *buf = txt_to_buf( text );
@@ -324,139 +385,91 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc
MEM_freeN( buf );
if( PyErr_Occurred( ) ) {
BPY_free_compiled_text( text );
if(PyErr_Occurred()) {
python_script_error_jump_text(text);
BPY_text_free_code(text);
}
}
if(text->compiled)
py_result = PyEval_EvalCode( text->compiled, py_dict, py_dict );
if(text->compiled) {
py_dict = PyC_DefaultNameSpace(fn_dummy);
py_result = PyEval_EvalCode(text->compiled, py_dict, py_dict);
}
}
else {
FILE *fp= fopen(fn, "r");
py_dict = bpy_namespace_dict_new(fn);
if(fp) {
py_dict = PyC_DefaultNameSpace(fn);
#ifdef _WIN32
/* Previously we used PyRun_File to run directly the code on a FILE
/* Previously we used PyRun_File to run directly the code on a FILE
* object, but as written in the Python/C API Ref Manual, chapter 2,
* 'FILE structs for different C libraries can be different and
* 'FILE structs for different C libraries can be different and
* incompatible'.
* So now we load the script file data to a buffer */
char *pystring;
{
char *pystring;
fclose(fp);
fclose(fp);
pystring= MEM_mallocN(strlen(fn) + 32, "pystring");
pystring[0]= '\0';
sprintf(pystring, "exec(open(r'%s').read())", fn);
py_result = PyRun_String( pystring, Py_file_input, py_dict, py_dict );
MEM_freeN(pystring);
pystring= MEM_mallocN(strlen(fn) + 32, "pystring");
pystring[0]= '\0';
sprintf(pystring, "exec(open(r'%s').read())", fn);
py_result = PyRun_String( pystring, Py_file_input, py_dict, py_dict );
MEM_freeN(pystring);
}
#else
py_result = PyRun_File(fp, fn, Py_file_input, py_dict, py_dict);
fclose(fp);
#endif
}
else {
PyErr_Format(PyExc_SystemError, "Python file \"%s\" could not be opened: %s", fn, strerror(errno));
PyErr_Format(PyExc_IOError, "Python file \"%s\" could not be opened: %s", fn, strerror(errno));
py_result= NULL;
}
}
if (!py_result) {
if(text) {
python_script_error_jump_text(text);
}
BPy_errors_to_report(reports);
} else {
Py_DECREF( py_result );
}
PyDict_SetItemString(PyThreadState_GET()->interp->modules, "__main__", Py_None);
bpy_context_clear(C, &gilstate);
return py_result ? 1:0;
}
/* TODO - move into bpy_space.c ? */
/* GUI interface routines */
/* Copied from Draw.c */
static void exit_pydraw( SpaceScript * sc, short err )
{
Script *script = NULL;
if( !sc || !sc->script )
return;
script = sc->script;
if( err ) {
BPy_errors_to_report(NULL); // TODO, reports
script->flags = 0; /* mark script struct for deletion */
SCRIPT_SET_NULL(script);
script->scriptname[0] = '\0';
script->scriptarg[0] = '\0';
// XXX 2.5 error_pyscript();
// XXX 2.5 scrarea_queue_redraw( sc->area );
}
#if 0 // XXX 2.5
BPy_Set_DrawButtonsList(sc->but_refs);
BPy_Free_DrawButtonsList(); /*clear all temp button references*/
if(py_dict) {
#ifdef PYMODULE_CLEAR_WORKAROUND
PyModuleObject *mmod= (PyModuleObject *)PyDict_GetItemString(PyThreadState_GET()->interp->modules, "__main__");
PyObject *dict_back = mmod->md_dict;
/* freeing the module will clear the namespace,
* gives problems running classes defined in this namespace being used later. */
mmod->md_dict= NULL;
Py_DECREF(dict_back);
#endif
sc->but_refs = NULL;
Py_XDECREF( ( PyObject * ) script->py_draw );
Py_XDECREF( ( PyObject * ) script->py_event );
Py_XDECREF( ( PyObject * ) script->py_button );
script->py_draw = script->py_event = script->py_button = NULL;
}
static int bpy_run_script_init(bContext *C, SpaceScript * sc)
{
if (sc->script==NULL)
return 0;
if (sc->script->py_draw==NULL && sc->script->scriptname[0] != '\0')
BPY_run_python_script(C, sc->script->scriptname, NULL, NULL);
if (sc->script->py_draw==NULL)
return 0;
return 1;
}
int BPY_run_script_space_draw(const struct bContext *C, SpaceScript * sc)
{
if (bpy_run_script_init( (bContext *)C, sc)) {
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *result = PyObject_CallObject( sc->script->py_draw, NULL );
if (result==NULL)
exit_pydraw(sc, 1);
PyGILState_Release(gilstate);
#undef PYMODULE_CLEAR_WORKAROUND
}
return 1;
PyC_MainModule_Restore(main_mod);
bpy_context_clear(C, &gilstate);
return (py_result != NULL);
}
// XXX - not used yet, listeners dont get a context
int BPY_run_script_space_listener(bContext *C, SpaceScript * sc)
/* Can run a file or text block */
int BPY_filepath_exec(bContext *C, const char *filepath, struct ReportList *reports)
{
if (bpy_run_script_init(C, sc)) {
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *result = PyObject_CallObject( sc->script->py_draw, NULL );
if (result==NULL)
exit_pydraw(sc, 1);
PyGILState_Release(gilstate);
}
return 1;
return python_script_exec(C, filepath, NULL, reports);
}
int BPY_text_exec(bContext *C, struct Text *text, struct ReportList *reports)
{
return python_script_exec(C, NULL, text, reports);
}
void BPY_DECREF(void *pyob_ptr)
@@ -466,61 +479,12 @@ void BPY_DECREF(void *pyob_ptr)
PyGILState_Release(gilstate);
}
#if 0
/* called from the the scripts window, assume context is ok */
int BPY_run_python_script_space(const char *modulename, const char *func)
{
PyObject *py_dict, *py_result= NULL;
char pystring[512];
PyGILState_STATE gilstate;
/* for calling the module function */
PyObject *py_func,
gilstate = PyGILState_Ensure();
py_dict = bpy_namespace_dict_new("<dummy>");
PyObject *module = PyImport_ImportModule(scpt->script.filename);
if (module==NULL) {
PyErr_SetFormat(PyExc_SystemError, "could not import '%s'", scpt->script.filename);
}
else {
py_func = PyObject_GetAttrString(modulename, func);
if (py_func==NULL) {
PyErr_SetFormat(PyExc_SystemError, "module has no function '%s.%s'\n", scpt->script.filename, func);
}
else {
Py_DECREF(py_func);
if (!PyCallable_Check(py_func)) {
PyErr_SetFormat(PyExc_SystemError, "module item is not callable '%s.%s'\n", scpt->script.filename, func);
}
else {
py_result= PyObject_CallObject(py_func, NULL); // XXX will need args eventually
}
}
}
if (!py_result) {
BPy_errors_to_report(NULL); // TODO - reports
} else
Py_DECREF( py_result );
Py_XDECREF(module);
PyDict_SetItemString(PyThreadState_GET()->interp->modules, "__main__", Py_None);
PyGILState_Release(gilstate);
return 1;
}
#endif
int BPY_eval_button(bContext *C, const char *expr, double *value)
int BPY_button_exec(bContext *C, const char *expr, double *value)
{
PyGILState_STATE gilstate;
PyObject *py_dict, *mod, *retval;
int error_ret = 0;
PyObject *main_mod= NULL;
if (!value || !expr) return -1;
@@ -530,8 +494,10 @@ int BPY_eval_button(bContext *C, const char *expr, double *value)
}
bpy_context_set(C, &gilstate);
py_dict= bpy_namespace_dict_new("<blender button>");
PyC_MainModule_Backup(&main_mod);
py_dict= PyC_DefaultNameSpace("<blender button>");
mod = PyImport_ImportModule("math");
if (mod) {
@@ -581,16 +547,17 @@ int BPY_eval_button(bContext *C, const char *expr, double *value)
BPy_errors_to_report(CTX_wm_reports(C));
}
PyDict_SetItemString(PyThreadState_GET()->interp->modules, "__main__", Py_None);
PyC_MainModule_Backup(&main_mod);
bpy_context_clear(C, &gilstate);
return error_ret;
}
int BPY_eval_string(bContext *C, const char *expr)
int BPY_string_exec(bContext *C, const char *expr)
{
PyGILState_STATE gilstate;
PyObject *main_mod= NULL;
PyObject *py_dict, *retval;
int error_ret = 0;
@@ -602,7 +569,9 @@ int BPY_eval_string(bContext *C, const char *expr)
bpy_context_set(C, &gilstate);
py_dict= bpy_namespace_dict_new("<blender string>");
PyC_MainModule_Backup(&main_mod);
py_dict= PyC_DefaultNameSpace("<blender string>");
retval = PyRun_String(expr, Py_eval_input, py_dict, py_dict);
@@ -615,15 +584,15 @@ int BPY_eval_string(bContext *C, const char *expr)
Py_DECREF(retval);
}
PyDict_SetItemString(PyThreadState_GET()->interp->modules, "__main__", Py_None);
PyC_MainModule_Restore(main_mod);
bpy_context_clear(C, &gilstate);
return error_ret;
}
void BPY_load_user_modules(bContext *C)
void BPY_modules_load_user(bContext *C)
{
PyGILState_STATE gilstate;
Main *bmain= CTX_data_main(C);
@@ -656,7 +625,7 @@ void BPY_load_user_modules(bContext *C)
bpy_context_clear(C, &gilstate);
}
int BPY_context_get(bContext *C, const char *member, bContextDataResult *result)
int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *result)
{
PyObject *pyctx= (PyObject *)CTX_py_dict_get(C);
PyObject *item= PyDict_GetItemString(pyctx, member);
@@ -719,3 +688,102 @@ int BPY_context_get(bContext *C, const char *member, bContextDataResult *result)
return done;
}
#ifdef WITH_PYTHON_MODULE
#include "BLI_storage.h"
/* TODO, reloading the module isnt functional at the moment. */
extern int main_python(int argc, const char **argv);
static struct PyModuleDef bpy_proxy_def = {
PyModuleDef_HEAD_INIT,
"bpy", /* m_name */
NULL, /* m_doc */
0, /* m_size */
NULL, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
PyObject *mod;
} dealloc_obj;
/* call once __file__ is set */
void bpy_module_delay_init(PyObject *bpy_proxy)
{
const int argc= 1;
const char *argv[2];
const char *filename_rel= PyModule_GetFilename(bpy_proxy); /* can be relative */
char filename_abs[1024];
BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs));
BLI_path_cwd(filename_abs);
argv[0]= filename_abs;
argv[1]= NULL;
// printf("module found %s\n", argv[0]);
main_python(argc, argv);
/* initialized in BPy_init_modules() */
PyDict_Update(PyModule_GetDict(bpy_proxy), PyModule_GetDict(bpy_package_py));
}
static void dealloc_obj_dealloc(PyObject *self);
static PyTypeObject dealloc_obj_Type = {{{0}}};
/* use our own dealloc so we can free a property if we use one */
static void dealloc_obj_dealloc(PyObject *self)
{
bpy_module_delay_init(((dealloc_obj *)self)->mod);
/* Note, for subclassed PyObjects we cant just call PyObject_DEL() directly or it will crash */
dealloc_obj_Type.tp_free(self);
}
PyMODINIT_FUNC
PyInit_bpy(void)
{
PyObject *bpy_proxy= PyModule_Create(&bpy_proxy_def);
/* Problem:
* 1) this init function is expected to have a private member defined - 'md_def'
* but this is only set for C defined modules (not py packages)
* so we cant return 'bpy_package_py' as is.
*
* 2) there is a 'bpy' C module for python to load which is basically all of blender,
* and there is scripts/bpy/__init__.py,
* we may end up having to rename this module so there is no naming conflict here eg:
* 'from blender import bpy'
*
* 3) we dont know the filename at this point, workaround by assigning a dummy value
* which calls back when its freed so the real loading can take place.
*/
/* assign an object which is freed after __file__ is assigned */
dealloc_obj *dob;
/* assign dummy type */
dealloc_obj_Type.tp_name = "dealloc_obj";
dealloc_obj_Type.tp_basicsize = sizeof(dealloc_obj);
dealloc_obj_Type.tp_dealloc = dealloc_obj_dealloc;
dealloc_obj_Type.tp_flags = Py_TPFLAGS_DEFAULT;
if(PyType_Ready(&dealloc_obj_Type) < 0)
return NULL;
dob= (dealloc_obj *) dealloc_obj_Type.tp_alloc(&dealloc_obj_Type, 0);
dob->mod= bpy_proxy; /* borrow */
PyModule_AddObject(bpy_proxy, "__file__", (PyObject *)dob); /* borrow */
return bpy_proxy;
}
#endif

View File

@@ -24,14 +24,18 @@
*/
/* Note, this module is not to be used directly by the user.
* its accessed from blender with bpy.__ops__
* Internally its exposed as '_bpy.ops', which provides functions for 'bpy.ops', a python package.
* */
#include <Python.h>
#include "bpy_operator.h"
#include "bpy_operator_wrap.h"
#include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
#include "bpy_util.h"
#include "BLI_utildefines.h"
#include "RNA_enum_types.h"
#include "WM_api.h"
@@ -39,30 +43,53 @@
#include "MEM_guardedalloc.h"
#include "BKE_report.h"
#include "BKE_context.h"
static PyObject *pyop_poll( PyObject * self, PyObject * args)
static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
{
wmOperatorType *ot;
char *opname;
PyObject *context_dict= NULL; /* optional args */
PyObject *context_dict_back;
char *context_str= NULL;
PyObject *ret;
int context= WM_OP_EXEC_DEFAULT;
// XXX Todo, work out a better solution for passing on context, could make a tuple from self and pack the name and Context into it...
bContext *C = BPy_GetContext();
bContext *C= (bContext *)BPy_GetContext();
if (!PyArg_ParseTuple(args, "s|O:_bpy.ops.poll", &opname, &context_dict))
if(C==NULL) {
PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators");
return NULL;
}
if (!PyArg_ParseTuple(args, "s|Os:_bpy.ops.poll", &opname, &context_dict, &context_str))
return NULL;
ot= WM_operatortype_find(opname, TRUE);
if (ot == NULL) {
PyErr_Format(PyExc_SystemError, "Polling operator \"bpy.ops.%s\" error, could not be found", opname);
PyErr_Format(PyExc_AttributeError, "Polling operator \"bpy.ops.%s\" error, could not be found", opname);
return NULL;
}
if(!PyDict_Check(context_dict))
if(context_str) {
if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) {
char *enum_str= BPy_enum_as_string(operator_context_items);
PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s.poll\" error, expected a string enum in (%.200s)", opname, enum_str);
MEM_freeN(enum_str);
return NULL;
}
}
if(context_dict==NULL || context_dict==Py_None) {
context_dict= NULL;
}
else if (!PyDict_Check(context_dict)) {
PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s.poll\" error, custom context expected a dict or None, got a %.200s", opname, Py_TYPE(context_dict)->tp_name);
return NULL;
}
context_dict_back= CTX_py_dict_get(C);
@@ -70,7 +97,7 @@ static PyObject *pyop_poll( PyObject * self, PyObject * args)
Py_XINCREF(context_dict); /* so we done loose it */
/* main purpose of thsi function */
ret= WM_operator_poll((bContext*)C, ot) ? Py_True : Py_False;
ret= WM_operator_poll_context((bContext*)C, ot, context) ? Py_True : Py_False;
/* restore with original context dict, probably NULL but need this for nested operator calls */
Py_XDECREF(context_dict);
@@ -80,7 +107,7 @@ static PyObject *pyop_poll( PyObject * self, PyObject * args)
return ret;
}
static PyObject *pyop_call( PyObject * self, PyObject * args)
static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
{
wmOperatorType *ot;
int error_val = 0;
@@ -97,7 +124,12 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
int context= WM_OP_EXEC_DEFAULT;
// XXX Todo, work out a better solution for passing on context, could make a tuple from self and pack the name and Context into it...
bContext *C = BPy_GetContext();
bContext *C = (bContext *)BPy_GetContext();
if(C==NULL) {
PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators");
return NULL;
}
if (!PyArg_ParseTuple(args, "sO|O!s:_bpy.ops.call", &opname, &context_dict, &PyDict_Type, &kw, &context_str))
return NULL;
@@ -105,10 +137,15 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
ot= WM_operatortype_find(opname, TRUE);
if (ot == NULL) {
PyErr_Format( PyExc_SystemError, "Calling operator \"bpy.ops.%s\" error, could not be found", opname);
PyErr_Format(PyExc_AttributeError, "Calling operator \"bpy.ops.%s\" error, could not be found", opname);
return NULL;
}
if(!pyrna_write_check()) {
PyErr_Format(PyExc_RuntimeError, "Calling operator \"bpy.ops.%s\" error, can't modify blend data in this state (drawing/rendering)", opname);
return NULL;
}
if(context_str) {
if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) {
char *enum_str= BPy_enum_as_string(operator_context_items);
@@ -118,20 +155,28 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
}
}
if(!PyDict_Check(context_dict))
if(context_dict==NULL || context_dict==Py_None) {
context_dict= NULL;
}
else if (!PyDict_Check(context_dict)) {
PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s\" error, custom context expected a dict or None, got a %.200s", opname, Py_TYPE(context_dict)->tp_name);
return NULL;
}
context_dict_back= CTX_py_dict_get(C);
CTX_py_dict_set(C, (void *)context_dict);
Py_XINCREF(context_dict); /* so we done loose it */
if(WM_operator_poll((bContext*)C, ot) == FALSE) {
PyErr_Format( PyExc_SystemError, "Operator bpy.ops.%.200s.poll() failed, context is incorrect", opname);
if(WM_operator_poll_context((bContext*)C, ot, context) == FALSE) {
const char *msg= CTX_wm_operator_poll_msg_get(C);
PyErr_Format(PyExc_RuntimeError, "Operator bpy.ops.%.200s.poll() %.200s", opname, msg ? msg : "failed, context is incorrect");
CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */
error_val= -1;
}
else {
WM_operator_properties_create_ptr(&ptr, ot);
WM_operator_properties_sanitize(&ptr, 0);
if(kw && PyDict_Size(kw))
error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: ");
@@ -145,7 +190,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
operator_ret= WM_operator_call_py(C, ot, context, &ptr, reports);
if(BPy_reports_to_error(reports))
if(BPy_reports_to_error(reports, FALSE))
error_val = -1;
/* operator output is nice to have in the terminal/console too */
@@ -189,12 +234,18 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
return NULL;
}
/* when calling bpy.ops.wm.read_factory_settings() bpy.data's main pointer is freed by clear_globals(),
* further access will crash blender. setting context is not needed in this case, only calling because this
* function corrects bpy.data (internal Main pointer) */
BPY_modules_update(C);
/* 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)
static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args)
{
wmOperatorType *ot;
PointerRNA ptr;
@@ -207,15 +258,20 @@ static PyObject *pyop_as_string( PyObject * self, PyObject * args)
char *buf = NULL;
PyObject *pybuf;
bContext *C = BPy_GetContext();
bContext *C= (bContext *)BPy_GetContext();
if(C==NULL) {
PyErr_SetString(PyExc_RuntimeError, "Context is None, cant get the string representation of this object.");
return NULL;
}
if (!PyArg_ParseTuple(args, "s|O!i:_bpy.ops.as_string", &opname, &PyDict_Type, &kw, &all_args))
return NULL;
ot= WM_operatortype_find(opname, TRUE);
if (ot == NULL) {
PyErr_Format( PyExc_SystemError, "_bpy.ops.as_string: operator \"%s\"could not be found", opname);
PyErr_Format(PyExc_AttributeError, "_bpy.ops.as_string: operator \"%.200s\"could not be found", opname);
return NULL;
}
@@ -246,7 +302,7 @@ static PyObject *pyop_as_string( PyObject * self, PyObject * args)
return pybuf;
}
static PyObject *pyop_dir(PyObject *self)
static PyObject *pyop_dir(PyObject *UNUSED(self))
{
PyObject *list = PyList_New(0), *name;
wmOperatorType *ot;
@@ -260,7 +316,7 @@ static PyObject *pyop_dir(PyObject *self)
return list;
}
static PyObject *pyop_getrna(PyObject *self, PyObject *value)
static PyObject *pyop_getrna(PyObject *UNUSED(self), PyObject *value)
{
wmOperatorType *ot;
PointerRNA ptr;
@@ -282,6 +338,7 @@ static PyObject *pyop_getrna(PyObject *self, PyObject *value)
/* XXX - should call WM_operator_properties_free */
WM_operator_properties_create_ptr(&ptr, ot);
WM_operator_properties_sanitize(&ptr, 0);
pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr);
@@ -289,24 +346,30 @@ static PyObject *pyop_getrna(PyObject *self, PyObject *value)
return (PyObject *)pyrna;
}
PyObject *BPY_operator_module( void )
static struct PyMethodDef bpy_ops_methods[] = {
{"poll", (PyCFunction) pyop_poll, METH_VARARGS, NULL},
{"call", (PyCFunction) pyop_call, METH_VARARGS, NULL},
{"as_string", (PyCFunction) pyop_as_string, METH_VARARGS, NULL},
{"dir", (PyCFunction) pyop_dir, METH_NOARGS, NULL},
{"get_rna", (PyCFunction) pyop_getrna, METH_O, NULL},
{"macro_define", (PyCFunction) PYOP_wrap_macro_define, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef bpy_ops_module = {
PyModuleDef_HEAD_INIT,
"_bpy.ops",
NULL,
-1,/* multiple "initialization" just copies the module dict. */
bpy_ops_methods,
NULL, NULL, NULL, NULL
};
PyObject *BPY_operator_module(void)
{
static PyMethodDef pyop_poll_meth = {"poll", (PyCFunction) pyop_poll, METH_VARARGS, NULL};
static PyMethodDef pyop_call_meth = {"call", (PyCFunction) pyop_call, METH_VARARGS, NULL};
static PyMethodDef pyop_as_string_meth ={"as_string", (PyCFunction) pyop_as_string, METH_VARARGS, NULL};
static PyMethodDef pyop_dir_meth = {"dir", (PyCFunction) pyop_dir, METH_NOARGS, NULL};
static PyMethodDef pyop_getrna_meth = {"get_rna", (PyCFunction) pyop_getrna, METH_O, NULL};
static PyMethodDef pyop_macro_def_meth ={"macro_define", (PyCFunction) PYOP_wrap_macro_define, METH_VARARGS, NULL};
PyObject *submodule;
PyObject *submodule = PyModule_New("_bpy.ops");
PyDict_SetItemString(PyImport_GetModuleDict(), "_bpy.ops", submodule);
PyModule_AddObject( submodule, "poll", PyCFunction_New(&pyop_poll_meth, NULL) );
PyModule_AddObject( submodule, "call", PyCFunction_New(&pyop_call_meth, NULL) );
PyModule_AddObject( submodule, "as_string",PyCFunction_New(&pyop_as_string_meth,NULL) );
PyModule_AddObject( submodule, "dir", PyCFunction_New(&pyop_dir_meth, NULL) );
PyModule_AddObject( submodule, "get_rna", PyCFunction_New(&pyop_getrna_meth, NULL) );
PyModule_AddObject( submodule, "macro_define",PyCFunction_New(&pyop_macro_def_meth, NULL) );
submodule= PyModule_Create(&bpy_ops_module);
return submodule;
}

View File

@@ -1,6 +1,5 @@
/**
* $Id: bpy_operator.h 21094 2009-06-23 00:09:26Z gsrb3d $
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -25,13 +24,6 @@
#ifndef BPY_OPERATOR_H
#define BPY_OPERATOR_H
#include <Python.h>
#include "RNA_access.h"
#include "RNA_types.h"
#include "DNA_windowmanager_types.h"
#include "BKE_context.h"
extern PyTypeObject pyop_base_Type;
#define BPy_OperatorBase_Check(v) (PyObject_TypeCheck(v, &pyop_base_Type))

View File

@@ -22,10 +22,14 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#include "bpy_operator_wrap.h"
#include "WM_api.h"
#include "WM_types.h"
#include "BLI_utildefines.h"
#include "RNA_define.h"
#include "bpy_rna.h"
@@ -83,7 +87,7 @@ void macro_wrapper(wmOperatorType *ot, void *userdata)
operator_properties_init(ot);
}
PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args)
PyObject *PYOP_wrap_macro_define(PyObject *UNUSED(self), PyObject *args)
{
wmOperatorType *ot;
wmOperatorTypeMacro *otmacro;

View File

@@ -1,6 +1,5 @@
/**
* $Id: bpy_operator_wrap.h 21094 2009-06-23 00:09:26Z gsrb3d $
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -25,8 +24,13 @@
#ifndef BPY_OPERATOR_WRAP_H
#define BPY_OPERATOR_WRAP_H
#include <Python.h>
struct wmOperatorType;
/* these are used for operator methods, used by bpy_operator.c */
PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args);
/* exposed to rna/wm api */
void operator_wrapper(struct wmOperatorType *ot, void *userdata);
void macro_wrapper(struct wmOperatorType *ot, void *userdata);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -25,36 +25,8 @@
#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_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_IntVectorProperty(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);
PyObject *BPy_RemoveProperty(PyObject *self, PyObject *args, PyObject *kw);
extern char BPy_BoolProperty_doc[];
extern char BPy_BoolVectorProperty_doc[];
extern char BPy_IntProperty_doc[];
extern char BPy_IntVectorProperty_doc[];
extern char BPy_FloatProperty_doc[];
extern char BPy_FloatVectorProperty_doc[];
extern char BPy_StringProperty_doc[];
extern char BPy_EnumProperty_doc[];
extern char BPy_PointerProperty_doc[];
extern char BPy_CollectionProperty_doc[];\
extern char BPy_RemoveProperty_doc[];
#define PYRNA_STACK_ARRAY 32
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -24,12 +24,11 @@
#ifndef BPY_RNA_H
#define BPY_RNA_H
#include <Python.h>
#include "RNA_access.h"
#include "RNA_types.h"
#include "BKE_idprop.h"
extern PyTypeObject pyrna_struct_meta_idprop_Type;
extern PyTypeObject pyrna_struct_Type;
extern PyTypeObject pyrna_prop_Type;
extern PyTypeObject pyrna_prop_array_Type;
@@ -40,21 +39,33 @@ extern PyTypeObject pyrna_prop_collection_Type;
#define BPy_PropertyRNA_Check(v) (PyObject_TypeCheck(v, &pyrna_prop_Type))
#define BPy_PropertyRNA_CheckExact(v) (Py_TYPE(v) == &pyrna_prop_Type)
/* play it safe and keep optional for now, need to test further now this affects looping on 10000's of verts for eg. */
// #define USE_WEAKREFS
typedef struct {
PyObject_HEAD /* required python macro */
PointerRNA ptr;
PointerRNA ptr;
#ifdef USE_WEAKREFS
PyObject *in_weakreflist;
#endif
} BPy_DummyPointerRNA;
typedef struct {
PyObject_HEAD /* required python macro */
PointerRNA ptr;
int freeptr; /* needed in some cases if ptr.data is created on the fly, free when deallocing */
#ifdef USE_WEAKREFS
PyObject *in_weakreflist;
#endif
} BPy_StructRNA;
typedef struct {
PyObject_HEAD /* required python macro */
PointerRNA ptr;
PropertyRNA *prop;
#ifdef USE_WEAKREFS
PyObject *in_weakreflist;
#endif
} BPy_PropertyRNA;
typedef struct {
@@ -65,6 +76,9 @@ typedef struct {
/* Arystan: this is a hack to allow sub-item r/w access like: face.uv[n][m] */
int arraydim; /* array dimension, e.g: 0 for face.uv, 2 for face.uv[n][m], etc. */
int arrayoffset; /* array first item offset, e.g. if face.uv is [4][2], arrayoffset for face.uv[n] is 2n */
#ifdef USE_WEAKREFS
PyObject *in_weakreflist;
#endif
} BPy_PropertyArrayRNA;
/* cheap trick */
@@ -98,12 +112,21 @@ void pyrna_alloc_types(void);
void pyrna_free_types(void);
/* primitive type conversion */
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(PointerRNA *ptr, PropertyRNA *prop, 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_array_index(PointerRNA *ptr, PropertyRNA *prop, int index);
PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop);
PyObject *pyrna_py_from_array_index(BPy_PropertyArrayRNA *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);
int pyrna_write_check(void);
void BPY_modules_update(struct bContext *C); //XXX temp solution
/* bpy.utils.(un)register_class */
extern PyMethodDef meth_bpy_register_class;
extern PyMethodDef meth_bpy_unregister_class;
#endif

View File

@@ -0,0 +1,628 @@
/*
* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Arystanbek Dyussenov
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#include "bpy_rna.h"
#include "BKE_global.h"
#include "MEM_guardedalloc.h"
#define MAX_ARRAY_DIMENSION 10
typedef void (*ItemConvertFunc)(PyObject *, char *);
typedef int (*ItemTypeCheckFunc)(PyObject *);
typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *);
/*
arr[3][4][5]
0 1 2 <- dimension index
*/
/*
arr[2] = x
py_to_array_index(arraydim=0, arrayoffset=0, index=2)
validate_array(lvalue_dim=0)
... make real index ...
*/
/* arr[3]=x, self->arraydim is 0, lvalue_dim is 1 */
/* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */
static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[],
ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
{
int i;
/* not the last dimension */
if (dim + 1 < totdim) {
/* check that a sequence contains dimsize[dim] items */
const int seq_size= PySequence_Size(seq);
for (i= 0; i < seq_size; i++) {
PyObject *item;
int ok= 1;
item= PySequence_GetItem(seq, i);
if (!PySequence_Check(item)) {
/* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */
PyErr_Format(PyExc_TypeError, "%s expected a sequence of %s, not %s", error_prefix, item_type_str, Py_TYPE(item)->tp_name);
ok= 0;
}
/* arr[3][4][5]
dimsize[1]=4
dimsize[2]=5
dim=0 */
else if (PySequence_Size(item) != dimsize[dim + 1]) {
/* BLI_snprintf(error_str, error_str_size, "sequences of dimension %d should contain %d items", (int)dim + 1, (int)dimsize[dim + 1]); */
PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items", error_prefix, (int)dim + 1, (int)dimsize[dim + 1]);
ok= 0;
}
else if (!validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix)) {
ok= 0;
}
Py_DECREF(item);
if (!ok)
return 0;
}
}
else {
/* check that items are of correct type */
const int seq_size= PySequence_Size(seq);
for (i= 0; i < seq_size; i++) {
PyObject *item= PySequence_GetItem(seq, i);
if (!check_item_type(item)) {
Py_DECREF(item);
/* BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); */
PyErr_Format(PyExc_TypeError, "%s expected sequence items of type %s, not %s", error_prefix, item_type_str, Py_TYPE(item)->tp_name);
return 0;
}
Py_DECREF(item);
}
}
return 1;
}
/* Returns the number of items in a single- or multi-dimensional sequence. */
static int count_items(PyObject *seq, int dim)
{
int totitem= 0;
if(dim > 1) {
const int seq_size= PySequence_Size(seq);
int i;
for (i= 0; i < seq_size; i++) {
PyObject *item= PySequence_GetItem(seq, i);
totitem += count_items(item, dim - 1);
Py_DECREF(item);
}
}
else {
totitem= PySequence_Size(seq);
}
return totitem;
}
/* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int *totitem, const char *error_prefix)
{
int dimsize[MAX_ARRAY_DIMENSION];
int tot, totdim, len;
totdim= RNA_property_array_dimension(ptr, prop, dimsize);
tot= count_items(rvalue, totdim);
if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
if (RNA_property_array_length(ptr, prop) != tot) {
#if 0
/* length is flexible */
if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) {
/* BLI_snprintf(error_str, error_str_size, "%s.%s: array length cannot be changed to %d", RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */
PyErr_Format(PyExc_ValueError, "%s %s.%s: array length cannot be changed to %d", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot);
return 0;
}
#else
*totitem= tot;
return 1;
#endif
}
len= tot;
}
else {
/* length is a constraint */
if (!lvalue_dim) {
len= RNA_property_array_length(ptr, prop);
}
/* array item assignment */
else {
int i;
len= 1;
/* arr[3][4][5]
arr[2] = x
dimsize={4, 5}
dimsize[1] = 4
dimsize[2] = 5
lvalue_dim=0, totdim=3
arr[2][3] = x
lvalue_dim=1
arr[2][3][4] = x
lvalue_dim=2 */
for (i= lvalue_dim; i < totdim; i++)
len *= dimsize[i];
}
if (tot != len) {
/* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */
PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, sequence must have %d items total, not %d", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), len, tot);
return 0;
}
}
*totitem= len;
return 1;
}
static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *totitem, const char *error_prefix)
{
int dimsize[MAX_ARRAY_DIMENSION];
int totdim= RNA_property_array_dimension(ptr, prop, dimsize);
/* validate type first because length validation may modify property array length */
if (!validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix))
return 0;
return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix);
}
static char *copy_value_single(PyObject *item, PointerRNA *ptr, PropertyRNA *prop, char *data, unsigned int item_size, int *index, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
{
if (!data) {
char value[sizeof(int)];
convert_item(item, value);
rna_set_index(ptr, prop, *index, value);
*index = *index + 1;
}
else {
convert_item(item, data);
data += item_size;
}
return data;
}
static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, int dim, char *data, unsigned int item_size, int *index, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
{
unsigned int i;
int totdim= RNA_property_array_dimension(ptr, prop, NULL);
const int seq_size= PySequence_Size(seq);
for (i= 0; i < seq_size; i++) {
PyObject *item= PySequence_GetItem(seq, i);
if (dim + 1 < totdim) {
data= copy_values(item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
}
else {
data= copy_value_single(item, ptr, prop, data, item_size, index, convert_item, rna_set_index);
}
Py_DECREF(item);
}
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)
{
/*int totdim, dim_size[MAX_ARRAY_DIMENSION];*/
int totitem;
char *data= NULL;
/*totdim= RNA_property_array_dimension(ptr, prop, dim_size);*/ /*UNUSED*/
if (!validate_array(py, ptr, prop, 0, check_item_type, item_type_str, &totitem, error_prefix)) {
return 0;
}
if (totitem) {
/* note: this code is confusing */
if(param_data && RNA_property_flag(prop) & PROP_DYNAMIC) {
/* not freeing allocated mem, RNA_parameter_list_free() will do this */
ParameterDynAlloc *param_alloc= (ParameterDynAlloc *)param_data;
param_alloc->array_tot= (int)totitem;
param_alloc->array= MEM_callocN(item_size * totitem, "py_to_array dyn"); /* freeing param list will free */
data= param_alloc->array;
}
else if (param_data) {
data= param_data;
}
else {
data= PyMem_MALLOC(item_size * totitem);
}
copy_values(py, ptr, prop, 0, data, item_size, NULL, convert_item, NULL);
if (param_data==NULL) {
/* NULL can only pass through in case RNA property arraylength is 0 (impossible?) */
rna_set_array(ptr, prop, data);
PyMem_FREE(data);
}
}
return 1;
}
static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int arrayoffset, int index, ItemTypeCheckFunc check_item_type, const char *item_type_str, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
{
int totdim, dimsize[MAX_ARRAY_DIMENSION];
int totitem, i;
totdim= RNA_property_array_dimension(ptr, prop, dimsize);
/* convert index */
/* arr[3][4][5]
arr[2] = x
lvalue_dim=0, index = 0 + 2 * 4 * 5
arr[2][3] = x
lvalue_dim=1, index = 40 + 3 * 5 */
lvalue_dim++;
for (i= lvalue_dim; i < totdim; i++)
index *= dimsize[i];
index += arrayoffset;
if(lvalue_dim == totdim) { /* single item, assign directly */
if(!check_item_type(py)) {
PyErr_Format(PyExc_TypeError, "%s %.200s.%.200s, expected a %s type, not %s", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), item_type_str, Py_TYPE(py)->tp_name);
return 0;
}
copy_value_single(py, ptr, prop, NULL, 0, &index, convert_item, rna_set_index);
}
else {
if (!validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix)) {
return 0;
}
if (totitem) {
copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index);
}
}
return 1;
}
static void py_to_float(PyObject *py, char *data)
{
*(float*)data= (float)PyFloat_AsDouble(py);
}
static void py_to_int(PyObject *py, char *data)
{
*(int*)data= (int)PyLong_AsSsize_t(py);
}
static void py_to_bool(PyObject *py, char *data)
{
*(int*)data= (int)PyObject_IsTrue(py);
}
static int py_float_check(PyObject *py)
{
/* accept both floats and integers */
return PyNumber_Check(py);
}
static int py_int_check(PyObject *py)
{
/* accept only integers */
return PyLong_Check(py);
}
static int py_bool_check(PyObject *py)
{
return PyBool_Check(py);
}
static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
{
RNA_property_float_set_index(ptr, prop, index, *(float*)value);
}
static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
{
RNA_property_int_set_index(ptr, prop, index, *(int*)value);
}
static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
{
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 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);
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);
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);
break;
default:
PyErr_SetString(PyExc_TypeError, "not an array type");
ret= 0;
}
return ret;
}
int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix)
{
int ret;
switch (RNA_property_type(prop)) {
case PROP_FLOAT:
ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_float_check, "float", py_to_float, float_set_index, error_prefix);
break;
case PROP_INT:
ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_int_check, "int", py_to_int, int_set_index, error_prefix);
break;
case PROP_BOOLEAN:
ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_bool_check, "boolean", py_to_bool, bool_set_index, error_prefix);
break;
default:
PyErr_SetString(PyExc_TypeError, "not an array type");
ret= 0;
}
return ret;
}
PyObject *pyrna_array_index(PointerRNA *ptr, PropertyRNA *prop, int index)
{
PyObject *item;
switch (RNA_property_type(prop)) {
case PROP_FLOAT:
item= PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index));
break;
case PROP_BOOLEAN:
item= PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index));
break;
case PROP_INT:
item= PyLong_FromSsize_t(RNA_property_int_get_index(ptr, prop, index));
break;
default:
PyErr_SetString(PyExc_TypeError, "not an array type");
item= NULL;
}
return item;
}
#if 0
/* XXX this is not used (and never will?) */
/* Given an array property, creates an N-dimensional tuple of values. */
static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop, int dim, int *index)
{
PyObject *tuple;
int i, len;
int totdim= RNA_property_array_dimension(ptr, prop, NULL);
len= RNA_property_multi_array_length(ptr, prop, dim);
tuple= PyTuple_New(len);
for (i= 0; i < len; i++) {
PyObject *item;
if (dim + 1 < totdim)
item= pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
else {
item= pyrna_array_index(ptr, prop, *index);
*index= *index + 1;
}
if (!item) {
Py_DECREF(tuple);
return NULL;
}
PyTuple_SET_ITEM(tuple, i, item);
}
return tuple;
}
#endif
PyObject *pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index)
{
int totdim, arraydim, arrayoffset, dimsize[MAX_ARRAY_DIMENSION], i, len;
BPy_PropertyArrayRNA *ret= NULL;
arraydim= self ? self->arraydim : 0;
arrayoffset = self ? self->arrayoffset : 0;
/* just in case check */
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);
PyErr_SetString(PyExc_IndexError, "out of range");
return NULL;
}
totdim= RNA_property_array_dimension(ptr, prop, dimsize);
if (arraydim + 1 < totdim) {
ret= (BPy_PropertyArrayRNA*)pyrna_prop_CreatePyObject(ptr, prop);
ret->arraydim= arraydim + 1;
/* arr[3][4][5]
x = arr[2]
index = 0 + 2 * 4 * 5
x = arr[2][3]
index = offset + 3 * 5 */
for (i= arraydim + 1; i < totdim; i++)
index *= dimsize[i];
ret->arrayoffset= arrayoffset + index;
}
else {
index = arrayoffset + index;
ret= (BPy_PropertyArrayRNA *)pyrna_array_index(ptr, prop, index);
}
return (PyObject*)ret;
}
PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
{
PyObject *ret;
ret= pyrna_math_object_from_array(ptr, prop);
/* is this a maths object? */
if (ret) return ret;
return pyrna_prop_CreatePyObject(ptr, prop);
}
/* TODO, multi-dimensional arrays */
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
{
int len= RNA_property_array_length(ptr, prop);
int type;
int i;
if(len==0) /* possible with dynamic arrays */
return 0;
if (RNA_property_array_dimension(ptr, prop, NULL) > 1) {
PyErr_SetString(PyExc_TypeError, "PropertyRNA - multi dimensional arrays not supported yet");
return -1;
}
type= RNA_property_type(prop);
switch (type) {
case PROP_FLOAT:
{
float value_f= PyFloat_AsDouble(value);
if(value_f==-1 && PyErr_Occurred()) {
PyErr_Clear();
return 0;
}
else {
float tmp[32];
float *tmp_arr;
if(len * sizeof(float) > sizeof(tmp)) {
tmp_arr= PyMem_MALLOC(len * sizeof(float));
}
else {
tmp_arr= tmp;
}
RNA_property_float_get_array(ptr, prop, tmp_arr);
for(i=0; i<len; i++)
if(tmp_arr[i] == value_f)
break;
if(tmp_arr != tmp)
PyMem_FREE(tmp_arr);
return i<len ? 1 : 0;
}
break;
}
case PROP_BOOLEAN:
case PROP_INT:
{
int value_i= PyLong_AsSsize_t(value);
if(value_i==-1 && PyErr_Occurred()) {
PyErr_Clear();
return 0;
}
else {
int tmp[32];
int *tmp_arr;
if(len * sizeof(int) > sizeof(tmp)) {
tmp_arr= PyMem_MALLOC(len * sizeof(int));
}
else {
tmp_arr= tmp;
}
if(type==PROP_BOOLEAN)
RNA_property_boolean_get_array(ptr, prop, tmp_arr);
else
RNA_property_int_get_array(ptr, prop, tmp_arr);
for(i=0; i<len; i++)
if(tmp_arr[i] == value_i)
break;
if(tmp_arr != tmp)
PyMem_FREE(tmp_arr);
return i<len ? 1 : 0;
}
break;
}
}
/* should never reach this */
PyErr_SetString(PyExc_TypeError, "PropertyRNA - type not in float/bool/int");
return -1;
}

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -22,11 +22,16 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#include "bpy_rna.h"
#include "bpy_rna_callback.h"
#include "bpy_util.h"
#include "BLI_utildefines.h"
#include "DNA_screen_types.h"
#include "BKE_context.h"
#include "ED_space_api.h"
@@ -34,7 +39,7 @@
#define RNA_CAPSULE_ID "RNA_HANDLE"
#define RNA_CAPSULE_ID_INVALID "RNA_HANDLE_REMOVED"
void cb_region_draw(const bContext *C, ARegion *ar, void *customdata)
static void cb_region_draw(const bContext *C, ARegion *UNUSED(ar), void *customdata)
{
PyObject *cb_func, *cb_args, *result;
PyGILState_STATE gilstate;
@@ -110,7 +115,7 @@ PyObject *pyrna_callback_remove(BPy_StructRNA *self, PyObject *args)
handle= PyCapsule_GetPointer(py_handle, RNA_CAPSULE_ID);
if(handle==NULL) {
PyErr_SetString(PyExc_ValueError, "callback_remove(handle): NULL handle given, invalid or already removed.");
PyErr_SetString(PyExc_ValueError, "callback_remove(handle): NULL handle given, invalid or already removed");
return NULL;
}

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -25,5 +25,5 @@
struct BPy_StructRNA;
struct PyObject;
struct PyObject *pyrna_callback_add(struct BPy_StructRNA *self, struct PyObject *args);
struct PyObject *pyrna_callback_remove(struct BPy_StructRNA *self, struct PyObject *args);
PyObject *pyrna_callback_add(BPy_StructRNA *self, PyObject *args);
PyObject *pyrna_callback_remove(BPy_StructRNA *self, PyObject *args);

View File

@@ -0,0 +1,151 @@
/*
* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#include <frameobject.h>
#include "bpy_traceback.h"
static const char *traceback_filepath(PyTracebackObject *tb)
{
return _PyUnicode_AsString(tb->tb_frame->f_code->co_filename);
}
/* copied from pythonrun.c, 3.2.0 */
static int
parse_syntax_error(PyObject *err, PyObject **message, const char **filename,
int *lineno, int *offset, const char **text)
{
long hold;
PyObject *v;
/* old style errors */
if (PyTuple_Check(err))
return PyArg_ParseTuple(err, "O(ziiz)", message, filename,
lineno, offset, text);
/* new style errors. `err' is an instance */
if (! (v = PyObject_GetAttrString(err, "msg")))
goto finally;
*message = v;
if (!(v = PyObject_GetAttrString(err, "filename")))
goto finally;
if (v == Py_None)
*filename = NULL;
else if (! (*filename = _PyUnicode_AsString(v)))
goto finally;
Py_DECREF(v);
if (!(v = PyObject_GetAttrString(err, "lineno")))
goto finally;
hold = PyLong_AsLong(v);
Py_DECREF(v);
v = NULL;
if (hold < 0 && PyErr_Occurred())
goto finally;
*lineno = (int)hold;
if (!(v = PyObject_GetAttrString(err, "offset")))
goto finally;
if (v == Py_None) {
*offset = -1;
Py_DECREF(v);
v = NULL;
} else {
hold = PyLong_AsLong(v);
Py_DECREF(v);
v = NULL;
if (hold < 0 && PyErr_Occurred())
goto finally;
*offset = (int)hold;
}
if (!(v = PyObject_GetAttrString(err, "text")))
goto finally;
if (v == Py_None)
*text = NULL;
else if (!PyUnicode_Check(v) ||
!(*text = _PyUnicode_AsString(v)))
goto finally;
Py_DECREF(v);
return 1;
finally:
Py_XDECREF(v);
return 0;
}
/* end copied function! */
void python_script_error_jump(const char *filepath, int *lineno, int *offset)
{
PyObject *exception, *value;
PyTracebackObject *tb;
*lineno= -1;
*offset= 0;
PyErr_Fetch(&exception, &value, (PyObject **)&tb);
if(exception && PyErr_GivenExceptionMatches(exception, PyExc_SyntaxError)) {
/* no traceback available when SyntaxError.
* python has no api's to this. reference parse_syntax_error() from pythonrun.c */
PyErr_NormalizeException(&exception, &value, (PyObject **)&tb);
PyErr_Restore(exception, value, (PyObject *)tb); /* takes away reference! */
if(value) { /* should always be true */
PyObject *message;
const char *filename, *text;
if(parse_syntax_error(value, &message, &filename, lineno, offset, &text)) {
/* python adds a '/', prefix, so check for both */
if( (strcmp(filename, filepath) == 0) ||
((filename[0] == '\\' || filename[0] == '/') && strcmp(filename + 1, filepath) == 0)
) {
/* good */
}
else {
*lineno= -1;
}
}
else {
*lineno= -1;
}
}
/* this avoids an abort in Python 2.3's garbage collecting */
}
else {
PyErr_NormalizeException(&exception, &value, (PyObject **)&tb);
PyErr_Restore(exception, value, (PyObject *)tb); /* takes away reference! */
PyErr_Print();
for(tb= (PyTracebackObject *)PySys_GetObject("last_traceback"); tb && (PyObject *)tb != Py_None; tb= tb->tb_next) {
if(strcmp(traceback_filepath(tb), filepath) != 0) {
*lineno= tb->tb_lineno;
break;
}
}
}
}

View File

@@ -0,0 +1,28 @@
/*
* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BPY_TRACEBACK_H
#define BPY_TRACEBACK_H
void python_script_error_jump(const char *filepath, int *lineno, int *offset);
#endif // BPY_TRACEBACK_H

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -22,6 +22,8 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#include "bpy_util.h"
#include "BLI_dynstr.h"
#include "MEM_guardedalloc.h"
@@ -30,97 +32,9 @@
#include "../generic/py_capi_utils.h"
bContext* __py_context = NULL;
bContext* BPy_GetContext(void) { return __py_context; };
void BPy_SetContext(bContext *C) { __py_context= C; };
int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_class, BPY_class_attr_check* class_attrs, PyObject **py_class_attrs)
{
PyObject *item, *fitem;
PyObject *py_arg_count;
int i, arg_count;
if (base_class) {
if (!PyObject_IsSubclass(class, base_class)) {
PyObject *name= PyObject_GetAttrString(base_class, "__name__");
PyErr_Format( PyExc_AttributeError, "expected %s subclass of class \"%s\"", class_type, name ? _PyUnicode_AsString(name):"<UNKNOWN>");
Py_XDECREF(name);
return -1;
}
}
for(i= 0;class_attrs->name; class_attrs++, i++) {
item = PyObject_GetAttrString(class, class_attrs->name);
if (py_class_attrs)
py_class_attrs[i]= item;
if (item==NULL) {
if ((class_attrs->flag & BPY_CLASS_ATTR_OPTIONAL)==0) {
PyErr_Format( PyExc_AttributeError, "expected %s class to have an \"%s\" attribute", class_type, class_attrs->name);
return -1;
}
PyErr_Clear();
}
else {
Py_DECREF(item); /* no need to keep a ref, the class owns it */
if((item==Py_None) && (class_attrs->flag & BPY_CLASS_ATTR_NONE_OK)) {
/* dont do anything, this is ok, dont bother checking other types */
}
else {
switch(class_attrs->type) {
case 's':
if (PyUnicode_Check(item)==0) {
PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a string", class_type, class_attrs->name);
return -1;
}
if(class_attrs->len != -1 && class_attrs->len < PyUnicode_GetSize(item)) {
PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute string to be shorter then %d", class_type, class_attrs->name, class_attrs->len);
return -1;
}
break;
case 'l':
if (PyList_Check(item)==0) {
PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a list", class_type, class_attrs->name);
return -1;
}
if(class_attrs->len != -1 && class_attrs->len < PyList_GET_SIZE(item)) {
PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute list to be shorter then %d", class_type, class_attrs->name, class_attrs->len);
return -1;
}
break;
case 'f':
if (PyMethod_Check(item))
fitem= PyMethod_Function(item); /* py 2.x */
else
fitem= item; /* py 3.x */
if (PyFunction_Check(fitem)==0) {
PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a function", class_type, class_attrs->name);
return -1;
}
if (class_attrs->arg_count >= 0) { /* -1 if we dont care*/
py_arg_count = PyObject_GetAttrString(PyFunction_GET_CODE(fitem), "co_argcount");
arg_count = PyLong_AsSsize_t(py_arg_count);
Py_DECREF(py_arg_count);
if (arg_count != class_attrs->arg_count) {
PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" function to have %d args", class_type, class_attrs->name, class_attrs->arg_count);
return -1;
}
}
break;
}
}
}
}
return 0;
}
static bContext* __py_context = NULL;
bContext* BPy_GetContext(void) { return __py_context; }
void BPy_SetContext(bContext *C) { __py_context= C; }
char *BPy_enum_as_string(EnumPropertyItem *item)
{
@@ -138,14 +52,18 @@ char *BPy_enum_as_string(EnumPropertyItem *item)
return cstring;
}
int BPy_reports_to_error(ReportList *reports)
short BPy_reports_to_error(ReportList *reports, const short clear)
{
char *report_str;
report_str= BKE_reports_string(reports, RPT_ERROR);
if(clear) {
BKE_reports_clear(reports);
}
if(report_str) {
PyErr_SetString(PyExc_SystemError, report_str);
PyErr_SetString(PyExc_RuntimeError, report_str);
MEM_freeN(report_str);
}
@@ -153,7 +71,7 @@ int BPy_reports_to_error(ReportList *reports)
}
int BPy_errors_to_report(ReportList *reports)
short BPy_errors_to_report(ReportList *reports)
{
PyObject *pystring;
PyObject *pystring_format= NULL; // workaround, see below
@@ -201,7 +119,7 @@ int BPy_errors_to_report(ReportList *reports)
}
/* array utility function */
int PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, char *error_prefix)
int PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, const char *error_prefix)
{
PyObject *value_fast;
int value_len;
@@ -215,7 +133,7 @@ int PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, ch
if(value_len != length) {
Py_DECREF(value);
PyErr_Format(PyExc_TypeError, "%s: invalid sequence length. expected %d, got %d.", error_prefix, length, value_len);
PyErr_Format(PyExc_TypeError, "%.200s: invalid sequence length. expected %d, got %d", error_prefix, length, value_len);
return -1;
}
@@ -240,14 +158,14 @@ int PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, ch
}
else {
Py_DECREF(value_fast);
PyErr_Format(PyExc_TypeError, "%s: internal error %s is invalid.", error_prefix, type->tp_name);
PyErr_Format(PyExc_TypeError, "%s: internal error %s is invalid", error_prefix, type->tp_name);
return -1;
}
Py_DECREF(value_fast);
if(PyErr_Occurred()) {
PyErr_Format(PyExc_TypeError, "%s: one or more items could not be used as a %s.", error_prefix, type->tp_name);
PyErr_Format(PyExc_TypeError, "%s: one or more items could not be used as a %s", error_prefix, type->tp_name);
return -1;
}

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -22,8 +22,6 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
#ifndef BPY_UTIL_H
#define BPY_UTIL_H
@@ -36,29 +34,13 @@
struct EnumPropertyItem;
struct ReportList;
/* Class type checking, use for checking classes can be added as operators, panels etc */
typedef struct BPY_class_attr_check {
const char *name; /* name of the class attribute */
char type; /* 's' = string, 'f' = function, 'l' = list, (add as needed) */
int arg_count; /* only for function types, -1 for undefined, includes self arg */
int len; /* only for string types currently */
int flag; /* other options */
} BPY_class_attr_check;
/* BPY_class_attr_check, flag */
#define BPY_CLASS_ATTR_OPTIONAL 1
#define BPY_CLASS_ATTR_NONE_OK 2
int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_class, BPY_class_attr_check* class_attrs, PyObject **py_class_attrs);
char *BPy_enum_as_string(struct EnumPropertyItem *item);
#define BLANK_PYTHON_TYPE {PyVarObject_HEAD_INIT(NULL, 0) 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
#define BLANK_PYTHON_TYPE {PyVarObject_HEAD_INIT(NULL, 0) NULL}
/* error reporting */
int BPy_reports_to_error(struct ReportList *reports);
int BPy_errors_to_report(struct ReportList *reports);
short BPy_reports_to_error(struct ReportList *reports, const short clear);
short BPy_errors_to_report(struct ReportList *reports);
/* TODO - find a better solution! */
struct bContext *BPy_GetContext(void);

View File

@@ -1,4 +1,4 @@
/**
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -27,11 +27,10 @@
*/
/* python, will come back */
//void BPY_run_python_script() {}
//void BPY_start_python() {}
void BPY_call_importloader() {}
//void BPY_free_compiled_text() {}
void BPY_pyconstraint_eval() {}
void BPY_pyconstraint_target() {}
int BPY_is_pyconstraint() {return 0;}
void BPY_pyconstraint_update() {}
//void BPY_script_exec(void) {}
//void BPY_python_start(void) {}
//void BPY_text_free_code(void) {}
void BPY_pyconstraint_exec(void) {}
void BPY_pyconstraint_target(void) {}
int BPY_is_pyconstraint(void) {return 0;}
void BPY_pyconstraint_update(void) {}

View File

@@ -18,114 +18,125 @@
#
# #**** END GPL LICENSE BLOCK #****
# <pep8 compliant>
if 1:
# Print once every 1000
GEN_PATH = True
PRINT_DATA = False
PRINT_DATA_INT = 1000
VERBOSE = False
VERBOSE_TYPE = False
MAX_RECURSIVE = 8
# Print once every 1000
GEN_PATH = True
PRINT_DATA = False
PRINT_DATA_INT = 1000
VERBOSE = False
VERBOSE_TYPE = False
MAX_RECURSIVE = 8
else:
# Print everything
GEN_PATH = True
PRINT_DATA = True
PRINT_DATA_INT = 0
VERBOSE = False
VERBOSE_TYPE = False
MAX_RECURSIVE = 8
# Print everything
GEN_PATH = True
PRINT_DATA = True
PRINT_DATA_INT = 0
VERBOSE = False
VERBOSE_TYPE = False
MAX_RECURSIVE = 8
seek_count = [0]
def seek(r, txt, recurs):
seek_count[0] += 1
seek_count[0] += 1
if PRINT_DATA_INT:
if not (seek_count[0] % PRINT_DATA_INT):
print(seek_count[0], txt)
if PRINT_DATA_INT:
if not (seek_count[0] % PRINT_DATA_INT):
print(seek_count[0], txt)
if PRINT_DATA:
print(txt)
if PRINT_DATA:
print(txt)
newtxt = ''
newtxt = ''
if recurs > MAX_RECURSIVE:
#print ("Recursion is over max")
#print (txt)
return
if recurs > MAX_RECURSIVE:
#print ("Recursion is over max")
#print (txt)
return
type_r = type(r)
type_r = type(r)
# print(type_r)
# print(dir(r))
# print(type_r)
# print(dir(r))
# basic types
if type_r in (float, int, bool, type(None)):
if PRINT_DATA:
print(txt + ' -> ' + str(r))
return
# basic types
if type_r in (float, int, bool, type(None)):
if PRINT_DATA:
print(txt + ' -> ' + str(r))
return
if type_r == str:
if PRINT_DATA:
print(txt + ' -> "' + str(r) + '"')
return
if type_r == str:
if PRINT_DATA:
print(txt + ' -> "' + str(r) + '"')
return
try: keys = r.keys()
except: keys = None
try:
keys = r.keys()
except:
keys = None
if keys != None:
if PRINT_DATA:
print(txt + '.keys() - ' + str(r.keys()))
if keys != None:
if PRINT_DATA:
print(txt + '.keys() - ' + str(r.keys()))
try: __members__ = dir(r)
except: __members__ = []
try:
__members__ = dir(r)
except:
__members__ = []
for item in __members__:
if item.startswith('__'):
continue
for item in __members__:
if item.startswith("__"):
continue
if GEN_PATH: newtxt = txt + '.' + item
if GEN_PATH:
newtxt = txt + '.' + item
if item == 'rna_type' and VERBOSE_TYPE==False: # just avoid because it spits out loads of data
continue
if item == 'rna_type' and VERBOSE_TYPE == False: # just avoid because it spits out loads of data
continue
try: value = getattr(r, item)
except: value = None
value = getattr(r, item, None)
seek( value, newtxt, recurs + 1)
seek(value, newtxt, recurs + 1)
if keys:
for k in keys:
if GEN_PATH:
newtxt = txt + '["' + k + '"]'
seek(r.__getitem__(k), newtxt, recurs + 1)
if keys:
for k in keys:
if GEN_PATH: newtxt = txt + '["' + k + '"]'
seek(r.__getitem__(k), newtxt, recurs+1)
else:
try:
length = len(r)
except:
length = 0
else:
try: length = len( r )
except: length = 0
if VERBOSE == False and length >= 4:
for i in (0, length - 1):
if i > 0:
if PRINT_DATA:
print((" " * len(txt)) + " ... skipping " + str(length - 2) + " items ...")
if VERBOSE==False and length >= 4:
for i in (0, length-1):
if i>0:
if PRINT_DATA:
print((' '*len(txt)) + ' ... skipping '+str(length-2)+' items ...')
if GEN_PATH: newtxt = txt + '[' + str(i) + ']'
seek(r[i], newtxt, recurs+1)
else:
for i in range(length):
if GEN_PATH: newtxt = txt + '[' + str(i) + ']'
seek(r[i], newtxt, recurs+1)
if GEN_PATH:
newtxt = txt + '[' + str(i) + ']'
seek(r[i], newtxt, recurs + 1)
else:
for i in range(length):
if GEN_PATH:
newtxt = txt + '[' + str(i) + ']'
seek(r[i], newtxt, recurs + 1)
seek(bpy.data, 'bpy.data', 0)
# seek(bpy.types, 'bpy.types', 0)
'''
for d in dir(bpy.types):
t = getattr(bpy.types, d)
t = getattr(bpy.types, d)
try: r = t.bl_rna
except: r = None
if r:
except: r = None
if r:
seek(r, 'bpy.types.' + d + '.bl_rna', 0)
'''