merge with/from trunk at r35190
This commit is contained in:
@@ -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" */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
"""
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
"""
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import mathutils
|
||||
|
||||
# todo
|
||||
@@ -1,3 +0,0 @@
|
||||
import mathutils
|
||||
|
||||
# todo
|
||||
@@ -1,3 +0,0 @@
|
||||
import mathutils
|
||||
|
||||
# todo
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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§ion=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()
|
||||
@@ -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
|
||||
@@ -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}")
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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..
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
1895
source/blender/python/generic/mathutils_Matrix.c
Normal file
1895
source/blender/python/generic/mathutils_Matrix.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
2274
source/blender/python/generic/mathutils_Vector.c
Normal file
2274
source/blender/python/generic/mathutils_Vector.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
882
source/blender/python/generic/mathutils_geometry.c
Normal file
882
source/blender/python/generic/mathutils_geometry.c
Normal 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;
|
||||
}
|
||||
@@ -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
137
source/blender/python/generic/noise.c → source/blender/python/generic/noise_py_api.c
Executable file → Normal file
137
source/blender/python/generic/noise.c → source/blender/python/generic/noise_py_api.c
Executable file → Normal 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
|
||||
};
|
||||
29
source/blender/python/generic/noise_py_api.h
Normal file
29
source/blender/python/generic/noise_py_api.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
77
source/blender/python/intern/CMakeLists.txt
Normal file
77
source/blender/python/intern/CMakeLists.txt
Normal 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}")
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
36
source/blender/python/intern/bpy_driver.h
Normal file
36
source/blender/python/intern/bpy_driver.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
628
source/blender/python/intern/bpy_rna_array.c
Normal file
628
source/blender/python/intern/bpy_rna_array.c
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
151
source/blender/python/intern/bpy_traceback.c
Normal file
151
source/blender/python/intern/bpy_traceback.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
source/blender/python/intern/bpy_traceback.h
Normal file
28
source/blender/python/intern/bpy_traceback.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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)
|
||||
'''
|
||||
|
||||
|
||||
Reference in New Issue
Block a user