From 479c970375baacc23912f63fa6b9e1cf20332ca5 Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Thu, 16 Jul 2009 22:23:01 +0000 Subject: [PATCH] odd, this didn't get committed before --- source/blender/python/BPY_extern.h | 8 +- source/blender/python/CMakeLists.txt | 4 + source/blender/python/Makefile | 4 +- source/blender/python/SConscript | 6 +- source/blender/python/generic/BGL.c | 1610 +++++++++++++ source/blender/python/generic/BGL.h | 338 +++ source/blender/python/generic/Geometry.c | 542 +++++ source/blender/python/generic/Geometry.h | 39 + source/blender/python/generic/Makefile | 66 + source/blender/python/generic/Mathutils.c | 1266 ++++++++++ source/blender/python/generic/Mathutils.h | 116 + .../python/generic/bpy_internal_import.c | 341 +++ .../python/generic/bpy_internal_import.h | 50 + source/blender/python/generic/euler.c | 651 ++++++ source/blender/python/generic/euler.h | 60 + source/blender/python/generic/matrix.c | 1358 +++++++++++ source/blender/python/generic/matrix.h | 66 + source/blender/python/generic/quat.c | 879 +++++++ source/blender/python/generic/quat.h | 60 + source/blender/python/generic/vector.c | 2078 +++++++++++++++++ source/blender/python/generic/vector.h | 55 + source/blender/python/intern/Makefile | 3 +- source/blender/python/intern/bpy_compat.h | 28 +- source/blender/python/intern/bpy_interface.c | 216 +- source/blender/python/intern/bpy_operator.c | 24 +- source/blender/python/intern/bpy_operator.h | 2 +- .../blender/python/intern/bpy_operator_wrap.c | 205 +- .../blender/python/intern/bpy_operator_wrap.h | 2 +- source/blender/python/intern/bpy_rna.c | 1314 ++++++++--- source/blender/python/intern/bpy_rna.h | 4 +- source/blender/python/intern/bpy_ui.c | 5 +- source/blender/python/intern/bpy_ui.h | 2 +- source/blender/python/intern/bpy_util.c | 122 +- source/blender/python/intern/bpy_util.h | 5 +- 34 files changed, 11046 insertions(+), 483 deletions(-) create mode 100644 source/blender/python/generic/BGL.c create mode 100644 source/blender/python/generic/BGL.h create mode 100644 source/blender/python/generic/Geometry.c create mode 100644 source/blender/python/generic/Geometry.h create mode 100644 source/blender/python/generic/Makefile create mode 100644 source/blender/python/generic/Mathutils.c create mode 100644 source/blender/python/generic/Mathutils.h create mode 100644 source/blender/python/generic/bpy_internal_import.c create mode 100644 source/blender/python/generic/bpy_internal_import.h create mode 100644 source/blender/python/generic/euler.c create mode 100644 source/blender/python/generic/euler.h create mode 100644 source/blender/python/generic/matrix.c create mode 100644 source/blender/python/generic/matrix.h create mode 100644 source/blender/python/generic/quat.c create mode 100644 source/blender/python/generic/quat.h create mode 100644 source/blender/python/generic/vector.c create mode 100644 source/blender/python/generic/vector.h diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index ff3e89a6e25..c9fb5260e53 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -1,5 +1,5 @@ /* - * $Id: BPY_extern.h 12334 2007-10-21 23:00:29Z aligorith $ + * $Id: BPY_extern.h 21462 2009-07-09 15:40:04Z ton $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -50,6 +50,8 @@ struct bConstraintTarget; /* DNA_constraint_types.h*/ struct Script; /* DNA_screen_types.h */ struct BPyMenu; struct bContext; +struct ReportList; + #ifdef __cplusplus extern "C" { #endif @@ -97,8 +99,8 @@ extern "C" { 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 ); // 2.5 working - int BPY_run_script_space_draw(struct bContext *C, struct SpaceScript * sc); // 2.5 working + 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 void BPY_run_ui_scripts(struct bContext *C, int reload); // 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 diff --git a/source/blender/python/CMakeLists.txt b/source/blender/python/CMakeLists.txt index d15970e1df4..7700e6bc2aa 100644 --- a/source/blender/python/CMakeLists.txt +++ b/source/blender/python/CMakeLists.txt @@ -24,10 +24,12 @@ # ***** END GPL LICENSE BLOCK ***** FILE(GLOB SRC intern/*.c) +FILE(GLOB GENSRC generic/*.c) SET(INC . ../../../intern/guardedalloc ../blenlib ../makesdna ../makesrna ../blenkernel ../editors/include ../windowmanager ${PYTHON_INC} + ../../../extern/glew/include ) IF(WITH_OPENEXR) @@ -47,3 +49,5 @@ ENDIF(WITH_FFMPEG) ADD_DEFINITIONS(-DWITH_CCGSUBSURF) BLENDERLIB(bf_python "${SRC}" "${INC}") +BLENDERLIB(bf_gen_python "${GENSRC}" "${INC}") + diff --git a/source/blender/python/Makefile b/source/blender/python/Makefile index c830fbb3ccf..b120dc6ad46 100644 --- a/source/blender/python/Makefile +++ b/source/blender/python/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile 14444 2008-04-16 22:40:48Z hos $ +# $Id: Makefile 21094 2009-06-23 00:09:26Z gsrb3d $ # # ***** BEGIN GPL LICENSE BLOCK ***** # @@ -29,6 +29,6 @@ # Bounces make to subdirectories. SOURCEDIR = source/blender/python -DIRS = intern +DIRS = intern generic include nan_subdirs.mk diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript index 9d7fcf6a9cf..73dc171fc3e 100644 --- a/source/blender/python/SConscript +++ b/source/blender/python/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('intern/*.c') incs = '. ../editors/include ../makesdna ../makesrna ../blenlib ../blenkernel ../nodes' incs += ' ../imbuf ../blenloader ../render/extern/include ../windowmanager' -incs += ' #intern/guardedalloc #intern/memutil' +incs += ' #intern/guardedalloc #intern/memutil #extern/glew/include' incs += ' ' + env['BF_PYTHON_INC'] defs = [] @@ -15,3 +15,7 @@ if env['OURPLATFORM'] in ('win32-mingw', 'win32-vc') and env['BF_DEBUG']: env.BlenderLib( libname = 'bf_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core'], priority = [140]) + +# generic +sources = env.Glob('generic/*.c') +env.BlenderLib( libname = 'bf_gen_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core'], priority = [361]) # ketsji is 360 diff --git a/source/blender/python/generic/BGL.c b/source/blender/python/generic/BGL.c new file mode 100644 index 00000000000..773e8958fbb --- /dev/null +++ b/source/blender/python/generic/BGL.c @@ -0,0 +1,1610 @@ +/* + * $Id: BGL.c 21218 2009-06-28 13:27:06Z campbellbarton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL LICENSE BLOCK ***** +*/ + +/* This file is the Blender.BGL part of opy_draw.c, from the old + * bpython/intern dir, with minor changes to adapt it to the new Python + * implementation. The BGL submodule "wraps" OpenGL functions and constants, + * allowing script writers to make OpenGL calls in their Python scripts. */ + +#include "BGL.h" /*This must come first */ + +#include "MEM_guardedalloc.h" + +static int type_size( int type ); +static Buffer *make_buffer( int type, int ndimensions, int *dimensions ); + +static char Method_Buffer_doc[] = + "(type, dimensions, [template]) - Create a new Buffer object\n\n\ +(type) - The format to store data in\n\ +(dimensions) - An int or sequence specifying the dimensions of the buffer\n\ +[template] - A sequence of matching dimensions to the buffer to be created\n\ + which will be used to initialize the Buffer.\n\n\ +If a template is not passed in all fields will be initialized to 0.\n\n\ +The type should be one of GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, or GL_DOUBLE.\n\ +If the dimensions are specified as an int a linear buffer will be\n\ +created. If a sequence is passed for the dimensions the buffer\n\ +will have len(sequence) dimensions, where the size for each dimension\n\ +is determined by the value in the sequence at that index.\n\n\ +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 ); + +/* Buffer sequence methods */ + +static int Buffer_len( PyObject * self ); +static PyObject *Buffer_item( PyObject * self, int i ); +static PyObject *Buffer_slice( PyObject * self, int begin, int end ); +static int Buffer_ass_item( PyObject * self, int i, PyObject * v ); +static int Buffer_ass_slice( PyObject * self, int begin, int end, + PyObject * seq ); + +static PySequenceMethods Buffer_SeqMethods = { + ( inquiry ) Buffer_len, /*sq_length */ + ( binaryfunc ) 0, /*sq_concat */ + ( ssizeargfunc ) 0, /*sq_repeat */ + ( ssizeargfunc ) Buffer_item, /*sq_item */ + ( ssizessizeargfunc ) Buffer_slice, /*sq_slice */ + ( ssizeobjargproc ) Buffer_ass_item, /*sq_ass_item */ + ( ssizessizeobjargproc ) Buffer_ass_slice, /*sq_ass_slice */ +}; + +static void Buffer_dealloc( PyObject * self ); +static PyObject *Buffer_tolist( PyObject * self ); +static PyObject *Buffer_dimensions( PyObject * self ); +static PyObject *Buffer_getattr( PyObject * self, char *name ); +static PyObject *Buffer_repr( PyObject * self ); + +PyTypeObject buffer_Type = { +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif + "buffer", /*tp_name */ + sizeof( Buffer ), /*tp_basicsize */ + 0, /*tp_itemsize */ + ( destructor ) Buffer_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) Buffer_getattr, /*tp_getattr */ + ( setattrfunc ) 0, /*tp_setattr */ + 0, /*tp_compare */ + ( reprfunc ) Buffer_repr, /*tp_repr */ + 0, /*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) {\ + arg_def##nargs arg_list; \ + ret_def_##ret; \ + if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\ + ret_set_##ret gl##funcname (arg_var##nargs arg_list);\ + ret_ret_##ret; \ +} + +#define BGLU_Wrap(nargs, funcname, ret, arg_list) \ +static PyObject *Method_##funcname (PyObject *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;\ + ret_set_##ret glu##funcname (arg_var##nargs arg_list);\ + ret_ret_##ret; \ +} + +/* #endif */ + +/********/ +static int type_size(int type) +{ + switch (type) { + case GL_BYTE: + return sizeof(char); + case GL_SHORT: + return sizeof(short); + case GL_INT: + return sizeof(int); + case GL_FLOAT: + return sizeof(float); + case GL_DOUBLE: + return sizeof(double); + } + return -1; +} + +static Buffer *make_buffer(int type, int ndimensions, int *dimensions) +{ + Buffer *buffer; + void *buf= NULL; + int i, size, length; + + length= 1; + for (i=0; iparent= NULL; + buffer->ndimensions= ndimensions; + buffer->dimensions= dimensions; + buffer->type= type; + buffer->buf.asvoid= buf; + + for (i= 0; ibuf.asbyte[i]= 0; + else if (type==GL_SHORT) + buffer->buf.asshort[i]= 0; + else if (type==GL_INT) + buffer->buf.asint[i]= 0; + else if (type==GL_FLOAT) + buffer->buf.asfloat[i]= 0.0f; + else if (type==GL_DOUBLE) + buffer->buf.asdouble[i]= 0.0; + } + return buffer; +} + +static PyObject *Method_Buffer (PyObject *self, PyObject *args) +{ + PyObject *length_ob= NULL, *template= NULL; + Buffer *buffer; + + int i, type; + int *dimensions = 0, ndimensions = 0; + + if (!PyArg_ParseTuple(args, "iO|O", &type, &length_ob, &template)) { + 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) { + 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)) { + ndimensions= 1; + dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions"); + dimensions[0]= PyLong_AsLong(length_ob); + } else if (PySequence_Check(length_ob)) { + ndimensions= PySequence_Length(length_ob); + dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions"); + for (i=0; idimensions[0]; +} + +static PyObject *Buffer_item(PyObject *self, int i) +{ + Buffer *buf= (Buffer *) self; + + if (i >= buf->dimensions[0]) { + PyErr_SetString(PyExc_IndexError, "array index out of range"); + return NULL; + } + + if (buf->ndimensions==1) { + switch (buf->type) { + case GL_BYTE: return Py_BuildValue("b", buf->buf.asbyte[i]); + case GL_SHORT: return Py_BuildValue("h", buf->buf.asshort[i]); + case GL_INT: return Py_BuildValue("i", buf->buf.asint[i]); + case GL_FLOAT: return PyFloat_FromDouble(buf->buf.asfloat[i]); + case GL_DOUBLE: return Py_BuildValue("d", buf->buf.asdouble[i]); + } + } else { + Buffer *newbuf; + int j, length, size; + + length= 1; + for (j=1; jndimensions; j++) { + length*= buf->dimensions[j]; + } + size= type_size(buf->type); + + newbuf= (Buffer *) PyObject_NEW(Buffer, &buffer_Type); + + Py_INCREF(self); + newbuf->parent= self; + + newbuf->ndimensions= buf->ndimensions-1; + newbuf->type= buf->type; + newbuf->buf.asvoid= buf->buf.asbyte + i*length*size; + newbuf->dimensions= MEM_mallocN(newbuf->ndimensions*sizeof(int), + "Buffer dimensions"); + memcpy(newbuf->dimensions, buf->dimensions+1, + newbuf->ndimensions*sizeof(int)); + + return (PyObject *) newbuf; + } + + return NULL; +} + +static PyObject *Buffer_slice(PyObject *self, int begin, int end) +{ + Buffer *buf= (Buffer *) self; + PyObject *list; + int count; + + if (begin<0) begin= 0; + if (end>buf->dimensions[0]) + end= buf->dimensions[0]; + if (begin>end) begin= end; + + list= PyList_New(end-begin); + + for (count= begin; count= buf->dimensions[0]) { + PyErr_SetString(PyExc_IndexError, "array assignment index out of range"); + return -1; + } + + if (buf->ndimensions!=1) { + PyObject *row= Buffer_item(self, i); + int ret; + + if (!row) return -1; + ret= Buffer_ass_slice(row, 0, buf->dimensions[1], v); + Py_DECREF(row); + return ret; + } + + if (buf->type==GL_BYTE) { + if (!PyArg_Parse(v, "b;Coordinates must be ints", &buf->buf.asbyte[i])) + return -1; + } else if (buf->type==GL_SHORT) { + if (!PyArg_Parse(v, "h;Coordinates must be ints", &buf->buf.asshort[i])) + return -1; + + } else if (buf->type==GL_INT) { + if (!PyArg_Parse(v, "i;Coordinates must be ints", &buf->buf.asint[i])) + return -1; + } else if (buf->type==GL_FLOAT) { + if (!PyArg_Parse(v, "f;Coordinates must be floats", &buf->buf.asfloat[i])) + return -1; + } else if (buf->type==GL_DOUBLE) { + if (!PyArg_Parse(v, "d;Coordinates must be floats", &buf->buf.asdouble[i])) + return -1; + } + return 0; +} + +static int Buffer_ass_slice(PyObject *self, int begin, int end, PyObject *seq) +{ + Buffer *buf= (Buffer *) self; + PyObject *item; + int count, err=0; + + if (begin<0) begin= 0; + if (end>buf->dimensions[0]) end= buf->dimensions[0]; + if (begin>end) begin= end; + + if (!PySequence_Check(seq)) { + PyErr_SetString(PyExc_TypeError, + "illegal argument type for built-in operation"); + return -1; + } + + if (PySequence_Length(seq)!=(end-begin)) { + PyErr_SetString(PyExc_TypeError, "size mismatch in assignment"); + return -1; + } + + for (count= begin; countparent) Py_DECREF (buf->parent); + else MEM_freeN (buf->buf.asvoid); + + MEM_freeN (buf->dimensions); + + PyObject_DEL (self); +} + +static PyObject *Buffer_tolist(PyObject *self) +{ + int i, len= ((Buffer *)self)->dimensions[0]; + PyObject *list= PyList_New(len); + + for (i=0; indimensions); + int i; + + for (i= 0; indimensions; i++) { + PyList_SetItem(list, i, PyLong_FromLong(buffer->dimensions[i])); + } + + return list; +} + +static PyObject *Buffer_getattr(PyObject *self, char *name) +{ + if (strcmp(name, "list")==0) return Buffer_tolist(self); + else if (strcmp(name, "dimensions")==0) return Buffer_dimensions(self); + + PyErr_SetString(PyExc_AttributeError, name); + return NULL; +} + +static PyObject *Buffer_repr(PyObject *self) +{ + PyObject *list= Buffer_tolist(self); + PyObject *repr= PyObject_Repr(list); + Py_DECREF(list); + + return repr; +} + + +BGL_Wrap(2, Accum, void, (GLenum, GLfloat)) +BGL_Wrap(2, AlphaFunc, void, (GLenum, GLclampf)) +BGL_Wrap(3, AreTexturesResident, GLboolean, (GLsizei, GLuintP, GLbooleanP)) +BGL_Wrap(1, Begin, void, (GLenum)) +BGL_Wrap(2, BindTexture, void, (GLenum, GLuint)) +BGL_Wrap(7, Bitmap, void, (GLsizei, GLsizei, GLfloat, + GLfloat, GLfloat, GLfloat, GLubyteP)) +BGL_Wrap(2, BlendFunc, void, (GLenum, GLenum)) +BGL_Wrap(1, CallList, void, (GLuint)) +BGL_Wrap(3, CallLists, void, (GLsizei, GLenum, GLvoidP)) +BGL_Wrap(1, Clear, void, (GLbitfield)) +BGL_Wrap(4, ClearAccum, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(4, ClearColor, void, (GLclampf, GLclampf, GLclampf, GLclampf)) +BGL_Wrap(1, ClearDepth, void, (GLclampd)) +BGL_Wrap(1, ClearIndex, void, (GLfloat)) +BGL_Wrap(1, ClearStencil, void, (GLint)) +BGL_Wrap(2, ClipPlane, void, (GLenum, GLdoubleP)) +BGL_Wrap(3, Color3b, void, (GLbyte, GLbyte, GLbyte)) +BGL_Wrap(1, Color3bv, void, (GLbyteP)) +BGL_Wrap(3, Color3d, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, Color3dv, void, (GLdoubleP)) +BGL_Wrap(3, Color3f, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, Color3fv, void, (GLfloatP)) +BGL_Wrap(3, Color3i, void, (GLint, GLint, GLint)) +BGL_Wrap(1, Color3iv, void, (GLintP)) +BGL_Wrap(3, Color3s, void, (GLshort, GLshort, GLshort)) +BGL_Wrap(1, Color3sv, void, (GLshortP)) +BGL_Wrap(3, Color3ub, void, (GLubyte, GLubyte, GLubyte)) +BGL_Wrap(1, Color3ubv, void, (GLubyteP)) +BGL_Wrap(3, Color3ui, void, (GLuint, GLuint, GLuint)) +BGL_Wrap(1, Color3uiv, void, (GLuintP)) +BGL_Wrap(3, Color3us, void, (GLushort, GLushort, GLushort)) +BGL_Wrap(1, Color3usv, void, (GLushortP)) +BGL_Wrap(4, Color4b, void, (GLbyte, GLbyte, GLbyte, GLbyte)) +BGL_Wrap(1, Color4bv, void, (GLbyteP)) +BGL_Wrap(4, Color4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, Color4dv, void, (GLdoubleP)) +BGL_Wrap(4, Color4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, Color4fv, void, (GLfloatP)) +BGL_Wrap(4, Color4i, void, (GLint, GLint, GLint, GLint)) +BGL_Wrap(1, Color4iv, void, (GLintP)) +BGL_Wrap(4, Color4s, void, (GLshort, GLshort, GLshort, GLshort)) +BGL_Wrap(1, Color4sv, void, (GLshortP)) +BGL_Wrap(4, Color4ub, void, (GLubyte, GLubyte, GLubyte, GLubyte)) +BGL_Wrap(1, Color4ubv, void, (GLubyteP)) +BGL_Wrap(4, Color4ui, void, (GLuint, GLuint, GLuint, GLuint)) +BGL_Wrap(1, Color4uiv, void, (GLuintP)) +BGL_Wrap(4, Color4us, void, (GLushort, GLushort, GLushort, GLushort)) +BGL_Wrap(1, Color4usv, void, (GLushortP)) +BGL_Wrap(4, ColorMask, void, (GLboolean, GLboolean, GLboolean, GLboolean)) +BGL_Wrap(2, ColorMaterial, void, (GLenum, GLenum)) +BGL_Wrap(5, CopyPixels, void, (GLint, GLint, GLsizei, GLsizei, GLenum)) +BGL_Wrap(1, CullFace, void, (GLenum)) +BGL_Wrap(2, DeleteLists, void, (GLuint, GLsizei)) +BGL_Wrap(2, DeleteTextures, void, (GLsizei, GLuintP)) +BGL_Wrap(1, DepthFunc, void, (GLenum)) +BGL_Wrap(1, DepthMask, void, (GLboolean)) +BGL_Wrap(2, DepthRange, void, (GLclampd, GLclampd)) +BGL_Wrap(1, Disable, void, (GLenum)) +BGL_Wrap(1, DrawBuffer, void, (GLenum)) +BGL_Wrap(5, DrawPixels, void, (GLsizei, GLsizei, GLenum, GLenum, GLvoidP)) +BGL_Wrap(1, EdgeFlag, void, (GLboolean)) +BGL_Wrap(1, EdgeFlagv, void, (GLbooleanP)) +BGL_Wrap(1, Enable, void, (GLenum)) +BGL_Wrap(1, End, void, (void)) +BGL_Wrap(1, EndList, void, (void)) +BGL_Wrap(1, EvalCoord1d, void, (GLdouble)) +BGL_Wrap(1, EvalCoord1dv, void, (GLdoubleP)) +BGL_Wrap(1, EvalCoord1f, void, (GLfloat)) +BGL_Wrap(1, EvalCoord1fv, void, (GLfloatP)) +BGL_Wrap(2, EvalCoord2d, void, (GLdouble, GLdouble)) +BGL_Wrap(1, EvalCoord2dv, void, (GLdoubleP)) +BGL_Wrap(2, EvalCoord2f, void, (GLfloat, GLfloat)) +BGL_Wrap(1, EvalCoord2fv, void, (GLfloatP)) +BGL_Wrap(3, EvalMesh1, void, (GLenum, GLint, GLint)) +BGL_Wrap(5, EvalMesh2, void, (GLenum, GLint, GLint, GLint, GLint)) +BGL_Wrap(1, EvalPoint1, void, (GLint)) +BGL_Wrap(2, EvalPoint2, void, (GLint, GLint)) +BGL_Wrap(3, FeedbackBuffer, void, (GLsizei, GLenum, GLfloatP)) +BGL_Wrap(1, Finish, void, (void)) +BGL_Wrap(1, Flush, void, (void)) +BGL_Wrap(2, Fogf, void, (GLenum, GLfloat)) +BGL_Wrap(2, Fogfv, void, (GLenum, GLfloatP)) +BGL_Wrap(2, Fogi, void, (GLenum, GLint)) +BGL_Wrap(2, Fogiv, void, (GLenum, GLintP)) +BGL_Wrap(1, FrontFace, void, (GLenum)) +BGL_Wrap(6, Frustum, void, (GLdouble, GLdouble, + GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, GenLists, GLuint, (GLsizei)) +BGL_Wrap(2, GenTextures, void, (GLsizei, GLuintP)) +BGL_Wrap(2, GetBooleanv, void, (GLenum, GLbooleanP)) +BGL_Wrap(2, GetClipPlane, void, (GLenum, GLdoubleP)) +BGL_Wrap(2, GetDoublev, void, (GLenum, GLdoubleP)) +BGL_Wrap(1, GetError, GLenum, (void)) +BGL_Wrap(2, GetFloatv, void, (GLenum, GLfloatP)) +BGL_Wrap(2, GetIntegerv, void, (GLenum, GLintP)) +BGL_Wrap(3, GetLightfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetLightiv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(3, GetMapdv, void, (GLenum, GLenum, GLdoubleP)) +BGL_Wrap(3, GetMapfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetMapiv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(3, GetMaterialfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetMaterialiv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(2, GetPixelMapfv, void, (GLenum, GLfloatP)) +BGL_Wrap(2, GetPixelMapuiv, void, (GLenum, GLuintP)) +BGL_Wrap(2, GetPixelMapusv, void, (GLenum, GLushortP)) +BGL_Wrap(1, GetPolygonStipple,void, (GLubyteP)) +BGL_Wrap(1, GetString, GLstring, (GLenum)) +BGL_Wrap(3, GetTexEnvfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetTexEnviv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(3, GetTexGendv, void, (GLenum, GLenum, GLdoubleP)) +BGL_Wrap(3, GetTexGenfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetTexGeniv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(5, GetTexImage, void, (GLenum, GLint, GLenum, GLenum, GLvoidP)) +BGL_Wrap(4, GetTexLevelParameterfv, void, (GLenum, GLint, GLenum, GLfloatP)) +BGL_Wrap(4, GetTexLevelParameteriv, void, (GLenum, GLint, GLenum, GLintP)) +BGL_Wrap(3, GetTexParameterfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, GetTexParameteriv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(2, Hint, void, (GLenum, GLenum)) +BGL_Wrap(1, IndexMask, void, (GLuint)) +BGL_Wrap(1, Indexd, void, (GLdouble)) +BGL_Wrap(1, Indexdv, void, (GLdoubleP)) +BGL_Wrap(1, Indexf, void, (GLfloat)) +BGL_Wrap(1, Indexfv, void, (GLfloatP)) +BGL_Wrap(1, Indexi, void, (GLint)) +BGL_Wrap(1, Indexiv, void, (GLintP)) +BGL_Wrap(1, Indexs, void, (GLshort)) +BGL_Wrap(1, Indexsv, void, (GLshortP)) +BGL_Wrap(1, InitNames, void, (void)) +BGL_Wrap(1, IsEnabled, GLboolean, (GLenum)) +BGL_Wrap(1, IsList, GLboolean, (GLuint)) +BGL_Wrap(1, IsTexture, GLboolean, (GLuint)) +BGL_Wrap(2, LightModelf, void, (GLenum, GLfloat)) +BGL_Wrap(2, LightModelfv, void, (GLenum, GLfloatP)) +BGL_Wrap(2, LightModeli, void, (GLenum, GLint)) +BGL_Wrap(2, LightModeliv, void, (GLenum, GLintP)) +BGL_Wrap(3, Lightf, void, (GLenum, GLenum, GLfloat)) +BGL_Wrap(3, Lightfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, Lighti, void, (GLenum, GLenum, GLint)) +BGL_Wrap(3, Lightiv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(2, LineStipple, void, (GLint, GLushort)) +BGL_Wrap(1, LineWidth, void, (GLfloat)) +BGL_Wrap(1, ListBase, void, (GLuint)) +BGL_Wrap(1, LoadIdentity, void, (void)) +BGL_Wrap(1, LoadMatrixd, void, (GLdoubleP)) +BGL_Wrap(1, LoadMatrixf, void, (GLfloatP)) +BGL_Wrap(1, LoadName, void, (GLuint)) +BGL_Wrap(1, LogicOp, void, (GLenum)) +BGL_Wrap(6, Map1d, void, (GLenum, GLdouble, GLdouble, + GLint, GLint, GLdoubleP)) +BGL_Wrap(6, Map1f, void, (GLenum, GLfloat, GLfloat, + GLint, GLint, GLfloatP)) +BGL_Wrap(10, Map2d, void, (GLenum, GLdouble, GLdouble, + GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdoubleP)) +BGL_Wrap(10, Map2f, void, (GLenum, GLfloat, GLfloat, + GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloatP)) +BGL_Wrap(3, MapGrid1d, void, (GLint, GLdouble, GLdouble)) +BGL_Wrap(3, MapGrid1f, void, (GLint, GLfloat, GLfloat)) +BGL_Wrap(6, MapGrid2d, void, (GLint, GLdouble, GLdouble, + GLint, GLdouble, GLdouble)) +BGL_Wrap(6, MapGrid2f, void, (GLint, GLfloat, GLfloat, + GLint, GLfloat, GLfloat)) +BGL_Wrap(3, Materialf, void, (GLenum, GLenum, GLfloat)) +BGL_Wrap(3, Materialfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, Materiali, void, (GLenum, GLenum, GLint)) +BGL_Wrap(3, Materialiv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(1, MatrixMode, void, (GLenum)) +BGL_Wrap(1, MultMatrixd, void, (GLdoubleP)) +BGL_Wrap(1, MultMatrixf, void, (GLfloatP)) +BGL_Wrap(2, NewList, void, (GLuint, GLenum)) +BGL_Wrap(3, Normal3b, void, (GLbyte, GLbyte, GLbyte)) +BGL_Wrap(1, Normal3bv, void, (GLbyteP)) +BGL_Wrap(3, Normal3d, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, Normal3dv, void, (GLdoubleP)) +BGL_Wrap(3, Normal3f, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, Normal3fv, void, (GLfloatP)) +BGL_Wrap(3, Normal3i, void, (GLint, GLint, GLint)) +BGL_Wrap(1, Normal3iv, void, (GLintP)) +BGL_Wrap(3, Normal3s, void, (GLshort, GLshort, GLshort)) +BGL_Wrap(1, Normal3sv, void, (GLshortP)) +BGL_Wrap(6, Ortho, void, (GLdouble, GLdouble, + GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, PassThrough, void, (GLfloat)) +BGL_Wrap(3, PixelMapfv, void, (GLenum, GLint, GLfloatP)) +BGL_Wrap(3, PixelMapuiv, void, (GLenum, GLint, GLuintP)) +BGL_Wrap(3, PixelMapusv, void, (GLenum, GLint, GLushortP)) +BGL_Wrap(2, PixelStoref, void, (GLenum, GLfloat)) +BGL_Wrap(2, PixelStorei, void, (GLenum, GLint)) +BGL_Wrap(2, PixelTransferf, void, (GLenum, GLfloat)) +BGL_Wrap(2, PixelTransferi, void, (GLenum, GLint)) +BGL_Wrap(2, PixelZoom, void, (GLfloat, GLfloat)) +BGL_Wrap(1, PointSize, void, (GLfloat)) +BGL_Wrap(2, PolygonMode, void, (GLenum, GLenum)) +BGL_Wrap(2, PolygonOffset, void, (GLfloat, GLfloat)) +BGL_Wrap(1, PolygonStipple, void, (GLubyteP)) +BGL_Wrap(1, PopAttrib, void, (void)) +BGL_Wrap(1, PopClientAttrib, void, (void)) +BGL_Wrap(1, PopMatrix, void, (void)) +BGL_Wrap(1, PopName, void, (void)) +BGL_Wrap(3, PrioritizeTextures, void, (GLsizei, GLuintP, GLclampfP)) +BGL_Wrap(1, PushAttrib, void, (GLbitfield)) +BGL_Wrap(1, PushClientAttrib, void, (GLbitfield)) +BGL_Wrap(1, PushMatrix, void, (void)) +BGL_Wrap(1, PushName, void, (GLuint)) +BGL_Wrap(2, RasterPos2d, void, (GLdouble, GLdouble)) +BGL_Wrap(1, RasterPos2dv, void, (GLdoubleP)) +BGL_Wrap(2, RasterPos2f, void, (GLfloat, GLfloat)) +BGL_Wrap(1, RasterPos2fv, void, (GLfloatP)) +BGL_Wrap(2, RasterPos2i, void, (GLint, GLint)) +BGL_Wrap(1, RasterPos2iv, void, (GLintP)) +BGL_Wrap(2, RasterPos2s, void, (GLshort, GLshort)) +BGL_Wrap(1, RasterPos2sv, void, (GLshortP)) +BGL_Wrap(3, RasterPos3d, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, RasterPos3dv, void, (GLdoubleP)) +BGL_Wrap(3, RasterPos3f, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, RasterPos3fv, void, (GLfloatP)) +BGL_Wrap(3, RasterPos3i, void, (GLint, GLint, GLint)) +BGL_Wrap(1, RasterPos3iv, void, (GLintP)) +BGL_Wrap(3, RasterPos3s, void, (GLshort, GLshort, GLshort)) +BGL_Wrap(1, RasterPos3sv, void, (GLshortP)) +BGL_Wrap(4, RasterPos4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, RasterPos4dv, void, (GLdoubleP)) +BGL_Wrap(4, RasterPos4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, RasterPos4fv, void, (GLfloatP)) +BGL_Wrap(4, RasterPos4i, void, (GLint, GLint, GLint, GLint)) +BGL_Wrap(1, RasterPos4iv, void, (GLintP)) +BGL_Wrap(4, RasterPos4s, void, (GLshort, GLshort, GLshort, GLshort)) +BGL_Wrap(1, RasterPos4sv, void, (GLshortP)) +BGL_Wrap(1, ReadBuffer, void, (GLenum)) +BGL_Wrap(7, ReadPixels, void, (GLint, GLint, GLsizei, + GLsizei, GLenum, GLenum, GLvoidP)) +BGL_Wrap(4, Rectd, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(2, Rectdv, void, (GLdoubleP, GLdoubleP)) +BGL_Wrap(4, Rectf, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(2, Rectfv, void, (GLfloatP, GLfloatP)) +BGL_Wrap(4, Recti, void, (GLint, GLint, GLint, GLint)) +BGL_Wrap(2, Rectiv, void, (GLintP, GLintP)) +BGL_Wrap(4, Rects, void, (GLshort, GLshort, GLshort, GLshort)) +BGL_Wrap(2, Rectsv, void, (GLshortP, GLshortP)) +BGL_Wrap(1, RenderMode, GLint, (GLenum)) +BGL_Wrap(4, Rotated, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(4, Rotatef, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(3, Scaled, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(3, Scalef, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(4, Scissor, void, (GLint, GLint, GLsizei, GLsizei)) +BGL_Wrap(2, SelectBuffer, void, (GLsizei, GLuintP)) +BGL_Wrap(1, ShadeModel, void, (GLenum)) +BGL_Wrap(3, StencilFunc, void, (GLenum, GLint, GLuint)) +BGL_Wrap(1, StencilMask, void, (GLuint)) +BGL_Wrap(3, StencilOp, void, (GLenum, GLenum, GLenum)) +BGL_Wrap(1, TexCoord1d, void, (GLdouble)) +BGL_Wrap(1, TexCoord1dv, void, (GLdoubleP)) +BGL_Wrap(1, TexCoord1f, void, (GLfloat)) +BGL_Wrap(1, TexCoord1fv, void, (GLfloatP)) +BGL_Wrap(1, TexCoord1i, void, (GLint)) +BGL_Wrap(1, TexCoord1iv, void, (GLintP)) +BGL_Wrap(1, TexCoord1s, void, (GLshort)) +BGL_Wrap(1, TexCoord1sv, void, (GLshortP)) +BGL_Wrap(2, TexCoord2d, void, (GLdouble, GLdouble)) +BGL_Wrap(1, TexCoord2dv, void, (GLdoubleP)) +BGL_Wrap(2, TexCoord2f, void, (GLfloat, GLfloat)) +BGL_Wrap(1, TexCoord2fv, void, (GLfloatP)) +BGL_Wrap(2, TexCoord2i, void, (GLint, GLint)) +BGL_Wrap(1, TexCoord2iv, void, (GLintP)) +BGL_Wrap(2, TexCoord2s, void, (GLshort, GLshort)) +BGL_Wrap(1, TexCoord2sv, void, (GLshortP)) +BGL_Wrap(3, TexCoord3d, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, TexCoord3dv, void, (GLdoubleP)) +BGL_Wrap(3, TexCoord3f, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, TexCoord3fv, void, (GLfloatP)) +BGL_Wrap(3, TexCoord3i, void, (GLint, GLint, GLint)) +BGL_Wrap(1, TexCoord3iv, void, (GLintP)) +BGL_Wrap(3, TexCoord3s, void, (GLshort, GLshort, GLshort)) +BGL_Wrap(1, TexCoord3sv, void, (GLshortP)) +BGL_Wrap(4, TexCoord4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, TexCoord4dv, void, (GLdoubleP)) +BGL_Wrap(4, TexCoord4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, TexCoord4fv, void, (GLfloatP)) +BGL_Wrap(4, TexCoord4i, void, (GLint, GLint, GLint, GLint)) +BGL_Wrap(1, TexCoord4iv, void, (GLintP)) +BGL_Wrap(4, TexCoord4s, void, (GLshort, GLshort, GLshort, GLshort)) +BGL_Wrap(1, TexCoord4sv, void, (GLshortP)) +BGL_Wrap(3, TexEnvf, void, (GLenum, GLenum, GLfloat)) +BGL_Wrap(3, TexEnvfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, TexEnvi, void, (GLenum, GLenum, GLint)) +BGL_Wrap(3, TexEnviv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(3, TexGend, void, (GLenum, GLenum, GLdouble)) +BGL_Wrap(3, TexGendv, void, (GLenum, GLenum, GLdoubleP)) +BGL_Wrap(3, TexGenf, void, (GLenum, GLenum, GLfloat)) +BGL_Wrap(3, TexGenfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, TexGeni, void, (GLenum, GLenum, GLint)) +BGL_Wrap(3, TexGeniv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(8, TexImage1D, void, (GLenum, GLint, GLint, + GLsizei, GLint, GLenum, GLenum, GLvoidP)) +BGL_Wrap(9, TexImage2D, void, (GLenum, GLint, GLint, + GLsizei, GLsizei, GLint, GLenum, GLenum, GLvoidP)) +BGL_Wrap(3, TexParameterf, void, (GLenum, GLenum, GLfloat)) +BGL_Wrap(3, TexParameterfv, void, (GLenum, GLenum, GLfloatP)) +BGL_Wrap(3, TexParameteri, void, (GLenum, GLenum, GLint)) +BGL_Wrap(3, TexParameteriv, void, (GLenum, GLenum, GLintP)) +BGL_Wrap(3, Translated, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(3, Translatef, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(2, Vertex2d, void, (GLdouble, GLdouble)) +BGL_Wrap(1, Vertex2dv, void, (GLdoubleP)) +BGL_Wrap(2, Vertex2f, void, (GLfloat, GLfloat)) +BGL_Wrap(1, Vertex2fv, void, (GLfloatP)) +BGL_Wrap(2, Vertex2i, void, (GLint, GLint)) +BGL_Wrap(1, Vertex2iv, void, (GLintP)) +BGL_Wrap(2, Vertex2s, void, (GLshort, GLshort)) +BGL_Wrap(1, Vertex2sv, void, (GLshortP)) +BGL_Wrap(3, Vertex3d, void, (GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, Vertex3dv, void, (GLdoubleP)) +BGL_Wrap(3, Vertex3f, void, (GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, Vertex3fv, void, (GLfloatP)) +BGL_Wrap(3, Vertex3i, void, (GLint, GLint, GLint)) +BGL_Wrap(1, Vertex3iv, void, (GLintP)) +BGL_Wrap(3, Vertex3s, void, (GLshort, GLshort, GLshort)) +BGL_Wrap(1, Vertex3sv, void, (GLshortP)) +BGL_Wrap(4, Vertex4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGL_Wrap(1, Vertex4dv, void, (GLdoubleP)) +BGL_Wrap(4, Vertex4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) +BGL_Wrap(1, Vertex4fv, void, (GLfloatP)) +BGL_Wrap(4, Vertex4i, void, (GLint, GLint, GLint, GLint)) +BGL_Wrap(1, Vertex4iv, void, (GLintP)) +BGL_Wrap(4, Vertex4s, void, (GLshort, GLshort, GLshort, GLshort)) +BGL_Wrap(1, Vertex4sv, void, (GLshortP)) +BGL_Wrap(4, Viewport, void, (GLint, GLint, GLsizei, GLsizei)) +BGLU_Wrap(4, Perspective, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGLU_Wrap(9, LookAt, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)) +BGLU_Wrap(4, Ortho2D, void, (GLdouble, GLdouble, GLdouble, GLdouble)) +BGLU_Wrap(5, PickMatrix, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLintP)) +BGLU_Wrap(9, Project, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP)) +BGLU_Wrap(9, UnProject, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP)) + +#undef MethodDef +#define MethodDef(func) {"gl"#func, Method_##func, METH_VARARGS, "no string"} +#define MethodDefu(func) {"glu"#func, Method_##func, METH_VARARGS, "no string"} +/* So that MethodDef(Accum) becomes: + * {"glAccum", Method_Accumfunc, METH_VARARGS} */ + +static struct PyMethodDef BGL_methods[] = { + {"Buffer", Method_Buffer, METH_VARARGS, Method_Buffer_doc}, + +/* #ifndef __APPLE__ */ + MethodDef(Accum), + MethodDef(AlphaFunc), + MethodDef(AreTexturesResident), + MethodDef(Begin), + MethodDef(BindTexture), + MethodDef(Bitmap), + MethodDef(BlendFunc), + MethodDef(CallList), + MethodDef(CallLists), + MethodDef(Clear), + MethodDef(ClearAccum), + MethodDef(ClearColor), + MethodDef(ClearDepth), + MethodDef(ClearIndex), + MethodDef(ClearStencil), + MethodDef(ClipPlane), + MethodDef(Color3b), + MethodDef(Color3bv), + MethodDef(Color3d), + MethodDef(Color3dv), + MethodDef(Color3f), + MethodDef(Color3fv), + MethodDef(Color3i), + MethodDef(Color3iv), + MethodDef(Color3s), + MethodDef(Color3sv), + MethodDef(Color3ub), + MethodDef(Color3ubv), + MethodDef(Color3ui), + MethodDef(Color3uiv), + MethodDef(Color3us), + MethodDef(Color3usv), + MethodDef(Color4b), + MethodDef(Color4bv), + MethodDef(Color4d), + MethodDef(Color4dv), + MethodDef(Color4f), + MethodDef(Color4fv), + MethodDef(Color4i), + MethodDef(Color4iv), + MethodDef(Color4s), + MethodDef(Color4sv), + MethodDef(Color4ub), + MethodDef(Color4ubv), + MethodDef(Color4ui), + MethodDef(Color4uiv), + MethodDef(Color4us), + MethodDef(Color4usv), + MethodDef(ColorMask), + MethodDef(ColorMaterial), + MethodDef(CopyPixels), + MethodDef(CullFace), + MethodDef(DeleteLists), + MethodDef(DeleteTextures), + MethodDef(DepthFunc), + MethodDef(DepthMask), + MethodDef(DepthRange), + MethodDef(Disable), + MethodDef(DrawBuffer), + MethodDef(DrawPixels), + MethodDef(EdgeFlag), + MethodDef(EdgeFlagv), + MethodDef(Enable), + MethodDef(End), + MethodDef(EndList), + MethodDef(EvalCoord1d), + MethodDef(EvalCoord1dv), + MethodDef(EvalCoord1f), + MethodDef(EvalCoord1fv), + MethodDef(EvalCoord2d), + MethodDef(EvalCoord2dv), + MethodDef(EvalCoord2f), + MethodDef(EvalCoord2fv), + MethodDef(EvalMesh1), + MethodDef(EvalMesh2), + MethodDef(EvalPoint1), + MethodDef(EvalPoint2), + MethodDef(FeedbackBuffer), + MethodDef(Finish), + MethodDef(Flush), + MethodDef(Fogf), + MethodDef(Fogfv), + MethodDef(Fogi), + MethodDef(Fogiv), + MethodDef(FrontFace), + MethodDef(Frustum), + MethodDef(GenLists), + MethodDef(GenTextures), + MethodDef(GetBooleanv), + MethodDef(GetClipPlane), + MethodDef(GetDoublev), + MethodDef(GetError), + MethodDef(GetFloatv), + MethodDef(GetIntegerv), + MethodDef(GetLightfv), + MethodDef(GetLightiv), + MethodDef(GetMapdv), + MethodDef(GetMapfv), + MethodDef(GetMapiv), + MethodDef(GetMaterialfv), + MethodDef(GetMaterialiv), + MethodDef(GetPixelMapfv), + MethodDef(GetPixelMapuiv), + MethodDef(GetPixelMapusv), + MethodDef(GetPolygonStipple), + MethodDef(GetString), + MethodDef(GetTexEnvfv), + MethodDef(GetTexEnviv), + MethodDef(GetTexGendv), + MethodDef(GetTexGenfv), + MethodDef(GetTexGeniv), + MethodDef(GetTexImage), + MethodDef(GetTexLevelParameterfv), + MethodDef(GetTexLevelParameteriv), + MethodDef(GetTexParameterfv), + MethodDef(GetTexParameteriv), + MethodDef(Hint), + MethodDef(IndexMask), + MethodDef(Indexd), + MethodDef(Indexdv), + MethodDef(Indexf), + MethodDef(Indexfv), + MethodDef(Indexi), + MethodDef(Indexiv), + MethodDef(Indexs), + MethodDef(Indexsv), + MethodDef(InitNames), + MethodDef(IsEnabled), + MethodDef(IsList), + MethodDef(IsTexture), + MethodDef(LightModelf), + MethodDef(LightModelfv), + MethodDef(LightModeli), + MethodDef(LightModeliv), + MethodDef(Lightf), + MethodDef(Lightfv), + MethodDef(Lighti), + MethodDef(Lightiv), + MethodDef(LineStipple), + MethodDef(LineWidth), + MethodDef(ListBase), + MethodDef(LoadIdentity), + MethodDef(LoadMatrixd), + MethodDef(LoadMatrixf), + MethodDef(LoadName), + MethodDef(LogicOp), + MethodDef(Map1d), + MethodDef(Map1f), + MethodDef(Map2d), + MethodDef(Map2f), + MethodDef(MapGrid1d), + MethodDef(MapGrid1f), + MethodDef(MapGrid2d), + MethodDef(MapGrid2f), + MethodDef(Materialf), + MethodDef(Materialfv), + MethodDef(Materiali), + MethodDef(Materialiv), + MethodDef(MatrixMode), + MethodDef(MultMatrixd), + MethodDef(MultMatrixf), + MethodDef(NewList), + MethodDef(Normal3b), + MethodDef(Normal3bv), + MethodDef(Normal3d), + MethodDef(Normal3dv), + MethodDef(Normal3f), + MethodDef(Normal3fv), + MethodDef(Normal3i), + MethodDef(Normal3iv), + MethodDef(Normal3s), + MethodDef(Normal3sv), + MethodDef(Ortho), + MethodDef(PassThrough), + MethodDef(PixelMapfv), + MethodDef(PixelMapuiv), + MethodDef(PixelMapusv), + MethodDef(PixelStoref), + MethodDef(PixelStorei), + MethodDef(PixelTransferf), + MethodDef(PixelTransferi), + MethodDef(PixelZoom), + MethodDef(PointSize), + MethodDef(PolygonMode), + MethodDef(PolygonOffset), + MethodDef(PolygonStipple), + MethodDef(PopAttrib), + MethodDef(PopClientAttrib), + MethodDef(PopMatrix), + MethodDef(PopName), + MethodDef(PrioritizeTextures), + MethodDef(PushAttrib), + MethodDef(PushClientAttrib), + MethodDef(PushMatrix), + MethodDef(PushName), + MethodDef(RasterPos2d), + MethodDef(RasterPos2dv), + MethodDef(RasterPos2f), + MethodDef(RasterPos2fv), + MethodDef(RasterPos2i), + MethodDef(RasterPos2iv), + MethodDef(RasterPos2s), + MethodDef(RasterPos2sv), + MethodDef(RasterPos3d), + MethodDef(RasterPos3dv), + MethodDef(RasterPos3f), + MethodDef(RasterPos3fv), + MethodDef(RasterPos3i), + MethodDef(RasterPos3iv), + MethodDef(RasterPos3s), + MethodDef(RasterPos3sv), + MethodDef(RasterPos4d), + MethodDef(RasterPos4dv), + MethodDef(RasterPos4f), + MethodDef(RasterPos4fv), + MethodDef(RasterPos4i), + MethodDef(RasterPos4iv), + MethodDef(RasterPos4s), + MethodDef(RasterPos4sv), + MethodDef(ReadBuffer), + MethodDef(ReadPixels), + MethodDef(Rectd), + MethodDef(Rectdv), + MethodDef(Rectf), + MethodDef(Rectfv), + MethodDef(Recti), + MethodDef(Rectiv), + MethodDef(Rects), + MethodDef(Rectsv), + MethodDef(RenderMode), + MethodDef(Rotated), + MethodDef(Rotatef), + MethodDef(Scaled), + MethodDef(Scalef), + MethodDef(Scissor), + MethodDef(SelectBuffer), + MethodDef(ShadeModel), + MethodDef(StencilFunc), + MethodDef(StencilMask), + MethodDef(StencilOp), + MethodDef(TexCoord1d), + MethodDef(TexCoord1dv), + MethodDef(TexCoord1f), + MethodDef(TexCoord1fv), + MethodDef(TexCoord1i), + MethodDef(TexCoord1iv), + MethodDef(TexCoord1s), + MethodDef(TexCoord1sv), + MethodDef(TexCoord2d), + MethodDef(TexCoord2dv), + MethodDef(TexCoord2f), + MethodDef(TexCoord2fv), + MethodDef(TexCoord2i), + MethodDef(TexCoord2iv), + MethodDef(TexCoord2s), + MethodDef(TexCoord2sv), + MethodDef(TexCoord3d), + MethodDef(TexCoord3dv), + MethodDef(TexCoord3f), + MethodDef(TexCoord3fv), + MethodDef(TexCoord3i), + MethodDef(TexCoord3iv), + MethodDef(TexCoord3s), + MethodDef(TexCoord3sv), + MethodDef(TexCoord4d), + MethodDef(TexCoord4dv), + MethodDef(TexCoord4f), + MethodDef(TexCoord4fv), + MethodDef(TexCoord4i), + MethodDef(TexCoord4iv), + MethodDef(TexCoord4s), + MethodDef(TexCoord4sv), + MethodDef(TexEnvf), + MethodDef(TexEnvfv), + MethodDef(TexEnvi), + MethodDef(TexEnviv), + MethodDef(TexGend), + MethodDef(TexGendv), + MethodDef(TexGenf), + MethodDef(TexGenfv), + MethodDef(TexGeni), + MethodDef(TexGeniv), + MethodDef(TexImage1D), + MethodDef(TexImage2D), + MethodDef(TexParameterf), + MethodDef(TexParameterfv), + MethodDef(TexParameteri), + MethodDef(TexParameteriv), + MethodDef(Translated), + MethodDef(Translatef), + MethodDef(Vertex2d), + MethodDef(Vertex2dv), + MethodDef(Vertex2f), + MethodDef(Vertex2fv), + MethodDef(Vertex2i), + MethodDef(Vertex2iv), + MethodDef(Vertex2s), + MethodDef(Vertex2sv), + MethodDef(Vertex3d), + MethodDef(Vertex3dv), + MethodDef(Vertex3f), + MethodDef(Vertex3fv), + MethodDef(Vertex3i), + MethodDef(Vertex3iv), + MethodDef(Vertex3s), + MethodDef(Vertex3sv), + MethodDef(Vertex4d), + MethodDef(Vertex4dv), + MethodDef(Vertex4f), + MethodDef(Vertex4fv), + MethodDef(Vertex4i), + MethodDef(Vertex4iv), + MethodDef(Vertex4s), + MethodDef(Vertex4sv), + MethodDef(Viewport), + MethodDefu(Perspective), + MethodDefu(LookAt), + MethodDefu(Ortho2D), + MethodDefu(PickMatrix), + MethodDefu(Project), + MethodDefu(UnProject), +/* #endif */ + {NULL, NULL, 0, NULL} +}; + +#if (PY_VERSION_HEX >= 0x03000000) +static struct PyModuleDef BGL_module_def = { + PyModuleDef_HEAD_INIT, + "BGL", /* m_name */ + 0, /* m_doc */ + 0, /* m_size */ + BGL_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; +#endif + +PyObject *BGL_Init(const char *from) +{ + PyObject *mod, *dict, *item; +#if (PY_VERSION_HEX >= 0x03000000) + mod = PyModule_Create(&BGL_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), BGL_module_def.m_name, mod); +#else + mod= Py_InitModule(from, BGL_methods); +#endif + dict= PyModule_GetDict(mod); + + if( PyType_Ready( &buffer_Type) < 0) + return NULL; /* should never happen */ + +#define EXPP_ADDCONST(x) PyDict_SetItemString(dict, #x, item=PyLong_FromLong((int)x)); Py_DECREF(item) + +/* So, for example: + * EXPP_ADDCONST(GL_CURRENT_BIT) becomes + * PyDict_SetItemString(dict, "GL_CURRENT_BIT", item=PyLong_FromLong(GL_CURRENT_BIT)); Py_DECREF(item) */ + + EXPP_ADDCONST(GL_CURRENT_BIT); + EXPP_ADDCONST(GL_POINT_BIT); + EXPP_ADDCONST(GL_LINE_BIT); + EXPP_ADDCONST(GL_POLYGON_BIT); + EXPP_ADDCONST(GL_POLYGON_STIPPLE_BIT); + EXPP_ADDCONST(GL_PIXEL_MODE_BIT); + EXPP_ADDCONST(GL_LIGHTING_BIT); + EXPP_ADDCONST(GL_FOG_BIT); + EXPP_ADDCONST(GL_DEPTH_BUFFER_BIT); + EXPP_ADDCONST(GL_ACCUM_BUFFER_BIT); + EXPP_ADDCONST(GL_STENCIL_BUFFER_BIT); + EXPP_ADDCONST(GL_VIEWPORT_BIT); + EXPP_ADDCONST(GL_TRANSFORM_BIT); + EXPP_ADDCONST(GL_ENABLE_BIT); + EXPP_ADDCONST(GL_COLOR_BUFFER_BIT); + EXPP_ADDCONST(GL_HINT_BIT); + EXPP_ADDCONST(GL_EVAL_BIT); + EXPP_ADDCONST(GL_LIST_BIT); + EXPP_ADDCONST(GL_TEXTURE_BIT); + EXPP_ADDCONST(GL_SCISSOR_BIT); + EXPP_ADDCONST(GL_ALL_ATTRIB_BITS); + EXPP_ADDCONST(GL_CLIENT_ALL_ATTRIB_BITS); + + EXPP_ADDCONST(GL_FALSE); + EXPP_ADDCONST(GL_TRUE); + + EXPP_ADDCONST(GL_POINTS); + EXPP_ADDCONST(GL_LINES); + EXPP_ADDCONST(GL_LINE_LOOP); + EXPP_ADDCONST(GL_LINE_STRIP); + EXPP_ADDCONST(GL_TRIANGLES); + EXPP_ADDCONST(GL_TRIANGLE_STRIP); + EXPP_ADDCONST(GL_TRIANGLE_FAN); + EXPP_ADDCONST(GL_QUADS); + EXPP_ADDCONST(GL_QUAD_STRIP); + EXPP_ADDCONST(GL_POLYGON); + + EXPP_ADDCONST(GL_ACCUM); + EXPP_ADDCONST(GL_LOAD); + EXPP_ADDCONST(GL_RETURN); + EXPP_ADDCONST(GL_MULT); + EXPP_ADDCONST(GL_ADD); + + EXPP_ADDCONST(GL_NEVER); + EXPP_ADDCONST(GL_LESS); + EXPP_ADDCONST(GL_EQUAL); + EXPP_ADDCONST(GL_LEQUAL); + EXPP_ADDCONST(GL_GREATER); + EXPP_ADDCONST(GL_NOTEQUAL); + EXPP_ADDCONST(GL_GEQUAL); + EXPP_ADDCONST(GL_ALWAYS); + + EXPP_ADDCONST(GL_ZERO); + EXPP_ADDCONST(GL_ONE); + EXPP_ADDCONST(GL_SRC_COLOR); + EXPP_ADDCONST(GL_ONE_MINUS_SRC_COLOR); + EXPP_ADDCONST(GL_SRC_ALPHA); + EXPP_ADDCONST(GL_ONE_MINUS_SRC_ALPHA); + EXPP_ADDCONST(GL_DST_ALPHA); + EXPP_ADDCONST(GL_ONE_MINUS_DST_ALPHA); + + EXPP_ADDCONST(GL_DST_COLOR); + EXPP_ADDCONST(GL_ONE_MINUS_DST_COLOR); + EXPP_ADDCONST(GL_SRC_ALPHA_SATURATE); + + EXPP_ADDCONST(GL_NONE); + EXPP_ADDCONST(GL_FRONT_LEFT); + EXPP_ADDCONST(GL_FRONT_RIGHT); + EXPP_ADDCONST(GL_BACK_LEFT); + EXPP_ADDCONST(GL_BACK_RIGHT); + EXPP_ADDCONST(GL_FRONT); + EXPP_ADDCONST(GL_BACK); + EXPP_ADDCONST(GL_LEFT); + EXPP_ADDCONST(GL_RIGHT); + EXPP_ADDCONST(GL_FRONT_AND_BACK); + EXPP_ADDCONST(GL_AUX0); + EXPP_ADDCONST(GL_AUX1); + EXPP_ADDCONST(GL_AUX2); + EXPP_ADDCONST(GL_AUX3); + + EXPP_ADDCONST(GL_NO_ERROR); + EXPP_ADDCONST(GL_INVALID_ENUM); + EXPP_ADDCONST(GL_INVALID_VALUE); + EXPP_ADDCONST(GL_INVALID_OPERATION); + EXPP_ADDCONST(GL_STACK_OVERFLOW); + EXPP_ADDCONST(GL_STACK_UNDERFLOW); + EXPP_ADDCONST(GL_OUT_OF_MEMORY); + + EXPP_ADDCONST(GL_2D); + EXPP_ADDCONST(GL_3D); + EXPP_ADDCONST(GL_3D_COLOR); + EXPP_ADDCONST(GL_3D_COLOR_TEXTURE); + EXPP_ADDCONST(GL_4D_COLOR_TEXTURE); + + EXPP_ADDCONST(GL_PASS_THROUGH_TOKEN); + EXPP_ADDCONST(GL_POINT_TOKEN); + EXPP_ADDCONST(GL_LINE_TOKEN); + EXPP_ADDCONST(GL_POLYGON_TOKEN); + EXPP_ADDCONST(GL_BITMAP_TOKEN); + EXPP_ADDCONST(GL_DRAW_PIXEL_TOKEN); + EXPP_ADDCONST(GL_COPY_PIXEL_TOKEN); + EXPP_ADDCONST(GL_LINE_RESET_TOKEN); + + EXPP_ADDCONST(GL_EXP); + EXPP_ADDCONST(GL_EXP2); + + EXPP_ADDCONST(GL_CW); + EXPP_ADDCONST(GL_CCW); + + EXPP_ADDCONST(GL_COEFF); + EXPP_ADDCONST(GL_ORDER); + EXPP_ADDCONST(GL_DOMAIN); + + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_I); + EXPP_ADDCONST(GL_PIXEL_MAP_S_TO_S); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_R); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_G); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_B); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_A); + EXPP_ADDCONST(GL_PIXEL_MAP_R_TO_R); + EXPP_ADDCONST(GL_PIXEL_MAP_G_TO_G); + EXPP_ADDCONST(GL_PIXEL_MAP_B_TO_B); + EXPP_ADDCONST(GL_PIXEL_MAP_A_TO_A); + + EXPP_ADDCONST(GL_CURRENT_COLOR); + EXPP_ADDCONST(GL_CURRENT_INDEX); + EXPP_ADDCONST(GL_CURRENT_NORMAL); + EXPP_ADDCONST(GL_CURRENT_TEXTURE_COORDS); + EXPP_ADDCONST(GL_CURRENT_RASTER_COLOR); + EXPP_ADDCONST(GL_CURRENT_RASTER_INDEX); + EXPP_ADDCONST(GL_CURRENT_RASTER_TEXTURE_COORDS); + EXPP_ADDCONST(GL_CURRENT_RASTER_POSITION); + EXPP_ADDCONST(GL_CURRENT_RASTER_POSITION_VALID); + EXPP_ADDCONST(GL_CURRENT_RASTER_DISTANCE); + EXPP_ADDCONST(GL_POINT_SMOOTH); + EXPP_ADDCONST(GL_POINT_SIZE); + EXPP_ADDCONST(GL_POINT_SIZE_RANGE); + EXPP_ADDCONST(GL_POINT_SIZE_GRANULARITY); + EXPP_ADDCONST(GL_LINE_SMOOTH); + EXPP_ADDCONST(GL_LINE_WIDTH); + EXPP_ADDCONST(GL_LINE_WIDTH_RANGE); + EXPP_ADDCONST(GL_LINE_WIDTH_GRANULARITY); + EXPP_ADDCONST(GL_LINE_STIPPLE); + EXPP_ADDCONST(GL_LINE_STIPPLE_PATTERN); + EXPP_ADDCONST(GL_LINE_STIPPLE_REPEAT); + EXPP_ADDCONST(GL_LIST_MODE); + EXPP_ADDCONST(GL_MAX_LIST_NESTING); + EXPP_ADDCONST(GL_LIST_BASE); + EXPP_ADDCONST(GL_LIST_INDEX); + EXPP_ADDCONST(GL_POLYGON_MODE); + EXPP_ADDCONST(GL_POLYGON_SMOOTH); + EXPP_ADDCONST(GL_POLYGON_STIPPLE); + EXPP_ADDCONST(GL_EDGE_FLAG); + EXPP_ADDCONST(GL_CULL_FACE); + EXPP_ADDCONST(GL_CULL_FACE_MODE); + EXPP_ADDCONST(GL_FRONT_FACE); + EXPP_ADDCONST(GL_LIGHTING); + EXPP_ADDCONST(GL_LIGHT_MODEL_LOCAL_VIEWER); + EXPP_ADDCONST(GL_LIGHT_MODEL_TWO_SIDE); + EXPP_ADDCONST(GL_LIGHT_MODEL_AMBIENT); + EXPP_ADDCONST(GL_SHADE_MODEL); + EXPP_ADDCONST(GL_COLOR_MATERIAL_FACE); + EXPP_ADDCONST(GL_COLOR_MATERIAL_PARAMETER); + EXPP_ADDCONST(GL_COLOR_MATERIAL); + EXPP_ADDCONST(GL_FOG); + EXPP_ADDCONST(GL_FOG_INDEX); + EXPP_ADDCONST(GL_FOG_DENSITY); + EXPP_ADDCONST(GL_FOG_START); + EXPP_ADDCONST(GL_FOG_END); + EXPP_ADDCONST(GL_FOG_MODE); + EXPP_ADDCONST(GL_FOG_COLOR); + EXPP_ADDCONST(GL_DEPTH_RANGE); + EXPP_ADDCONST(GL_DEPTH_TEST); + EXPP_ADDCONST(GL_DEPTH_WRITEMASK); + EXPP_ADDCONST(GL_DEPTH_CLEAR_VALUE); + EXPP_ADDCONST(GL_DEPTH_FUNC); + EXPP_ADDCONST(GL_ACCUM_CLEAR_VALUE); + EXPP_ADDCONST(GL_STENCIL_TEST); + EXPP_ADDCONST(GL_STENCIL_CLEAR_VALUE); + EXPP_ADDCONST(GL_STENCIL_FUNC); + EXPP_ADDCONST(GL_STENCIL_VALUE_MASK); + EXPP_ADDCONST(GL_STENCIL_FAIL); + EXPP_ADDCONST(GL_STENCIL_PASS_DEPTH_FAIL); + EXPP_ADDCONST(GL_STENCIL_PASS_DEPTH_PASS); + EXPP_ADDCONST(GL_STENCIL_REF); + EXPP_ADDCONST(GL_STENCIL_WRITEMASK); + EXPP_ADDCONST(GL_MATRIX_MODE); + EXPP_ADDCONST(GL_NORMALIZE); + EXPP_ADDCONST(GL_VIEWPORT); + EXPP_ADDCONST(GL_MODELVIEW_STACK_DEPTH); + EXPP_ADDCONST(GL_PROJECTION_STACK_DEPTH); + EXPP_ADDCONST(GL_TEXTURE_STACK_DEPTH); + EXPP_ADDCONST(GL_MODELVIEW_MATRIX); + EXPP_ADDCONST(GL_PROJECTION_MATRIX); + EXPP_ADDCONST(GL_TEXTURE_MATRIX); + EXPP_ADDCONST(GL_ATTRIB_STACK_DEPTH); + EXPP_ADDCONST(GL_ALPHA_TEST); + EXPP_ADDCONST(GL_ALPHA_TEST_FUNC); + EXPP_ADDCONST(GL_ALPHA_TEST_REF); + EXPP_ADDCONST(GL_DITHER); + EXPP_ADDCONST(GL_BLEND_DST); + EXPP_ADDCONST(GL_BLEND_SRC); + EXPP_ADDCONST(GL_BLEND); + EXPP_ADDCONST(GL_LOGIC_OP_MODE); + EXPP_ADDCONST(GL_LOGIC_OP); + EXPP_ADDCONST(GL_AUX_BUFFERS); + EXPP_ADDCONST(GL_DRAW_BUFFER); + EXPP_ADDCONST(GL_READ_BUFFER); + EXPP_ADDCONST(GL_SCISSOR_BOX); + EXPP_ADDCONST(GL_SCISSOR_TEST); + EXPP_ADDCONST(GL_INDEX_CLEAR_VALUE); + EXPP_ADDCONST(GL_INDEX_WRITEMASK); + EXPP_ADDCONST(GL_COLOR_CLEAR_VALUE); + EXPP_ADDCONST(GL_COLOR_WRITEMASK); + EXPP_ADDCONST(GL_INDEX_MODE); + EXPP_ADDCONST(GL_RGBA_MODE); + EXPP_ADDCONST(GL_DOUBLEBUFFER); + EXPP_ADDCONST(GL_STEREO); + EXPP_ADDCONST(GL_RENDER_MODE); + EXPP_ADDCONST(GL_PERSPECTIVE_CORRECTION_HINT); + EXPP_ADDCONST(GL_POINT_SMOOTH_HINT); + EXPP_ADDCONST(GL_LINE_SMOOTH_HINT); + EXPP_ADDCONST(GL_POLYGON_SMOOTH_HINT); + EXPP_ADDCONST(GL_FOG_HINT); + EXPP_ADDCONST(GL_TEXTURE_GEN_S); + EXPP_ADDCONST(GL_TEXTURE_GEN_T); + EXPP_ADDCONST(GL_TEXTURE_GEN_R); + EXPP_ADDCONST(GL_TEXTURE_GEN_Q); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_I_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_S_TO_S_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_R_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_G_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_B_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_A_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_R_TO_R_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_G_TO_G_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_B_TO_B_SIZE); + EXPP_ADDCONST(GL_PIXEL_MAP_A_TO_A_SIZE); + EXPP_ADDCONST(GL_UNPACK_SWAP_BYTES); + EXPP_ADDCONST(GL_UNPACK_LSB_FIRST); + EXPP_ADDCONST(GL_UNPACK_ROW_LENGTH); + EXPP_ADDCONST(GL_UNPACK_SKIP_ROWS); + EXPP_ADDCONST(GL_UNPACK_SKIP_PIXELS); + EXPP_ADDCONST(GL_UNPACK_ALIGNMENT); + EXPP_ADDCONST(GL_PACK_SWAP_BYTES); + EXPP_ADDCONST(GL_PACK_LSB_FIRST); + EXPP_ADDCONST(GL_PACK_ROW_LENGTH); + EXPP_ADDCONST(GL_PACK_SKIP_ROWS); + EXPP_ADDCONST(GL_PACK_SKIP_PIXELS); + EXPP_ADDCONST(GL_PACK_ALIGNMENT); + EXPP_ADDCONST(GL_MAP_COLOR); + EXPP_ADDCONST(GL_MAP_STENCIL); + EXPP_ADDCONST(GL_INDEX_SHIFT); + EXPP_ADDCONST(GL_INDEX_OFFSET); + EXPP_ADDCONST(GL_RED_SCALE); + EXPP_ADDCONST(GL_RED_BIAS); + EXPP_ADDCONST(GL_ZOOM_X); + EXPP_ADDCONST(GL_ZOOM_Y); + EXPP_ADDCONST(GL_GREEN_SCALE); + EXPP_ADDCONST(GL_GREEN_BIAS); + EXPP_ADDCONST(GL_BLUE_SCALE); + EXPP_ADDCONST(GL_BLUE_BIAS); + EXPP_ADDCONST(GL_ALPHA_SCALE); + EXPP_ADDCONST(GL_ALPHA_BIAS); + EXPP_ADDCONST(GL_DEPTH_SCALE); + EXPP_ADDCONST(GL_DEPTH_BIAS); + EXPP_ADDCONST(GL_MAX_EVAL_ORDER); + EXPP_ADDCONST(GL_MAX_LIGHTS); + EXPP_ADDCONST(GL_MAX_CLIP_PLANES); + EXPP_ADDCONST(GL_MAX_TEXTURE_SIZE); + EXPP_ADDCONST(GL_MAX_PIXEL_MAP_TABLE); + EXPP_ADDCONST(GL_MAX_ATTRIB_STACK_DEPTH); + EXPP_ADDCONST(GL_MAX_MODELVIEW_STACK_DEPTH); + EXPP_ADDCONST(GL_MAX_NAME_STACK_DEPTH); + EXPP_ADDCONST(GL_MAX_PROJECTION_STACK_DEPTH); + EXPP_ADDCONST(GL_MAX_TEXTURE_STACK_DEPTH); + EXPP_ADDCONST(GL_MAX_VIEWPORT_DIMS); + EXPP_ADDCONST(GL_SUBPIXEL_BITS); + EXPP_ADDCONST(GL_INDEX_BITS); + EXPP_ADDCONST(GL_RED_BITS); + EXPP_ADDCONST(GL_GREEN_BITS); + EXPP_ADDCONST(GL_BLUE_BITS); + EXPP_ADDCONST(GL_ALPHA_BITS); + EXPP_ADDCONST(GL_DEPTH_BITS); + EXPP_ADDCONST(GL_STENCIL_BITS); + EXPP_ADDCONST(GL_ACCUM_RED_BITS); + EXPP_ADDCONST(GL_ACCUM_GREEN_BITS); + EXPP_ADDCONST(GL_ACCUM_BLUE_BITS); + EXPP_ADDCONST(GL_ACCUM_ALPHA_BITS); + EXPP_ADDCONST(GL_NAME_STACK_DEPTH); + EXPP_ADDCONST(GL_AUTO_NORMAL); + EXPP_ADDCONST(GL_MAP1_COLOR_4); + EXPP_ADDCONST(GL_MAP1_INDEX); + EXPP_ADDCONST(GL_MAP1_NORMAL); + EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_1); + EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_2); + EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_3); + EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_4); + EXPP_ADDCONST(GL_MAP1_VERTEX_3); + EXPP_ADDCONST(GL_MAP1_VERTEX_4); + EXPP_ADDCONST(GL_MAP2_COLOR_4); + EXPP_ADDCONST(GL_MAP2_INDEX); + EXPP_ADDCONST(GL_MAP2_NORMAL); + EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_1); + EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_2); + EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_3); + EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_4); + EXPP_ADDCONST(GL_MAP2_VERTEX_3); + EXPP_ADDCONST(GL_MAP2_VERTEX_4); + EXPP_ADDCONST(GL_MAP1_GRID_DOMAIN); + EXPP_ADDCONST(GL_MAP1_GRID_SEGMENTS); + EXPP_ADDCONST(GL_MAP2_GRID_DOMAIN); + EXPP_ADDCONST(GL_MAP2_GRID_SEGMENTS); + EXPP_ADDCONST(GL_TEXTURE_1D); + EXPP_ADDCONST(GL_TEXTURE_2D); + + EXPP_ADDCONST(GL_TEXTURE_WIDTH); + EXPP_ADDCONST(GL_TEXTURE_HEIGHT); + EXPP_ADDCONST(GL_TEXTURE_COMPONENTS); + EXPP_ADDCONST(GL_TEXTURE_BORDER_COLOR); + EXPP_ADDCONST(GL_TEXTURE_BORDER); + + EXPP_ADDCONST(GL_DONT_CARE); + EXPP_ADDCONST(GL_FASTEST); + EXPP_ADDCONST(GL_NICEST); + + EXPP_ADDCONST(GL_AMBIENT); + EXPP_ADDCONST(GL_DIFFUSE); + EXPP_ADDCONST(GL_SPECULAR); + EXPP_ADDCONST(GL_POSITION); + EXPP_ADDCONST(GL_SPOT_DIRECTION); + EXPP_ADDCONST(GL_SPOT_EXPONENT); + EXPP_ADDCONST(GL_SPOT_CUTOFF); + EXPP_ADDCONST(GL_CONSTANT_ATTENUATION); + EXPP_ADDCONST(GL_LINEAR_ATTENUATION); + EXPP_ADDCONST(GL_QUADRATIC_ATTENUATION); + + EXPP_ADDCONST(GL_COMPILE); + EXPP_ADDCONST(GL_COMPILE_AND_EXECUTE); + + EXPP_ADDCONST(GL_BYTE); + EXPP_ADDCONST(GL_UNSIGNED_BYTE); + EXPP_ADDCONST(GL_SHORT); + EXPP_ADDCONST(GL_UNSIGNED_SHORT); + EXPP_ADDCONST(GL_INT); + EXPP_ADDCONST(GL_UNSIGNED_INT); + EXPP_ADDCONST(GL_FLOAT); + EXPP_ADDCONST(GL_DOUBLE); + EXPP_ADDCONST(GL_2_BYTES); + EXPP_ADDCONST(GL_3_BYTES); + EXPP_ADDCONST(GL_4_BYTES); + + EXPP_ADDCONST(GL_CLEAR); + EXPP_ADDCONST(GL_AND); + EXPP_ADDCONST(GL_AND_REVERSE); + EXPP_ADDCONST(GL_COPY); + EXPP_ADDCONST(GL_AND_INVERTED); + EXPP_ADDCONST(GL_NOOP); + EXPP_ADDCONST(GL_XOR); + EXPP_ADDCONST(GL_OR); + EXPP_ADDCONST(GL_NOR); + EXPP_ADDCONST(GL_EQUIV); + EXPP_ADDCONST(GL_INVERT); + EXPP_ADDCONST(GL_OR_REVERSE); + EXPP_ADDCONST(GL_COPY_INVERTED); + EXPP_ADDCONST(GL_OR_INVERTED); + EXPP_ADDCONST(GL_NAND); + EXPP_ADDCONST(GL_SET); + + EXPP_ADDCONST(GL_EMISSION); + EXPP_ADDCONST(GL_SHININESS); + EXPP_ADDCONST(GL_AMBIENT_AND_DIFFUSE); + EXPP_ADDCONST(GL_COLOR_INDEXES); + + EXPP_ADDCONST(GL_MODELVIEW); + EXPP_ADDCONST(GL_PROJECTION); + EXPP_ADDCONST(GL_TEXTURE); + + EXPP_ADDCONST(GL_COLOR); + EXPP_ADDCONST(GL_DEPTH); + EXPP_ADDCONST(GL_STENCIL); + + EXPP_ADDCONST(GL_COLOR_INDEX); + EXPP_ADDCONST(GL_STENCIL_INDEX); + EXPP_ADDCONST(GL_DEPTH_COMPONENT); + EXPP_ADDCONST(GL_RED); + EXPP_ADDCONST(GL_GREEN); + EXPP_ADDCONST(GL_BLUE); + EXPP_ADDCONST(GL_ALPHA); + EXPP_ADDCONST(GL_RGB); + EXPP_ADDCONST(GL_RGBA); + EXPP_ADDCONST(GL_LUMINANCE); + EXPP_ADDCONST(GL_LUMINANCE_ALPHA); + + EXPP_ADDCONST(GL_BITMAP); + + EXPP_ADDCONST(GL_POINT); + EXPP_ADDCONST(GL_LINE); + EXPP_ADDCONST(GL_FILL); + + EXPP_ADDCONST(GL_RENDER); + EXPP_ADDCONST(GL_FEEDBACK); + EXPP_ADDCONST(GL_SELECT); + + EXPP_ADDCONST(GL_FLAT); + EXPP_ADDCONST(GL_SMOOTH); + + EXPP_ADDCONST(GL_KEEP); + EXPP_ADDCONST(GL_REPLACE); + EXPP_ADDCONST(GL_INCR); + EXPP_ADDCONST(GL_DECR); + + EXPP_ADDCONST(GL_VENDOR); + EXPP_ADDCONST(GL_RENDERER); + EXPP_ADDCONST(GL_VERSION); + EXPP_ADDCONST(GL_EXTENSIONS); + + EXPP_ADDCONST(GL_S); + EXPP_ADDCONST(GL_T); + EXPP_ADDCONST(GL_R); + EXPP_ADDCONST(GL_Q); + + EXPP_ADDCONST(GL_MODULATE); + EXPP_ADDCONST(GL_DECAL); + + EXPP_ADDCONST(GL_TEXTURE_ENV_MODE); + EXPP_ADDCONST(GL_TEXTURE_ENV_COLOR); + + EXPP_ADDCONST(GL_TEXTURE_ENV); + + EXPP_ADDCONST(GL_EYE_LINEAR); + EXPP_ADDCONST(GL_OBJECT_LINEAR); + EXPP_ADDCONST(GL_SPHERE_MAP); + + EXPP_ADDCONST(GL_TEXTURE_GEN_MODE); + EXPP_ADDCONST(GL_OBJECT_PLANE); + EXPP_ADDCONST(GL_EYE_PLANE); + + EXPP_ADDCONST(GL_NEAREST); + EXPP_ADDCONST(GL_LINEAR); + + EXPP_ADDCONST(GL_NEAREST_MIPMAP_NEAREST); + EXPP_ADDCONST(GL_LINEAR_MIPMAP_NEAREST); + EXPP_ADDCONST(GL_NEAREST_MIPMAP_LINEAR); + EXPP_ADDCONST(GL_LINEAR_MIPMAP_LINEAR); + + EXPP_ADDCONST(GL_TEXTURE_MAG_FILTER); + EXPP_ADDCONST(GL_TEXTURE_MIN_FILTER); + EXPP_ADDCONST(GL_TEXTURE_WRAP_S); + EXPP_ADDCONST(GL_TEXTURE_WRAP_T); + + EXPP_ADDCONST(GL_CLAMP); + EXPP_ADDCONST(GL_REPEAT); + + EXPP_ADDCONST(GL_CLIP_PLANE0); + EXPP_ADDCONST(GL_CLIP_PLANE1); + EXPP_ADDCONST(GL_CLIP_PLANE2); + EXPP_ADDCONST(GL_CLIP_PLANE3); + EXPP_ADDCONST(GL_CLIP_PLANE4); + EXPP_ADDCONST(GL_CLIP_PLANE5); + + EXPP_ADDCONST(GL_LIGHT0); + EXPP_ADDCONST(GL_LIGHT1); + EXPP_ADDCONST(GL_LIGHT2); + EXPP_ADDCONST(GL_LIGHT3); + EXPP_ADDCONST(GL_LIGHT4); + EXPP_ADDCONST(GL_LIGHT5); + EXPP_ADDCONST(GL_LIGHT6); + EXPP_ADDCONST(GL_LIGHT7); + + EXPP_ADDCONST(GL_POLYGON_OFFSET_UNITS); + EXPP_ADDCONST(GL_POLYGON_OFFSET_POINT); + EXPP_ADDCONST(GL_POLYGON_OFFSET_LINE); + EXPP_ADDCONST(GL_POLYGON_OFFSET_FILL); + EXPP_ADDCONST(GL_POLYGON_OFFSET_FACTOR); + + EXPP_ADDCONST(GL_TEXTURE_PRIORITY); + EXPP_ADDCONST(GL_TEXTURE_RESIDENT); + EXPP_ADDCONST(GL_TEXTURE_BINDING_1D); + EXPP_ADDCONST(GL_TEXTURE_BINDING_2D); + + return mod; +} + diff --git a/source/blender/python/generic/BGL.h b/source/blender/python/generic/BGL.h new file mode 100644 index 00000000000..acd4d3adca3 --- /dev/null +++ b/source/blender/python/generic/BGL.h @@ -0,0 +1,338 @@ +/* + * $Id: BGL.h 21094 2009-06-23 00:09:26Z gsrb3d $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL LICENSE BLOCK ***** +*/ + +/* This is the Blender.BGL part of opy_draw.c, from the old bpython/intern + * dir, with minor changes to adapt it to the new Python implementation. + * The BGL submodule "wraps" OpenGL functions and constants, allowing script + * 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 + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "../intern/bpy_compat.h" + +PyObject *BGL_Init( const char *from ); + +/*@ Buffer Object */ +/*@ For Python access to OpenGL functions requiring a pointer. */ + +typedef struct _Buffer { + PyObject_VAR_HEAD + PyObject * parent; + + int type; /* GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT */ + int ndimensions; + int *dimensions; + + union { + char *asbyte; + short *asshort; + int *asint; + float *asfloat; + double *asdouble; + + void *asvoid; + } buf; +} Buffer; + + +/*@ By golly George! It looks like fancy pants macro time!!! */ + +/* +#define int_str "i" +#define int_var(number) bgl_int##number +#define int_ref(number) &bgl_int##number +#define int_def(number) int int_var(number) + +#define float_str "f" +#define float_var(number) bgl_float##number +#define float_ref(number) &bgl_float##number +#define float_def(number) float float_var(number) +*/ + +/* TYPE_str is the string to pass to Py_ArgParse (for the format) */ +/* TYPE_var is the name to pass to the GL function */ +/* TYPE_ref is the pointer to pass to Py_ArgParse (to store in) */ +/* TYPE_def is the C initialization of the variable */ + +#define void_str "" +#define void_var(num) +#define void_ref(num) &bgl_var##num +#define void_def(num) char bgl_var##num + +#define buffer_str "O!" +#define buffer_var(number) (bgl_buffer##number)->buf.asvoid +#define buffer_ref(number) &buffer_Type, &bgl_buffer##number +#define buffer_def(number) Buffer *bgl_buffer##number + +/* GL Pointer fields, handled by buffer type */ +/* GLdoubleP, GLfloatP, GLintP, GLuintP, GLshortP */ + +#define GLbooleanP_str "O!" +#define GLbooleanP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLbooleanP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLbooleanP_def(number) Buffer *bgl_buffer##number + +#define GLbyteP_str "O!" +#define GLbyteP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLbyteP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLbyteP_def(number) Buffer *bgl_buffer##number + +#define GLubyteP_str "O!" +#define GLubyteP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLubyteP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLubyteP_def(number) Buffer *bgl_buffer##number + +#define GLintP_str "O!" +#define GLintP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLintP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLintP_def(number) Buffer *bgl_buffer##number + +#define GLuintP_str "O!" +#define GLuintP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLuintP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLuintP_def(number) Buffer *bgl_buffer##number + +#define GLshortP_str "O!" +#define GLshortP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLshortP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLshortP_def(number) Buffer *bgl_buffer##number + +#define GLushortP_str "O!" +#define GLushortP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLushortP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLushortP_def(number) Buffer *bgl_buffer##number + +#define GLfloatP_str "O!" +#define GLfloatP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLfloatP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLfloatP_def(number) Buffer *bgl_buffer##number + +#define GLdoubleP_str "O!" +#define GLdoubleP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLdoubleP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLdoubleP_def(number) Buffer *bgl_buffer##number + +#define GLclampfP_str "O!" +#define GLclampfP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLclampfP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLclampfP_def(number) Buffer *bgl_buffer##number + +#define GLvoidP_str "O!" +#define GLvoidP_var(number) (bgl_buffer##number)->buf.asvoid +#define GLvoidP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLvoidP_def(number) Buffer *bgl_buffer##number + +#define buffer_str "O!" +#define buffer_var(number) (bgl_buffer##number)->buf.asvoid +#define buffer_ref(number) &buffer_Type, &bgl_buffer##number +#define buffer_def(number) Buffer *bgl_buffer##number + +/*@The standard GL typedefs are used as prototypes, we can't + * use the GL type directly because Py_ArgParse expects normal + * C types. + * + * Py_ArgParse doesn't grok writing into unsigned variables, + * so we use signed everything (even stuff that should be unsigned. + */ + +/* typedef unsigned int GLenum; */ +#define GLenum_str "i" +#define GLenum_var(num) bgl_var##num +#define GLenum_ref(num) &bgl_var##num +#define GLenum_def(num) /* unsigned */ int GLenum_var(num) + +/* typedef unsigned int GLboolean; */ +#define GLboolean_str "b" +#define GLboolean_var(num) bgl_var##num +#define GLboolean_ref(num) &bgl_var##num +#define GLboolean_def(num) /* unsigned */ char GLboolean_var(num) + +/* typedef unsigned int GLbitfield; */ +#define GLbitfield_str "i" +#define GLbitfield_var(num) bgl_var##num +#define GLbitfield_ref(num) &bgl_var##num +#define GLbitfield_def(num) /* unsigned */ int GLbitfield_var(num) + +/* typedef signed char GLbyte; */ +#define GLbyte_str "b" +#define GLbyte_var(num) bgl_var##num +#define GLbyte_ref(num) &bgl_var##num +#define GLbyte_def(num) signed char GLbyte_var(num) + +/* typedef short GLshort; */ +#define GLshort_str "h" +#define GLshort_var(num) bgl_var##num +#define GLshort_ref(num) &bgl_var##num +#define GLshort_def(num) short GLshort_var(num) + +/* typedef int GLint; */ +#define GLint_str "i" +#define GLint_var(num) bgl_var##num +#define GLint_ref(num) &bgl_var##num +#define GLint_def(num) int GLint_var(num) + +/* typedef int GLsizei; */ +#define GLsizei_str "i" +#define GLsizei_var(num) bgl_var##num +#define GLsizei_ref(num) &bgl_var##num +#define GLsizei_def(num) int GLsizei_var(num) + +/* typedef unsigned char GLubyte; */ +#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_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_var(num) bgl_var##num +#define GLuint_ref(num) &bgl_var##num +#define GLuint_def(num) /* unsigned */ int GLuint_var(num) + +/* typedef float GLfloat; */ +#define GLfloat_str "f" +#define GLfloat_var(num) bgl_var##num +#define GLfloat_ref(num) &bgl_var##num +#define GLfloat_def(num) float GLfloat_var(num) + +/* typedef float GLclampf; */ +#define GLclampf_str "f" +#define GLclampf_var(num) bgl_var##num +#define GLclampf_ref(num) &bgl_var##num +#define GLclampf_def(num) float GLclampf_var(num) + +/* typedef double GLdouble; */ +#define GLdouble_str "d" +#define GLdouble_var(num) bgl_var##num +#define GLdouble_ref(num) &bgl_var##num +#define GLdouble_def(num) double GLdouble_var(num) + +/* typedef double GLclampd; */ +#define GLclampd_str "d" +#define GLclampd_var(num) bgl_var##num +#define GLclampd_ref(num) &bgl_var##num +#define GLclampd_def(num) double GLclampd_var(num) + +/* typedef void GLvoid; */ +/* #define GLvoid_str "" */ +/* #define GLvoid_var(num) bgl_var##num */ +/* #define GLvoid_ref(num) &bgl_var##num */ +/* #define GLvoid_def(num) char bgl_var##num */ + +#define arg_def1(a1) a1##_def(1) +#define arg_def2(a1, a2) arg_def1(a1); a2##_def(2) +#define arg_def3(a1, a2, a3) arg_def2(a1, a2); a3##_def(3) +#define arg_def4(a1, a2, a3, a4) arg_def3(a1, a2, a3); a4##_def(4) +#define arg_def5(a1, a2, a3, a4, a5) arg_def4(a1, a2, a3, a4); a5##_def(5) +#define arg_def6(a1, a2, a3, a4, a5, a6)arg_def5(a1, a2, a3, a4, a5); a6##_def(6) +#define arg_def7(a1, a2, a3, a4, a5, a6, a7)arg_def6(a1, a2, a3, a4, a5, a6); a7##_def(7) +#define arg_def8(a1, a2, a3, a4, a5, a6, a7, a8)arg_def7(a1, a2, a3, a4, a5, a6, a7); a8##_def(8) +#define arg_def9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_def8(a1, a2, a3, a4, a5, a6, a7, a8); a9##_def(9) +#define arg_def10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_def9(a1, a2, a3, a4, a5, a6, a7, a8, a9); a10##_def(10) + +#define arg_var1(a1) a1##_var(1) +#define arg_var2(a1, a2) arg_var1(a1), a2##_var(2) +#define arg_var3(a1, a2, a3) arg_var2(a1, a2), a3##_var(3) +#define arg_var4(a1, a2, a3, a4) arg_var3(a1, a2, a3), a4##_var(4) +#define arg_var5(a1, a2, a3, a4, a5) arg_var4(a1, a2, a3, a4), a5##_var(5) +#define arg_var6(a1, a2, a3, a4, a5, a6)arg_var5(a1, a2, a3, a4, a5), a6##_var(6) +#define arg_var7(a1, a2, a3, a4, a5, a6, a7)arg_var6(a1, a2, a3, a4, a5, a6), a7##_var(7) +#define arg_var8(a1, a2, a3, a4, a5, a6, a7, a8)arg_var7(a1, a2, a3, a4, a5, a6, a7), a8##_var(8) +#define arg_var9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_var8(a1, a2, a3, a4, a5, a6, a7, a8), a9##_var(9) +#define arg_var10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_var9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10##_var(10) + +#define arg_ref1(a1) a1##_ref(1) +#define arg_ref2(a1, a2) arg_ref1(a1), a2##_ref(2) +#define arg_ref3(a1, a2, a3) arg_ref2(a1, a2), a3##_ref(3) +#define arg_ref4(a1, a2, a3, a4) arg_ref3(a1, a2, a3), a4##_ref(4) +#define arg_ref5(a1, a2, a3, a4, a5) arg_ref4(a1, a2, a3, a4), a5##_ref(5) +#define arg_ref6(a1, a2, a3, a4, a5, a6)arg_ref5(a1, a2, a3, a4, a5), a6##_ref(6) +#define arg_ref7(a1, a2, a3, a4, a5, a6, a7)arg_ref6(a1, a2, a3, a4, a5, a6), a7##_ref(7) +#define arg_ref8(a1, a2, a3, a4, a5, a6, a7, a8)arg_ref7(a1, a2, a3, a4, a5, a6, a7), a8##_ref(8) +#define arg_ref9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_ref8(a1, a2, a3, a4, a5, a6, a7, a8), a9##_ref(9) +#define arg_ref10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_ref9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10##_ref(10) + +#define arg_str1(a1) a1##_str +#define arg_str2(a1, a2) arg_str1(a1) a2##_str +#define arg_str3(a1, a2, a3) arg_str2(a1, a2) a3##_str +#define arg_str4(a1, a2, a3, a4) arg_str3(a1, a2, a3) a4##_str +#define arg_str5(a1, a2, a3, a4, a5) arg_str4(a1, a2, a3, a4) a5##_str +#define arg_str6(a1, a2, a3, a4, a5, a6)arg_str5(a1, a2, a3, a4, a5) a6##_str +#define arg_str7(a1, a2, a3, a4, a5, a6, a7)arg_str6(a1, a2, a3, a4, a5, a6) a7##_str +#define arg_str8(a1, a2, a3, a4, a5, a6, a7, a8)arg_str7(a1, a2, a3, a4, a5, a6, a7) a8##_str +#define arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_str8(a1, a2, a3, a4, a5, a6, a7, a8) a9##_str +#define arg_str10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9) a10##_str + +#define ret_def_void +#define ret_set_void +/* would use Py_RETURN_NONE - except for py 2.3 doesnt have it */ +#define ret_ret_void { Py_INCREF(Py_None); return Py_None; } + +#define ret_def_GLint int ret_int +#define ret_set_GLint ret_int= +#define ret_ret_GLint return PyLong_FromLong(ret_int); + +#define ret_def_GLuint unsigned int ret_uint +#define ret_set_GLuint ret_uint= +#define ret_ret_GLuint return PyLong_FromLong((long) ret_uint); + +#define ret_def_GLenum unsigned int ret_uint +#define ret_set_GLenum ret_uint= +#define ret_ret_GLenum return PyLong_FromLong((long) ret_uint); + +#define ret_def_GLboolean unsigned char ret_bool +#define ret_set_GLboolean ret_bool= +#define ret_ret_GLboolean return PyLong_FromLong((long) ret_bool); + +#define ret_def_GLstring const unsigned char *ret_str; +#define ret_set_GLstring ret_str= + +#define ret_ret_GLstring \ + if (ret_str) {\ + return PyUnicode_FromString(ret_str);\ + } else {\ + PyErr_SetString(PyExc_AttributeError, "could not get opengl string");\ + return NULL;\ + } + +#endif /* EXPP_BGL_H */ diff --git a/source/blender/python/generic/Geometry.c b/source/blender/python/generic/Geometry.c new file mode 100644 index 00000000000..3c713a5f62d --- /dev/null +++ b/source/blender/python/generic/Geometry.c @@ -0,0 +1,542 @@ +/* + * $Id: Geometry.c 21254 2009-06-30 00:42:17Z campbellbarton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * 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" + +/* - Not needed for now though other geometry functions will probably need them +#include "BLI_arithb.h" +#include "BKE_utildefines.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_arithb.h" + +#define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp +#define eul 0.000001 + +/*-- forward declarations -- */ +static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq ); +static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args ); +static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args ); +static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args ); +static PyObject *M_Geometry_PointInQuad2D( PyObject * self, PyObject * args ); +static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * args ); +static PyObject *M_Geometry_BezierInterp( PyObject * self, PyObject * args ); + + +/*-------------------------DOC STRINGS ---------------------------*/ +static char M_Geometry_doc[] = "The Blender Geometry module\n\n"; +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[] = ""; +/*-----------------------METHOD DEFINITIONS ----------------------*/ +struct PyMethodDef M_Geometry_methods[] = { + {"PolyFill", ( PyCFunction ) M_Geometry_PolyFill, METH_O, M_Geometry_PolyFill_doc}, + {"LineIntersect2D", ( PyCFunction ) M_Geometry_LineIntersect2D, METH_VARARGS, M_Geometry_LineIntersect2D_doc}, + {"ClosestPointOnLine", ( PyCFunction ) M_Geometry_ClosestPointOnLine, METH_VARARGS, M_Geometry_ClosestPointOnLine_doc}, + {"PointInTriangle2D", ( PyCFunction ) M_Geometry_PointInTriangle2D, METH_VARARGS, M_Geometry_PointInTriangle2D_doc}, + {"PointInQuad2D", ( PyCFunction ) M_Geometry_PointInQuad2D, METH_VARARGS, M_Geometry_PointInQuad2D_doc}, + {"BoxPack2D", ( PyCFunction ) M_Geometry_BoxPack2D, METH_O, M_Geometry_BoxPack2D_doc}, + {"BezierInterp", ( PyCFunction ) M_Geometry_BezierInterp, METH_VARARGS, M_Geometry_BezierInterp_doc}, + {NULL, NULL, 0, NULL} +}; + +#if (PY_VERSION_HEX >= 0x03000000) +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 */ +}; +#endif + +/*----------------------------MODULE INIT-------------------------*/ +PyObject *Geometry_Init(const char *from) +{ + PyObject *submodule; + +#if (PY_VERSION_HEX >= 0x03000000) + submodule = PyModule_Create(&M_Geometry_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), M_Geometry_module_def.m_name, submodule); +#else + submodule = Py_InitModule3(from, M_Geometry_methods, M_Geometry_doc); +#endif + + return (submodule); +} + +/*----------------------------------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; indexvec[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); + + /* 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) < eul || fabs(b1y - b2y) < eul) { + 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) < eul) { /* verticle line */ + if (fabs(b1x-b2x) < eul){ /*verticle second line */ + Py_RETURN_NONE; /* 2 verticle lines dont intersect. */ + } + else if (fabs(b1y-b2y) < eul) { + /*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) < eul) { /* hoz line1 */ + if (fabs(b2y-b1y) < eul) { /*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 = lambda_cp_line_ex(pt_in, l1, l2, pt_out); + + 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(IsectPT2Df(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(IsectPQ2Df(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 alredy 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 +#include "Mathutils.h" + +PyObject *Geometry_Init( const char *from ); + +#endif /* EXPP_Geometry_H */ diff --git a/source/blender/python/generic/Makefile b/source/blender/python/generic/Makefile new file mode 100644 index 00000000000..8faed3b622c --- /dev/null +++ b/source/blender/python/generic/Makefile @@ -0,0 +1,66 @@ +# +# $Id: Makefile 21094 2009-06-23 00:09:26Z gsrb3d $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# 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 += -I$(NAN_SOUNDSYSTEM)/include $(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.. diff --git a/source/blender/python/generic/Mathutils.c b/source/blender/python/generic/Mathutils.c new file mode 100644 index 00000000000..538dc6a8823 --- /dev/null +++ b/source/blender/python/generic/Mathutils.c @@ -0,0 +1,1266 @@ +/* + * $Id: Mathutils.c 21559 2009-07-13 12:17:07Z campbellbarton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * 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 "Mathutils.h" + +#include "BLI_arithb.h" +#include "PIL_time.h" +#include "BLI_rand.h" +#include "BKE_utildefines.h" + +//-------------------------DOC STRINGS --------------------------- +static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n"; +static char M_Mathutils_Rand_doc[] = "() - return a random number"; +static char M_Mathutils_AngleBetweenVecs_doc[] = "() - returns the angle between two vectors in degrees"; +static char M_Mathutils_MidpointVecs_doc[] = "() - return the vector to the midpoint between two vectors"; +static char M_Mathutils_ProjectVecs_doc[] = "() - returns the projection vector from the projection of vecA onto vecB"; +static char M_Mathutils_RotationMatrix_doc[] = "() - construct a rotation matrix from an angle and axis of rotation"; +static char M_Mathutils_ScaleMatrix_doc[] = "() - construct a scaling matrix from a scaling factor"; +static char M_Mathutils_OrthoProjectionMatrix_doc[] = "() - construct a orthographic projection matrix from a selected plane"; +static char M_Mathutils_ShearMatrix_doc[] = "() - construct a shearing matrix from a plane of shear and a shear factor"; +static char M_Mathutils_TranslationMatrix_doc[] = "(vec) - create a translation matrix from a vector"; +static char M_Mathutils_Slerp_doc[] = "() - returns the interpolation between two quaternions"; +static char M_Mathutils_DifferenceQuats_doc[] = "() - return the angular displacment difference between two quats"; +static char M_Mathutils_Intersect_doc[] = "(v1, v2, v3, ray, orig, clip=1) - returns the intersection between a ray and a triangle, if possible, returns None otherwise"; +static char M_Mathutils_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined"; +static char M_Mathutils_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined"; +static char M_Mathutils_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined"; +static char M_Mathutils_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other"; +//-----------------------METHOD DEFINITIONS ---------------------- + +static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args); +static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args); +static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args); +static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args); +static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args); +static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * value); +static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args); +static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args); +static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args); +static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args); +static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args); +static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args ); + +struct PyMethodDef M_Mathutils_methods[] = { + {"Rand", (PyCFunction) M_Mathutils_Rand, METH_VARARGS, M_Mathutils_Rand_doc}, + {"AngleBetweenVecs", (PyCFunction) M_Mathutils_AngleBetweenVecs, METH_VARARGS, M_Mathutils_AngleBetweenVecs_doc}, + {"MidpointVecs", (PyCFunction) M_Mathutils_MidpointVecs, METH_VARARGS, M_Mathutils_MidpointVecs_doc}, + {"ProjectVecs", (PyCFunction) M_Mathutils_ProjectVecs, METH_VARARGS, M_Mathutils_ProjectVecs_doc}, + {"RotationMatrix", (PyCFunction) M_Mathutils_RotationMatrix, METH_VARARGS, M_Mathutils_RotationMatrix_doc}, + {"ScaleMatrix", (PyCFunction) M_Mathutils_ScaleMatrix, METH_VARARGS, M_Mathutils_ScaleMatrix_doc}, + {"ShearMatrix", (PyCFunction) M_Mathutils_ShearMatrix, METH_VARARGS, M_Mathutils_ShearMatrix_doc}, + {"TranslationMatrix", (PyCFunction) M_Mathutils_TranslationMatrix, METH_O, M_Mathutils_TranslationMatrix_doc}, + {"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc}, + {"DifferenceQuats", (PyCFunction) M_Mathutils_DifferenceQuats, METH_VARARGS,M_Mathutils_DifferenceQuats_doc}, + {"Slerp", (PyCFunction) M_Mathutils_Slerp, METH_VARARGS, M_Mathutils_Slerp_doc}, + {"Intersect", ( PyCFunction ) M_Mathutils_Intersect, METH_VARARGS, M_Mathutils_Intersect_doc}, + {"TriangleArea", ( PyCFunction ) M_Mathutils_TriangleArea, METH_VARARGS, M_Mathutils_TriangleArea_doc}, + {"TriangleNormal", ( PyCFunction ) M_Mathutils_TriangleNormal, METH_VARARGS, M_Mathutils_TriangleNormal_doc}, + {"QuadNormal", ( PyCFunction ) M_Mathutils_QuadNormal, METH_VARARGS, M_Mathutils_QuadNormal_doc}, + {"LineIntersect", ( PyCFunction ) M_Mathutils_LineIntersect, METH_VARARGS, M_Mathutils_LineIntersect_doc}, + {NULL, NULL, 0, NULL} +}; + +/*----------------------------MODULE INIT-------------------------*/ +/* from can be Blender.Mathutils or GameLogic.Mathutils for the BGE */ + +#if (PY_VERSION_HEX >= 0x03000000) +static struct PyModuleDef M_Mathutils_module_def = { + PyModuleDef_HEAD_INIT, + "Mathutils", /* m_name */ + M_Mathutils_doc, /* m_doc */ + 0, /* m_size */ + M_Mathutils_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; +#endif + +PyObject *Mathutils_Init(const char *from) +{ + PyObject *submodule; + + //seed the generator for the rand function + BLI_srand((unsigned int) (PIL_check_seconds_timer() * 0x7FFFFFFF)); + +#if (PY_VERSION_HEX < 0x03000000) + vector_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES; + matrix_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES; + euler_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES; + quaternion_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES; +#endif + + if( PyType_Ready( &vector_Type ) < 0 ) + return NULL; + if( PyType_Ready( &matrix_Type ) < 0 ) + return NULL; + if( PyType_Ready( &euler_Type ) < 0 ) + return NULL; + if( PyType_Ready( &quaternion_Type ) < 0 ) + return NULL; + +#if (PY_VERSION_HEX >= 0x03000000) + submodule = PyModule_Create(&M_Mathutils_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), M_Mathutils_module_def.m_name, submodule); +#else + submodule = Py_InitModule3(from, M_Mathutils_methods, M_Mathutils_doc); +#endif + + /* each type has its own new() function */ + PyModule_AddObject( submodule, "Vector", (PyObject *)&vector_Type ); + PyModule_AddObject( submodule, "Matrix", (PyObject *)&matrix_Type ); + PyModule_AddObject( submodule, "Euler", (PyObject *)&euler_Type ); + PyModule_AddObject( submodule, "Quaternion", (PyObject *)&quaternion_Type ); + + mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb); + + return (submodule); +} + +//-----------------------------METHODS---------------------------- +//-----------------quat_rotation (internal)----------- +//This function multiplies a vector/point * quat or vice versa +//to rotate the point/vector by the quaternion +//arguments should all be 3D +PyObject *quat_rotation(PyObject *arg1, PyObject *arg2) +{ + float rot[3]; + QuaternionObject *quat = NULL; + VectorObject *vec = NULL; + + if(QuaternionObject_Check(arg1)){ + quat = (QuaternionObject*)arg1; + if(!BaseMath_ReadCallback(quat)) + return NULL; + + if(VectorObject_Check(arg2)){ + vec = (VectorObject*)arg2; + + if(!BaseMath_ReadCallback(vec)) + return NULL; + + rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] - + 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] + + 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] - + quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0]; + rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] + + 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] - + quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] - + 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1]; + rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] + + quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] - + quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] - + quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2]; + return newVectorObject(rot, 3, Py_NEW, NULL); + } + }else if(VectorObject_Check(arg1)){ + vec = (VectorObject*)arg1; + + if(!BaseMath_ReadCallback(vec)) + return NULL; + + if(QuaternionObject_Check(arg2)){ + quat = (QuaternionObject*)arg2; + if(!BaseMath_ReadCallback(quat)) + return NULL; + + rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] - + 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] + + 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] - + quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0]; + rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] + + 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] - + quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] - + 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1]; + rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] + + quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] - + quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] - + quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2]; + return newVectorObject(rot, 3, Py_NEW, NULL); + } + } + + PyErr_SetString(PyExc_RuntimeError, "quat_rotation(internal): internal problem rotating vector/point\n"); + return NULL; + +} + +//----------------------------------Mathutils.Rand() -------------------- +//returns a random number between a high and low value +static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args) +{ + float high, low, range; + double drand; + //initializers + high = 1.0; + low = 0.0; + + if(!PyArg_ParseTuple(args, "|ff", &low, &high)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.Rand(): expected nothing or optional (float, float)\n"); + return NULL; + } + + if((high < low) || (high < 0 && low > 0)) { + PyErr_SetString(PyExc_ValueError, "Mathutils.Rand(): high value should be larger than low value\n"); + return NULL; + } + //get the random number 0 - 1 + drand = BLI_drand(); + + //set it to range + range = high - low; + drand = drand * range; + drand = drand + low; + + return PyFloat_FromDouble(drand); +} +//----------------------------------VECTOR FUNCTIONS--------------------- +//----------------------------------Mathutils.AngleBetweenVecs() --------- +//calculates the angle between 2 vectors +static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f; + int x, size; + + if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) + goto AttributeError1; //not vectors + if(vec1->size != vec2->size) + goto AttributeError1; //bad sizes + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) + return NULL; + + //since size is the same.... + size = vec1->size; + + for(x = 0; x < size; x++) { + test_v1 += vec1->vec[x] * vec1->vec[x]; + test_v2 += vec2->vec[x] * vec2->vec[x]; + } + if (!test_v1 || !test_v2){ + goto AttributeError2; //zero-length vector + } + + //dot product + for(x = 0; x < size; x++) { + dot += vec1->vec[x] * vec2->vec[x]; + } + dot /= (sqrt(test_v1) * sqrt(test_v2)); + + angleRads = (double)saacos(dot); + +#ifdef USE_MATHUTILS_DEG + return PyFloat_FromDouble(angleRads * (180/ Py_PI)); +#else + return PyFloat_FromDouble(angleRads); +#endif +AttributeError1: + PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n"); + return NULL; + +AttributeError2: + PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): zero length vectors are not acceptable arguments\n"); + return NULL; +} +//----------------------------------Mathutils.MidpointVecs() ------------- +//calculates the midpoint between 2 vectors +static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + float vec[4]; + int x; + + if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); + return NULL; + } + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) + return NULL; + + for(x = 0; x < vec1->size; x++) { + vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]); + } + return newVectorObject(vec, vec1->size, Py_NEW, NULL); +} +//----------------------------------Mathutils.ProjectVecs() ------------- +//projects vector 1 onto vector 2 +static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + float vec[4]; + double dot = 0.0f, dot2 = 0.0f; + int x, size; + + if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n"); + return NULL; + } + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) + return NULL; + + + //since they are the same size... + size = vec1->size; + + //get dot products + for(x = 0; x < size; x++) { + dot += vec1->vec[x] * vec2->vec[x]; + dot2 += vec2->vec[x] * vec2->vec[x]; + } + //projection + dot /= dot2; + for(x = 0; x < size; x++) { + vec[x] = (float)(dot * vec2->vec[x]); + } + return newVectorObject(vec, size, Py_NEW, NULL); +} +//----------------------------------MATRIX FUNCTIONS-------------------- +//----------------------------------Mathutils.RotationMatrix() ---------- +//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. +//creates a rotation matrix +static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args) +{ + VectorObject *vec = NULL; + char *axis = NULL; + int matSize; + float angle = 0.0f, norm = 0.0f, cosAngle = 0.0f, sinAngle = 0.0f; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple(args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(): expected float int and optional string and vector\n"); + return NULL; + } + +#ifdef USE_MATHUTILS_DEG + /* Clamp to -360:360 */ + while (angle<-360.0f) + angle+=360.0; + while (angle>360.0f) + angle-=360.0; +#else + while (angle<-(Py_PI*2)) + angle+=(Py_PI*2); + while (angle>(Py_PI*2)) + angle-=(Py_PI*2); +#endif + + if(matSize != 2 && matSize != 3 && matSize != 4) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); + return NULL; + } + if(matSize == 2 && (axis != NULL || vec != NULL)) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n"); + return NULL; + } + if((matSize == 3 || matSize == 4) && axis == NULL) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n"); + return NULL; + } + if(axis) { + if(((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) && vec == NULL) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please define the arbitrary axis of rotation\n"); + return NULL; + } + } + if(vec) { + if(vec->size != 3) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(vec)) + return NULL; + + } +#ifdef USE_MATHUTILS_DEG + //convert to radians + angle = angle * (float) (Py_PI / 180); +#endif + + if(axis == NULL && matSize == 2) { + //2D rotation matrix + mat[0] = (float) cos (angle); + mat[1] = (float) sin (angle); + mat[2] = -((float) sin(angle)); + mat[3] = (float) cos(angle); + } else if((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0)) { + //rotation around X + mat[0] = 1.0f; + mat[4] = (float) cos(angle); + mat[5] = (float) sin(angle); + mat[7] = -((float) sin(angle)); + mat[8] = (float) cos(angle); + } else if((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0)) { + //rotation around Y + mat[0] = (float) cos(angle); + mat[2] = -((float) sin(angle)); + mat[4] = 1.0f; + mat[6] = (float) sin(angle); + mat[8] = (float) cos(angle); + } else if((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0)) { + //rotation around Z + mat[0] = (float) cos(angle); + mat[1] = (float) sin(angle); + mat[3] = -((float) sin(angle)); + mat[4] = (float) cos(angle); + mat[8] = 1.0f; + } else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) { + //arbitrary rotation + //normalize arbitrary axis + norm = (float) sqrt(vec->vec[0] * vec->vec[0] + + vec->vec[1] * vec->vec[1] + + vec->vec[2] * vec->vec[2]); + vec->vec[0] /= norm; + vec->vec[1] /= norm; + vec->vec[2] /= norm; + + if (isnan(vec->vec[0]) || isnan(vec->vec[1]) || isnan(vec->vec[2])) { + /* zero length vector, return an identity matrix, could also return an error */ + mat[0]= mat[4] = mat[8] = 1.0f; + } else { + /* create matrix */ + cosAngle = (float) cos(angle); + sinAngle = (float) sin(angle); + mat[0] = ((vec->vec[0] * vec->vec[0]) * (1 - cosAngle)) + + cosAngle; + mat[1] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) + + (vec->vec[2] * sinAngle); + mat[2] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) - + (vec->vec[1] * sinAngle); + mat[3] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) - + (vec->vec[2] * sinAngle); + mat[4] = ((vec->vec[1] * vec->vec[1]) * (1 - cosAngle)) + + cosAngle; + mat[5] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) + + (vec->vec[0] * sinAngle); + mat[6] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) + + (vec->vec[1] * sinAngle); + mat[7] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) - + (vec->vec[0] * sinAngle); + mat[8] = ((vec->vec[2] * vec->vec[2]) * (1 - cosAngle)) + + cosAngle; + } + } else { + PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n"); + return NULL; + } + if(matSize == 4) { + //resize matrix + mat[10] = mat[8]; + mat[9] = mat[7]; + mat[8] = mat[6]; + mat[7] = 0.0f; + mat[6] = mat[5]; + mat[5] = mat[4]; + mat[4] = mat[3]; + mat[3] = 0.0f; + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); +} +//----------------------------------Mathutils.TranslationMatrix() ------- +//creates a translation matrix +static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * vec) +{ + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!VectorObject_Check(vec)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.TranslationMatrix(): expected vector\n"); + return NULL; + } + if(vec->size != 3 && vec->size != 4) { + PyErr_SetString(PyExc_TypeError, "Mathutils.TranslationMatrix(): vector must be 3D or 4D\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(vec)) + return NULL; + + //create a identity matrix and add translation + Mat4One((float(*)[4]) mat); + mat[12] = vec->vec[0]; + mat[13] = vec->vec[1]; + mat[14] = vec->vec[2]; + + return newMatrixObject(mat, 4, 4, Py_NEW, NULL); +} +//----------------------------------Mathutils.ScaleMatrix() ------------- +//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. +//creates a scaling matrix +static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args) +{ + VectorObject *vec = NULL; + float norm = 0.0f, factor; + int matSize, x; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple(args, "fi|O!", &factor, &matSize, &vector_Type, &vec)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.ScaleMatrix(): expected float int and optional vector\n"); + return NULL; + } + if(matSize != 2 && matSize != 3 && matSize != 4) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.ScaleMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); + return NULL; + } + if(vec) { + if(vec->size > 2 && matSize == 2) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(vec)) + return NULL; + + } + if(vec == NULL) { //scaling along axis + if(matSize == 2) { + mat[0] = factor; + mat[3] = factor; + } else { + mat[0] = factor; + mat[4] = factor; + mat[8] = factor; + } + } else { //scaling in arbitrary direction + //normalize arbitrary axis + for(x = 0; x < vec->size; x++) { + norm += vec->vec[x] * vec->vec[x]; + } + norm = (float) sqrt(norm); + for(x = 0; x < vec->size; x++) { + vec->vec[x] /= norm; + } + if(matSize == 2) { + mat[0] = 1 +((factor - 1) *(vec->vec[0] * vec->vec[0])); + mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1])); + mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[1])); + mat[3] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1])); + } else { + mat[0] = 1 + ((factor - 1) *(vec->vec[0] * vec->vec[0])); + mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1])); + mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[2])); + mat[3] =((factor - 1) *(vec->vec[0] * vec->vec[1])); + mat[4] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1])); + mat[5] =((factor - 1) *(vec->vec[1] * vec->vec[2])); + mat[6] =((factor - 1) *(vec->vec[0] * vec->vec[2])); + mat[7] =((factor - 1) *(vec->vec[1] * vec->vec[2])); + mat[8] = 1 + ((factor - 1) *(vec->vec[2] * vec->vec[2])); + } + } + if(matSize == 4) { + //resize matrix + mat[10] = mat[8]; + mat[9] = mat[7]; + mat[8] = mat[6]; + mat[7] = 0.0f; + mat[6] = mat[5]; + mat[5] = mat[4]; + mat[4] = mat[3]; + mat[3] = 0.0f; + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); +} +//----------------------------------Mathutils.OrthoProjectionMatrix() --- +//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. +//creates an ortho projection matrix +static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args) +{ + VectorObject *vec = NULL; + char *plane; + int matSize, x; + float norm = 0.0f; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple(args, "si|O!", &plane, &matSize, &vector_Type, &vec)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.OrthoProjectionMatrix(): expected string and int and optional vector\n"); + return NULL; + } + if(matSize != 2 && matSize != 3 && matSize != 4) { + PyErr_SetString(PyExc_AttributeError,"Mathutils.OrthoProjectionMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); + return NULL; + } + if(vec) { + if(vec->size > 2 && matSize == 2) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(vec)) + return NULL; + + } + if(vec == NULL) { //ortho projection onto cardinal plane + if(((strcmp(plane, "x") == 0) + || (strcmp(plane, "X") == 0)) && matSize == 2) { + mat[0] = 1.0f; + } else if(((strcmp(plane, "y") == 0) + || (strcmp(plane, "Y") == 0)) + && matSize == 2) { + mat[3] = 1.0f; + } else if(((strcmp(plane, "xy") == 0) + || (strcmp(plane, "XY") == 0)) + && matSize > 2) { + mat[0] = 1.0f; + mat[4] = 1.0f; + } else if(((strcmp(plane, "xz") == 0) + || (strcmp(plane, "XZ") == 0)) + && matSize > 2) { + mat[0] = 1.0f; + mat[8] = 1.0f; + } else if(((strcmp(plane, "yz") == 0) + || (strcmp(plane, "YZ") == 0)) + && matSize > 2) { + mat[4] = 1.0f; + mat[8] = 1.0f; + } else { + PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: x, y, xy, xz, yz\n"); + return NULL; + } + } else { //arbitrary plane + //normalize arbitrary axis + for(x = 0; x < vec->size; x++) { + norm += vec->vec[x] * vec->vec[x]; + } + norm = (float) sqrt(norm); + for(x = 0; x < vec->size; x++) { + vec->vec[x] /= norm; + } + if(((strcmp(plane, "r") == 0) + || (strcmp(plane, "R") == 0)) && matSize == 2) { + mat[0] = 1 - (vec->vec[0] * vec->vec[0]); + mat[1] = -(vec->vec[0] * vec->vec[1]); + mat[2] = -(vec->vec[0] * vec->vec[1]); + mat[3] = 1 - (vec->vec[1] * vec->vec[1]); + } else if(((strcmp(plane, "r") == 0) + || (strcmp(plane, "R") == 0)) + && matSize > 2) { + mat[0] = 1 - (vec->vec[0] * vec->vec[0]); + mat[1] = -(vec->vec[0] * vec->vec[1]); + mat[2] = -(vec->vec[0] * vec->vec[2]); + mat[3] = -(vec->vec[0] * vec->vec[1]); + mat[4] = 1 - (vec->vec[1] * vec->vec[1]); + mat[5] = -(vec->vec[1] * vec->vec[2]); + mat[6] = -(vec->vec[0] * vec->vec[2]); + mat[7] = -(vec->vec[1] * vec->vec[2]); + mat[8] = 1 - (vec->vec[2] * vec->vec[2]); + } else { + PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: 'r' expected for axis designation\n"); + return NULL; + } + } + if(matSize == 4) { + //resize matrix + mat[10] = mat[8]; + mat[9] = mat[7]; + mat[8] = mat[6]; + mat[7] = 0.0f; + mat[6] = mat[5]; + mat[5] = mat[4]; + mat[4] = mat[3]; + mat[3] = 0.0f; + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); +} +//----------------------------------Mathutils.ShearMatrix() ------------- +//creates a shear matrix +static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args) +{ + int matSize; + char *plane; + float factor; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple(args, "sfi", &plane, &factor, &matSize)) { + PyErr_SetString(PyExc_TypeError,"Mathutils.ShearMatrix(): expected string float and int\n"); + return NULL; + } + if(matSize != 2 && matSize != 3 && matSize != 4) { + PyErr_SetString(PyExc_AttributeError,"Mathutils.ShearMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); + return NULL; + } + + if(((strcmp(plane, "x") == 0) || (strcmp(plane, "X") == 0)) + && matSize == 2) { + mat[0] = 1.0f; + mat[2] = factor; + mat[3] = 1.0f; + } else if(((strcmp(plane, "y") == 0) + || (strcmp(plane, "Y") == 0)) && matSize == 2) { + mat[0] = 1.0f; + mat[1] = factor; + mat[3] = 1.0f; + } else if(((strcmp(plane, "xy") == 0) + || (strcmp(plane, "XY") == 0)) && matSize > 2) { + mat[0] = 1.0f; + mat[4] = 1.0f; + mat[6] = factor; + mat[7] = factor; + } else if(((strcmp(plane, "xz") == 0) + || (strcmp(plane, "XZ") == 0)) && matSize > 2) { + mat[0] = 1.0f; + mat[3] = factor; + mat[4] = 1.0f; + mat[5] = factor; + mat[8] = 1.0f; + } else if(((strcmp(plane, "yz") == 0) + || (strcmp(plane, "YZ") == 0)) && matSize > 2) { + mat[0] = 1.0f; + mat[1] = factor; + mat[2] = factor; + mat[4] = 1.0f; + mat[8] = 1.0f; + } else { + PyErr_SetString(PyExc_AttributeError, "Mathutils.ShearMatrix(): expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n"); + return NULL; + } + if(matSize == 4) { + //resize matrix + mat[10] = mat[8]; + mat[9] = mat[7]; + mat[8] = mat[6]; + mat[7] = 0.0f; + mat[6] = mat[5]; + mat[5] = mat[4]; + mat[4] = mat[3]; + mat[3] = 0.0f; + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); +} +//----------------------------------QUATERNION FUNCTIONS----------------- + +//----------------------------------Mathutils.DifferenceQuats() --------- +//returns the difference between 2 quaternions +static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args) +{ + QuaternionObject *quatU = NULL, *quatV = NULL; + float quat[4], tempQuat[4]; + double dot = 0.0f; + int x; + + if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU, &quaternion_Type, &quatV)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.DifferenceQuats(): expected Quaternion types"); + return NULL; + } + + if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV)) + return NULL; + + tempQuat[0] = quatU->quat[0]; + tempQuat[1] = -quatU->quat[1]; + tempQuat[2] = -quatU->quat[2]; + tempQuat[3] = -quatU->quat[3]; + + dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] + + tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]); + + for(x = 0; x < 4; x++) { + tempQuat[x] /= (float)(dot * dot); + } + QuatMul(quat, tempQuat, quatV->quat); + return newQuaternionObject(quat, Py_NEW, NULL); +} +//----------------------------------Mathutils.Slerp() ------------------ +//attemps to interpolate 2 quaternions and return the result +static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args) +{ + QuaternionObject *quatU = NULL, *quatV = NULL; + float quat[4], quat_u[4], quat_v[4], param; + double x, y, dot, sinT, angle, IsinT; + int z; + + if(!PyArg_ParseTuple(args, "O!O!f", &quaternion_Type, &quatU, &quaternion_Type, &quatV, ¶m)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.Slerp(): expected Quaternion types and float"); + return NULL; + } + + if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV)) + return NULL; + + if(param > 1.0f || param < 0.0f) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0"); + return NULL; + } + + //copy quats + for(z = 0; z < 4; z++){ + quat_u[z] = quatU->quat[z]; + quat_v[z] = quatV->quat[z]; + } + + //dot product + dot = quat_u[0] * quat_v[0] + quat_u[1] * quat_v[1] + + quat_u[2] * quat_v[2] + quat_u[3] * quat_v[3]; + + //if negative negate a quat (shortest arc) + if(dot < 0.0f) { + quat_v[0] = -quat_v[0]; + quat_v[1] = -quat_v[1]; + quat_v[2] = -quat_v[2]; + quat_v[3] = -quat_v[3]; + dot = -dot; + } + if(dot > .99999f) { //very close + x = 1.0f - param; + y = param; + } else { + //calculate sin of angle + sinT = sqrt(1.0f - (dot * dot)); + //calculate angle + angle = atan2(sinT, dot); + //caluculate inverse of sin(theta) + IsinT = 1.0f / sinT; + x = sin((1.0f - param) * angle) * IsinT; + y = sin(param * angle) * IsinT; + } + //interpolate + quat[0] = (float)(quat_u[0] * x + quat_v[0] * y); + quat[1] = (float)(quat_u[1] * x + quat_v[1] * y); + quat[2] = (float)(quat_u[2] * x + quat_v[2] * y); + quat[3] = (float)(quat_u[3] * x + quat_v[3] * y); + + return newQuaternionObject(quat, Py_NEW, NULL); +} +//----------------------------------EULER FUNCTIONS---------------------- +//---------------------------------INTERSECTION FUNCTIONS-------------------- +//----------------------------------Mathutils.Intersect() ------------------- +static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args ) +{ + VectorObject *ray, *ray_off, *vec1, *vec2, *vec3; + float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3]; + float det, inv_det, u, v, t; + int clip = 1; + + if(!PyArg_ParseTuple(args, "O!O!O!O!O!|i", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off , &clip)) { + PyErr_SetString( PyExc_TypeError, "expected 5 vector types\n" ); + return NULL; + } + if(vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) { + PyErr_SetString( PyExc_TypeError, "only 3D vectors for all parameters\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(ray) || !BaseMath_ReadCallback(ray_off)) + return NULL; + + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + + VECCOPY(dir, ray->vec); + Normalize(dir); + + VECCOPY(orig, ray_off->vec); + + /* find vectors for two edges sharing v1 */ + VecSubf(e1, v2, v1); + VecSubf(e2, v3, v1); + + /* begin calculating determinant - also used to calculated U parameter */ + Crossf(pvec, dir, e2); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = Inpf(e1, pvec); + + if (det > -0.000001 && det < 0.000001) { + Py_RETURN_NONE; + } + + inv_det = 1.0f / det; + + /* calculate distance from v1 to ray origin */ + VecSubf(tvec, orig, v1); + + /* calculate U parameter and test bounds */ + u = Inpf(tvec, pvec) * inv_det; + if (clip && (u < 0.0f || u > 1.0f)) { + Py_RETURN_NONE; + } + + /* prepare to test the V parameter */ + Crossf(qvec, tvec, e1); + + /* calculate V parameter and test bounds */ + v = Inpf(dir, qvec) * inv_det; + + if (clip && (v < 0.0f || u + v > 1.0f)) { + Py_RETURN_NONE; + } + + /* calculate t, ray intersects triangle */ + t = Inpf(e2, qvec) * inv_det; + + VecMulf(dir, t); + VecAddf(pvec, orig, dir); + + return newVectorObject(pvec, 3, Py_NEW, NULL); +} +//----------------------------------Mathutils.LineIntersect() ------------------- +/* Line-Line intersection using algorithm from mathworld.wolfram.com */ +static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args ) +{ + PyObject * tuple; + VectorObject *vec1, *vec2, *vec3, *vec4; + float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3]; + + if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) { + PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" ); + return NULL; + } + if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->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 = LineIntersectLine(v1, v2, v3, v4, i1, i2); + + if (result == 0) { + /* colinear */ + Py_RETURN_NONE; + } + else { + tuple = PyTuple_New( 2 ); + PyTuple_SetItem( tuple, 0, newVectorObject(i1, vec1->size, Py_NEW, NULL) ); + PyTuple_SetItem( tuple, 1, newVectorObject(i2, vec1->size, Py_NEW, NULL) ); + return tuple; + } + } + else { + PyErr_SetString( PyExc_TypeError, "2D/3D vectors only\n" ); + return NULL; + } +} + + + +//---------------------------------NORMALS FUNCTIONS-------------------- +//----------------------------------Mathutils.QuadNormal() ------------------- +static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args ) +{ + VectorObject *vec1; + VectorObject *vec2; + VectorObject *vec3; + VectorObject *vec4; + float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3], n1[3], n2[3]; + + if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) { + PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" ); + return NULL; + } + if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) { + PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" ); + return NULL; + } + if( vec1->size != 3 ) { + PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" ); + return NULL; + } + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4)) + return NULL; + + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + VECCOPY(v4, vec4->vec); + + /* find vectors for two edges sharing v2 */ + VecSubf(e1, v1, v2); + VecSubf(e2, v3, v2); + + Crossf(n1, e2, e1); + Normalize(n1); + + /* find vectors for two edges sharing v4 */ + VecSubf(e1, v3, v4); + VecSubf(e2, v1, v4); + + Crossf(n2, e2, e1); + Normalize(n2); + + /* adding and averaging the normals of both triangles */ + VecAddf(n1, n2, n1); + Normalize(n1); + + return newVectorObject(n1, 3, Py_NEW, NULL); +} + +//----------------------------Mathutils.TriangleNormal() ------------------- +static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args ) +{ + VectorObject *vec1, *vec2, *vec3; + float v1[3], v2[3], v3[3], e1[3], e2[3], n[3]; + + if( !PyArg_ParseTuple( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3 ) ) { + PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" ); + return NULL; + } + if( vec1->size != vec2->size || vec1->size != vec3->size ) { + PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" ); + return NULL; + } + if( vec1->size != 3 ) { + PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" ); + return NULL; + } + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3)) + return NULL; + + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + + /* find vectors for two edges sharing v2 */ + VecSubf(e1, v1, v2); + VecSubf(e2, v3, v2); + + Crossf(n, e2, e1); + Normalize(n); + + return newVectorObject(n, 3, Py_NEW, NULL); +} + +//--------------------------------- AREA FUNCTIONS-------------------- +//----------------------------------Mathutils.TriangleArea() ------------------- +static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args ) +{ + VectorObject *vec1, *vec2, *vec3; + float v1[3], v2[3], v3[3]; + + if( !PyArg_ParseTuple + ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2 + , &vector_Type, &vec3 ) ) { + PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n"); + return NULL; + } + if( vec1->size != vec2->size || vec1->size != vec3->size ) { + PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" ); + return NULL; + } + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3)) + return NULL; + + if (vec1->size == 3) { + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + + return PyFloat_FromDouble( AreaT3Dfl(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( AreaF2Dfl(v1, v2, v3) ); + } + else { + PyErr_SetString( PyExc_TypeError, "only 2D,3D vectors are supported\n" ); + return NULL; + } +} + +/* Utility functions */ + +/*---------------------- EXPP_FloatsAreEqual ------------------------- + Floating point comparisons + floatStep = number of representable floats allowable in between + float A and float B to be considered equal. */ +int EXPP_FloatsAreEqual(float A, float B, int floatSteps) +{ + int a, b, delta; + assert(floatSteps > 0 && floatSteps < (4 * 1024 * 1024)); + a = *(int*)&A; + if (a < 0) + a = 0x80000000 - a; + b = *(int*)&B; + if (b < 0) + b = 0x80000000 - b; + delta = abs(a - b); + if (delta <= floatSteps) + return 1; + return 0; +} +/*---------------------- EXPP_VectorsAreEqual ------------------------- + Builds on EXPP_FloatsAreEqual to test vectors */ +int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps) +{ + int x; + for (x=0; x< size; x++){ + if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0) + return 0; + } + return 1; +} + + +/* 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}; + +int Mathutils_RegisterCallback(Mathutils_Callback *cb) +{ + int i; + + /* find the first free slot */ + for(i= 0; mathutils_callbacks[i]; i++) { + if(mathutils_callbacks[i]==cb) /* alredy registered? */ + return i; + } + + mathutils_callbacks[i] = cb; + return i; +} + +/* use macros to check for NULL */ +int _BaseMathObject_ReadCallback(BaseMathObject *self) +{ + Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; + if(cb->get(self->cb_user, self->cb_subtype, self->data)) + return 1; + + PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name); + return 0; +} + +int _BaseMathObject_WriteCallback(BaseMathObject *self) +{ + Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; + if(cb->set(self->cb_user, self->cb_subtype, self->data)) + return 1; + + PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name); + return 0; +} + +int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index) +{ + Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; + if(cb->get_index(self->cb_user, self->cb_subtype, self->data, index)) + return 1; + + PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name); + return 0; +} + +int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index) +{ + Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; + if(cb->set_index(self->cb_user, self->cb_subtype, self->data, index)) + return 1; + + PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name); + return 0; +} + +/* BaseMathObject generic functions for all mathutils types */ +PyObject *BaseMathObject_getOwner( BaseMathObject * self, void *type ) +{ + PyObject *ret= self->cb_user ? self->cb_user : Py_None; + Py_INCREF(ret); + return ret; +} + +PyObject *BaseMathObject_getWrapped( BaseMathObject *self, void *type ) +{ + return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1:0); +} + +void BaseMathObject_dealloc(BaseMathObject * self) +{ + /* only free non wrapped */ + if(self->wrapped != Py_WRAP) + PyMem_Free(self->data); + + Py_XDECREF(self->cb_user); + Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes +} + diff --git a/source/blender/python/generic/Mathutils.h b/source/blender/python/generic/Mathutils.h new file mode 100644 index 00000000000..9716414e587 --- /dev/null +++ b/source/blender/python/generic/Mathutils.h @@ -0,0 +1,116 @@ +/* + * $Id: Mathutils.h 21499 2009-07-10 18:09:53Z campbellbarton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * 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 + * + * ***** END GPL LICENSE BLOCK ***** +*/ +//Include this file for access to vector, quat, matrix, euler, etc... + +#ifndef EXPP_Mathutils_H +#define EXPP_Mathutils_H + +#include +#include "../intern/bpy_compat.h" +#include "vector.h" +#include "matrix.h" +#include "quat.h" +#include "euler.h" + +/* #define USE_MATHUTILS_DEG - for backwards compat */ + +/* Can cast different mathutils types to this, use for generic funcs */ + +typedef struct { + PyObject_VAR_HEAD + float *data; /*array of data (alias), wrapped status depends on wrapped status */ + PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ + unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ + unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ + unsigned char wrapped; /* wrapped data type? */ +} BaseMathObject; + +PyObject *BaseMathObject_getOwner( BaseMathObject * self, void * ); +PyObject *BaseMathObject_getWrapped( BaseMathObject *self, void * ); +void BaseMathObject_dealloc(BaseMathObject * self); + + + + +PyObject *Mathutils_Init( const char * from ); + +PyObject *quat_rotation(PyObject *arg1, PyObject *arg2); + +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 + + +/* Mathutils is used by the BGE and Blender so have to define + * some things here for luddite mac users of py2.3 */ +#ifndef Py_RETURN_NONE +#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif +#ifndef Py_RETURN_FALSE +#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False +#endif +#ifndef Py_RETURN_TRUE +#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True +#endif + +typedef struct Mathutils_Callback Mathutils_Callback; + +typedef int (*BaseMathCheckFunc)(PyObject *); +typedef int (*BaseMathGetFunc)(PyObject *, int, float *); +typedef int (*BaseMathSetFunc)(PyObject *, int, float *); +typedef int (*BaseMathGetIndexFunc)(PyObject *, int, float *, int); +typedef int (*BaseMathSetIndexFunc)(PyObject *, int, float *, int); + +struct Mathutils_Callback { + int (*check)(PyObject *user); /* checks the user is still valid */ + int (*get)(PyObject *user, int subtype, float *from); /* gets the vector from the user */ + int (*set)(PyObject *user, int subtype, float *to); /* sets the users vector values once the vector is modified */ + int (*get_index)(PyObject *user, int subtype, float *from,int index); /* same as above but only for an index */ + int (*set_index)(PyObject *user, int subtype, float *to, int index); /* same as above but only for an index */ +}; + +int Mathutils_RegisterCallback(Mathutils_Callback *cb); + +int _BaseMathObject_ReadCallback(BaseMathObject *self); +int _BaseMathObject_WriteCallback(BaseMathObject *self); +int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index); +int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index); + +/* since this is called so often avoid where possible */ +#define BaseMath_ReadCallback(_self) (((_self)->cb_user ? _BaseMathObject_ReadCallback((BaseMathObject *)_self):1)) +#define BaseMath_WriteCallback(_self) (((_self)->cb_user ?_BaseMathObject_WriteCallback((BaseMathObject *)_self):1)) +#define BaseMath_ReadIndexCallback(_self, _index) (((_self)->cb_user ? _BaseMathObject_ReadIndexCallback((BaseMathObject *)_self, _index):1)) +#define BaseMath_WriteIndexCallback(_self, _index) (((_self)->cb_user ? _BaseMathObject_WriteIndexCallback((BaseMathObject *)_self, _index):1)) + +#endif /* EXPP_Mathutils_H */ diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c new file mode 100644 index 00000000000..b1d943ea74a --- /dev/null +++ b/source/blender/python/generic/bpy_internal_import.c @@ -0,0 +1,341 @@ +/* + * $Id: bpy_internal_import.c 21094 2009-06-23 00:09:26Z gsrb3d $ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL LICENSE BLOCK ***** +*/ + +#include "bpy_internal_import.h" +#include "DNA_text_types.h" +#include "DNA_ID.h" + +#include "MEM_guardedalloc.h" +#include "BKE_text.h" /* txt_to_buf */ +#include "BKE_main.h" + +static Main *bpy_import_main= NULL; + +static void free_compiled_text(Text *text) +{ + if(text->compiled) { + Py_DECREF(( PyObject * )text->compiled); + } + text->compiled= NULL; +} + +struct Main *bpy_import_main_get(void) +{ + return bpy_import_main; +} + +void bpy_import_main_set(struct Main *maggie) +{ + bpy_import_main= maggie; +} + + +PyObject *bpy_text_import( char *name, int *found ) +{ + Text *text; + char txtname[22]; /* 21+NULL */ + char *buf = NULL; + int namelen = strlen( name ); +//XXX Main *maggie= bpy_import_main ? bpy_import_main:G.main; + Main *maggie= bpy_import_main; + + *found= 0; + + if (namelen>21-3) return NULL; /* we know this cant be importable, the name is too long for blender! */ + + memcpy( txtname, name, namelen ); + memcpy( &txtname[namelen], ".py", 4 ); + + for(text = maggie->text.first; text; text = text->id.next) { + if( !strcmp( txtname, text->id.name+2 ) ) + break; + } + + if( !text ) + return NULL; + else + *found = 1; + + if( !text->compiled ) { + buf = txt_to_buf( text ); + text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input ); + MEM_freeN( buf ); + + if( PyErr_Occurred( ) ) { + PyErr_Print( ); + PyErr_Clear( ); + PySys_SetObject("last_traceback", NULL); + free_compiled_text( text ); + return NULL; + } + } + + return PyImport_ExecCodeModule( name, text->compiled ); +} + + +/* + * find in-memory module and recompile + */ + +PyObject *bpy_text_reimport( PyObject *module, int *found ) +{ + Text *text; + char *txtname; + char *name; + char *buf = NULL; +//XXX Main *maggie= bpy_import_main ? bpy_import_main:G.main; + Main *maggie= bpy_import_main; + + *found= 0; + + /* get name, filename from the module itself */ + + txtname = PyModule_GetFilename( module ); + name = PyModule_GetName( module ); + if( !txtname || !name) + return NULL; + + /* look up the text object */ + text = ( Text * ) & ( maggie->text.first ); + while( text ) { + if( !strcmp( txtname, text->id.name+2 ) ) + break; + text = text->id.next; + } + + /* uh-oh.... didn't find it */ + if( !text ) + return NULL; + else + *found = 1; + + /* if previously compiled, free the object */ + /* (can't see how could be NULL, but check just in case) */ + if( text->compiled ){ + Py_DECREF( (PyObject *)text->compiled ); + } + + /* compile the buffer */ + buf = txt_to_buf( text ); + text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input ); + MEM_freeN( buf ); + + /* if compile failed.... return this error */ + if( PyErr_Occurred( ) ) { + PyErr_Print( ); + PyErr_Clear( ); + PySys_SetObject("last_traceback", NULL); + free_compiled_text( text ); + return NULL; + } + + /* make into a module */ + return PyImport_ExecCodeModule( name, text->compiled ); +} + + +static PyObject *blender_import( PyObject * self, PyObject * args, PyObject * kw) +{ + PyObject *exception, *err, *tb; + char *name; + int found= 0; + PyObject *globals = NULL, *locals = NULL, *fromlist = NULL; + PyObject *newmodule; + + //PyObject_Print(args, stderr, 0); +#if (PY_VERSION_HEX >= 0x02060000) + int dummy_val; /* what does this do?*/ + static char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", 0}; + + if( !PyArg_ParseTupleAndKeywords( args, kw, "s|OOOi:bpy_import_meth", kwlist, + &name, &globals, &locals, &fromlist, &dummy_val) ) + return NULL; +#else + static char *kwlist[] = {"name", "globals", "locals", "fromlist", 0}; + + if( !PyArg_ParseTupleAndKeywords( args, kw, "s|OOO:bpy_import_meth", kwlist, + &name, &globals, &locals, &fromlist ) ) + return NULL; +#endif + + /* import existing builtin modules or modules that have been imported alredy */ + newmodule = PyImport_ImportModuleEx( name, globals, locals, fromlist ); + + if(newmodule) + return newmodule; + + PyErr_Fetch( &exception, &err, &tb ); /* get the python error incase we cant import as blender text either */ + + /* importing from existing modules failed, see if we have this module as blender text */ + newmodule = bpy_text_import( name, &found ); + + if( newmodule ) {/* found module as blender text, ignore above exception */ + PyErr_Clear( ); + Py_XDECREF( exception ); + Py_XDECREF( err ); + Py_XDECREF( tb ); + /* printf( "imported from text buffer...\n" ); */ + } + else if (found==1) { /* blender text module failed to execute but was found, use its error message */ + Py_XDECREF( exception ); + Py_XDECREF( err ); + Py_XDECREF( tb ); + return NULL; + } + else { + /* no blender text was found that could import the module + * rause the original error from PyImport_ImportModuleEx */ + PyErr_Restore( exception, err, tb ); + } + return newmodule; +} + + +/* + * our reload() module, to handle reloading in-memory scripts + */ + +static PyObject *blender_reload( PyObject * self, PyObject * args ) +{ + PyObject *exception, *err, *tb; + PyObject *module = NULL; + PyObject *newmodule = NULL; + int found= 0; + + /* check for a module arg */ + if( !PyArg_ParseTuple( args, "O:bpy_reload_meth", &module ) ) + return NULL; + + /* try reimporting from file */ + newmodule = PyImport_ReloadModule( module ); + if( newmodule ) + return newmodule; + + /* no file, try importing from memory */ + PyErr_Fetch( &exception, &err, &tb ); /*restore for probable later use */ + + newmodule = bpy_text_reimport( module, &found ); + if( newmodule ) {/* found module as blender text, ignore above exception */ + PyErr_Clear( ); + Py_XDECREF( exception ); + Py_XDECREF( err ); + Py_XDECREF( tb ); + /* printf( "imported from text buffer...\n" ); */ + } + else if (found==1) { /* blender text module failed to execute but was found, use its error message */ + Py_XDECREF( exception ); + Py_XDECREF( err ); + Py_XDECREF( tb ); + return NULL; + } + else { + /* no blender text was found that could import the module + * rause the original error from PyImport_ImportModuleEx */ + PyErr_Restore( exception, err, tb ); + } + + return newmodule; +} + +PyMethodDef bpy_import_meth[] = { {"bpy_import_meth", blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"} }; +PyMethodDef bpy_reload_meth[] = { {"bpy_reload_meth", blender_reload, METH_VARARGS, "blenders reload"} }; + + +/* Clear user modules. + * This is to clear any modules that could be defined from running scripts in blender. + * + * Its also needed for the BGE Python api so imported scripts are not used between levels + * + * This clears every modules that has a __file__ attribute (is not a builtin) + * + * Note that clearing external python modules is important for the BGE otherwise + * it wont reload scripts between loading different blend files or while making the game. + * - use 'clear_all' arg in this case. + * + * Since pythons bultins include a full path even for win32. + * even if we remove a python module a reimport will bring it back again. + */ + +#if 0 // not used anymore but may still come in handy later + +#if defined(WIN32) || defined(WIN64) +#define SEPSTR "\\" +#else +#define SEPSTR "/" +#endif + + +void bpy_text_clear_modules(int clear_all) +{ + PyObject *modules= PySys_GetObject("modules"); + + char *fname; + char *file_extension; + + /* looping over the dict */ + PyObject *key, *value; + int pos = 0; + + /* new list */ + PyObject *list; + + if (modules==NULL) + return; /* should never happen but just incase */ + + list= PyList_New(0); + + /* go over sys.modules and remove anything with a + * sys.modukes[x].__file__ thats ends with a .py and has no path + */ + while (PyDict_Next(modules, &pos, &key, &value)) { + fname= PyModule_GetFilename(value); + if(fname) { + if (clear_all || ((strstr(fname, SEPSTR))==0)) { /* no path ? */ + file_extension = strstr(fname, ".py"); + if(file_extension && (*(file_extension + 3) == '\0' || *(file_extension + 4) == '\0')) { /* .py or pyc extension? */ + /* now we can be fairly sure its a python import from the blendfile */ + PyList_Append(list, key); /* free'd with the list */ + } + } + } + else { + PyErr_Clear(); + } + } + + /* remove all our modules */ + for(pos=0; pos < PyList_Size(list); pos++) { + /* PyObject_Print(key, stderr, 0); */ + key= PyList_GET_ITEM(list, pos); + PyDict_DelItem(modules, key); + } + + Py_DECREF(list); /* removes all references from append */ +} +#endif diff --git a/source/blender/python/generic/bpy_internal_import.h b/source/blender/python/generic/bpy_internal_import.h new file mode 100644 index 00000000000..7b692f3607f --- /dev/null +++ b/source/blender/python/generic/bpy_internal_import.h @@ -0,0 +1,50 @@ +/* + * $Id: bpy_internal_import.h 21094 2009-06-23 00:09:26Z gsrb3d $ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** +*/ + +/* Note, the BGE needs to use this too, keep it minimal */ + +#ifndef EXPP_bpy_import_h +#define EXPP_bpy_import_h + +#include +#include "../intern/bpy_compat.h" +#include "compile.h" /* for the PyCodeObject */ +#include "eval.h" /* for PyEval_EvalCode */ + +PyObject* bpy_text_import( char *name, int *found ); +PyObject* bpy_text_reimport( PyObject *module, int *found ); +/* void bpy_text_clear_modules( int clear_all );*/ /* Clear user modules */ +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); + + +#endif /* EXPP_bpy_import_h */ diff --git a/source/blender/python/generic/euler.c b/source/blender/python/generic/euler.c new file mode 100644 index 00000000000..b29bbd2055e --- /dev/null +++ b/source/blender/python/generic/euler.c @@ -0,0 +1,651 @@ +/* + * $Id: euler.c 21462 2009-07-09 15:40:04Z ton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "Mathutils.h" + +#include "BLI_arithb.h" +#include "BKE_utildefines.h" +#include "BLI_blenlib.h" + + +//-------------------------DOC STRINGS --------------------------- + +static PyObject *Euler_Zero( EulerObject * self ); +static PyObject *Euler_Unique( EulerObject * self ); +static PyObject *Euler_ToMatrix( EulerObject * self ); +static PyObject *Euler_ToQuat( EulerObject * self ); +static PyObject *Euler_Rotate( EulerObject * self, PyObject *args ); +static PyObject *Euler_MakeCompatible( EulerObject * self, EulerObject *value ); +static PyObject *Euler_copy( EulerObject * self, PyObject *args ); + +//-----------------------METHOD DEFINITIONS ---------------------- +static struct PyMethodDef Euler_methods[] = { + {"zero", (PyCFunction) Euler_Zero, METH_NOARGS, NULL}, + {"unique", (PyCFunction) Euler_Unique, METH_NOARGS, NULL}, + {"toMatrix", (PyCFunction) Euler_ToMatrix, METH_NOARGS, NULL}, + {"toQuat", (PyCFunction) Euler_ToQuat, METH_NOARGS, NULL}, + {"rotate", (PyCFunction) Euler_Rotate, METH_VARARGS, NULL}, + {"makeCompatible", (PyCFunction) Euler_MakeCompatible, METH_O, NULL}, + {"__copy__", (PyCFunction) Euler_copy, METH_VARARGS, NULL}, + {"copy", (PyCFunction) Euler_copy, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +//----------------------------------Mathutils.Euler() ------------------- +//makes a new euler for you to play with +static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwargs) +{ + PyObject *listObject = NULL; + int size, i; + float eul[3]; + PyObject *e; + + size = PyTuple_GET_SIZE(args); + if (size == 1) { + listObject = PyTuple_GET_ITEM(args, 0); + if (PySequence_Check(listObject)) { + size = PySequence_Length(listObject); + } else { // Single argument was not a sequence + PyErr_SetString(PyExc_TypeError, "Mathutils.Euler(): 3d numeric sequence expected\n"); + return NULL; + } + } else if (size == 0) { + //returns a new empty 3d euler + return newEulerObject(NULL, Py_NEW, NULL); + } else { + listObject = args; + } + + if (size != 3) { // Invalid euler size + PyErr_SetString(PyExc_AttributeError, "Mathutils.Euler(): 3d numeric sequence expected\n"); + return NULL; + } + + for (i=0; ieul[x] * ((float)Py_PI / 180); + } + EulToQuat(eul, quat); +#else + EulToQuat(self->eul, quat); +#endif + + return newQuaternionObject(quat, Py_NEW, NULL); +} +//----------------------------Euler.toMatrix()--------------------- +//return a matrix representation of the euler +static PyObject *Euler_ToMatrix(EulerObject * self) +{ + float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; + + if(!BaseMath_ReadCallback(self)) + return NULL; + +#ifdef USE_MATHUTILS_DEG + { + float eul[3]; + int x; + + for(x = 0; x < 3; x++) { + eul[x] = self->eul[x] * ((float)Py_PI / 180); + } + EulToMat3(eul, (float (*)[3]) mat); + } +#else + EulToMat3(self->eul, (float (*)[3]) mat); +#endif + return newMatrixObject(mat, 3, 3 , Py_NEW, NULL); +} +//----------------------------Euler.unique()----------------------- +//sets the x,y,z values to a unique euler rotation +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; + +#ifdef USE_MATHUTILS_DEG + //radians + heading = self->eul[0] * (float)Py_PI / 180; + pitch = self->eul[1] * (float)Py_PI / 180; + bank = self->eul[2] * (float)Py_PI / 180; +#else + heading = self->eul[0]; + pitch = self->eul[1]; + bank = self->eul[2]; +#endif + + //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; + +#ifdef USE_MATHUTILS_DEG + //back to degrees + self->eul[0] = (float)(heading * 180 / (float)Py_PI); + self->eul[1] = (float)(pitch * 180 / (float)Py_PI); + self->eul[2] = (float)(bank * 180 / (float)Py_PI); +#endif + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject *)self; +} +//----------------------------Euler.zero()------------------------- +//sets the euler to 0,0,0 +static PyObject *Euler_Zero(EulerObject * self) +{ + self->eul[0] = 0.0; + self->eul[1] = 0.0; + self->eul[2] = 0.0; + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject *)self; +} +//----------------------------Euler.rotate()----------------------- +//rotates a euler a certain amount and returns the result +//should return a unique euler rotation (i.e. no 720 degree pitches :) +static PyObject *Euler_Rotate(EulerObject * self, PyObject *args) +{ + float angle = 0.0f; + char *axis; + + if(!PyArg_ParseTuple(args, "fs", &angle, &axis)){ + PyErr_SetString(PyExc_TypeError, "euler.rotate():expected angle (float) and axis (x,y,z)"); + return NULL; + } + if(!STREQ3(axis,"x","y","z")){ + PyErr_SetString(PyExc_TypeError, "euler.rotate(): expected axis to be 'x', 'y' or 'z'"); + return NULL; + } + + if(!BaseMath_ReadCallback(self)) + return NULL; + +#ifdef USE_MATHUTILS_DEG + { + int x; + + //covert to radians + angle *= ((float)Py_PI / 180); + for(x = 0; x < 3; x++) { + self->eul[x] *= ((float)Py_PI / 180); + } + } +#endif + euler_rot(self->eul, angle, *axis); + +#ifdef USE_MATHUTILS_DEG + { + int x; + //convert back from radians + for(x = 0; x < 3; x++) { + self->eul[x] *= (180 / (float)Py_PI); + } + } +#endif + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value) +{ +#ifdef USE_MATHUTILS_DEG + float eul_from_rad[3]; + int x; +#endif + + if(!EulerObject_Check(value)) { + PyErr_SetString(PyExc_TypeError, "euler.makeCompatible(euler):expected a single euler argument."); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) + return NULL; + +#ifdef USE_MATHUTILS_DEG + //covert to radians + for(x = 0; x < 3; x++) { + self->eul[x] = self->eul[x] * ((float)Py_PI / 180); + eul_from_rad[x] = value->eul[x] * ((float)Py_PI / 180); + } + compatible_eul(self->eul, eul_from_rad); +#else + compatible_eul(self->eul, value->eul); +#endif + +#ifdef USE_MATHUTILS_DEG + //convert back from radians + for(x = 0; x < 3; x++) { + self->eul[x] *= (180 / (float)Py_PI); + } +#endif + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject *)self; +} + +//----------------------------Euler.rotate()----------------------- +// return a copy of the euler +static PyObject *Euler_copy(EulerObject * self, PyObject *args) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + return newEulerObject(self->eul, Py_NEW, Py_TYPE(self)); +} + +//----------------------------print object (internal)-------------- +//print the object to screen +static PyObject *Euler_repr(EulerObject * self) +{ + char str[64]; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + sprintf(str, "[%.6f, %.6f, %.6f](euler)", self->eul[0], self->eul[1], self->eul[2]); + return PyUnicode_FromString(str); +} +//------------------------tp_richcmpr +//returns -1 execption, 0 false, 1 true +static PyObject* Euler_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type) +{ + EulerObject *eulA = NULL, *eulB = NULL; + int result = 0; + + if(EulerObject_Check(objectA)) { + eulA = (EulerObject*)objectA; + if(!BaseMath_ReadCallback(eulA)) + return NULL; + } + if(EulerObject_Check(objectB)) { + eulB = (EulerObject*)objectB; + if(!BaseMath_ReadCallback(eulB)) + return NULL; + } + + if (!eulA || !eulB){ + if (comparison_type == Py_NE){ + Py_RETURN_TRUE; + }else{ + Py_RETURN_FALSE; + } + } + eulA = (EulerObject*)objectA; + eulB = (EulerObject*)objectB; + + switch (comparison_type){ + case Py_EQ: + result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1); + break; + case Py_NE: + result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1); + if (result == 0){ + result = 1; + }else{ + result = 0; + } + break; + default: + printf("The result of the comparison could not be evaluated"); + break; + } + if (result == 1){ + Py_RETURN_TRUE; + }else{ + Py_RETURN_FALSE; + } +} + +//---------------------SEQUENCE PROTOCOLS------------------------ +//----------------------------len(object)------------------------ +//sequence length +static int Euler_len(EulerObject * self) +{ + return 3; +} +//----------------------------object[]--------------------------- +//sequence accessor (get) +static PyObject *Euler_item(EulerObject * self, int i) +{ + if(i<0) i= 3-i; + + if(i < 0 || i >= 3) { + PyErr_SetString(PyExc_IndexError, "euler[attribute]: array index out of range"); + return NULL; + } + + if(!BaseMath_ReadIndexCallback(self, i)) + return NULL; + + return PyFloat_FromDouble(self->eul[i]); + +} +//----------------------------object[]------------------------- +//sequence accessor (set) +static int Euler_ass_item(EulerObject * self, int i, PyObject * value) +{ + float f = PyFloat_AsDouble(value); + + if(f == -1 && PyErr_Occurred()) { // parsed item not a number + PyErr_SetString(PyExc_TypeError, "euler[attribute] = x: argument not a number"); + return -1; + } + + if(i<0) i= 3-i; + + if(i < 0 || i >= 3){ + PyErr_SetString(PyExc_IndexError, "euler[attribute] = x: array assignment index out of range\n"); + return -1; + } + + self->eul[i] = f; + + if(!BaseMath_WriteIndexCallback(self, i)) + return -1; + + return 0; +} +//----------------------------object[z:y]------------------------ +//sequence slice (get) +static PyObject *Euler_slice(EulerObject * self, int begin, int end) +{ + PyObject *list = NULL; + int count; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + CLAMP(begin, 0, 3); + if (end<0) end= 4+end; + CLAMP(end, 0, 3); + begin = MIN2(begin,end); + + list = PyList_New(end - begin); + for(count = begin; count < end; count++) { + PyList_SetItem(list, count - begin, + PyFloat_FromDouble(self->eul[count])); + } + + return list; +} +//----------------------------object[z:y]------------------------ +//sequence slice (set) +static int Euler_ass_slice(EulerObject * self, int begin, int end, + PyObject * seq) +{ + int i, y, size = 0; + float eul[3]; + PyObject *e; + + if(!BaseMath_ReadCallback(self)) + return -1; + + CLAMP(begin, 0, 3); + if (end<0) end= 4+end; + CLAMP(end, 0, 3); + begin = MIN2(begin,end); + + size = PySequence_Length(seq); + if(size != (end - begin)){ + PyErr_SetString(PyExc_TypeError, "euler[begin:end] = []: size mismatch in slice assignment"); + return -1; + } + + for (i = 0; i < size; i++) { + e = PySequence_GetItem(seq, i); + if (e == NULL) { // Failed to read sequence + PyErr_SetString(PyExc_RuntimeError, "euler[begin:end] = []: unable to read sequence"); + return -1; + } + + eul[i] = (float)PyFloat_AsDouble(e); + Py_DECREF(e); + + if(eul[i]==-1 && PyErr_Occurred()) { // parsed item not a number + PyErr_SetString(PyExc_TypeError, "euler[begin:end] = []: sequence argument not a number"); + return -1; + } + } + //parsed well - now set in vector + for(y = 0; y < 3; y++){ + self->eul[begin + y] = eul[y]; + } + + BaseMath_WriteCallback(self); + return 0; +} +//-----------------PROTCOL DECLARATIONS-------------------------- +static PySequenceMethods Euler_SeqMethods = { + (inquiry) Euler_len, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (ssizeargfunc) 0, /* sq_repeat */ + (ssizeargfunc) Euler_item, /* sq_item */ + (ssizessizeargfunc) Euler_slice, /* sq_slice */ + (ssizeobjargproc) Euler_ass_item, /* sq_ass_item */ + (ssizessizeobjargproc) Euler_ass_slice, /* sq_ass_slice */ +}; + + +/* + * vector axis, vector.x/y/z/w + */ + +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 ) +{ + return Euler_ass_item(self, GET_INT_FROM_POINTER(type), value); +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef Euler_getseters[] = { + {"x", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler X axis", (void *)0}, + {"y", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler Y axis", (void *)1}, + {"z", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler Z axis", (void *)2}, + + {"wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, "True when this wraps blenders internal data", NULL}, + {"__owner__", (getter)BaseMathObject_getOwner, (setter)NULL, "Read only owner for vectors that depend on another object", NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +//------------------PY_OBECT DEFINITION-------------------------- +PyTypeObject euler_Type = { +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif + "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 + (reprfunc) Euler_repr, //tp_repr + 0, //tp_as_number + &Euler_SeqMethods, //tp_as_sequence + 0, //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 + 0, //tp_doc + 0, //tp_traverse + 0, //tp_clear + (richcmpfunc)Euler_richcmpr, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + Euler_methods, //tp_methods + 0, //tp_members + Euler_getseters, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //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 +}; +//------------------------newEulerObject (internal)------------- +//creates a new euler object +/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER + (i.e. it was allocated elsewhere by MEM_mallocN()) + pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON + (i.e. it must be created here with PyMEM_malloc())*/ +PyObject *newEulerObject(float *eul, int type, PyTypeObject *base_type) +{ + EulerObject *self; + int x; + + if(base_type) self = (EulerObject *)base_type->tp_alloc(base_type, 0); + else self = PyObject_NEW(EulerObject, &euler_Type); + + /* 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(3 * sizeof(float)); + if(!eul) { //new empty + for(x = 0; x < 3; x++) { + self->eul[x] = 0.0f; + } + }else{ + VECCOPY(self->eul, eul); + } + self->wrapped = Py_NEW; + }else{ //bad type + return NULL; + } + return (PyObject *)self; +} + +PyObject *newEulerObject_cb(PyObject *cb_user, int cb_type, int cb_subtype) +{ + EulerObject *self= (EulerObject *)newEulerObject(NULL, Py_NEW, NULL); + if(self) { + Py_INCREF(cb_user); + self->cb_user= cb_user; + self->cb_type= (unsigned char)cb_type; + self->cb_subtype= (unsigned char)cb_subtype; + } + + return (PyObject *)self; +} diff --git a/source/blender/python/generic/euler.h b/source/blender/python/generic/euler.h new file mode 100644 index 00000000000..16cf5d8c983 --- /dev/null +++ b/source/blender/python/generic/euler.h @@ -0,0 +1,60 @@ +/* + * $Id: euler.h 21254 2009-06-30 00:42:17Z campbellbarton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * 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): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#ifndef EXPP_euler_h +#define EXPP_euler_h + +#include +#include "../intern/bpy_compat.h" + +extern PyTypeObject euler_Type; +#define EulerObject_Check(_v) PyObject_TypeCheck((_v), &euler_Type) + +typedef struct { + PyObject_VAR_HEAD + float *eul; /*1D array of data */ + PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ + unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ + unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ + unsigned char wrapped; /* wrapped data type? */ + /* end BaseMathObject */ + +} EulerObject; + +/*struct data contains a pointer to the actual data that the +object uses. It can use either PyMem allocated data (which will +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 *newEulerObject( float *eul, int type, PyTypeObject *base_type); +PyObject *newEulerObject_cb(PyObject *cb_user, int cb_type, int cb_subtype); + +#endif /* EXPP_euler_h */ diff --git a/source/blender/python/generic/matrix.c b/source/blender/python/generic/matrix.c new file mode 100644 index 00000000000..210751eaaf1 --- /dev/null +++ b/source/blender/python/generic/matrix.c @@ -0,0 +1,1358 @@ +/* + * $Id: matrix.c 21293 2009-07-01 20:55:32Z campbellbarton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Michel Selten & Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "Mathutils.h" + +#include "BKE_utildefines.h" +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec); /* utility func */ + + +/* matrix vector callbacks */ +int mathutils_matrix_vector_cb_index= -1; + +static int mathutils_matrix_vector_check(MatrixObject *self) +{ + return BaseMath_ReadCallback(self); +} + +static int mathutils_matrix_vector_get(MatrixObject *self, int subtype, float *vec_from) +{ + int i; + if(!BaseMath_ReadCallback(self)) + return 0; + + for(i=0; icolSize; i++) + vec_from[i]= self->matrix[subtype][i]; + + return 1; +} + +static int mathutils_matrix_vector_set(MatrixObject *self, int subtype, float *vec_to) +{ + int i; + if(!BaseMath_ReadCallback(self)) + return 0; + + for(i=0; icolSize; i++) + self->matrix[subtype][i]= vec_to[i]; + + BaseMath_WriteCallback(self); + return 1; +} + +static int mathutils_matrix_vector_get_index(MatrixObject *self, int subtype, float *vec_from, int index) +{ + if(!BaseMath_ReadCallback(self)) + return 0; + + vec_from[index]= self->matrix[subtype][index]; + return 1; +} + +static int mathutils_matrix_vector_set_index(MatrixObject *self, int subtype, float *vec_to, int index) +{ + if(!BaseMath_ReadCallback(self)) + return 0; + + self->matrix[subtype][index]= vec_to[index]; + + BaseMath_WriteCallback(self); + return 1; +} + +Mathutils_Callback mathutils_matrix_vector_cb = { + mathutils_matrix_vector_check, + mathutils_matrix_vector_get, + mathutils_matrix_vector_set, + mathutils_matrix_vector_get_index, + mathutils_matrix_vector_set_index +}; +/* matrix vector callbacks, this is so you can do matrix[i][j] = val */ + +/*-------------------------DOC STRINGS ---------------------------*/ + +static PyObject *Matrix_Zero( MatrixObject * self ); +static PyObject *Matrix_Identity( MatrixObject * self ); +static PyObject *Matrix_Transpose( MatrixObject * self ); +static PyObject *Matrix_Determinant( MatrixObject * self ); +static PyObject *Matrix_Invert( MatrixObject * self ); +static PyObject *Matrix_TranslationPart( MatrixObject * self ); +static PyObject *Matrix_RotationPart( MatrixObject * self ); +static PyObject *Matrix_scalePart( MatrixObject * self ); +static PyObject *Matrix_Resize4x4( MatrixObject * self ); +static PyObject *Matrix_toEuler( MatrixObject * self, PyObject *args ); +static PyObject *Matrix_toQuat( MatrixObject * self ); +static PyObject *Matrix_copy( MatrixObject * self ); + +/*-----------------------METHOD DEFINITIONS ----------------------*/ +static struct PyMethodDef Matrix_methods[] = { + {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, NULL}, + {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, NULL}, + {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, NULL}, + {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, NULL}, + {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, NULL}, + {"translationPart", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, NULL}, + {"rotationPart", (PyCFunction) Matrix_RotationPart, METH_NOARGS, NULL}, + {"scalePart", (PyCFunction) Matrix_scalePart, METH_NOARGS, NULL}, + {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, NULL}, + {"toEuler", (PyCFunction) Matrix_toEuler, METH_VARARGS, NULL}, + {"toQuat", (PyCFunction) Matrix_toQuat, METH_NOARGS, NULL}, + {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, NULL}, + {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +//----------------------------------Mathutils.Matrix() ----------------- +//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. +//create a new matrix type +static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *argObject, *m, *s; + MatrixObject *mat; + int argSize, seqSize = 0, i, j; + float matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + float scalar; + + argSize = PyTuple_GET_SIZE(args); + if(argSize > 4){ //bad arg nums + PyErr_SetString(PyExc_AttributeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); + return NULL; + } else if (argSize == 0) { //return empty 4D matrix + return (PyObject *) newMatrixObject(NULL, 4, 4, Py_NEW, NULL); + }else if (argSize == 1){ + //copy constructor for matrix objects + argObject = PyTuple_GET_ITEM(args, 0); + if(MatrixObject_Check(argObject)){ + mat = (MatrixObject*)argObject; + if(!BaseMath_ReadCallback(mat)) + return NULL; + + memcpy(matrix, mat->contigPtr, sizeof(float) * mat->rowSize * mat->colSize); + } + }else{ //2-4 arguments (all seqs? all same size?) + for(i =0; i < argSize; i++){ + argObject = PyTuple_GET_ITEM(args, i); + if (PySequence_Check(argObject)) { //seq? + if(seqSize){ //0 at first + if(PySequence_Length(argObject) != seqSize){ //seq size not same + PyErr_SetString(PyExc_AttributeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); + return NULL; + } + } + seqSize = PySequence_Length(argObject); + }else{ //arg not a sequence + PyErr_SetString(PyExc_TypeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); + return NULL; + } + } + //all is well... let's continue parsing + for (i = 0; i < argSize; i++){ + m = PyTuple_GET_ITEM(args, i); + if (m == NULL) { // Failed to read sequence + PyErr_SetString(PyExc_RuntimeError, "Mathutils.Matrix(): failed to parse arguments...\n"); + return NULL; + } + + for (j = 0; j < seqSize; j++) { + s = PySequence_GetItem(m, j); + if (s == NULL) { // Failed to read sequence + PyErr_SetString(PyExc_RuntimeError, "Mathutils.Matrix(): failed to parse arguments...\n"); + return NULL; + } + + scalar= (float)PyFloat_AsDouble(s); + Py_DECREF(s); + + if(scalar==-1 && PyErr_Occurred()) { // parsed item is not a number + PyErr_SetString(PyExc_AttributeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); + return NULL; + } + + matrix[(seqSize*i)+j]= scalar; + } + } + } + return newMatrixObject(matrix, argSize, seqSize, Py_NEW, NULL); +} + +/*-----------------------------METHODS----------------------------*/ +/*---------------------------Matrix.toQuat() ---------------------*/ +static PyObject *Matrix_toQuat(MatrixObject * self) +{ + float quat[4]; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + /*must be 3-4 cols, 3-4 rows, square matrix*/ + if(self->colSize < 3 || self->rowSize < 3 || (self->colSize != self->rowSize)) { + PyErr_SetString(PyExc_AttributeError, "Matrix.toQuat(): inappropriate matrix size - expects 3x3 or 4x4 matrix"); + return NULL; + } + if(self->colSize == 3){ + Mat3ToQuat((float (*)[3])*self->matrix, quat); + }else{ + Mat4ToQuat((float (*)[4])*self->matrix, quat); + } + + return newQuaternionObject(quat, Py_NEW, NULL); +} +/*---------------------------Matrix.toEuler() --------------------*/ +PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args) +{ + float eul[3], eul_compatf[3]; + EulerObject *eul_compat = NULL; +#ifdef USE_MATHUTILS_DEG + int x; +#endif + + if(!BaseMath_ReadCallback(self)) + return NULL; + + if(!PyArg_ParseTuple(args, "|O!:toEuler", &euler_Type, &eul_compat)) + return NULL; + + if(eul_compat) { + if(!BaseMath_ReadCallback(eul_compat)) + return NULL; + +#ifdef USE_MATHUTILS_DEG + for(x = 0; x < 3; x++) { + eul_compatf[x] = eul_compat->eul[x] * ((float)Py_PI / 180); + } +#else + VECCOPY(eul_compatf, eul_compat->eul); +#endif + } + + /*must be 3-4 cols, 3-4 rows, square matrix*/ + if(self->colSize ==3 && self->rowSize ==3) { + if(eul_compat) Mat3ToCompatibleEul((float (*)[3])*self->matrix, eul, eul_compatf); + else Mat3ToEul((float (*)[3])*self->matrix, eul); + }else if (self->colSize ==4 && self->rowSize ==4) { + float tempmat3[3][3]; + Mat3CpyMat4(tempmat3, (float (*)[4])*self->matrix); + Mat3ToEul(tempmat3, eul); + if(eul_compat) Mat3ToCompatibleEul(tempmat3, eul, eul_compatf); + else Mat3ToEul(tempmat3, eul); + + }else { + PyErr_SetString(PyExc_AttributeError, "Matrix.toEuler(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n"); + return NULL; + } +#ifdef USE_MATHUTILS_DEG + /*have to convert to degrees*/ + for(x = 0; x < 3; x++) { + eul[x] *= (float) (180 / Py_PI); + } +#endif + return newEulerObject(eul, Py_NEW, NULL); +} +/*---------------------------Matrix.resize4x4() ------------------*/ +PyObject *Matrix_Resize4x4(MatrixObject * self) +{ + int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index; + + if(self->wrapped==Py_WRAP){ + PyErr_SetString(PyExc_TypeError, "cannot resize wrapped data - make a copy and resize that"); + return NULL; + } + if(self->cb_user){ + PyErr_SetString(PyExc_TypeError, "cannot resize owned data - make a copy and resize that"); + return NULL; + } + + self->contigPtr = PyMem_Realloc(self->contigPtr, (sizeof(float) * 16)); + if(self->contigPtr == NULL) { + PyErr_SetString(PyExc_MemoryError, "matrix.resize4x4(): problem allocating pointer space"); + return NULL; + } + self->matrix = PyMem_Realloc(self->matrix, (sizeof(float *) * 4)); + if(self->matrix == NULL) { + PyErr_SetString(PyExc_MemoryError, "matrix.resize4x4(): problem allocating pointer space"); + return NULL; + } + /*set row pointers*/ + for(x = 0; x < 4; x++) { + self->matrix[x] = self->contigPtr + (x * 4); + } + /*move data to new spot in array + clean*/ + for(blank_rows = (4 - self->rowSize); blank_rows > 0; blank_rows--){ + for(x = 0; x < 4; x++){ + index = (4 * (self->rowSize + (blank_rows - 1))) + x; + if (index == 10 || index == 15){ + self->contigPtr[index] = 1.0f; + }else{ + self->contigPtr[index] = 0.0f; + } + } + } + for(x = 1; x <= self->rowSize; x++){ + first_row_elem = (self->colSize * (self->rowSize - x)); + curr_pos = (first_row_elem + (self->colSize -1)); + new_pos = (4 * (self->rowSize - x )) + (curr_pos - first_row_elem); + for(blank_columns = (4 - self->colSize); blank_columns > 0; blank_columns--){ + self->contigPtr[new_pos + blank_columns] = 0.0f; + } + for(curr_pos = curr_pos; curr_pos >= first_row_elem; curr_pos--){ + self->contigPtr[new_pos] = self->contigPtr[curr_pos]; + new_pos--; + } + } + self->rowSize = 4; + self->colSize = 4; + + Py_INCREF(self); + return (PyObject *)self; +} +/*---------------------------Matrix.translationPart() ------------*/ +PyObject *Matrix_TranslationPart(MatrixObject * self) +{ + float vec[4]; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + if(self->colSize < 3 || self->rowSize < 4){ + PyErr_SetString(PyExc_AttributeError, "Matrix.translationPart: inappropriate matrix size"); + return NULL; + } + + vec[0] = self->matrix[3][0]; + vec[1] = self->matrix[3][1]; + vec[2] = self->matrix[3][2]; + + return newVectorObject(vec, 3, Py_NEW, NULL); +} +/*---------------------------Matrix.rotationPart() ---------------*/ +PyObject *Matrix_RotationPart(MatrixObject * self) +{ + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + if(self->colSize < 3 || self->rowSize < 3){ + PyErr_SetString(PyExc_AttributeError, "Matrix.rotationPart: inappropriate matrix size\n"); + return NULL; + } + + mat[0] = self->matrix[0][0]; + mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2]; + mat[3] = self->matrix[1][0]; + mat[4] = self->matrix[1][1]; + mat[5] = self->matrix[1][2]; + mat[6] = self->matrix[2][0]; + mat[7] = self->matrix[2][1]; + mat[8] = self->matrix[2][2]; + + return newMatrixObject(mat, 3, 3, Py_NEW, Py_TYPE(self)); +} +/*---------------------------Matrix.scalePart() --------------------*/ +PyObject *Matrix_scalePart(MatrixObject * self) +{ + float scale[3], rot[3]; + float mat[3][3], imat[3][3], tmat[3][3]; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + /*must be 3-4 cols, 3-4 rows, square matrix*/ + if(self->colSize == 4 && self->rowSize == 4) + Mat3CpyMat4(mat, (float (*)[4])*self->matrix); + else if(self->colSize == 3 && self->rowSize == 3) + Mat3CpyMat3(mat, (float (*)[3])*self->matrix); + else { + PyErr_SetString(PyExc_AttributeError, "Matrix.scalePart(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n"); + return NULL; + } + /* functionality copied from editobject.c apply_obmat */ + Mat3ToEul(mat, rot); + EulToMat3(rot, tmat); + Mat3Inv(imat, tmat); + Mat3MulMat3(tmat, imat, mat); + + scale[0]= tmat[0][0]; + scale[1]= tmat[1][1]; + scale[2]= tmat[2][2]; + return newVectorObject(scale, 3, Py_NEW, NULL); +} +/*---------------------------Matrix.invert() ---------------------*/ +PyObject *Matrix_Invert(MatrixObject * self) +{ + + int x, y, z = 0; + float det = 0.0f; + PyObject *f = NULL; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + if(self->rowSize != self->colSize){ + PyErr_SetString(PyExc_AttributeError, "Matrix.invert(ed): only square matrices are supported"); + return NULL; + } + + /*calculate the determinant*/ + f = Matrix_Determinant(self); + det = (float)PyFloat_AS_DOUBLE(f); /*Increfs, so we need to decref*/ + Py_DECREF(f); + + if(det != 0) { + /*calculate the classical adjoint*/ + if(self->rowSize == 2) { + mat[0] = self->matrix[1][1]; + mat[1] = -self->matrix[0][1]; + mat[2] = -self->matrix[1][0]; + mat[3] = self->matrix[0][0]; + } else if(self->rowSize == 3) { + Mat3Adj((float (*)[3]) mat,(float (*)[3]) *self->matrix); + } else if(self->rowSize == 4) { + Mat4Adj((float (*)[4]) mat, (float (*)[4]) *self->matrix); + } + /*divide by determinate*/ + for(x = 0; x < (self->rowSize * self->colSize); x++) { + mat[x] /= det; + } + /*set values*/ + for(x = 0; x < self->rowSize; x++) { + for(y = 0; y < self->colSize; y++) { + self->matrix[x][y] = mat[z]; + z++; + } + } + /*transpose + Matrix_Transpose(self);*/ + } else { + PyErr_SetString(PyExc_ValueError, "matrix does not have an inverse"); + return NULL; + } + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject *)self; +} + + +/*---------------------------Matrix.determinant() ----------------*/ +PyObject *Matrix_Determinant(MatrixObject * self) +{ + float det = 0.0f; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + if(self->rowSize != self->colSize){ + PyErr_SetString(PyExc_AttributeError, "Matrix.determinant: only square matrices are supported"); + return NULL; + } + + if(self->rowSize == 2) { + det = Det2x2(self->matrix[0][0], self->matrix[0][1], + self->matrix[1][0], self->matrix[1][1]); + } else if(self->rowSize == 3) { + det = Det3x3(self->matrix[0][0], self->matrix[0][1], + self->matrix[0][2], self->matrix[1][0], + self->matrix[1][1], self->matrix[1][2], + self->matrix[2][0], self->matrix[2][1], + self->matrix[2][2]); + } else { + det = Det4x4((float (*)[4]) *self->matrix); + } + + return PyFloat_FromDouble( (double) det ); +} +/*---------------------------Matrix.transpose() ------------------*/ +PyObject *Matrix_Transpose(MatrixObject * self) +{ + float t = 0.0f; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + if(self->rowSize != self->colSize){ + PyErr_SetString(PyExc_AttributeError, "Matrix.transpose(d): only square matrices are supported"); + return NULL; + } + + if(self->rowSize == 2) { + t = self->matrix[1][0]; + self->matrix[1][0] = self->matrix[0][1]; + self->matrix[0][1] = t; + } else if(self->rowSize == 3) { + Mat3Transp((float (*)[3])*self->matrix); + } else { + Mat4Transp((float (*)[4])*self->matrix); + } + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject *)self; +} + + +/*---------------------------Matrix.zero() -----------------------*/ +PyObject *Matrix_Zero(MatrixObject * self) +{ + int row, col; + + for(row = 0; row < self->rowSize; row++) { + for(col = 0; col < self->colSize; col++) { + self->matrix[row][col] = 0.0f; + } + } + + if(!BaseMath_WriteCallback(self)) + return NULL; + + Py_INCREF(self); + return (PyObject *)self; +} +/*---------------------------Matrix.identity(() ------------------*/ +PyObject *Matrix_Identity(MatrixObject * self) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + if(self->rowSize != self->colSize){ + PyErr_SetString(PyExc_AttributeError, "Matrix.identity: only square matrices are supported\n"); + return NULL; + } + + if(self->rowSize == 2) { + self->matrix[0][0] = 1.0f; + self->matrix[0][1] = 0.0f; + self->matrix[1][0] = 0.0f; + self->matrix[1][1] = 1.0f; + } else if(self->rowSize == 3) { + Mat3One((float (*)[3]) *self->matrix); + } else { + Mat4One((float (*)[4]) *self->matrix); + } + + if(!BaseMath_WriteCallback(self)) + return NULL; + + Py_INCREF(self); + return (PyObject *)self; +} + +/*---------------------------Matrix.inverted() ------------------*/ +PyObject *Matrix_copy(MatrixObject * self) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + return (PyObject*)newMatrixObject((float (*))*self->matrix, self->rowSize, self->colSize, Py_NEW, Py_TYPE(self)); +} + +/*----------------------------print object (internal)-------------*/ +/*print the object to screen*/ +static PyObject *Matrix_repr(MatrixObject * self) +{ + int x, y; + char buffer[48], str[1024]; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + BLI_strncpy(str,"",1024); + for(x = 0; x < self->rowSize; x++){ + sprintf(buffer, "["); + strcat(str,buffer); + for(y = 0; y < (self->colSize - 1); y++) { + sprintf(buffer, "%.6f, ", self->matrix[x][y]); + strcat(str,buffer); + } + if(x < (self->rowSize-1)){ + sprintf(buffer, "%.6f](matrix [row %d])\n", self->matrix[x][y], x); + strcat(str,buffer); + }else{ + sprintf(buffer, "%.6f](matrix [row %d])", self->matrix[x][y], x); + strcat(str,buffer); + } + } + + return PyUnicode_FromString(str); +} +/*------------------------tp_richcmpr*/ +/*returns -1 execption, 0 false, 1 true*/ +static PyObject* Matrix_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type) +{ + MatrixObject *matA = NULL, *matB = NULL; + int result = 0; + + if (!MatrixObject_Check(objectA) || !MatrixObject_Check(objectB)){ + if (comparison_type == Py_NE){ + Py_RETURN_TRUE; + }else{ + Py_RETURN_FALSE; + } + } + matA = (MatrixObject*)objectA; + matB = (MatrixObject*)objectB; + + if(!BaseMath_ReadCallback(matA) || !BaseMath_ReadCallback(matB)) + return NULL; + + if (matA->colSize != matB->colSize || matA->rowSize != matB->rowSize){ + if (comparison_type == Py_NE){ + Py_RETURN_TRUE; + }else{ + Py_RETURN_FALSE; + } + } + + switch (comparison_type){ + case Py_EQ: + /*contigPtr is basically a really long vector*/ + result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr, + (matA->rowSize * matA->colSize), 1); + break; + case Py_NE: + result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr, + (matA->rowSize * matA->colSize), 1); + if (result == 0){ + result = 1; + }else{ + result = 0; + } + break; + default: + printf("The result of the comparison could not be evaluated"); + break; + } + if (result == 1){ + Py_RETURN_TRUE; + }else{ + Py_RETURN_FALSE; + } +} + +/*---------------------SEQUENCE PROTOCOLS------------------------ + ----------------------------len(object)------------------------ + sequence length*/ +static int Matrix_len(MatrixObject * self) +{ + return (self->rowSize); +} +/*----------------------------object[]--------------------------- + sequence accessor (get) + the wrapped vector gives direct access to the matrix data*/ +static PyObject *Matrix_item(MatrixObject * self, int i) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + if(i < 0 || i >= self->rowSize) { + PyErr_SetString(PyExc_IndexError, "matrix[attribute]: array index out of range"); + return NULL; + } + return newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, i); +} +/*----------------------------object[]------------------------- + sequence accessor (set)*/ +static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob) +{ + int y, x, size = 0; + float vec[4]; + PyObject *m, *f; + + if(!BaseMath_ReadCallback(self)) + return -1; + + if(i >= self->rowSize || i < 0){ + PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad row\n"); + return -1; + } + + if(PySequence_Check(ob)){ + size = PySequence_Length(ob); + if(size != self->colSize){ + PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad sequence size\n"); + return -1; + } + for (x = 0; x < size; x++) { + m = PySequence_GetItem(ob, x); + if (m == NULL) { /*Failed to read sequence*/ + PyErr_SetString(PyExc_RuntimeError, "matrix[attribute] = x: unable to read sequence\n"); + return -1; + } + + f = PyNumber_Float(m); + if(f == NULL) { /*parsed item not a number*/ + Py_DECREF(m); + PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: sequence argument not a number\n"); + return -1; + } + + vec[x] = (float)PyFloat_AS_DOUBLE(f); + Py_DECREF(m); + Py_DECREF(f); + } + /*parsed well - now set in matrix*/ + for(y = 0; y < size; y++){ + self->matrix[i][y] = vec[y]; + } + + BaseMath_WriteCallback(self); + return 0; + }else{ + PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: expects a sequence of column size\n"); + return -1; + } +} +/*----------------------------object[z:y]------------------------ + sequence slice (get)*/ +static PyObject *Matrix_slice(MatrixObject * self, int begin, int end) +{ + + PyObject *list = NULL; + int count; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + CLAMP(begin, 0, self->rowSize); + CLAMP(end, 0, self->rowSize); + begin = MIN2(begin,end); + + list = PyList_New(end - begin); + for(count = begin; count < end; count++) { + PyList_SetItem(list, count - begin, + newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, count)); + + } + + return list; +} +/*----------------------------object[z:y]------------------------ + sequence slice (set)*/ +static int Matrix_ass_slice(MatrixObject * self, int begin, int end, PyObject * seq) +{ + int i, x, y, size, sub_size = 0; + float mat[16], f; + PyObject *subseq; + PyObject *m; + + if(!BaseMath_ReadCallback(self)) + return -1; + + CLAMP(begin, 0, self->rowSize); + CLAMP(end, 0, self->rowSize); + begin = MIN2(begin,end); + + if(PySequence_Check(seq)){ + size = PySequence_Length(seq); + if(size != (end - begin)){ + PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment\n"); + return -1; + } + /*parse sub items*/ + for (i = 0; i < size; i++) { + /*parse each sub sequence*/ + subseq = PySequence_GetItem(seq, i); + if (subseq == NULL) { /*Failed to read sequence*/ + PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence"); + return -1; + } + + if(PySequence_Check(subseq)){ + /*subsequence is also a sequence*/ + sub_size = PySequence_Length(subseq); + if(sub_size != self->colSize){ + Py_DECREF(subseq); + PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment\n"); + return -1; + } + for (y = 0; y < sub_size; y++) { + m = PySequence_GetItem(subseq, y); + if (m == NULL) { /*Failed to read sequence*/ + Py_DECREF(subseq); + PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence\n"); + return -1; + } + + f = PyFloat_AsDouble(m); /* faster to assume a float and raise an error after */ + if(f == -1 && PyErr_Occurred()) { /*parsed item not a number*/ + Py_DECREF(m); + Py_DECREF(subseq); + PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: sequence argument not a number\n"); + return -1; + } + + mat[(i * self->colSize) + y] = f; + Py_DECREF(m); + } + }else{ + Py_DECREF(subseq); + PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation\n"); + return -1; + } + Py_DECREF(subseq); + } + /*parsed well - now set in matrix*/ + for(x = 0; x < (size * sub_size); x++){ + self->matrix[begin + (int)floor(x / self->colSize)][x % self->colSize] = mat[x]; + } + + BaseMath_WriteCallback(self); + return 0; + }else{ + PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation\n"); + return -1; + } +} +/*------------------------NUMERIC PROTOCOLS---------------------- + ------------------------obj + obj------------------------------*/ +static PyObject *Matrix_add(PyObject * m1, PyObject * m2) +{ + int x, y; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + MatrixObject *mat1 = NULL, *mat2 = NULL; + + mat1 = (MatrixObject*)m1; + mat2 = (MatrixObject*)m2; + + if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) { + PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation...."); + return NULL; + } + + if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2)) + return NULL; + + if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){ + PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation"); + return NULL; + } + + for(x = 0; x < mat1->rowSize; x++) { + for(y = 0; y < mat1->colSize; y++) { + mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y]; + } + } + + return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL); +} +/*------------------------obj - obj------------------------------ + subtraction*/ +static PyObject *Matrix_sub(PyObject * m1, PyObject * m2) +{ + int x, y; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + MatrixObject *mat1 = NULL, *mat2 = NULL; + + mat1 = (MatrixObject*)m1; + mat2 = (MatrixObject*)m2; + + if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) { + PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation...."); + return NULL; + } + + if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2)) + return NULL; + + if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){ + PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation"); + return NULL; + } + + for(x = 0; x < mat1->rowSize; x++) { + for(y = 0; y < mat1->colSize; y++) { + mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y]; + } + } + + return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL); +} +/*------------------------obj * obj------------------------------ + mulplication*/ +static PyObject *Matrix_mul(PyObject * m1, PyObject * m2) +{ + int x, y, z; + float scalar; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + double dot = 0.0f; + MatrixObject *mat1 = NULL, *mat2 = NULL; + + if(MatrixObject_Check(m1)) { + mat1 = (MatrixObject*)m1; + if(!BaseMath_ReadCallback(mat1)) + return NULL; + } + if(MatrixObject_Check(m2)) { + mat2 = (MatrixObject*)m2; + if(!BaseMath_ReadCallback(mat2)) + return NULL; + } + + if(mat1 && mat2) { /*MATRIX * MATRIX*/ + if(mat1->colSize != mat2->rowSize){ + PyErr_SetString(PyExc_AttributeError,"Matrix multiplication: matrix A rowsize must equal matrix B colsize"); + return NULL; + } + for(x = 0; x < mat1->rowSize; x++) { + for(y = 0; y < mat2->colSize; y++) { + for(z = 0; z < mat1->colSize; z++) { + dot += (mat1->matrix[x][z] * mat2->matrix[z][y]); + } + mat[((x * mat1->rowSize) + y)] = (float)dot; + dot = 0.0f; + } + } + + return newMatrixObject(mat, mat1->rowSize, mat2->colSize, Py_NEW, NULL); + } + + if(mat1==NULL){ + scalar=PyFloat_AsDouble(m1); // may not be a float... + if ((scalar == -1.0 && PyErr_Occurred())==0) { /*FLOAT/INT * MATRIX, this line annoys theeth, lets see if he finds it */ + for(x = 0; x < mat2->rowSize; x++) { + for(y = 0; y < mat2->colSize; y++) { + mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y]; + } + } + return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW, NULL); + } + + PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation"); + return NULL; + } + else /* if(mat1) { */ { + + if(VectorObject_Check(m2)) { /* MATRIX*VECTOR */ + return column_vector_multiplication(mat1, (VectorObject *)m2); /* vector update done inside the function */ + } + else { + scalar= PyFloat_AsDouble(m2); + if ((scalar == -1.0 && PyErr_Occurred())==0) { /* MATRIX*FLOAT/INT */ + for(x = 0; x < mat1->rowSize; x++) { + for(y = 0; y < mat1->colSize; y++) { + mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y]; + } + } + return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL); + } + } + PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation"); + return NULL; + } + + PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation\n"); + return NULL; +} +static PyObject* Matrix_inv(MatrixObject *self) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + return Matrix_Invert(self); +} + +/*-----------------PROTOCOL DECLARATIONS--------------------------*/ +static PySequenceMethods Matrix_SeqMethods = { + (inquiry) Matrix_len, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (ssizeargfunc) 0, /* sq_repeat */ + (ssizeargfunc) Matrix_item, /* sq_item */ + (ssizessizeargfunc) Matrix_slice, /* sq_slice */ + (ssizeobjargproc) Matrix_ass_item, /* sq_ass_item */ + (ssizessizeobjargproc) Matrix_ass_slice, /* sq_ass_slice */ +}; + + + +#if (PY_VERSION_HEX >= 0x03000000) +static PyObject *Matrix_subscript(MatrixObject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += self->rowSize; + return Matrix_item(self, i); + } else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyList_New(0); + } + else if (step == 1) { + return Matrix_slice(self, start, stop); + } + else { + PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies"); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "vector indices must be integers, not %.200s", + item->ob_type->tp_name); + return NULL; + } +} + +static int Matrix_ass_subscript(MatrixObject* self, PyObject* item, PyObject* value) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += self->rowSize; + return Matrix_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0) + return -1; + + if (step == 1) + return Matrix_ass_slice(self, start, stop, value); + else { + PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies"); + return -1; + } + } + else { + PyErr_Format(PyExc_TypeError, + "matrix indices must be integers, not %.200s", + item->ob_type->tp_name); + return -1; + } +} + +static PyMappingMethods Matrix_AsMapping = { + (lenfunc)Matrix_len, + (binaryfunc)Matrix_subscript, + (objobjargproc)Matrix_ass_subscript +}; +#endif /* (PY_VERSION_HEX >= 0x03000000) */ + + + +#if (PY_VERSION_HEX >= 0x03000000) +static PyNumberMethods Matrix_NumMethods = { + (binaryfunc) Matrix_add, /*nb_add*/ + (binaryfunc) Matrix_sub, /*nb_subtract*/ + (binaryfunc) Matrix_mul, /*nb_multiply*/ + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + (unaryfunc) 0, /*nb_negative*/ + (unaryfunc) 0, /*tp_positive*/ + (unaryfunc) 0, /*tp_absolute*/ + (inquiry) 0, /*tp_bool*/ + (unaryfunc) Matrix_inv, /*nb_invert*/ + 0, /*nb_lshift*/ + (binaryfunc)0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + 0, /*nb_int*/ + 0, /*nb_reserved*/ + 0, /*nb_float*/ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + 0, /* nb_floor_divide */ + 0, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ + 0, /* nb_index */ +}; +#else +static PyNumberMethods Matrix_NumMethods = { + (binaryfunc) Matrix_add, /* __add__ */ + (binaryfunc) Matrix_sub, /* __sub__ */ + (binaryfunc) Matrix_mul, /* __mul__ */ + (binaryfunc) 0, /* __div__ */ + (binaryfunc) 0, /* __mod__ */ + (binaryfunc) 0, /* __divmod__ */ + (ternaryfunc) 0, /* __pow__ */ + (unaryfunc) 0, /* __neg__ */ + (unaryfunc) 0, /* __pos__ */ + (unaryfunc) 0, /* __abs__ */ + (inquiry) 0, /* __nonzero__ */ + (unaryfunc) Matrix_inv, /* __invert__ */ + (binaryfunc) 0, /* __lshift__ */ + (binaryfunc) 0, /* __rshift__ */ + (binaryfunc) 0, /* __and__ */ + (binaryfunc) 0, /* __xor__ */ + (binaryfunc) 0, /* __or__ */ + /*(coercion)*/ 0, /* __coerce__ */ + (unaryfunc) 0, /* __int__ */ + (unaryfunc) 0, /* __long__ */ + (unaryfunc) 0, /* __float__ */ + (unaryfunc) 0, /* __oct__ */ + (unaryfunc) 0, /* __hex__ */ +}; +#endif + +static PyObject *Matrix_getRowSize( MatrixObject * self, void *type ) +{ + return PyLong_FromLong((long) self->rowSize); +} + +static PyObject *Matrix_getColSize( MatrixObject * self, void *type ) +{ + return PyLong_FromLong((long) self->colSize); +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef Matrix_getseters[] = { + {"rowSize", (getter)Matrix_getRowSize, (setter)NULL, "", NULL}, + {"colSize", (getter)Matrix_getColSize, (setter)NULL, "", NULL}, + {"wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, "", NULL}, + {"__owner__",(getter)BaseMathObject_getOwner, (setter)NULL, "", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + +/*------------------PY_OBECT DEFINITION--------------------------*/ +PyTypeObject matrix_Type = { +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif + "matrix", /*tp_name*/ + sizeof(MatrixObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)BaseMathObject_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc) Matrix_repr, /*tp_repr*/ + &Matrix_NumMethods, /*tp_as_number*/ + &Matrix_SeqMethods, /*tp_as_sequence*/ +#if (PY_VERSION_HEX >= 0x03000000) + &Matrix_AsMapping, /*tp_as_mapping*/ +#else + 0, +#endif + 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*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + (richcmpfunc)Matrix_richcmpr, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + Matrix_methods, /*tp_methods*/ + 0, /*tp_members*/ + Matrix_getseters, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + Matrix_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*/ +}; + +/*------------------------newMatrixObject (internal)------------- +creates a new matrix object +self->matrix self->contiguous_ptr (reference to data.xxx) + [0]------------->[0] + [1] + [2] + [1]------------->[3] + [4] + [5] + .... +self->matrix[1][1] = self->contigPtr[4] */ + +/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER + (i.e. it was allocated elsewhere by MEM_mallocN()) + pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON + (i.e. it must be created here with PyMEM_malloc())*/ +PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type, PyTypeObject *base_type) +{ + MatrixObject *self; + int x, row, col; + + /*matrix objects can be any 2-4row x 2-4col matrix*/ + if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4){ + PyErr_SetString(PyExc_RuntimeError, "matrix(): row and column sizes must be between 2 and 4"); + return NULL; + } + + if(base_type) self = (MatrixObject *)base_type->tp_alloc(base_type, 0); + else self = PyObject_NEW(MatrixObject, &matrix_Type); + + self->rowSize = rowSize; + self->colSize = colSize; + + /* init callbacks as NULL */ + self->cb_user= NULL; + self->cb_type= self->cb_subtype= 0; + + if(type == Py_WRAP){ + self->contigPtr = mat; + /*create pointer array*/ + self->matrix = PyMem_Malloc(rowSize * sizeof(float *)); + if(self->matrix == NULL) { /*allocation failure*/ + PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space"); + return NULL; + } + /*pointer array points to contigous memory*/ + for(x = 0; x < rowSize; x++) { + self->matrix[x] = self->contigPtr + (x * colSize); + } + self->wrapped = Py_WRAP; + }else if (type == Py_NEW){ + self->contigPtr = PyMem_Malloc(rowSize * colSize * sizeof(float)); + if(self->contigPtr == NULL) { /*allocation failure*/ + PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space\n"); + return NULL; + } + /*create pointer array*/ + self->matrix = PyMem_Malloc(rowSize * sizeof(float *)); + if(self->matrix == NULL) { /*allocation failure*/ + PyMem_Free(self->contigPtr); + PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space"); + return NULL; + } + /*pointer array points to contigous memory*/ + for(x = 0; x < rowSize; x++) { + self->matrix[x] = self->contigPtr + (x * colSize); + } + /*parse*/ + if(mat) { /*if a float array passed*/ + for(row = 0; row < rowSize; row++) { + for(col = 0; col < colSize; col++) { + self->matrix[row][col] = mat[(row * colSize) + col]; + } + } + } else if (rowSize == colSize ) { /*or if no arguments are passed return identity matrix for square matrices */ + Matrix_Identity(self); + Py_DECREF(self); + } + self->wrapped = Py_NEW; + }else{ /*bad type*/ + return NULL; + } + return (PyObject *) self; +} + +PyObject *newMatrixObject_cb(PyObject *cb_user, int rowSize, int colSize, int cb_type, int cb_subtype) +{ + MatrixObject *self= (MatrixObject *)newMatrixObject(NULL, rowSize, colSize, Py_NEW, NULL); + if(self) { + Py_INCREF(cb_user); + self->cb_user= cb_user; + self->cb_type= (unsigned char)cb_type; + self->cb_subtype= (unsigned char)cb_subtype; + } + return (PyObject *) self; +} + +//----------------column_vector_multiplication (internal)--------- +//COLUMN VECTOR Multiplication (Matrix X Vector) +// [1][2][3] [a] +// [4][5][6] * [b] +// [7][8][9] [c] +//vector/matrix multiplication IS NOT COMMUTATIVE!!!! +static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec) +{ + float vecNew[4], vecCopy[4]; + double dot = 0.0f; + int x, y, z = 0; + + if(!BaseMath_ReadCallback(mat) || !BaseMath_ReadCallback(vec)) + return NULL; + + if(mat->rowSize != vec->size){ + if(mat->rowSize == 4 && vec->size != 3){ + PyErr_SetString(PyExc_AttributeError, "matrix * vector: matrix row size and vector size must be the same"); + return NULL; + }else{ + vecCopy[3] = 1.0f; + } + } + + for(x = 0; x < vec->size; x++){ + vecCopy[x] = vec->vec[x]; + } + + for(x = 0; x < mat->rowSize; x++) { + for(y = 0; y < mat->colSize; y++) { + dot += mat->matrix[x][y] * vecCopy[y]; + } + vecNew[z++] = (float)dot; + dot = 0.0f; + } + return newVectorObject(vecNew, vec->size, Py_NEW, NULL); +} diff --git a/source/blender/python/generic/matrix.h b/source/blender/python/generic/matrix.h new file mode 100644 index 00000000000..bb598e07061 --- /dev/null +++ b/source/blender/python/generic/matrix.h @@ -0,0 +1,66 @@ +/* + * $Id: matrix.h 21254 2009-06-30 00:42:17Z campbellbarton $ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * 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): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#ifndef EXPP_matrix_h +#define EXPP_matrix_h + +#include + +extern PyTypeObject matrix_Type; +#define MatrixObject_Check(_v) PyObject_TypeCheck((_v), &matrix_Type) + +typedef float **ptRow; +typedef struct _Matrix { /* keep aligned with BaseMathObject in Mathutils.h */ + PyObject_VAR_HEAD + float *contigPtr; /*1D array of data (alias)*/ + PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ + unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ + unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ + unsigned char wrapped; /*is wrapped data?*/ + /* end BaseMathObject */ + + unsigned char rowSize; + unsigned int colSize; + ptRow matrix; /*ptr to the contigPtr (accessor)*/ + +} MatrixObject; + +/*struct data contains a pointer to the actual data that the +object uses. It can use either PyMem allocated data (which will +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); + +extern int mathutils_matrix_vector_cb_index; +extern struct Mathutils_Callback mathutils_matrix_vector_cb; + +#endif /* EXPP_matrix_H */ diff --git a/source/blender/python/generic/quat.c b/source/blender/python/generic/quat.c new file mode 100644 index 00000000000..bcd66e0fc82 --- /dev/null +++ b/source/blender/python/generic/quat.c @@ -0,0 +1,879 @@ +/* + * $Id: quat.c 21462 2009-07-09 15:40:04Z ton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "Mathutils.h" + +#include "BLI_arithb.h" +#include "BKE_utildefines.h" +#include "BLI_blenlib.h" + + +//-------------------------DOC STRINGS --------------------------- + +static PyObject *Quaternion_Identity( QuaternionObject * self ); +static PyObject *Quaternion_Negate( QuaternionObject * self ); +static PyObject *Quaternion_Conjugate( QuaternionObject * self ); +static PyObject *Quaternion_Inverse( QuaternionObject * self ); +static PyObject *Quaternion_Normalize( QuaternionObject * self ); +static PyObject *Quaternion_ToEuler( QuaternionObject * self, PyObject *args ); +static PyObject *Quaternion_ToMatrix( QuaternionObject * self ); +static PyObject *Quaternion_Cross( QuaternionObject * self, QuaternionObject * value ); +static PyObject *Quaternion_Dot( QuaternionObject * self, QuaternionObject * value ); +static PyObject *Quaternion_copy( QuaternionObject * self ); + +//-----------------------METHOD DEFINITIONS ---------------------- +static struct PyMethodDef Quaternion_methods[] = { + {"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, NULL}, + {"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, NULL}, + {"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, NULL}, + {"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, NULL}, + {"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, NULL}, + {"toEuler", (PyCFunction) Quaternion_ToEuler, METH_VARARGS, NULL}, + {"toMatrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, NULL}, + {"cross", (PyCFunction) Quaternion_Cross, METH_O, NULL}, + {"dot", (PyCFunction) Quaternion_Dot, METH_O, NULL}, + {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, NULL}, + {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +//----------------------------------Mathutils.Quaternion() -------------- +static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *listObject = NULL, *n, *q; + int size, i; + float quat[4]; + double angle = 0.0f; + + size = PyTuple_GET_SIZE(args); + if (size == 1 || size == 2) { //seq? + listObject = PyTuple_GET_ITEM(args, 0); + if (PySequence_Check(listObject)) { + size = PySequence_Length(listObject); + if ((size == 4 && PySequence_Length(args) !=1) || + (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) { + // invalid args/size + PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + if(size == 3){ //get angle in axis/angle + n = PySequence_GetItem(args, 1); + if(n == NULL) { // parsed item not a number or getItem fail + PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + + angle = PyFloat_AsDouble(n); + Py_DECREF(n); + + if (angle==-1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + } + }else{ + listObject = PyTuple_GET_ITEM(args, 1); + if (size>1 && PySequence_Check(listObject)) { + size = PySequence_Length(listObject); + if (size != 3) { + // invalid args/size + PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + angle = PyFloat_AsDouble(PyTuple_GET_ITEM(args, 0)); + + if (angle==-1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + } else { // argument was not a sequence + PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + } + } else if (size == 0) { //returns a new empty quat + return newQuaternionObject(NULL, Py_NEW, NULL); + } else { + listObject = args; + } + + if (size == 3) { // invalid quat size + if(PySequence_Length(args) != 2){ + PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + }else{ + if(size != 4){ + PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + } + + for (i=0; iquat, mat); + +#ifdef USE_MATHUTILS_DEG + { + float eul_compatf[3]; + int x; + + for(x = 0; x < 3; x++) { + eul_compatf[x] = eul_compat->eul[x] * ((float)Py_PI / 180); + } + Mat3ToCompatibleEul(mat, eul, eul_compatf); + } +#else + Mat3ToCompatibleEul(mat, eul, eul_compat->eul); +#endif + } + else { + QuatToEul(self->quat, eul); + } + +#ifdef USE_MATHUTILS_DEG + { + int x; + + for(x = 0; x < 3; x++) { + eul[x] *= (180 / (float)Py_PI); + } + } +#endif + return newEulerObject(eul, Py_NEW, NULL); +} +//----------------------------Quaternion.toMatrix()------------------ +//return the quat as a matrix +static PyObject *Quaternion_ToMatrix(QuaternionObject * self) +{ + float mat[9]; /* all values are set */ + + if(!BaseMath_ReadCallback(self)) + return NULL; + + QuatToMat3(self->quat, (float (*)[3]) mat); + return newMatrixObject(mat, 3, 3, Py_NEW, NULL); +} + +//----------------------------Quaternion.cross(other)------------------ +//return the cross quat +static PyObject *Quaternion_Cross(QuaternionObject * self, QuaternionObject * value) +{ + float quat[4]; + + if (!QuaternionObject_Check(value)) { + PyErr_SetString( PyExc_TypeError, "quat.cross(value): expected a quaternion argument" ); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) + return NULL; + + QuatMul(quat, self->quat, value->quat); + return newQuaternionObject(quat, Py_NEW, NULL); +} + +//----------------------------Quaternion.dot(other)------------------ +//return the dot quat +static PyObject *Quaternion_Dot(QuaternionObject * self, QuaternionObject * value) +{ + if (!QuaternionObject_Check(value)) { + PyErr_SetString( PyExc_TypeError, "quat.dot(value): expected a quaternion argument" ); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) + return NULL; + + return PyFloat_FromDouble(QuatDot(self->quat, value->quat)); +} + +//----------------------------Quaternion.normalize()---------------- +//normalize the axis of rotation of [theta,vector] +static PyObject *Quaternion_Normalize(QuaternionObject * self) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + NormalQuat(self->quat); + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject*)self; +} +//----------------------------Quaternion.inverse()------------------ +//invert the quat +static PyObject *Quaternion_Inverse(QuaternionObject * self) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + QuatInv(self->quat); + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject*)self; +} +//----------------------------Quaternion.identity()----------------- +//generate the identity quaternion +static PyObject *Quaternion_Identity(QuaternionObject * self) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + QuatOne(self->quat); + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject*)self; +} +//----------------------------Quaternion.negate()------------------- +//negate the quat +static PyObject *Quaternion_Negate(QuaternionObject * self) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + QuatMulf(self->quat, -1.0f); + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject*)self; +} +//----------------------------Quaternion.conjugate()---------------- +//negate the vector part +static PyObject *Quaternion_Conjugate(QuaternionObject * self) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + QuatConj(self->quat); + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject*)self; +} +//----------------------------Quaternion.copy()---------------- +//return a copy of the quat +static PyObject *Quaternion_copy(QuaternionObject * self) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + return newQuaternionObject(self->quat, Py_NEW, Py_TYPE(self)); +} + +//----------------------------print object (internal)-------------- +//print the object to screen +static PyObject *Quaternion_repr(QuaternionObject * self) +{ + char str[64]; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + sprintf(str, "[%.6f, %.6f, %.6f, %.6f](quaternion)", self->quat[0], self->quat[1], self->quat[2], self->quat[3]); + return PyUnicode_FromString(str); +} +//------------------------tp_richcmpr +//returns -1 execption, 0 false, 1 true +static PyObject* Quaternion_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type) +{ + QuaternionObject *quatA = NULL, *quatB = NULL; + int result = 0; + + if(QuaternionObject_Check(objectA)) { + quatA = (QuaternionObject*)objectA; + if(!BaseMath_ReadCallback(quatA)) + return NULL; + } + if(QuaternionObject_Check(objectB)) { + quatB = (QuaternionObject*)objectB; + if(!BaseMath_ReadCallback(quatB)) + return NULL; + } + + if (!quatA || !quatB){ + if (comparison_type == Py_NE){ + Py_RETURN_TRUE; + }else{ + Py_RETURN_FALSE; + } + } + + switch (comparison_type){ + case Py_EQ: + result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, 4, 1); + break; + case Py_NE: + result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, 4, 1); + if (result == 0){ + result = 1; + }else{ + result = 0; + } + break; + default: + printf("The result of the comparison could not be evaluated"); + break; + } + if (result == 1){ + Py_RETURN_TRUE; + }else{ + Py_RETURN_FALSE; + } +} + +//---------------------SEQUENCE PROTOCOLS------------------------ +//----------------------------len(object)------------------------ +//sequence length +static int Quaternion_len(QuaternionObject * self) +{ + return 4; +} +//----------------------------object[]--------------------------- +//sequence accessor (get) +static PyObject *Quaternion_item(QuaternionObject * self, int i) +{ + if(i<0) i= 4-i; + + if(i < 0 || i >= 4) { + PyErr_SetString(PyExc_IndexError, "quaternion[attribute]: array index out of range\n"); + return NULL; + } + + if(!BaseMath_ReadIndexCallback(self, i)) + return NULL; + + return PyFloat_FromDouble(self->quat[i]); + +} +//----------------------------object[]------------------------- +//sequence accessor (set) +static int Quaternion_ass_item(QuaternionObject * self, int i, PyObject * ob) +{ + float scalar= (float)PyFloat_AsDouble(ob); + if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ + PyErr_SetString(PyExc_TypeError, "quaternion[index] = x: index argument not a number\n"); + return -1; + } + + if(i<0) i= 4-i; + + if(i < 0 || i >= 4){ + PyErr_SetString(PyExc_IndexError, "quaternion[attribute] = x: array assignment index out of range\n"); + return -1; + } + self->quat[i] = scalar; + + if(!BaseMath_WriteIndexCallback(self, i)) + return -1; + + return 0; +} +//----------------------------object[z:y]------------------------ +//sequence slice (get) +static PyObject *Quaternion_slice(QuaternionObject * self, int begin, int end) +{ + PyObject *list = NULL; + int count; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + CLAMP(begin, 0, 4); + if (end<0) end= 5+end; + CLAMP(end, 0, 4); + begin = MIN2(begin,end); + + list = PyList_New(end - begin); + for(count = begin; count < end; count++) { + PyList_SetItem(list, count - begin, + PyFloat_FromDouble(self->quat[count])); + } + + return list; +} +//----------------------------object[z:y]------------------------ +//sequence slice (set) +static int Quaternion_ass_slice(QuaternionObject * self, int begin, int end, PyObject * seq) +{ + int i, y, size = 0; + float quat[4]; + PyObject *q; + + if(!BaseMath_ReadCallback(self)) + return -1; + + CLAMP(begin, 0, 4); + if (end<0) end= 5+end; + CLAMP(end, 0, 4); + begin = MIN2(begin,end); + + size = PySequence_Length(seq); + if(size != (end - begin)){ + PyErr_SetString(PyExc_TypeError, "quaternion[begin:end] = []: size mismatch in slice assignment\n"); + return -1; + } + + for (i = 0; i < size; i++) { + q = PySequence_GetItem(seq, i); + if (q == NULL) { // Failed to read sequence + PyErr_SetString(PyExc_RuntimeError, "quaternion[begin:end] = []: unable to read sequence\n"); + return -1; + } + + quat[i]= (float)PyFloat_AsDouble(q); + Py_DECREF(q); + + if(quat[i]==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ + PyErr_SetString(PyExc_TypeError, "quaternion[begin:end] = []: sequence argument not a number\n"); + return -1; + } + } + //parsed well - now set in vector + for(y = 0; y < size; y++) + self->quat[begin + y] = quat[y]; + + BaseMath_WriteCallback(self); + return 0; +} +//------------------------NUMERIC PROTOCOLS---------------------- +//------------------------obj + obj------------------------------ +//addition +static PyObject *Quaternion_add(PyObject * q1, PyObject * q2) +{ + float quat[4]; + QuaternionObject *quat1 = NULL, *quat2 = NULL; + + if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { + PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation....\n"); + return NULL; + } + quat1 = (QuaternionObject*)q1; + quat2 = (QuaternionObject*)q2; + + if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2)) + return NULL; + + QuatAdd(quat, quat1->quat, quat2->quat, 1.0f); + return newQuaternionObject(quat, Py_NEW, NULL); +} +//------------------------obj - obj------------------------------ +//subtraction +static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2) +{ + int x; + float quat[4]; + QuaternionObject *quat1 = NULL, *quat2 = NULL; + + if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { + PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation....\n"); + return NULL; + } + + quat1 = (QuaternionObject*)q1; + quat2 = (QuaternionObject*)q2; + + if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2)) + return NULL; + + for(x = 0; x < 4; x++) { + quat[x] = quat1->quat[x] - quat2->quat[x]; + } + + return newQuaternionObject(quat, Py_NEW, NULL); +} +//------------------------obj * obj------------------------------ +//mulplication +static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2) +{ + float quat[4], scalar; + QuaternionObject *quat1 = NULL, *quat2 = NULL; + VectorObject *vec = NULL; + + if(QuaternionObject_Check(q1)) { + quat1 = (QuaternionObject*)q1; + if(!BaseMath_ReadCallback(quat1)) + return NULL; + } + if(QuaternionObject_Check(q2)) { + quat2 = (QuaternionObject*)q2; + if(!BaseMath_ReadCallback(quat2)) + return NULL; + } + + if(quat1 && quat2) { /* QUAT*QUAT (dot product) */ + return PyFloat_FromDouble(QuatDot(quat1->quat, quat2->quat)); + } + + /* the only case this can happen (for a supported type is "FLOAT*QUAT" ) */ + if(!QuaternionObject_Check(q1)) { + scalar= PyFloat_AsDouble(q1); + if ((scalar == -1.0 && PyErr_Occurred())==0) { /* FLOAT*QUAT */ + QUATCOPY(quat, quat2->quat); + QuatMulf(quat, scalar); + return newQuaternionObject(quat, Py_NEW, NULL); + } + PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: val * quat, val is not an acceptable type"); + return NULL; + } + else { /* QUAT*SOMETHING */ + if(VectorObject_Check(q2)){ /* QUAT*VEC */ + vec = (VectorObject*)q2; + if(vec->size != 3){ + PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: only 3D vector rotations currently supported\n"); + return NULL; + } + return quat_rotation((PyObject*)quat1, (PyObject*)vec); /* vector updating done inside the func */ + } + + scalar= PyFloat_AsDouble(q2); + if ((scalar == -1.0 && PyErr_Occurred())==0) { /* QUAT*FLOAT */ + QUATCOPY(quat, quat1->quat); + QuatMulf(quat, scalar); + return newQuaternionObject(quat, Py_NEW, NULL); + } + } + + PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: arguments not acceptable for this operation\n"); + return NULL; +} + +//-----------------PROTOCOL DECLARATIONS-------------------------- +static PySequenceMethods Quaternion_SeqMethods = { + (inquiry) Quaternion_len, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (ssizeargfunc) 0, /* sq_repeat */ + (ssizeargfunc) Quaternion_item, /* sq_item */ + (ssizessizeargfunc) Quaternion_slice, /* sq_slice */ + (ssizeobjargproc) Quaternion_ass_item, /* sq_ass_item */ + (ssizessizeobjargproc) Quaternion_ass_slice, /* sq_ass_slice */ +}; + +#if (PY_VERSION_HEX >= 0x03000000) +static PyNumberMethods Quaternion_NumMethods = { + (binaryfunc) Quaternion_add, /*nb_add*/ + (binaryfunc) Quaternion_sub, /*nb_subtract*/ + (binaryfunc) Quaternion_mul, /*nb_multiply*/ + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + (unaryfunc) 0, /*nb_negative*/ + (unaryfunc) 0, /*tp_positive*/ + (unaryfunc) 0, /*tp_absolute*/ + (inquiry) 0, /*tp_bool*/ + (unaryfunc) 0, /*nb_invert*/ + 0, /*nb_lshift*/ + (binaryfunc)0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + 0, /*nb_int*/ + 0, /*nb_reserved*/ + 0, /*nb_float*/ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + 0, /* nb_floor_divide */ + 0, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ + 0, /* nb_index */ +}; +#else +static PyNumberMethods Quaternion_NumMethods = { + (binaryfunc) Quaternion_add, /* __add__ */ + (binaryfunc) Quaternion_sub, /* __sub__ */ + (binaryfunc) Quaternion_mul, /* __mul__ */ + (binaryfunc) 0, /* __div__ */ + (binaryfunc) 0, /* __mod__ */ + (binaryfunc) 0, /* __divmod__ */ + (ternaryfunc) 0, /* __pow__ */ + (unaryfunc) 0, /* __neg__ */ + (unaryfunc) 0, /* __pos__ */ + (unaryfunc) 0, /* __abs__ */ + (inquiry) 0, /* __nonzero__ */ + (unaryfunc) 0, /* __invert__ */ + (binaryfunc) 0, /* __lshift__ */ + (binaryfunc) 0, /* __rshift__ */ + (binaryfunc) 0, /* __and__ */ + (binaryfunc) 0, /* __xor__ */ + (binaryfunc) 0, /* __or__ */ + /*(coercion)*/ 0, /* __coerce__ */ + (unaryfunc) 0, /* __int__ */ + (unaryfunc) 0, /* __long__ */ + (unaryfunc) 0, /* __float__ */ + (unaryfunc) 0, /* __oct__ */ + (unaryfunc) 0, /* __hex__ */ +}; +#endif + +static PyObject *Quaternion_getAxis( QuaternionObject * self, void *type ) +{ + return Quaternion_item(self, GET_INT_FROM_POINTER(type)); +} + +static int Quaternion_setAxis( QuaternionObject * self, PyObject * value, void * type ) +{ + return Quaternion_ass_item(self, GET_INT_FROM_POINTER(type), value); +} + +static PyObject *Quaternion_getMagnitude( QuaternionObject * self, void *type ) +{ + return PyFloat_FromDouble(sqrt(QuatDot(self->quat, self->quat))); +} + +static PyObject *Quaternion_getAngle( QuaternionObject * self, void *type ) +{ + double ang = self->quat[0]; + ang = 2 * (saacos(ang)); +#ifdef USE_MATHUTILS_DEG + ang *= (180 / Py_PI); +#endif + return PyFloat_FromDouble(ang); +} + +static PyObject *Quaternion_getAxisVec( QuaternionObject * self, void *type ) +{ + int i; + float vec[3]; + double mag = self->quat[0] * (Py_PI / 180); + mag = 2 * (saacos(mag)); + mag = sin(mag / 2); + for(i = 0; i < 3; i++) + vec[i] = (float)(self->quat[i + 1] / mag); + + Normalize(vec); + //If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations + if( EXPP_FloatsAreEqual(vec[0], 0.0f, 10) && + EXPP_FloatsAreEqual(vec[1], 0.0f, 10) && + EXPP_FloatsAreEqual(vec[2], 0.0f, 10) ){ + vec[0] = 1.0f; + } + return (PyObject *) newVectorObject(vec, 3, Py_NEW, NULL); +} + + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef Quaternion_getseters[] = { + {"w", + (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, + "Quaternion W value", + (void *)0}, + {"x", + (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, + "Quaternion X axis", + (void *)1}, + {"y", + (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, + "Quaternion Y axis", + (void *)2}, + {"z", + (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, + "Quaternion Z axis", + (void *)3}, + {"magnitude", + (getter)Quaternion_getMagnitude, (setter)NULL, + "Size of the quaternion", + NULL}, + {"angle", + (getter)Quaternion_getAngle, (setter)NULL, + "angle of the quaternion", + NULL}, + {"axis", + (getter)Quaternion_getAxisVec, (setter)NULL, + "quaternion axis as a vector", + NULL}, + {"wrapped", + (getter)BaseMathObject_getWrapped, (setter)NULL, + "True when this wraps blenders internal data", + NULL}, + {"__owner__", + (getter)BaseMathObject_getOwner, (setter)NULL, + "Read only owner for vectors that depend on another object", + NULL}, + + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + + +//------------------PY_OBECT DEFINITION-------------------------- +PyTypeObject quaternion_Type = { +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif + "quaternion", //tp_name + sizeof(QuaternionObject), //tp_basicsize + 0, //tp_itemsize + (destructor)BaseMathObject_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + 0, //tp_compare + (reprfunc) Quaternion_repr, //tp_repr + &Quaternion_NumMethods, //tp_as_number + &Quaternion_SeqMethods, //tp_as_sequence + 0, //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 + 0, //tp_doc + 0, //tp_traverse + 0, //tp_clear + (richcmpfunc)Quaternion_richcmpr, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + Quaternion_methods, //tp_methods + 0, //tp_members + Quaternion_getseters, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + Quaternion_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 +}; +//------------------------newQuaternionObject (internal)------------- +//creates a new quaternion object +/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER + (i.e. it was allocated elsewhere by MEM_mallocN()) + pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON + (i.e. it must be created here with PyMEM_malloc())*/ +PyObject *newQuaternionObject(float *quat, int type, PyTypeObject *base_type) +{ + QuaternionObject *self; + + if(base_type) self = (QuaternionObject *)base_type->tp_alloc(base_type, 0); + else self = PyObject_NEW(QuaternionObject, &quaternion_Type); + + /* init callbacks as NULL */ + self->cb_user= NULL; + self->cb_type= self->cb_subtype= 0; + + if(type == Py_WRAP){ + self->quat = quat; + self->wrapped = Py_WRAP; + }else if (type == Py_NEW){ + self->quat = PyMem_Malloc(4 * sizeof(float)); + if(!quat) { //new empty + QuatOne(self->quat); + }else{ + QUATCOPY(self->quat, quat); + } + self->wrapped = Py_NEW; + }else{ //bad type + return NULL; + } + return (PyObject *) self; +} + +PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype) +{ + QuaternionObject *self= (QuaternionObject *)newQuaternionObject(NULL, Py_NEW, NULL); + if(self) { + Py_INCREF(cb_user); + self->cb_user= cb_user; + self->cb_type= (unsigned char)cb_type; + self->cb_subtype= (unsigned char)cb_subtype; + } + + return (PyObject *)self; +} diff --git a/source/blender/python/generic/quat.h b/source/blender/python/generic/quat.h new file mode 100644 index 00000000000..8cf963b54c6 --- /dev/null +++ b/source/blender/python/generic/quat.h @@ -0,0 +1,60 @@ +/* + * $Id: quat.h 21254 2009-06-30 00:42:17Z campbellbarton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * 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): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#ifndef EXPP_quat_h +#define EXPP_quat_h + +#include +#include "../intern/bpy_compat.h" + +extern PyTypeObject quaternion_Type; +#define QuaternionObject_Check(_v) PyObject_TypeCheck((_v), &quaternion_Type) + +typedef struct { /* keep aligned with BaseMathObject in Mathutils.h */ + PyObject_VAR_HEAD + float *quat; /* 1D array of data (alias) */ + PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ + unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ + unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ + unsigned char wrapped; /* wrapped data type? */ + /* end BaseMathObject */ + +} QuaternionObject; + +/*struct data contains a pointer to the actual data that the +object uses. It can use either PyMem allocated data (which will +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 *newQuaternionObject( float *quat, int type, PyTypeObject *base_type); +PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype); + +#endif /* EXPP_quat_h */ diff --git a/source/blender/python/generic/vector.c b/source/blender/python/generic/vector.c new file mode 100644 index 00000000000..1101524c1c5 --- /dev/null +++ b/source/blender/python/generic/vector.c @@ -0,0 +1,2078 @@ +/* + * $Id: vector.c 21462 2009-07-09 15:40:04Z ton $ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * + * Contributor(s): Willian P. Germano, Joseph Gilbert, Ken Hughes, Alex Fraser, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "Mathutils.h" + +#include "BLI_blenlib.h" +#include "BKE_utildefines.h" +#include "BLI_arithb.h" + +#define MAX_DIMENSIONS 4 +/* Swizzle axes get packed into a single value that is used as a closure. Each + axis uses SWIZZLE_BITS_PER_AXIS bits. The first bit (SWIZZLE_VALID_AXIS) is + used as a sentinel: if it is unset, the axis is not valid. */ +#define SWIZZLE_BITS_PER_AXIS 3 +#define SWIZZLE_VALID_AXIS 0x4 +#define SWIZZLE_AXIS 0x3 + +static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat); /* utility func */ + +/*-----------------------METHOD DEFINITIONS ----------------------*/ +static PyObject *Vector_Zero( VectorObject * self ); +static PyObject *Vector_Normalize( VectorObject * self ); +static PyObject *Vector_Negate( VectorObject * self ); +static PyObject *Vector_Resize2D( VectorObject * self ); +static PyObject *Vector_Resize3D( VectorObject * self ); +static PyObject *Vector_Resize4D( VectorObject * self ); +static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ); +static PyObject *Vector_Reflect( VectorObject *self, VectorObject *value ); +static PyObject *Vector_Cross( VectorObject * self, VectorObject * value ); +static PyObject *Vector_Dot( VectorObject * self, VectorObject * value ); +static PyObject *Vector_copy( VectorObject * self ); + +static struct PyMethodDef Vector_methods[] = { + {"zero", (PyCFunction) Vector_Zero, METH_NOARGS, NULL}, + {"normalize", (PyCFunction) Vector_Normalize, METH_NOARGS, NULL}, + {"negate", (PyCFunction) Vector_Negate, METH_NOARGS, NULL}, + {"resize2D", (PyCFunction) Vector_Resize2D, METH_NOARGS, NULL}, + {"resize3D", (PyCFunction) Vector_Resize3D, METH_NOARGS, NULL}, + {"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, NULL}, + {"toTrackQuat", ( PyCFunction ) Vector_ToTrackQuat, METH_VARARGS, NULL}, + {"reflect", ( PyCFunction ) Vector_Reflect, METH_O, NULL}, + {"cross", ( PyCFunction ) Vector_Cross, METH_O, NULL}, + {"dot", ( PyCFunction ) Vector_Dot, METH_O, NULL}, + {"copy", (PyCFunction) Vector_copy, METH_NOARGS, NULL}, + {"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +//----------------------------------Mathutils.Vector() ------------------ +// Supports 2D, 3D, and 4D vector objects both int and float values +// accepted. Mixed float and int values accepted. Ints are parsed to float +static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *listObject = NULL; + int size, i; + float vec[4], f; + PyObject *v; + + size = PyTuple_GET_SIZE(args); /* we know its a tuple because its an arg */ + if (size == 1) { + listObject = PyTuple_GET_ITEM(args, 0); + if (PySequence_Check(listObject)) { + size = PySequence_Length(listObject); + } else { // Single argument was not a sequence + PyErr_SetString(PyExc_TypeError, "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n"); + return NULL; + } + } else if (size == 0) { + //returns a new empty 3d vector + return newVectorObject(NULL, 3, Py_NEW, type); + } else { + listObject = args; + } + + if (size<2 || size>4) { // Invalid vector size + PyErr_SetString(PyExc_AttributeError, "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n"); + return NULL; + } + + for (i=0; isize; i++) { + self->vec[i] = 0.0f; + } + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject*)self; +} +/*----------------------------Vector.normalize() ----------------- + normalize the vector data to a unit vector */ +static PyObject *Vector_Normalize(VectorObject * self) +{ + int i; + float norm = 0.0f; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + for(i = 0; i < self->size; i++) { + norm += self->vec[i] * self->vec[i]; + } + norm = (float) sqrt(norm); + for(i = 0; i < self->size; i++) { + self->vec[i] /= norm; + } + + BaseMath_WriteCallback(self); + Py_INCREF(self); + return (PyObject*)self; +} + + +/*----------------------------Vector.resize2D() ------------------ + resize the vector to x,y */ +static PyObject *Vector_Resize2D(VectorObject * self) +{ + if(self->wrapped==Py_WRAP) { + PyErr_SetString(PyExc_TypeError, "vector.resize2d(): cannot resize wrapped data - only python vectors\n"); + return NULL; + } + if(self->cb_user) { + PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner"); + return NULL; + } + + self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 2)); + if(self->vec == NULL) { + PyErr_SetString(PyExc_MemoryError, "vector.resize2d(): problem allocating pointer space\n\n"); + return NULL; + } + + self->size = 2; + Py_INCREF(self); + return (PyObject*)self; +} +/*----------------------------Vector.resize3D() ------------------ + resize the vector to x,y,z */ +static PyObject *Vector_Resize3D(VectorObject * self) +{ + if (self->wrapped==Py_WRAP) { + PyErr_SetString(PyExc_TypeError, "vector.resize3d(): cannot resize wrapped data - only python vectors\n"); + return NULL; + } + if(self->cb_user) { + PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner"); + return NULL; + } + + self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 3)); + if(self->vec == NULL) { + PyErr_SetString(PyExc_MemoryError, "vector.resize3d(): problem allocating pointer space\n\n"); + return NULL; + } + + if(self->size == 2) + self->vec[2] = 0.0f; + + self->size = 3; + Py_INCREF(self); + return (PyObject*)self; +} +/*----------------------------Vector.resize4D() ------------------ + resize the vector to x,y,z,w */ +static PyObject *Vector_Resize4D(VectorObject * self) +{ + if(self->wrapped==Py_WRAP) { + PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize wrapped data - only python vectors"); + return NULL; + } + if(self->cb_user) { + PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner"); + return NULL; + } + + self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 4)); + if(self->vec == NULL) { + PyErr_SetString(PyExc_MemoryError, "vector.resize4d(): problem allocating pointer space\n\n"); + return NULL; + } + if(self->size == 2){ + self->vec[2] = 0.0f; + self->vec[3] = 1.0f; + }else if(self->size == 3){ + self->vec[3] = 1.0f; + } + self->size = 4; + Py_INCREF(self); + return (PyObject*)self; +} +/*----------------------------Vector.toTrackQuat(track, up) ---------------------- + extract a quaternion from the vector and the track and up axis */ +static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ) +{ + float vec[3], quat[4]; + char *strack, *sup; + short track = 2, up = 1; + + if( !PyArg_ParseTuple ( args, "|ss", &strack, &sup ) ) { + PyErr_SetString( PyExc_TypeError, "expected optional two strings\n" ); + return NULL; + } + if (self->size != 3) { + PyErr_SetString( PyExc_TypeError, "only for 3D vectors\n" ); + return NULL; + } + + if(!BaseMath_ReadCallback(self)) + return NULL; + + if (strack) { + if (strlen(strack) == 2) { + if (strack[0] == '-') { + switch(strack[1]) { + case 'X': + case 'x': + track = 3; + break; + case 'Y': + case 'y': + track = 4; + break; + case 'z': + case 'Z': + track = 5; + break; + default: + PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" ); + return NULL; + } + } + else { + PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" ); + return NULL; + } + } + else if (strlen(strack) == 1) { + switch(strack[0]) { + case '-': + case 'X': + case 'x': + track = 0; + break; + case 'Y': + case 'y': + track = 1; + break; + case 'z': + case 'Z': + track = 2; + break; + default: + PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" ); + return NULL; + } + } + else { + PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" ); + return NULL; + } + } + + if (sup) { + if (strlen(sup) == 1) { + switch(*sup) { + case 'X': + case 'x': + up = 0; + break; + case 'Y': + case 'y': + up = 1; + break; + case 'z': + case 'Z': + up = 2; + break; + default: + PyErr_SetString( PyExc_ValueError, "only X, Y or Z for up axis\n" ); + return NULL; + } + } + else { + PyErr_SetString( PyExc_ValueError, "only X, Y or Z for up axis\n" ); + return NULL; + } + } + + if (track == up) { + PyErr_SetString( PyExc_ValueError, "Can't have the same axis for track and up\n" ); + return NULL; + } + + /* + flip vector around, since vectoquat expect a vector from target to tracking object + and the python function expects the inverse (a vector to the target). + */ + vec[0] = -self->vec[0]; + vec[1] = -self->vec[1]; + vec[2] = -self->vec[2]; + + vectoquat(vec, track, up, quat); + + return newQuaternionObject(quat, Py_NEW, NULL); +} + +/*----------------------------Vector.reflect(mirror) ---------------------- + return a reflected vector on the mirror normal + ((2 * DotVecs(vec, mirror)) * mirror) - vec + using arithb.c would be nice here */ +static PyObject *Vector_Reflect( VectorObject * self, VectorObject * value ) +{ + float mirror[3]; + float vec[3]; + float reflect[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float dot2; + + /* for normalizing */ + int i; + float norm = 0.0f; + + if (!VectorObject_Check(value)) { + PyErr_SetString( PyExc_TypeError, "vec.reflect(value): expected a vector argument" ); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) + return NULL; + + mirror[0] = value->vec[0]; + mirror[1] = value->vec[1]; + if (value->size > 2) mirror[2] = value->vec[2]; + else mirror[2] = 0.0; + + /* normalize, whos idea was it not to use arithb.c? :-/ */ + for(i = 0; i < 3; i++) { + norm += mirror[i] * mirror[i]; + } + norm = (float) sqrt(norm); + for(i = 0; i < 3; i++) { + mirror[i] /= norm; + } + /* done */ + + vec[0] = self->vec[0]; + vec[1] = self->vec[1]; + if (self->size > 2) vec[2] = self->vec[2]; + else vec[2] = 0.0; + + dot2 = 2 * vec[0]*mirror[0]+vec[1]*mirror[1]+vec[2]*mirror[2]; + + reflect[0] = (dot2 * mirror[0]) - vec[0]; + reflect[1] = (dot2 * mirror[1]) - vec[1]; + reflect[2] = (dot2 * mirror[2]) - vec[2]; + + return newVectorObject(reflect, self->size, Py_NEW, NULL); +} + +static PyObject *Vector_Cross( VectorObject * self, VectorObject * value ) +{ + VectorObject *vecCross = NULL; + + if (!VectorObject_Check(value)) { + PyErr_SetString( PyExc_TypeError, "vec.cross(value): expected a vector argument" ); + return NULL; + } + + if(self->size != 3 || value->size != 3) { + PyErr_SetString(PyExc_AttributeError, "vec.cross(value): expects both vectors to be 3D\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) + return NULL; + + vecCross = (VectorObject *)newVectorObject(NULL, 3, Py_NEW, NULL); + Crossf(vecCross->vec, self->vec, value->vec); + return (PyObject *)vecCross; +} + +static PyObject *Vector_Dot( VectorObject * self, VectorObject * value ) +{ + double dot = 0.0; + int x; + + if (!VectorObject_Check(value)) { + PyErr_SetString( PyExc_TypeError, "vec.cross(value): expected a vector argument" ); + return NULL; + } + + if(self->size != value->size) { + PyErr_SetString(PyExc_AttributeError, "vec.dot(value): expects both vectors to have the same size\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) + return NULL; + + for(x = 0; x < self->size; x++) { + dot += self->vec[x] * value->vec[x]; + } + return PyFloat_FromDouble(dot); +} + +/*----------------------------Vector.copy() -------------------------------------- + return a copy of the vector */ +static PyObject *Vector_copy(VectorObject * self) +{ + if(!BaseMath_ReadCallback(self)) + return NULL; + + return newVectorObject(self->vec, self->size, Py_NEW, Py_TYPE(self)); +} + +/*----------------------------print object (internal)------------- + print the object to screen */ +static PyObject *Vector_repr(VectorObject * self) +{ + int i; + char buffer[48], str[1024]; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + BLI_strncpy(str,"[",1024); + for(i = 0; i < self->size; i++){ + if(i < (self->size - 1)){ + sprintf(buffer, "%.6f, ", self->vec[i]); + strcat(str,buffer); + }else{ + sprintf(buffer, "%.6f", self->vec[i]); + strcat(str,buffer); + } + } + strcat(str, "](vector)"); + + return PyUnicode_FromString(str); +} +/*---------------------SEQUENCE PROTOCOLS------------------------ + ----------------------------len(object)------------------------ + sequence length*/ +static int Vector_len(VectorObject * self) +{ + return self->size; +} +/*----------------------------object[]--------------------------- + sequence accessor (get)*/ +static PyObject *Vector_item(VectorObject * self, int i) +{ + if(i<0) i= self->size-i; + + if(i < 0 || i >= self->size) { + PyErr_SetString(PyExc_IndexError,"vector[index]: out of range\n"); + return NULL; + } + + if(!BaseMath_ReadIndexCallback(self, i)) + return NULL; + + return PyFloat_FromDouble(self->vec[i]); + +} +/*----------------------------object[]------------------------- + sequence accessor (set)*/ +static int Vector_ass_item(VectorObject * self, int i, PyObject * ob) +{ + float scalar= (float)PyFloat_AsDouble(ob); + if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ + PyErr_SetString(PyExc_TypeError, "vector[index] = x: index argument not a number\n"); + return -1; + } + + if(i<0) i= self->size-i; + + if(i < 0 || i >= self->size){ + PyErr_SetString(PyExc_IndexError, "vector[index] = x: assignment index out of range\n"); + return -1; + } + self->vec[i] = scalar; + + if(!BaseMath_WriteIndexCallback(self, i)) + return -1; + return 0; +} + +/*----------------------------object[z:y]------------------------ + sequence slice (get) */ +static PyObject *Vector_slice(VectorObject * self, int begin, int end) +{ + PyObject *list = NULL; + int count; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + CLAMP(begin, 0, self->size); + if (end<0) end= self->size+end+1; + CLAMP(end, 0, self->size); + begin = MIN2(begin,end); + + list = PyList_New(end - begin); + for(count = begin; count < end; count++) { + PyList_SetItem(list, count - begin, + PyFloat_FromDouble(self->vec[count])); + } + + return list; +} +/*----------------------------object[z:y]------------------------ + sequence slice (set) */ +static int Vector_ass_slice(VectorObject * self, int begin, int end, + PyObject * seq) +{ + int i, y, size = 0; + float vec[4], scalar; + PyObject *v; + + if(!BaseMath_ReadCallback(self)) + return -1; + + CLAMP(begin, 0, self->size); + if (end<0) end= self->size+end+1; + CLAMP(end, 0, self->size); + begin = MIN2(begin,end); + + size = PySequence_Length(seq); + if(size != (end - begin)){ + PyErr_SetString(PyExc_TypeError, "vector[begin:end] = []: size mismatch in slice assignment\n"); + return -1; + } + + for (i = 0; i < size; i++) { + v = PySequence_GetItem(seq, i); + if (v == NULL) { /* Failed to read sequence */ + PyErr_SetString(PyExc_RuntimeError, "vector[begin:end] = []: unable to read sequence\n"); + return -1; + } + + scalar= (float)PyFloat_AsDouble(v); + if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ + Py_DECREF(v); + PyErr_SetString(PyExc_TypeError, "vector[begin:end] = []: sequence argument not a number\n"); + return -1; + } + + vec[i] = scalar; + Py_DECREF(v); + } + /*parsed well - now set in vector*/ + for(y = 0; y < size; y++){ + self->vec[begin + y] = vec[y]; + } + + if(!BaseMath_WriteCallback(self)) + return -1; + + return 0; +} +/*------------------------NUMERIC PROTOCOLS---------------------- + ------------------------obj + obj------------------------------ + addition*/ +static PyObject *Vector_add(PyObject * v1, PyObject * v2) +{ + int i; + float vec[4]; + + VectorObject *vec1 = NULL, *vec2 = NULL; + + if VectorObject_Check(v1) + vec1= (VectorObject *)v1; + + if VectorObject_Check(v2) + vec2= (VectorObject *)v2; + + /* make sure v1 is always the vector */ + if (vec1 && vec2 ) { + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) + return NULL; + + /*VECTOR + VECTOR*/ + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation\n"); + return NULL; + } + for(i = 0; i < vec1->size; i++) { + vec[i] = vec1->vec[i] + vec2->vec[i]; + } + return newVectorObject(vec, vec1->size, Py_NEW, NULL); + } + + PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation....\n"); + return NULL; +} + +/* ------------------------obj += obj------------------------------ + addition in place */ +static PyObject *Vector_iadd(PyObject * v1, PyObject * v2) +{ + int i; + + VectorObject *vec1 = NULL, *vec2 = NULL; + + if VectorObject_Check(v1) + vec1= (VectorObject *)v1; + + if VectorObject_Check(v2) + vec2= (VectorObject *)v2; + + /* make sure v1 is always the vector */ + if (vec1 && vec2 ) { + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) + return NULL; + + /*VECTOR + VECTOR*/ + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation\n"); + return NULL; + } + for(i = 0; i < vec1->size; i++) { + vec1->vec[i] += vec2->vec[i]; + } + Py_INCREF( v1 ); + return v1; + } + + BaseMath_WriteCallback(vec1); + PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation....\n"); + return NULL; +} + +/*------------------------obj - obj------------------------------ + subtraction*/ +static PyObject *Vector_sub(PyObject * v1, PyObject * v2) +{ + int i; + float vec[4]; + VectorObject *vec1 = NULL, *vec2 = NULL; + + if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) { + PyErr_SetString(PyExc_AttributeError, "Vector subtraction: arguments not valid for this operation....\n"); + return NULL; + } + vec1 = (VectorObject*)v1; + vec2 = (VectorObject*)v2; + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) + return NULL; + + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n"); + return NULL; + } + for(i = 0; i < vec1->size; i++) { + vec[i] = vec1->vec[i] - vec2->vec[i]; + } + + return newVectorObject(vec, vec1->size, Py_NEW, NULL); +} + +/*------------------------obj -= obj------------------------------ + subtraction*/ +static PyObject *Vector_isub(PyObject * v1, PyObject * v2) +{ + int i; + VectorObject *vec1 = NULL, *vec2 = NULL; + + if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) { + PyErr_SetString(PyExc_AttributeError, "Vector subtraction: arguments not valid for this operation....\n"); + return NULL; + } + vec1 = (VectorObject*)v1; + vec2 = (VectorObject*)v2; + + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) + return NULL; + + for(i = 0; i < vec1->size; i++) { + vec1->vec[i] = vec1->vec[i] - vec2->vec[i]; + } + + BaseMath_WriteCallback(vec1); + Py_INCREF( v1 ); + return v1; +} + +/*------------------------obj * obj------------------------------ + mulplication*/ +static PyObject *Vector_mul(PyObject * v1, PyObject * v2) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + float scalar; + + if VectorObject_Check(v1) { + vec1= (VectorObject *)v1; + if(!BaseMath_ReadCallback(vec1)) + return NULL; + } + if VectorObject_Check(v2) { + vec2= (VectorObject *)v2; + if(!BaseMath_ReadCallback(vec2)) + return NULL; + } + + + /* make sure v1 is always the vector */ + if (vec1 && vec2 ) { + int i; + double dot = 0.0f; + + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, "Vector multiplication: vectors must have the same dimensions for this operation\n"); + return NULL; + } + + /*dot product*/ + for(i = 0; i < vec1->size; i++) { + dot += vec1->vec[i] * vec2->vec[i]; + } + return PyFloat_FromDouble(dot); + } + + /*swap so vec1 is always the vector */ + if (vec2) { + vec1= vec2; + v2= v1; + } + + if (MatrixObject_Check(v2)) { + /* VEC * MATRIX */ + return row_vector_multiplication(vec1, (MatrixObject*)v2); + } else if (QuaternionObject_Check(v2)) { + QuaternionObject *quat = (QuaternionObject*)v2; /* quat_rotation validates */ + + if(vec1->size != 3) { + PyErr_SetString(PyExc_TypeError, "Vector multiplication: only 3D vector rotations (with quats) currently supported\n"); + return NULL; + } + return quat_rotation((PyObject*)vec1, (PyObject*)quat); + } + else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*FLOAT */ + int i; + float vec[4]; + + for(i = 0; i < vec1->size; i++) { + vec[i] = vec1->vec[i] * scalar; + } + return newVectorObject(vec, vec1->size, Py_NEW, NULL); + + } + + PyErr_SetString(PyExc_TypeError, "Vector multiplication: arguments not acceptable for this operation\n"); + return NULL; +} + +/*------------------------obj *= obj------------------------------ + in place mulplication */ +static PyObject *Vector_imul(PyObject * v1, PyObject * v2) +{ + VectorObject *vec = (VectorObject *)v1; + int i; + float scalar; + + if(!BaseMath_ReadCallback(vec)) + return NULL; + + /* only support vec*=float and vec*=mat + vec*=vec result is a float so that wont work */ + if (MatrixObject_Check(v2)) { + float vecCopy[4]; + int x,y, size = vec->size; + MatrixObject *mat= (MatrixObject*)v2; + + if(!BaseMath_ReadCallback(mat)) + return NULL; + + if(mat->colSize != size){ + if(mat->rowSize == 4 && vec->size != 3){ + PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same"); + return NULL; + } else { + vecCopy[3] = 1.0f; + } + } + + for(i = 0; i < size; i++){ + vecCopy[i] = vec->vec[i]; + } + + size = MIN2(size, mat->colSize); + + /*muliplication*/ + for(x = 0, i = 0; x < size; x++, i++) { + double dot = 0.0f; + for(y = 0; y < mat->rowSize; y++) { + dot += mat->matrix[y][x] * vecCopy[y]; + } + vec->vec[i] = (float)dot; + } + } + else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*=FLOAT */ + + for(i = 0; i < vec->size; i++) { + vec->vec[i] *= scalar; + } + } + else { + PyErr_SetString(PyExc_TypeError, "Vector multiplication: arguments not acceptable for this operation\n"); + return NULL; + } + + BaseMath_WriteCallback(vec); + Py_INCREF( v1 ); + return v1; +} + +/*------------------------obj / obj------------------------------ + divide*/ +static PyObject *Vector_div(PyObject * v1, PyObject * v2) +{ + int i; + float vec[4], scalar; + VectorObject *vec1 = NULL; + + if(!VectorObject_Check(v1)) { /* not a vector */ + PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n"); + return NULL; + } + vec1 = (VectorObject*)v1; /* vector */ + + if(!BaseMath_ReadCallback(vec1)) + return NULL; + + scalar = (float)PyFloat_AsDouble(v2); + if(scalar== -1.0f && PyErr_Occurred()) { /* parsed item not a number */ + PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n"); + return NULL; + } + + if(scalar==0.0) { /* not a vector */ + PyErr_SetString(PyExc_ZeroDivisionError, "Vector division: divide by zero error.\n"); + return NULL; + } + + for(i = 0; i < vec1->size; i++) { + vec[i] = vec1->vec[i] / scalar; + } + return newVectorObject(vec, vec1->size, Py_NEW, NULL); +} + +/*------------------------obj /= obj------------------------------ + divide*/ +static PyObject *Vector_idiv(PyObject * v1, PyObject * v2) +{ + int i; + float scalar; + VectorObject *vec1 = (VectorObject*)v1; + + if(!BaseMath_ReadCallback(vec1)) + return NULL; + + scalar = (float)PyFloat_AsDouble(v2); + if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ + PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n"); + return NULL; + } + + if(scalar==0.0) { /* not a vector */ + PyErr_SetString(PyExc_ZeroDivisionError, "Vector division: divide by zero error.\n"); + return NULL; + } + for(i = 0; i < vec1->size; i++) { + vec1->vec[i] /= scalar; + } + + BaseMath_WriteCallback(vec1); + + Py_INCREF( v1 ); + return v1; +} + +/*-------------------------- -obj ------------------------------- + returns the negative of this object*/ +static PyObject *Vector_neg(VectorObject *self) +{ + int i; + float vec[4]; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + for(i = 0; i < self->size; i++){ + vec[i] = -self->vec[i]; + } + + return newVectorObject(vec, self->size, Py_NEW, Py_TYPE(self)); +} + +/*------------------------vec_magnitude_nosqrt (internal) - for comparing only */ +static double vec_magnitude_nosqrt(float *data, int size) +{ + double dot = 0.0f; + int i; + + for(i=0; isize != vecB->size){ + if (comparison_type == Py_NE){ + Py_RETURN_TRUE; + }else{ + Py_RETURN_FALSE; + } + } + + switch (comparison_type){ + case Py_LT: + lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); + lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); + if( lenA < lenB ){ + result = 1; + } + break; + case Py_LE: + lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); + lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); + if( lenA < lenB ){ + result = 1; + }else{ + result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB)); + } + break; + case Py_EQ: + result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->size, 1); + break; + case Py_NE: + result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->size, 1); + if (result == 0){ + result = 1; + }else{ + result = 0; + } + break; + case Py_GT: + lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); + lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); + if( lenA > lenB ){ + result = 1; + } + break; + case Py_GE: + lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); + lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); + if( lenA > lenB ){ + result = 1; + }else{ + result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB)); + } + break; + default: + printf("The result of the comparison could not be evaluated"); + break; + } + if (result == 1){ + Py_RETURN_TRUE; + }else{ + Py_RETURN_FALSE; + } +} + +/*-----------------PROTCOL DECLARATIONS--------------------------*/ +static PySequenceMethods Vector_SeqMethods = { + (inquiry) Vector_len, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (ssizeargfunc) 0, /* sq_repeat */ + (ssizeargfunc) Vector_item, /* sq_item */ +#if (PY_VERSION_HEX < 0x03000000) + (ssizessizeargfunc) Vector_slice, /* sq_slice */ /* PY2 ONLY */ +#else + NULL, +#endif + (ssizeobjargproc) Vector_ass_item, /* sq_ass_item */ +#if (PY_VERSION_HEX < 0x03000000) + (ssizessizeobjargproc) Vector_ass_slice, /* sq_ass_slice */ /* PY2 ONLY */ +#else + NULL, +#endif +}; + + +#if (PY_VERSION_HEX >= 0x03000000) +static PyObject *Vector_subscript(VectorObject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += self->size; + return Vector_item(self, i); + } else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((PySliceObject*)item, self->size, &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyList_New(0); + } + else if (step == 1) { + return Vector_slice(self, start, stop); + } + else { + PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors"); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "vector indices must be integers, not %.200s", + item->ob_type->tp_name); + return NULL; + } +} + +static int Vector_ass_subscript(VectorObject* self, PyObject* item, PyObject* value) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += self->size; + return Vector_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((PySliceObject*)item, self->size, &start, &stop, &step, &slicelength) < 0) + return -1; + + if (step == 1) + return Vector_ass_slice(self, start, stop, value); + else { + PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors"); + return -1; + } + } + else { + PyErr_Format(PyExc_TypeError, + "vector indices must be integers, not %.200s", + item->ob_type->tp_name); + return -1; + } +} + +static PyMappingMethods Vector_AsMapping = { + (lenfunc)Vector_len, + (binaryfunc)Vector_subscript, + (objobjargproc)Vector_ass_subscript +}; +#endif /* (PY_VERSION_HEX >= 0x03000000) */ + +#if (PY_VERSION_HEX >= 0x03000000) +static PyNumberMethods Vector_NumMethods = { + (binaryfunc) Vector_add, /*nb_add*/ + (binaryfunc) Vector_sub, /*nb_subtract*/ + (binaryfunc) Vector_mul, /*nb_multiply*/ + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + (unaryfunc) Vector_neg, /*nb_negative*/ + (unaryfunc) 0, /*tp_positive*/ + (unaryfunc) 0, /*tp_absolute*/ + (inquiry) 0, /*tp_bool*/ + (unaryfunc) 0, /*nb_invert*/ + 0, /*nb_lshift*/ + (binaryfunc)0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + 0, /*nb_int*/ + 0, /*nb_reserved*/ + 0, /*nb_float*/ + Vector_iadd, /* nb_inplace_add */ + Vector_isub, /* nb_inplace_subtract */ + Vector_imul, /* nb_inplace_multiply */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + 0, /* nb_floor_divide */ + Vector_div, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + Vector_idiv, /* nb_inplace_true_divide */ + 0, /* nb_index */ +}; +#else +static PyNumberMethods Vector_NumMethods = { + (binaryfunc) Vector_add, /* __add__ */ + (binaryfunc) Vector_sub, /* __sub__ */ + (binaryfunc) Vector_mul, /* __mul__ */ + (binaryfunc) Vector_div, /* __div__ */ + (binaryfunc) NULL, /* __mod__ */ + (binaryfunc) NULL, /* __divmod__ */ + (ternaryfunc) NULL, /* __pow__ */ + (unaryfunc) Vector_neg, /* __neg__ */ + (unaryfunc) NULL, /* __pos__ */ + (unaryfunc) NULL, /* __abs__ */ + (inquiry) NULL, /* __nonzero__ */ + (unaryfunc) NULL, /* __invert__ */ + (binaryfunc) NULL, /* __lshift__ */ + (binaryfunc) NULL, /* __rshift__ */ + (binaryfunc) NULL, /* __and__ */ + (binaryfunc) NULL, /* __xor__ */ + (binaryfunc) NULL, /* __or__ */ + /*(coercion)*/ NULL, /* __coerce__ */ + (unaryfunc) NULL, /* __int__ */ + (unaryfunc) NULL, /* __long__ */ + (unaryfunc) NULL, /* __float__ */ + (unaryfunc) NULL, /* __oct__ */ + (unaryfunc) NULL, /* __hex__ */ + + /* Added in release 2.0 */ + (binaryfunc) Vector_iadd, /*__iadd__*/ + (binaryfunc) Vector_isub, /*__isub__*/ + (binaryfunc) Vector_imul, /*__imul__*/ + (binaryfunc) Vector_idiv, /*__idiv__*/ + (binaryfunc) NULL, /*__imod__*/ + (ternaryfunc) NULL, /*__ipow__*/ + (binaryfunc) NULL, /*__ilshift__*/ + (binaryfunc) NULL, /*__irshift__*/ + (binaryfunc) NULL, /*__iand__*/ + (binaryfunc) NULL, /*__ixor__*/ + (binaryfunc) NULL, /*__ior__*/ + + /* Added in release 2.2 */ + /* The following require the Py_TPFLAGS_HAVE_CLASS flag */ + (binaryfunc) NULL, /*__floordiv__ __rfloordiv__*/ + (binaryfunc) NULL, /*__truediv__ __rfloordiv__*/ + (binaryfunc) NULL, /*__ifloordiv__*/ + (binaryfunc) NULL, /*__itruediv__*/ +}; +#endif + +/*------------------PY_OBECT DEFINITION--------------------------*/ + +/* + * vector axis, vector.x/y/z/w + */ + +static PyObject *Vector_getAxis( VectorObject * self, void *type ) +{ + return Vector_item(self, GET_INT_FROM_POINTER(type)); +} + +static int Vector_setAxis( VectorObject * self, PyObject * value, void * type ) +{ + return Vector_ass_item(self, GET_INT_FROM_POINTER(type), value); +} + +/* vector.length */ +static PyObject *Vector_getLength( VectorObject * self, void *type ) +{ + double dot = 0.0f; + int i; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + for(i = 0; i < self->size; i++){ + dot += (self->vec[i] * self->vec[i]); + } + return PyFloat_FromDouble(sqrt(dot)); +} + +static int Vector_setLength( VectorObject * self, PyObject * value ) +{ + double dot = 0.0f, param; + int i; + + if(!BaseMath_ReadCallback(self)) + return -1; + + param= PyFloat_AsDouble( value ); + if(param==-1.0 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "length must be set to a number"); + return -1; + } + + if (param < 0) { + PyErr_SetString( PyExc_TypeError, "cannot set a vectors length to a negative value" ); + return -1; + } + if (param==0) { + for(i = 0; i < self->size; i++){ + self->vec[i]= 0; + } + return 0; + } + + for(i = 0; i < self->size; i++){ + dot += (self->vec[i] * self->vec[i]); + } + + if (!dot) /* cant sqrt zero */ + return 0; + + dot = sqrt(dot); + + if (dot==param) + return 0; + + dot= dot/param; + + for(i = 0; i < self->size; i++){ + self->vec[i]= self->vec[i] / (float)dot; + } + + BaseMath_WriteCallback(self); /* checked alredy */ + + return 0; +} + +/* Get a new Vector according to the provided swizzle. This function has little + error checking, as we are in control of the inputs: the closure is set by us + in Vector_createSwizzleGetSeter. */ +static PyObject *Vector_getSwizzle(VectorObject * self, void *closure) +{ + size_t axisA; + size_t axisB; + float vec[MAX_DIMENSIONS]; + unsigned int swizzleClosure; + + if(!BaseMath_ReadCallback(self)) + return NULL; + + /* Unpack the axes from the closure into an array. */ + axisA = 0; + swizzleClosure = (unsigned int) closure; + while (swizzleClosure & SWIZZLE_VALID_AXIS) + { + axisB = swizzleClosure & SWIZZLE_AXIS; + vec[axisA] = self->vec[axisB]; + swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; + axisA++; + } + + return newVectorObject(vec, axisA, Py_NEW, Py_TYPE(self)); +} + +/* Set the items of this vector using a swizzle. + - If value is a vector or list this operates like an array copy, except that + the destination is effectively re-ordered as defined by the swizzle. At + most min(len(source), len(dest)) values will be copied. + - If the value is scalar, it is copied to all axes listed in the swizzle. + - If an axis appears more than once in the swizzle, the final occurrance is + the one that determines its value. + + Returns 0 on success and -1 on failure. On failure, the vector will be + unchanged. */ +static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closure) +{ + VectorObject *vecVal; + PyObject *item; + size_t listLen; + float scalarVal; + + size_t axisB; + size_t axisA; + unsigned int swizzleClosure; + + float vecTemp[MAX_DIMENSIONS]; + + if(!BaseMath_ReadCallback(self)) + return -1; + + /* Check that the closure can be used with this vector: even 2D vectors have + swizzles defined for axes z and w, but they would be invalid. */ + swizzleClosure = (unsigned int) closure; + while (swizzleClosure & SWIZZLE_VALID_AXIS) + { + axisA = swizzleClosure & SWIZZLE_AXIS; + if (axisA >= self->size) + { + PyErr_SetString(PyExc_AttributeError, "Error: vector does not have specified axis.\n"); + return -1; + } + swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; + } + + if (VectorObject_Check(value)) + { + /* Copy vector contents onto swizzled axes. */ + vecVal = (VectorObject*) value; + axisB = 0; + swizzleClosure = (unsigned int) closure; + while (swizzleClosure & SWIZZLE_VALID_AXIS && axisB < vecVal->size) + { + axisA = swizzleClosure & SWIZZLE_AXIS; + vecTemp[axisA] = vecVal->vec[axisB]; + + swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; + axisB++; + } + memcpy(self->vec, vecTemp, axisB * sizeof(float)); + /* continue with BaseMathObject_WriteCallback at the end */ + } + else if (PyList_Check(value)) + { + /* Copy list contents onto swizzled axes. */ + listLen = PyList_Size(value); + swizzleClosure = (unsigned int) closure; + axisB = 0; + while (swizzleClosure & SWIZZLE_VALID_AXIS && axisB < listLen) + { + item = PyList_GetItem(value, axisB); + scalarVal = (float)PyFloat_AsDouble(item); + + if (scalarVal==-1.0 && PyErr_Occurred()) { + PyErr_SetString(PyExc_AttributeError, "Error: vector does not have specified axis.\n"); + return -1; + } + + + axisA = swizzleClosure & SWIZZLE_AXIS; + vecTemp[axisA] = scalarVal; + + swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; + axisB++; + } + memcpy(self->vec, vecTemp, axisB * sizeof(float)); + /* continue with BaseMathObject_WriteCallback at the end */ + } + else if (((scalarVal = (float)PyFloat_AsDouble(value)) == -1.0 && PyErr_Occurred())==0) + { + /* Assign the same value to each axis. */ + swizzleClosure = (unsigned int) closure; + while (swizzleClosure & SWIZZLE_VALID_AXIS) + { + axisA = swizzleClosure & SWIZZLE_AXIS; + self->vec[axisA] = scalarVal; + + swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; + } + /* continue with BaseMathObject_WriteCallback at the end */ + } + else { + PyErr_SetString( PyExc_TypeError, "Expected a Vector, list or scalar value." ); + return -1; + } + + if(!BaseMath_WriteCallback(vecVal)) + return -1; + else + return 0; +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef Vector_getseters[] = { + {"x", + (getter)Vector_getAxis, (setter)Vector_setAxis, + "Vector X axis", + (void *)0}, + {"y", + (getter)Vector_getAxis, (setter)Vector_setAxis, + "Vector Y axis", + (void *)1}, + {"z", + (getter)Vector_getAxis, (setter)Vector_setAxis, + "Vector Z axis", + (void *)2}, + {"w", + (getter)Vector_getAxis, (setter)Vector_setAxis, + "Vector Z axis", + (void *)3}, + {"length", + (getter)Vector_getLength, (setter)Vector_setLength, + "Vector Length", + NULL}, + {"magnitude", + (getter)Vector_getLength, (setter)Vector_setLength, + "Vector Length", + NULL}, + {"wrapped", + (getter)BaseMathObject_getWrapped, (setter)NULL, + "True when this wraps blenders internal data", + NULL}, + {"__owner__", + (getter)BaseMathObject_getOwner, (setter)NULL, + "Read only owner for vectors that depend on another object", + NULL}, + + /* autogenerated swizzle attrs, see python script below */ + {"xx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<= 2: + + for axis_0 in axises: + axis_0_pos = axis_pos[axis_0] + for axis_1 in axises: + axis_1_pos = axis_pos[axis_1] + axis_dict[axis_0+axis_1] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<2: + for axis_2 in axises: + axis_2_pos = axis_pos[axis_2] + axis_dict[axis_0+axis_1+axis_2] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<3: + for axis_3 in axises: + axis_3_pos = axis_pos[axis_3] + axis_dict[axis_0+axis_1+axis_2+axis_3] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif + /* For printing, in format "." */ + "vector", /* char *tp_name; */ + sizeof( VectorObject ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) BaseMathObject_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) Vector_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + &Vector_NumMethods, /* PyNumberMethods *tp_as_number; */ + &Vector_SeqMethods, /* PySequenceMethods *tp_as_sequence; */ +#if (PY_VERSION_HEX >= 0x03000000) + &Vector_AsMapping, /* PyMappingMethods *tp_as_mapping; */ +#else + NULL, +#endif + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + (richcmpfunc)Vector_richcmpr, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + Vector_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + Vector_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + Vector_new, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + + +/*------------------------newVectorObject (internal)------------- + creates a new vector object + pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER + (i.e. it was allocated elsewhere by MEM_mallocN()) + pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON + (i.e. it must be created here with PyMEM_malloc())*/ +PyObject *newVectorObject(float *vec, int size, int type, PyTypeObject *base_type) +{ + int i; + VectorObject *self; + + if(base_type) self = (VectorObject *)base_type->tp_alloc(base_type, 0); + else self = PyObject_NEW(VectorObject, &vector_Type); + + if(size > 4 || size < 2) + return NULL; + self->size = size; + + /* init callbacks as NULL */ + self->cb_user= NULL; + self->cb_type= self->cb_subtype= 0; + + if(type == Py_WRAP) { + self->vec = vec; + self->wrapped = Py_WRAP; + } else if (type == Py_NEW) { + self->vec = PyMem_Malloc(size * sizeof(float)); + if(!vec) { /*new empty*/ + for(i = 0; i < size; i++){ + self->vec[i] = 0.0f; + } + if(size == 4) /* do the homogenous thing */ + self->vec[3] = 1.0f; + }else{ + for(i = 0; i < size; i++){ + self->vec[i] = vec[i]; + } + } + self->wrapped = Py_NEW; + }else{ /*bad type*/ + return NULL; + } + return (PyObject *) self; +} + +PyObject *newVectorObject_cb(PyObject *cb_user, int size, int cb_type, int cb_subtype) +{ + float dummy[4] = {0.0, 0.0, 0.0, 0.0}; /* dummy init vector, callbacks will be used on access */ + VectorObject *self= (VectorObject *)newVectorObject(dummy, size, Py_NEW, NULL); + if(self) { + Py_INCREF(cb_user); + self->cb_user= cb_user; + self->cb_type= (unsigned char)cb_type; + self->cb_subtype= (unsigned char)cb_subtype; + } + + return (PyObject *)self; +} + +//-----------------row_vector_multiplication (internal)----------- +//ROW VECTOR Multiplication - Vector X Matrix +//[x][y][z] * [1][2][3] +// [4][5][6] +// [7][8][9] +//vector/matrix multiplication IS NOT COMMUTATIVE!!!! +static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat) +{ + float vecNew[4], vecCopy[4]; + double dot = 0.0f; + int x, y, z = 0, vec_size = vec->size; + + if(mat->colSize != vec_size){ + if(mat->rowSize == 4 && vec_size != 3){ + PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same"); + return NULL; + }else{ + vecCopy[3] = 1.0f; + } + } + + if(!BaseMath_ReadCallback(vec) || !BaseMath_ReadCallback(mat)) + return NULL; + + for(x = 0; x < vec_size; x++){ + vecCopy[x] = vec->vec[x]; + } + + //muliplication + for(x = 0; x < mat->colSize; x++) { + for(y = 0; y < mat->rowSize; y++) { + dot += mat->matrix[y][x] * vecCopy[y]; + } + vecNew[z++] = (float)dot; + dot = 0.0f; + } + return newVectorObject(vecNew, vec_size, Py_NEW, NULL); +} + +/*----------------------------Vector.negate() -------------------- + set the vector to it's negative -x, -y, -z */ +static PyObject *Vector_Negate(VectorObject * self) +{ + int i; + if(!BaseMath_ReadCallback(self)) + return NULL; + + for(i = 0; i < self->size; i++) + self->vec[i] = -(self->vec[i]); + + BaseMath_WriteCallback(self); // alredy checked for error + + Py_INCREF(self); + return (PyObject*)self; +} diff --git a/source/blender/python/generic/vector.h b/source/blender/python/generic/vector.h new file mode 100644 index 00000000000..316e0ced673 --- /dev/null +++ b/source/blender/python/generic/vector.h @@ -0,0 +1,55 @@ +/* $Id: vector.h 21254 2009-06-30 00:42:17Z campbellbarton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * 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): Willian P. Germano & Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#ifndef EXPP_vector_h +#define EXPP_vector_h + +#include +#include "../intern/bpy_compat.h" + +extern PyTypeObject vector_Type; +#define VectorObject_Check(_v) PyObject_TypeCheck((_v), &vector_Type) + +typedef struct { /* keep aligned with BaseMathObject in Mathutils.h */ + PyObject_VAR_HEAD + float *vec; /*1D array of data (alias), wrapped status depends on wrapped status */ + PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ + unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ + unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ + unsigned char wrapped; /* wrapped data type? */ + /* end BaseMathObject */ + + unsigned char size; /* vec size 2,3 or 4 */ +} VectorObject; + +/*prototypes*/ +PyObject *newVectorObject(float *vec, int size, int type, PyTypeObject *base_type); +PyObject *newVectorObject_cb(PyObject *user, int size, int callback_type, int subtype); + +#endif /* EXPP_vector_h */ diff --git a/source/blender/python/intern/Makefile b/source/blender/python/intern/Makefile index 3e28f5aac31..e0e0e942151 100644 --- a/source/blender/python/intern/Makefile +++ b/source/blender/python/intern/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile 11904 2007-08-31 16:16:33Z sirdude $ +# $Id: Makefile 21094 2009-06-23 00:09:26Z gsrb3d $ # # ***** BEGIN GPL LICENSE BLOCK ***** # @@ -37,6 +37,7 @@ CFLAGS += $(LEVEL_1_C_WARNINGS) # OpenGL and Python CPPFLAGS += $(OGL_CPPFLAGS) +CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) # PreProcessor stuff diff --git a/source/blender/python/intern/bpy_compat.h b/source/blender/python/intern/bpy_compat.h index ad6b7a5e85c..b9e02d62a57 100644 --- a/source/blender/python/intern/bpy_compat.h +++ b/source/blender/python/intern/bpy_compat.h @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: bpy_compat.h 21427 2009-07-08 14:26:43Z ton $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -85,9 +85,35 @@ typedef Py_ssize_t (*lenfunc)(PyObject *); #ifndef Py_RETURN_TRUE #define Py_RETURN_TRUE return PyBool_FromLong(1) #endif + +#define PyInt_FromSsize_t PyInt_FromLong +#define PyNumber_AsSsize_t(ob, exc) PyInt_AsLong(ob) +#define PyIndex_Check(ob) PyInt_Check(ob) + + #endif +#if PY_VERSION_HEX < 0x03000000 +#ifndef ssizeargfunc +#define ssizeargfunc intargfunc +#endif + +#ifndef ssizessizeargfunc +#define ssizessizeargfunc intintargfunc +#endif + +#ifndef ssizeobjargproc +#define ssizeobjargproc intobjargproc +#endif + +#ifndef ssizessizeobjargproc +#define ssizessizeobjargproc intintobjargproc +#endif +#endif + + + /* defined in bpy_util.c */ #if PY_VERSION_HEX < 0x03000000 PyObject *Py_CmpToRich(int op, int cmp); diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 7b3a67ebff5..a07c447c718 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -36,6 +36,14 @@ #include "BPY_extern.h" +#include "../generic/bpy_internal_import.h" // our own imports +/* external util modules */ + +#include "../generic/Mathutils.h" +#include "../generic/Geometry.h" +#include "../generic/BGL.h" + + void BPY_free_compiled_text( struct Text *text ) { if( text->compiled ) { @@ -56,12 +64,19 @@ static void bpy_init_modules( void ) PyModule_AddObject( mod, "data", BPY_rna_module() ); /* PyModule_AddObject( mod, "doc", BPY_rna_doc() ); */ PyModule_AddObject( mod, "types", BPY_rna_types() ); + PyModule_AddObject( mod, "props", BPY_rna_props() ); PyModule_AddObject( mod, "ops", BPY_operator_module() ); - PyModule_AddObject( mod, "ui", BPY_ui_module() ); // XXX very experemental, consider this a test, especially PyCObject is not meant to be perminant + PyModule_AddObject( mod, "ui", BPY_ui_module() ); // XXX very experimental, consider this a test, especially PyCObject is not meant to be permanent /* add the module so we can import it */ PyDict_SetItemString(PySys_GetObject("modules"), "bpy", mod); Py_DECREF(mod); + + + /* stand alone utility modules not related to blender directly */ + Geometry_Init("Geometry"); + Mathutils_Init("Mathutils"); + BGL_Init("BGL"); } #if (PY_VERSION_HEX < 0x02050000) @@ -100,6 +115,7 @@ static PyObject *CreateGlobalDictionary( bContext *C ) {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""}, {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""}, {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""}, {NULL, NULL, 0, NULL} }; @@ -116,13 +132,81 @@ static PyObject *CreateGlobalDictionary( bContext *C ) return dict; } +/* Use this so we can include our own python bundle */ +#if 0 +wchar_t* Py_GetPath(void) +{ + int i; + static wchar_t py_path[FILE_MAXDIR] = L""; + char *dirname= BLI_gethome_folder("python"); + if(dirname) { + i= mbstowcs(py_path, dirname, FILE_MAXDIR); + printf("py path %s, %d\n", dirname, i); + } + return py_path; +} +#endif + + +/* must be called before Py_Initialize */ +void BPY_start_python_path(void) +{ + char *py_path_bundle= BLI_gethome_folder("python"); + + if(py_path_bundle==NULL) + return; + + /* set the environment path */ + printf("found bundled python: %s\n", py_path_bundle); + +#if (defined(WIN32) || defined(WIN64)) +#if defined(FREE_WINDOWS) + { + char py_path[FILE_MAXDIR + 11] = ""; + sprintf(py_path, "PYTHONPATH=%s", py_path_bundle); + putenv(py_path); + } +#else + _putenv_s("PYTHONPATH", py_path_bundle); +#endif +#else +#ifdef __sgi + { + char py_path[FILE_MAXDIR + 11] = ""; + sprintf(py_path, "PYTHONPATH=%s", py_path_bundle); + putenv(py_path); + } +#else + setenv("PYTHONPATH", py_path_bundle, 1); +#endif +#endif + +} + + void BPY_start_python( int argc, char **argv ) { PyThreadState *py_tstate = NULL; + BPY_start_python_path(); /* allow to use our own included python */ + Py_Initialize( ); - //PySys_SetArgv( argc_copy, argv_copy ); +#if (PY_VERSION_HEX < 0x03000000) + PySys_SetArgv( argc, argv); +#else + /* sigh, why do python guys not have a char** version anymore? :( */ + { + int i; + PyObject *py_argv= PyList_New(argc); + + for (i=0; iscript; if( err ) { - PyErr_Print(); PyErr_Clear(); + BPy_errors_to_report(NULL); // TODO, reports script->flags = 0; /* mark script struct for deletion */ SCRIPT_SET_NULL(script); script->scriptname[0] = '\0'; @@ -250,7 +343,7 @@ static int bpy_run_script_init(bContext *C, SpaceScript * sc) return 0; if (sc->script->py_draw==NULL && sc->script->scriptname[0] != '\0') - BPY_run_python_script(C, sc->script->scriptname, NULL); + BPY_run_python_script(C, sc->script->scriptname, NULL, NULL); if (sc->script->py_draw==NULL) return 0; @@ -258,9 +351,9 @@ static int bpy_run_script_init(bContext *C, SpaceScript * sc) return 1; } -int BPY_run_script_space_draw(struct bContext *C, SpaceScript * sc) +int BPY_run_script_space_draw(const struct bContext *C, SpaceScript * sc) { - if (bpy_run_script_init(C, sc)) { + if (bpy_run_script_init( (bContext *)C, sc)) { PyGILState_STATE gilstate = PyGILState_Ensure(); PyObject *result = PyObject_CallObject( sc->script->py_draw, NULL ); @@ -329,7 +422,7 @@ int BPY_run_python_script_space(const char *modulename, const char *func) } if (!py_result) { - PyErr_Print(); PyErr_Clear(); + BPy_errors_to_report(NULL); // TODO - reports } else Py_DECREF( py_result ); @@ -357,69 +450,72 @@ void BPY_run_ui_scripts(bContext *C, int reload) DIR *dir; struct dirent *de; char *file_extension; + char *dirname; char path[FILE_MAX]; - char *dirname= BLI_gethome_folder("ui"); - int filelen; /* filename length */ + char *dirs[] = {"io", "ui", NULL}; + int a; PyGILState_STATE gilstate; PyObject *mod; - PyObject *sys_path_orig; - PyObject *sys_path_new; - - if(!dirname) - return; - - dir = opendir(dirname); + PyObject *sys_path; - if(!dir) - return; - gilstate = PyGILState_Ensure(); - /* backup sys.path */ - sys_path_orig= PySys_GetObject("path"); - Py_INCREF(sys_path_orig); /* dont free it */ - - sys_path_new= PyList_New(1); - PyList_SET_ITEM(sys_path_new, 0, PyUnicode_FromString(dirname)); - PySys_SetObject("path", sys_path_new); - Py_DECREF(sys_path_new); - // XXX - evil, need to access context BPy_SetContext(C); - - while((de = readdir(dir)) != NULL) { - /* We could stat the file but easier just to let python - * import it and complain if theres a problem */ + bpy_import_main_set(CTX_data_main(C)); + + + sys_path= PySys_GetObject("path"); /* borrow */ + PyList_Insert(sys_path, 0, Py_None); /* place holder, resizes the list */ + + for(a=0; dirs[a]; a++) { + dirname= BLI_gethome_folder(dirs[a]); + + if(!dirname) + continue; + + dir = opendir(dirname); + + if(!dir) + continue; - file_extension = strstr(de->d_name, ".py"); - - if(file_extension && *(file_extension + 3) == '\0') { - filelen = strlen(de->d_name); - BLI_strncpy(path, de->d_name, filelen-2); /* cut off the .py on copy */ + /* set the first dir in the sys.path for fast importing of modules */ + PyList_SetItem(sys_path, 0, PyUnicode_FromString(dirname)); /* steals the ref */ - mod= PyImport_ImportModuleLevel(path, NULL, NULL, NULL, 0); - if (mod) { - if (reload) { - PyObject *mod_orig= mod; - mod= PyImport_ReloadModule(mod); - Py_DECREF(mod_orig); + while((de = readdir(dir)) != NULL) { + /* We could stat the file but easier just to let python + * import it and complain if theres a problem */ + + file_extension = strstr(de->d_name, ".py"); + + if(file_extension && file_extension[3] == '\0') { + BLI_strncpy(path, de->d_name, (file_extension - de->d_name) + 1); /* cut off the .py on copy */ + mod= PyImport_ImportModuleLevel(path, NULL, NULL, NULL, 0); + if (mod) { + if (reload) { + PyObject *mod_orig= mod; + mod= PyImport_ReloadModule(mod); + Py_DECREF(mod_orig); + } } - } - - if(mod) { - Py_DECREF(mod); /* could be NULL from reloading */ - } else { - PyErr_Print(); PyErr_Clear(); - fprintf(stderr, "unable to import \"%s\" %s/%s\n", path, dirname, de->d_name); + + if(mod) { + Py_DECREF(mod); /* could be NULL from reloading */ + } else { + BPy_errors_to_report(NULL); + fprintf(stderr, "unable to import \"%s\" %s/%s\n", path, dirname, de->d_name); + } + } } - } - closedir(dir); + closedir(dir); + } - PySys_SetObject("path", sys_path_orig); - Py_DECREF(sys_path_orig); + PyList_SetSlice(sys_path, 0, 1, NULL); /* remove the first item */ + + bpy_import_main_set(NULL); PyGILState_Release(gilstate); #ifdef TIME_REGISTRATION @@ -530,7 +626,7 @@ static float pydriver_error(ChannelDriver *driver) 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); - PyErr_Print(); PyErr_Clear(); + BPy_errors_to_report(NULL); // TODO - reports return 0.0f; } @@ -589,7 +685,7 @@ float BPY_pydriver_eval (ChannelDriver *driver) } fprintf(stderr, "\tBPY_pydriver_eval() - couldn't add variable '%s' to namespace \n", dtar->name); - PyErr_Print(); PyErr_Clear(); + BPy_errors_to_report(NULL); // TODO - reports } } diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 004cf2fb7c7..3c03b543d24 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -1,6 +1,6 @@ /** - * $Id$ + * $Id: bpy_operator.c 21554 2009-07-13 08:33:51Z campbellbarton $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -68,7 +68,7 @@ static PyObject *pyop_base_call( PyObject * self, PyObject * args, PyObject * k return NULL; } - ot= WM_operatortype_find(opname); + ot= WM_operatortype_find(opname, 1); if (ot == NULL) { PyErr_Format( PyExc_SystemError, "Operator \"%s\"could not be found", opname); return NULL; @@ -130,11 +130,18 @@ static PyObject *pyop_base_getattro( BPy_OperatorBase * self, PyObject *pyname ) PyObject *ret; wmOperatorType *ot; - if ((ot= WM_operatortype_find(name))) { + /* First look for the operator, then our own methods if that fails. + * when methods are searched first, PyObject_GenericGetAttr will raise an error + * each time we want to call an operator, we could clear the error but I prefer + * not to since calling operators is a lot more common then adding and removing. - Campbell */ + + if ((ot= WM_operatortype_find(name, 1))) { ret = PyCFunction_New( pyop_base_call_meth, pyname); /* set the name string as self, PyCFunction_New incref's self */ } else if ((ret = PyObject_GenericGetAttr((PyObject *)self, pyname))) { - /* do nothing, this accounts for methoddef's add and remove */ + /* do nothing, this accounts for methoddef's add and remove + * An exception is raised when PyObject_GenericGetAttr fails + * but its ok because its overwritten below */ } else { PyErr_Format( PyExc_AttributeError, "Operator \"%s\" not found", name); @@ -170,7 +177,7 @@ static PyObject *pyop_base_rna(PyObject *self, PyObject *pyname) char *name = _PyUnicode_AsString(pyname); wmOperatorType *ot; - if ((ot= WM_operatortype_find(name))) { + if ((ot= WM_operatortype_find(name, 1))) { BPy_StructRNA *pyrna; PointerRNA ptr; @@ -191,6 +198,8 @@ PyTypeObject pyop_base_Type = {NULL}; PyObject *BPY_operator_module( void ) { + PyObject *ob; + pyop_base_Type.tp_name = "OperatorBase"; pyop_base_Type.tp_basicsize = sizeof( BPy_OperatorBase ); pyop_base_Type.tp_getattro = ( getattrofunc )pyop_base_getattro; @@ -201,6 +210,9 @@ PyObject *BPY_operator_module( void ) return NULL; //submodule = Py_InitModule3( "operator", M_rna_methods, "rna module" ); - return (PyObject *)PyObject_NEW( BPy_OperatorBase, &pyop_base_Type ); + ob = PyObject_NEW( BPy_OperatorBase, &pyop_base_Type ); + Py_INCREF(ob); + + return ob; } diff --git a/source/blender/python/intern/bpy_operator.h b/source/blender/python/intern/bpy_operator.h index 46ea144fd4d..0e826eab10e 100644 --- a/source/blender/python/intern/bpy_operator.h +++ b/source/blender/python/intern/bpy_operator.h @@ -1,6 +1,6 @@ /** - * $Id$ + * $Id: bpy_operator.h 21094 2009-06-23 00:09:26Z gsrb3d $ * * ***** BEGIN GPL LICENSE BLOCK ***** * diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 6ab990acdf5..d90607aceaa 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -1,6 +1,6 @@ /** - * $Id$ + * $Id: bpy_operator_wrap.c 21440 2009-07-08 21:31:28Z blendix $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -40,116 +40,13 @@ #include "bpy_compat.h" #include "bpy_util.h" +#include "../generic/bpy_internal_import.h" // our own imports + #define PYOP_ATTR_PROP "__props__" #define PYOP_ATTR_UINAME "__label__" #define PYOP_ATTR_IDNAME "__name__" /* use pythons class name */ #define PYOP_ATTR_DESCRIPTION "__doc__" /* use pythons docstring */ -static PyObject *pyop_dict_from_event(wmEvent *event) -{ - PyObject *dict= PyDict_New(); - PyObject *item; - char *cstring, ascii[2]; - - /* type */ - item= PyUnicode_FromString(WM_key_event_string(event->type)); - PyDict_SetItemString(dict, "type", item); Py_DECREF(item); - - /* val */ - switch(event->val) { - case KM_ANY: - cstring = "ANY"; - break; - case KM_RELEASE: - cstring = "RELEASE"; - break; - case KM_PRESS: - cstring = "PRESS"; - break; - default: - cstring = "UNKNOWN"; - break; - } - - item= PyUnicode_FromString(cstring); - PyDict_SetItemString(dict, "val", item); Py_DECREF(item); - - /* x, y (mouse) */ - item= PyLong_FromLong(event->x); - PyDict_SetItemString(dict, "x", item); Py_DECREF(item); - - item= PyLong_FromLong(event->y); - PyDict_SetItemString(dict, "y", item); Py_DECREF(item); - - item= PyLong_FromLong(event->prevx); - PyDict_SetItemString(dict, "prevx", item); Py_DECREF(item); - - item= PyLong_FromLong(event->prevy); - PyDict_SetItemString(dict, "prevy", item); Py_DECREF(item); - - /* ascii */ - ascii[0]= event->ascii; - ascii[1]= '\0'; - item= PyUnicode_FromString(ascii); - PyDict_SetItemString(dict, "ascii", item); Py_DECREF(item); - - /* modifier keys */ - item= PyLong_FromLong(event->shift); - PyDict_SetItemString(dict, "shift", item); Py_DECREF(item); - - item= PyLong_FromLong(event->ctrl); - PyDict_SetItemString(dict, "ctrl", item); Py_DECREF(item); - - item= PyLong_FromLong(event->alt); - PyDict_SetItemString(dict, "alt", item); Py_DECREF(item); - - item= PyLong_FromLong(event->oskey); - PyDict_SetItemString(dict, "oskey", item); Py_DECREF(item); - - - - /* modifier */ -#if 0 - item= PyTuple_New(0); - if(event->keymodifier & KM_SHIFT) { - _PyTuple_Resize(&item, size+1); - PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("SHIFT")); - size++; - } - if(event->keymodifier & KM_CTRL) { - _PyTuple_Resize(&item, size+1); - PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("CTRL")); - size++; - } - if(event->keymodifier & KM_ALT) { - _PyTuple_Resize(&item, size+1); - PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("ALT")); - size++; - } - if(event->keymodifier & KM_OSKEY) { - _PyTuple_Resize(&item, size+1); - PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("OSKEY")); - size++; - } - PyDict_SetItemString(dict, "keymodifier", item); Py_DECREF(item); -#endif - - return dict; -} - -/* TODO - a whole traceback would be ideal */ -static void pyop_error_report(ReportList *reports) -{ - PyObject *exception, *v, *tb; - PyErr_Fetch(&exception, &v, &tb); - if (exception == NULL) - return; - /* Now we know v != NULL too */ - BKE_report(reports, RPT_ERROR, _PyUnicode_AsString(v)); - - PyErr_Print(); -} - static struct BPY_flag_def pyop_ret_flags[] = { {"RUNNING_MODAL", OPERATOR_RUNNING_MODAL}, {"CANCELLED", OPERATOR_CANCELLED}, @@ -190,9 +87,13 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PyObject *ret= NULL, *py_class_instance, *item= NULL; int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED); PointerRNA ptr_context; - PyObject *py_context; + PointerRNA ptr_operator; + PointerRNA ptr_event; + PyObject *py_operator; PyGILState_STATE gilstate = PyGILState_Ensure(); + + bpy_import_main_set(CTX_data_main(C)); BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solutuon for this. @@ -206,15 +107,9 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve /* Assign instance attributes from operator properties */ { - PropertyRNA *prop, *iterprop; - CollectionPropertyIterator iter; const char *arg_name; - iterprop= RNA_struct_iterator_property(op->ptr->type); - RNA_property_collection_begin(op->ptr, iterprop, &iter); - - for(; iter.valid; RNA_property_collection_next(&iter)) { - prop= iter.ptr.data; + RNA_STRUCT_BEGIN(op->ptr, prop) { arg_name= RNA_property_identifier(prop); if (strcmp(arg_name, "rna_type")==0) continue; @@ -223,23 +118,33 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PyObject_SetAttrString(py_class_instance, arg_name, item); Py_DECREF(item); } - - RNA_property_collection_end(&iter); + RNA_STRUCT_END; } - + + /* set operator pointer RNA as instance "__operator__" attribute */ + RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator); + py_operator= pyrna_struct_CreatePyObject(&ptr_operator); + PyObject_SetAttrString(py_class_instance, "__operator__", py_operator); + Py_DECREF(py_operator); + + RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); if (mode==PYOP_INVOKE) { item= PyObject_GetAttrString(py_class, "invoke"); - args = PyTuple_New(2); - PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event)); + args = PyTuple_New(3); + + RNA_pointer_create(NULL, &RNA_Event, event, &ptr_event); + + // PyTuple_SET_ITEM "steals" object reference, it is + // an object passed shouldn't be DECREF'ed + PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context)); + PyTuple_SET_ITEM(args, 2, pyrna_struct_CreatePyObject(&ptr_event)); } else if (mode==PYOP_EXEC) { - item= PyObject_GetAttrString(py_class, "exec"); + item= PyObject_GetAttrString(py_class, "execute"); args = PyTuple_New(2); - RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); - py_context = pyrna_struct_CreatePyObject(&ptr_context); - PyTuple_SET_ITEM(args, 1, py_context); + PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context)); } else if (mode==PYOP_POLL) { item= PyObject_GetAttrString(py_class, "poll"); @@ -256,13 +161,13 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } if (ret == NULL) { /* covers py_class_instance failing too */ - pyop_error_report(op->reports); + BPy_errors_to_report(op->reports); } else { if (mode==PYOP_POLL) { if (PyBool_Check(ret) == 0) { PyErr_SetString(PyExc_ValueError, "Python poll function return value "); - pyop_error_report(op->reports); + BPy_errors_to_report(op->reports); } else { ret_flag= ret==Py_True ? 1:0; @@ -270,8 +175,9 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) { /* the returned value could not be converted into a flag */ - pyop_error_report(op->reports); - + BPy_errors_to_report(op->reports); + + ret_flag = OPERATOR_CANCELLED; } /* there is no need to copy the py keyword dict modified by * pyot->py_invoke(), back to the operator props since they are just @@ -284,7 +190,34 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve Py_DECREF(ret); } + /* print operator return value */ + if (mode != PYOP_POLL) { + char flag_str[100]; + char class_name[100]; + BPY_flag_def *flag_def = pyop_ret_flags; + + strcpy(flag_str, ""); + + while(flag_def->name) { + if (ret_flag & flag_def->flag) { + if(flag_str[1]) + sprintf(flag_str, "%s | %s", flag_str, flag_def->name); + else + strcpy(flag_str, flag_def->name); + } + flag_def++; + } + + /* get class name */ + item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME); + Py_DECREF(item); + strcpy(class_name, _PyUnicode_AsString(item)); + + fprintf(stderr, "%s's %s returned %s\n", class_name, mode == PYOP_EXEC ? "execute" : "invoke", flag_str); + } + PyGILState_Release(gilstate); + bpy_import_main_set(NULL); return ret_flag; } @@ -334,7 +267,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) /* api callbacks, detailed checks dont on adding */ if (PyObject_HasAttrString(py_class, "invoke")) ot->invoke= PYTHON_OT_invoke; - if (PyObject_HasAttrString(py_class, "exec")) + if (PyObject_HasAttrString(py_class, "execute")) ot->exec= PYTHON_OT_exec; if (PyObject_HasAttrString(py_class, "poll")) ot->poll= PYTHON_OT_poll; @@ -387,6 +320,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class) { PyObject *base_class, *item; + wmOperatorType *ot; char *idname= NULL; @@ -397,8 +331,8 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class) {PYOP_ATTR_UINAME, 's', 0, BPY_CLASS_ATTR_OPTIONAL}, {PYOP_ATTR_PROP, 'l', 0, BPY_CLASS_ATTR_OPTIONAL}, {PYOP_ATTR_DESCRIPTION, 's', 0, BPY_CLASS_ATTR_NONE_OK}, - {"exec", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, - {"invoke", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, + {"execute", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, + {"invoke", 'f', 3, BPY_CLASS_ATTR_OPTIONAL}, {"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {NULL, 0, 0, 0} }; @@ -417,9 +351,12 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class) Py_DECREF(item); idname = _PyUnicode_AsString(item); - if (WM_operatortype_find(idname)) { - PyErr_Format( PyExc_AttributeError, "Operator alredy exists with this name \"%s\"", idname); - return NULL; + /* remove if it already exists */ + if ((ot=WM_operatortype_exists(idname))) { + if(ot->pyop_data) { + Py_XDECREF((PyObject*)ot->pyop_data); + } + WM_operatortype_remove(idname); } /* If we have properties set, check its a list of dicts */ @@ -466,7 +403,7 @@ PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value) return NULL; } - if (!(ot= WM_operatortype_find(idname))) { + if (!(ot= WM_operatortype_exists(idname))) { PyErr_Format( PyExc_AttributeError, "Operator \"%s\" does not exists, cant remove", idname); return NULL; } diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h index 2929d57ab82..9718e2d6e65 100644 --- a/source/blender/python/intern/bpy_operator_wrap.h +++ b/source/blender/python/intern/bpy_operator_wrap.h @@ -1,6 +1,6 @@ /** - * $Id$ + * $Id: bpy_operator_wrap.h 21094 2009-06-23 00:09:26Z gsrb3d $ * * ***** BEGIN GPL LICENSE BLOCK ***** * diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 9fa7d1b6693..1a9139e5f88 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: bpy_rna.c 21564 2009-07-13 19:33:59Z campbellbarton $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -35,16 +35,102 @@ #include "RNA_define.h" /* for defining our own rna */ #include "MEM_guardedalloc.h" +#include "BKE_utildefines.h" #include "BKE_context.h" #include "BKE_global.h" /* evil G.* */ #include "BKE_report.h" -#if 0 -#define bpy_PyObject_New(type, typeobj) \ -( (type *) PyObject_Init( \ - (PyObject *) MEM_callocN( _PyObject_SIZE(typeobj), "python memory from bpy_rna.c" ), (typeobj)) ) -#else -#define bpy_PyObject_New(type, typeobj) PyObject_New(type, typeobj) +/* only for keyframing */ +#include "DNA_scene_types.h" +#include "ED_keyframing.h" + +#define USE_MATHUTILS + +#ifdef USE_MATHUTILS +#include "../generic/Mathutils.h" /* so we can have mathutils callbacks */ + +/* bpyrna vector/euler/quat callbacks */ +static int mathutils_rna_array_cb_index= -1; /* index for our callbacks */ + +static int mathutils_rna_generic_check(BPy_PropertyRNA *self) +{ + return self->prop?1:0; +} + +static int mathutils_rna_vector_get(BPy_PropertyRNA *self, int subtype, float *vec_from) +{ + if(self->prop==NULL) + return 0; + + RNA_property_float_get_array(&self->ptr, self->prop, vec_from); + return 1; +} + +static int mathutils_rna_vector_set(BPy_PropertyRNA *self, int subtype, float *vec_to) +{ + if(self->prop==NULL) + return 0; + + RNA_property_float_set_array(&self->ptr, self->prop, vec_to); + return 1; +} + +static int mathutils_rna_vector_get_index(BPy_PropertyRNA *self, int subtype, float *vec_from, int index) +{ + if(self->prop==NULL) + return 0; + + vec_from[index]= RNA_property_float_get_index(&self->ptr, self->prop, index); + return 1; +} + +static int mathutils_rna_vector_set_index(BPy_PropertyRNA *self, int subtype, float *vec_to, int index) +{ + if(self->prop==NULL) + return 0; + + RNA_property_float_set_index(&self->ptr, self->prop, index, vec_to[index]); + return 1; +} + +Mathutils_Callback mathutils_rna_array_cb = { + (BaseMathCheckFunc) mathutils_rna_generic_check, + (BaseMathGetFunc) mathutils_rna_vector_get, + (BaseMathSetFunc) mathutils_rna_vector_set, + (BaseMathGetIndexFunc) mathutils_rna_vector_get_index, + (BaseMathSetIndexFunc) mathutils_rna_vector_set_index +}; + + +/* bpyrna matrix callbacks */ +static int mathutils_rna_matrix_cb_index= -1; /* index for our callbacks */ + +static int mathutils_rna_matrix_get(BPy_PropertyRNA *self, int subtype, float *mat_from) +{ + if(self->prop==NULL) + return 0; + + RNA_property_float_get_array(&self->ptr, self->prop, mat_from); + return 1; +} + +static int mathutils_rna_matrix_set(BPy_PropertyRNA *self, int subtype, float *mat_to) +{ + if(self->prop==NULL) + return 0; + + RNA_property_float_set_array(&self->ptr, self->prop, mat_to); + return 1; +} + +Mathutils_Callback mathutils_rna_matrix_cb = { + (BaseMathCheckFunc) mathutils_rna_generic_check, + (BaseMathGetFunc) mathutils_rna_matrix_get, + (BaseMathSetFunc) mathutils_rna_matrix_set, + (BaseMathGetIndexFunc) NULL, + (BaseMathSetIndexFunc) NULL +}; + #endif static int pyrna_struct_compare( BPy_StructRNA * a, BPy_StructRNA * b ) @@ -81,39 +167,39 @@ static PyObject *pyrna_prop_richcmp(BPy_PropertyRNA * a, BPy_PropertyRNA * b, in /*----------------------repr--------------------------------------------*/ static PyObject *pyrna_struct_repr( BPy_StructRNA * self ) { - PropertyRNA *prop; - char str[512]; + PyObject *pyob; + char *name; /* print name if available */ - prop= RNA_struct_name_property(self->ptr.type); - if(prop) { - RNA_property_string_get(&self->ptr, prop, str); - return PyUnicode_FromFormat( "[BPy_StructRNA \"%s\" -> \"%s\"]", RNA_struct_identifier(self->ptr.type), str); + name= RNA_struct_name_get_alloc(&self->ptr, NULL, 0); + if(name) { + pyob= PyUnicode_FromFormat( "[BPy_StructRNA \"%.200s\" -> \"%.200s\"]", RNA_struct_identifier(self->ptr.type), name); + MEM_freeN(name); + return pyob; } - return PyUnicode_FromFormat( "[BPy_StructRNA \"%s\"]", RNA_struct_identifier(self->ptr.type)); + return PyUnicode_FromFormat( "[BPy_StructRNA \"%.200s\"]", RNA_struct_identifier(self->ptr.type)); } static PyObject *pyrna_prop_repr( BPy_PropertyRNA * self ) { - PropertyRNA *prop; + PyObject *pyob; PointerRNA ptr; - char str[512]; + char *name; /* if a pointer, try to print name of pointer target too */ if(RNA_property_type(self->prop) == PROP_POINTER) { ptr= RNA_property_pointer_get(&self->ptr, self->prop); + name= RNA_struct_name_get_alloc(&ptr, NULL, 0); - if(ptr.data) { - prop= RNA_struct_name_property(ptr.type); - if(prop) { - RNA_property_string_get(&ptr, prop, str); - return PyUnicode_FromFormat( "[BPy_PropertyRNA \"%s\" -> \"%s\" -> \"%s\" ]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop), str); - } + if(name) { + pyob= PyUnicode_FromFormat( "[BPy_PropertyRNA \"%.200s\" -> \"%.200s\" -> \"%.200s\" ]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop), name); + MEM_freeN(name); + return pyob; } } - return PyUnicode_FromFormat( "[BPy_PropertyRNA \"%s\" -> \"%s\"]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop)); + return PyUnicode_FromFormat( "[BPy_PropertyRNA \"%.200s\" -> \"%.200s\"]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop)); } static long pyrna_struct_hash( BPy_StructRNA * self ) @@ -124,24 +210,35 @@ static long pyrna_struct_hash( BPy_StructRNA * self ) /* use our own dealloc so we can free a property if we use one */ static void pyrna_struct_dealloc( BPy_StructRNA * self ) { - /* Note!! for some weired reason calling PyObject_DEL() directly crashes blender! */ if (self->freeptr && self->ptr.data) { IDP_FreeProperty(self->ptr.data); MEM_freeN(self->ptr.data); self->ptr.data= NULL; } + /* Note, for subclassed PyObjects we cant just call PyObject_DEL() directly or it will crash */ Py_TYPE(self)->tp_free(self); return; } static char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop) { - const EnumPropertyItem *item; - int totitem; + EnumPropertyItem *item; + char *result; + int free= 0; - RNA_property_enum_items(ptr, prop, &item, &totitem); - return (char*)BPy_enum_as_string((EnumPropertyItem*)item); + RNA_property_enum_items(BPy_GetContext(), ptr, prop, &item, NULL, &free); + if(item) { + result= (char*)BPy_enum_as_string(item); + } + else { + result= ""; + } + + if(free) + MEM_freeN(item); + + return result; } PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) @@ -152,7 +249,52 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) if (len > 0) { /* resolve the array from a new pytype */ - return pyrna_prop_CreatePyObject(ptr, prop); + PyObject *ret = pyrna_prop_CreatePyObject(ptr, prop); + +#ifdef USE_MATHUTILS + + /* return a mathutils vector where possible */ + if(RNA_property_type(prop)==PROP_FLOAT) { + switch(RNA_property_subtype(prop)) { + case PROP_VECTOR: + if(len>=2 && len <= 4) { + PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_array_cb_index, 0); + Py_DECREF(ret); /* the vector owns now */ + ret= vec_cb; /* return the vector instead */ + } + break; + case PROP_MATRIX: + if(len==16) { + PyObject *mat_cb= newMatrixObject_cb(ret, 4,4, mathutils_rna_matrix_cb_index, 0); + Py_DECREF(ret); /* the matrix owns now */ + ret= mat_cb; /* return the matrix instead */ + } + else if (len==9) { + PyObject *mat_cb= newMatrixObject_cb(ret, 3,3, mathutils_rna_matrix_cb_index, 0); + Py_DECREF(ret); /* the matrix owns now */ + ret= mat_cb; /* return the matrix instead */ + } + break; + case PROP_ROTATION: + if(len==3) { /* euler */ + PyObject *eul_cb= newEulerObject_cb(ret, mathutils_rna_array_cb_index, 0); + Py_DECREF(ret); /* the matrix owns now */ + ret= eul_cb; /* return the matrix instead */ + } + else if (len==4) { + PyObject *quat_cb= newQuaternionObject_cb(ret, mathutils_rna_array_cb_index, 0); + Py_DECREF(ret); /* the matrix owns now */ + ret= quat_cb; /* return the matrix instead */ + } + break; + default: + break; + } + } + +#endif + + return ret; } /* see if we can coorce into a python type - PropertyType */ @@ -179,11 +321,32 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) const char *identifier; int val = RNA_property_enum_get(ptr, prop); - if (RNA_property_enum_identifier(ptr, prop, val, &identifier)) { + if (RNA_property_enum_identifier(BPy_GetContext(), ptr, prop, val, &identifier)) { ret = PyUnicode_FromString( identifier ); } else { - PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val); - ret = NULL; + EnumPropertyItem *item; + int free= 0; + + /* don't throw error here, can't trust blender 100% to give the + * right values, python code should not generate error for that */ + RNA_property_enum_items(BPy_GetContext(), ptr, prop, &item, NULL, &free); + if(item && item->identifier) { + ret = PyUnicode_FromString( item->identifier ); + } + else { + /* prefer not fail silently incase of api errors, maybe disable it later */ + char error_str[128]; + sprintf(error_str, "RNA Warning: Current value \"%d\" matches no enum", val); + PyErr_Warn(PyExc_RuntimeWarning, error_str); + + ret = PyUnicode_FromString( "" ); + } + + if(free) + MEM_freeN(item); + + /*PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val); + ret = NULL;*/ } break; @@ -221,23 +384,15 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi const char *arg_name= NULL; PyObject *item; - PropertyRNA *prop, *iterprop; - CollectionPropertyIterator iter; - - iterprop= RNA_struct_iterator_property(ptr->type); - RNA_property_collection_begin(ptr, iterprop, &iter); - totkw = kw ? PyDict_Size(kw):0; - for(; iter.valid; RNA_property_collection_next(&iter)) { - prop= iter.ptr.data; - + RNA_STRUCT_BEGIN(ptr, prop) { arg_name= RNA_property_identifier(prop); if (strcmp(arg_name, "rna_type")==0) continue; if (kw==NULL) { - PyErr_Format( PyExc_AttributeError, "%s: no keywords, expected \"%s\"", error_prefix, arg_name ? arg_name : ""); + PyErr_Format( PyExc_AttributeError, "%.200s: no keywords, expected \"%.200s\"", error_prefix, arg_name ? arg_name : ""); error_val= -1; break; } @@ -245,7 +400,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi item= PyDict_GetItemString(kw, arg_name); if (item == NULL) { - PyErr_Format( PyExc_AttributeError, "%s: keyword \"%s\" missing", error_prefix, arg_name ? arg_name : ""); + PyErr_Format( PyExc_AttributeError, "%.200s: keyword \"%.200s\" missing", error_prefix, arg_name ? arg_name : ""); error_val = -1; /* pyrna_py_to_prop sets the error */ break; } @@ -257,8 +412,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi totkw--; } - - RNA_property_collection_end(&iter); + RNA_STRUCT_END; if (error_val==0 && totkw > 0) { /* some keywords were given that were not used :/ */ PyObject *key, *value; @@ -270,7 +424,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi arg_name= NULL; } - PyErr_Format( PyExc_AttributeError, "%s: keyword \"%s\" unrecognized", error_prefix, arg_name ? arg_name : ""); + PyErr_Format( PyExc_AttributeError, "%.200s: keyword \"%.200s\" unrecognized", error_prefix, arg_name ? arg_name : ""); error_val = -1; } @@ -279,12 +433,15 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw); -PyObject *pyrna_func_to_py(PointerRNA *ptr, FunctionRNA *func) +PyObject *pyrna_func_to_py(BPy_StructRNA *pyrna, FunctionRNA *func) { static PyMethodDef func_meth = {"", (PyCFunction)pyrna_func_call, METH_VARARGS|METH_KEYWORDS, "python rna function"}; PyObject *self= PyTuple_New(2); PyObject *ret; - PyTuple_SET_ITEM(self, 0, pyrna_struct_CreatePyObject(ptr)); + + PyTuple_SET_ITEM(self, 0, (PyObject *)pyrna); + Py_INCREF(pyrna); + PyTuple_SET_ITEM(self, 1, PyCObject_FromVoidPtr((void *)func, NULL)); ret= PyCFunction_New(&func_meth, self); @@ -302,15 +459,30 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v if (len > 0) { PyObject *item; + int py_len = -1; int i; - if (!PySequence_Check(value)) { - PyErr_SetString(PyExc_TypeError, "expected a python sequence type assigned to an RNA array."); + +#ifdef USE_MATHUTILS + if(MatrixObject_Check(value)) { + MatrixObject *mat = (MatrixObject*)value; + if(!BaseMath_ReadCallback(mat)) + return -1; + + py_len = mat->rowSize * mat->colSize; + } else /* continue... */ +#endif + if (PySequence_Check(value)) { + py_len= (int)PySequence_Length(value); + } + else { + PyErr_Format(PyExc_TypeError, "RNA array assignment expected a sequence instead of %.200s instance.", Py_TYPE(value)->tp_name); return -1; } + /* done getting the length */ - if ((int)PySequence_Length(value) != len) { - PyErr_SetString(PyExc_AttributeError, "python sequence length did not match the RNA array."); + if (py_len != len) { + PyErr_Format(PyExc_AttributeError, "python sequence length %d did not match the RNA array length %d.", py_len, len); return -1; } @@ -376,14 +548,21 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v else param_arr = MEM_mallocN(sizeof(float) * len, "pyrna float array"); - - /* collect the variables */ - for (i=0; icontigPtr, sizeof(float) * len); + } else /* continue... */ +#endif + { + /* collect the variables */ + for (i=0; iptr= itemptr; + BLI_addtail(lb, link); + } + else + RNA_property_collection_add(ptr, prop, &itemptr); + if(pyrna_pydict_to_props(&itemptr, item, "Converting a python list to an RNA collection")==-1) { Py_DECREF(item); return -1; @@ -667,117 +859,317 @@ static Py_ssize_t pyrna_prop_len( BPy_PropertyRNA * self ) return len; } -static PyObject *pyrna_prop_subscript( BPy_PropertyRNA * self, PyObject *key ) +/* internal use only */ +static PyObject *prop_subscript_collection_int(BPy_PropertyRNA * self, int keynum) { - PyObject *ret; PointerRNA newptr; - int keynum = 0; - char *keyname = NULL; - + + if(keynum < 0) keynum += RNA_property_collection_length(&self->ptr, self->prop); + + if(RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum, &newptr)) + return pyrna_struct_CreatePyObject(&newptr); + + PyErr_Format(PyExc_IndexError, "index %d out of range", keynum); + return NULL; +} +static PyObject *prop_subscript_array_int(BPy_PropertyRNA * self, int keynum) +{ + int len= RNA_property_array_length(self->prop); + + if(keynum < 0) keynum += len; + + if(keynum >= 0 && keynum < len) + return pyrna_prop_to_py_index(&self->ptr, self->prop, keynum); + + PyErr_Format(PyExc_IndexError, "index %d out of range", keynum); + return NULL; +} + +static PyObject *prop_subscript_collection_str(BPy_PropertyRNA * self, char *keyname) +{ + PointerRNA newptr; + if(RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr)) + return pyrna_struct_CreatePyObject(&newptr); + + PyErr_Format(PyExc_KeyError, "key \"%.200s\" not found", keyname); + return NULL; +} +/* static PyObject *prop_subscript_array_str(BPy_PropertyRNA * self, char *keyname) */ + + + + +#if PY_VERSION_HEX >= 0x03000000 +static PyObject *prop_subscript_collection_slice(BPy_PropertyRNA * self, int start, int stop) +{ + PointerRNA newptr; + PyObject *list = PyList_New(stop - start); + int count; + + start = MIN2(start,stop); /* values are clamped from */ + + for(count = start; count < stop; count++) { + if(RNA_property_collection_lookup_int(&self->ptr, self->prop, count - start, &newptr)) { + PyList_SetItem(list, count - start, pyrna_struct_CreatePyObject(&newptr)); + } + else { + Py_DECREF(list); + + PyErr_SetString(PyExc_RuntimeError, "error getting an rna struct from a collection"); + return NULL; + } + } + + return list; +} +static PyObject *prop_subscript_array_slice(BPy_PropertyRNA * self, int start, int stop) +{ + PyObject *list = PyList_New(stop - start); + int count; + + start = MIN2(start,stop); /* values are clamped from PySlice_GetIndicesEx */ + + for(count = start; count < stop; count++) + PyList_SetItem(list, count - start, pyrna_prop_to_py_index(&self->ptr, self->prop, count)); + + return list; +} +#endif + +static PyObject *prop_subscript_collection(BPy_PropertyRNA * self, PyObject *key) +{ if (PyUnicode_Check(key)) { - keyname = _PyUnicode_AsString(key); - } else if (PyLong_Check(key)) { - keynum = PyLong_AsSsize_t(key); - } else { - PyErr_SetString(PyExc_AttributeError, "invalid key, key must be a string or an int"); + return prop_subscript_collection_str(self, _PyUnicode_AsString(key)); + } + else if (PyIndex_Check(key)) { + Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + + return prop_subscript_collection_int(self, i); + } +#if PY_VERSION_HEX >= 0x03000000 + else if (PySlice_Check(key)) { + int len= RNA_property_collection_length(&self->ptr, self->prop); + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyList_New(0); + } + else if (step == 1) { + return prop_subscript_collection_slice(self, start, stop); + } + else { + PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna"); + return NULL; + } + } +#endif + else { + PyErr_Format(PyExc_TypeError, "invalid rna key, key must be a string or an int instead of %.200s instance.", Py_TYPE(key)->tp_name); return NULL; } - - if (RNA_property_type(self->prop) == PROP_COLLECTION) { - int ok; - if (keyname) ok = RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr); - else ok = RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum, &newptr); - - if (ok) { - ret = pyrna_struct_CreatePyObject(&newptr); - } else { - PyErr_SetString(PyExc_AttributeError, "out of range"); - ret = NULL; - } - - } else if (keyname) { - PyErr_SetString(PyExc_AttributeError, "string keys are only supported for collections"); - ret = NULL; - } else { - int len = RNA_property_array_length(self->prop); - - if (len==0) { /* not an array*/ - PyErr_Format(PyExc_AttributeError, "not an array or collection %d", keynum); - ret = NULL; - } - - if (keynum >= len){ - PyErr_SetString(PyExc_AttributeError, "index out of range"); - ret = NULL; - } else { /* not an array*/ - ret = pyrna_prop_to_py_index(&self->ptr, self->prop, keynum); - } - } - - return ret; } - -static int pyrna_prop_assign_subscript( BPy_PropertyRNA * self, PyObject *key, PyObject *value ) +static PyObject *prop_subscript_array(BPy_PropertyRNA * self, PyObject *key) { - int ret = 0; - int keynum = 0; - char *keyname = NULL; + /*if (PyUnicode_Check(key)) { + return prop_subscript_array_str(self, _PyUnicode_AsString(key)); + } else*/ + if (PyIndex_Check(key)) { + Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + return prop_subscript_array_int(self, PyLong_AsSsize_t(key)); + } +#if PY_VERSION_HEX >= 0x03000000 + else if (PySlice_Check(key)) { + int len= RNA_property_array_length(self->prop); + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyList_New(0); + } + else if (step == 1) { + return prop_subscript_array_slice(self, start, stop); + } + else { + PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna"); + return NULL; + } + } +#endif + else { + PyErr_SetString(PyExc_AttributeError, "invalid key, key must be an int"); + return NULL; + } +} + +static PyObject *pyrna_prop_subscript( BPy_PropertyRNA * self, PyObject *key ) +{ + if (RNA_property_type(self->prop) == PROP_COLLECTION) { + return prop_subscript_collection(self, key); + } else if (RNA_property_array_length(self->prop)) { /* arrays are currently fixed length, zero length means its not an array */ + return prop_subscript_array(self, key); + } else { + PyErr_SetString(PyExc_TypeError, "rna type is not an array or a collection"); + return NULL; + } + +} + +#if PY_VERSION_HEX >= 0x03000000 +static int prop_subscript_ass_array_slice(BPy_PropertyRNA * self, int begin, int end, PyObject *value) +{ + int count; + + /* values are clamped from */ + begin = MIN2(begin,end); + + for(count = begin; count < end; count++) { + if(pyrna_py_to_prop_index(&self->ptr, self->prop, count - begin, value) == -1) { + /* TODO - this is wrong since some values have been assigned... will need to fix that */ + return -1; /* pyrna_struct_CreatePyObject should set the error */ + } + } + + return 0; +} +#endif + +static int prop_subscript_ass_array_int(BPy_PropertyRNA * self, int keynum, PyObject *value) +{ + + int len= RNA_property_array_length(self->prop); + + if(keynum < 0) keynum += len; + + if(keynum >= 0 && keynum < len) + return pyrna_py_to_prop_index(&self->ptr, self->prop, keynum, value); + + PyErr_SetString(PyExc_IndexError, "out of range"); + return -1; +} + +static int pyrna_prop_ass_subscript( BPy_PropertyRNA * self, PyObject *key, PyObject *value ) +{ + /* char *keyname = NULL; */ /* not supported yet */ if (!RNA_property_editable(&self->ptr, self->prop)) { - PyErr_Format( PyExc_AttributeError, "PropertyRNA - attribute \"%s\" from \"%s\" is read-only", RNA_property_identifier(self->prop), RNA_struct_identifier(self->ptr.type) ); - return -1; - } - - if (PyUnicode_Check(key)) { - keyname = _PyUnicode_AsString(key); - } else if (PyLong_Check(key)) { - keynum = PyLong_AsSsize_t(key); - } else { - PyErr_SetString(PyExc_AttributeError, "PropertyRNA - invalid key, key must be a string or an int"); + PyErr_Format( PyExc_AttributeError, "PropertyRNA - attribute \"%.200s\" from \"%.200s\" is read-only", RNA_property_identifier(self->prop), RNA_struct_identifier(self->ptr.type) ); return -1; } + /* maybe one day we can support this... */ if (RNA_property_type(self->prop) == PROP_COLLECTION) { - PyErr_SetString(PyExc_AttributeError, "PropertyRNA - assignment is not supported for collections (yet)"); - ret = -1; - } else if (keyname) { - PyErr_SetString(PyExc_AttributeError, "PropertyRNA - string keys are only supported for collections"); - ret = -1; - } else { - int len = RNA_property_array_length(self->prop); - - if (len==0) { /* not an array*/ - PyErr_Format(PyExc_AttributeError, "PropertyRNA - not an array or collection %d", keynum); - ret = -1; + PyErr_Format( PyExc_AttributeError, "PropertyRNA - attribute \"%.200s\" from \"%.200s\" is a collection, assignment not supported", RNA_property_identifier(self->prop), RNA_struct_identifier(self->ptr.type) ); + return -1; + } + + if (PyIndex_Check(key)) { + Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + + return prop_subscript_ass_array_int(self, i, value); + } +#if PY_VERSION_HEX >= 0x03000000 + else if (PySlice_Check(key)) { + int len= RNA_property_array_length(self->prop); + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0) + return -1; + + if (slicelength <= 0) { + return 0; } - - if (keynum >= len){ - PyErr_SetString(PyExc_AttributeError, "PropertyRNA - index out of range"); - ret = -1; - } else { - ret = pyrna_py_to_prop_index(&self->ptr, self->prop, keynum, value); + else if (step == 1) { + return prop_subscript_ass_array_slice(self, start, stop, value); + } + else { + PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna"); + return -1; } } - - return ret; +#endif + else { + PyErr_SetString(PyExc_AttributeError, "invalid key, key must be an int"); + return -1; + } } - static PyMappingMethods pyrna_prop_as_mapping = { ( lenfunc ) pyrna_prop_len, /* mp_length */ ( binaryfunc ) pyrna_prop_subscript, /* mp_subscript */ - ( objobjargproc ) pyrna_prop_assign_subscript, /* mp_ass_subscript */ + ( objobjargproc ) pyrna_prop_ass_subscript, /* mp_ass_subscript */ }; +static int pyrna_prop_contains(BPy_PropertyRNA * self, PyObject *value) +{ + PointerRNA newptr; /* not used, just so RNA_property_collection_lookup_string runs */ + char *keyname = _PyUnicode_AsString(value); + + if(keyname==NULL) { + PyErr_SetString(PyExc_TypeError, "PropertyRNA - key in prop, key must be a string type"); + return -1; + } + + if (RNA_property_type(self->prop) != PROP_COLLECTION) { + PyErr_SetString(PyExc_TypeError, "PropertyRNA - key in prop, is only valid for collection types"); + return -1; + } + + + if (RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr)) + return 1; + + return 0; +} + +static PySequenceMethods pyrna_prop_as_sequence = { + NULL, /* Cant set the len otherwise it can evaluate as false */ + NULL, /* sq_concat */ + NULL, /* sq_repeat */ + NULL, /* sq_item */ + NULL, /* sq_slice */ + NULL, /* sq_ass_item */ + NULL, /* sq_ass_slice */ + (objobjproc)pyrna_prop_contains, /* sq_contains */ +}; + + +static PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA * self, PyObject *args) +{ + char *path; + int index= 0; + float cfra = CTX_data_scene(BPy_GetContext())->r.cfra; + + if(!RNA_struct_is_ID(self->ptr.type)) { + PyErr_SetString( PyExc_TypeError, "StructRNA - keyframe_insert only for ID type"); + return NULL; + } + + if (!PyArg_ParseTuple(args, "s|if:keyframe_insert", &path, &index, &cfra)) + return NULL; + + return PyBool_FromLong( insert_keyframe((ID *)self->ptr.data, NULL, NULL, path, index, cfra, 0)); +} + + static PyObject *pyrna_struct_dir(BPy_StructRNA * self) { PyObject *ret, *dict; PyObject *pystring; /* for looping over attrs and funcs */ - CollectionPropertyIterator iter; PropertyRNA *iterprop; /* Include this incase this instance is a subtype of a python class @@ -806,26 +1198,23 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA * self) /* * Collect RNA attributes */ - PropertyRNA *nameprop; char name[256], *nameptr; iterprop= RNA_struct_iterator_property(self->ptr.type); - RNA_property_collection_begin(&self->ptr, iterprop, &iter); - for(; iter.valid; RNA_property_collection_next(&iter)) { - if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) { - nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name)); - + RNA_PROP_BEGIN(&self->ptr, itemptr, iterprop) { + nameptr= RNA_struct_name_get_alloc(&itemptr, name, sizeof(name)); + + if(nameptr) { pystring = PyUnicode_FromString(nameptr); PyList_Append(ret, pystring); Py_DECREF(pystring); - if ((char *)&name != nameptr) + if(name != nameptr) MEM_freeN(nameptr); } } - RNA_property_collection_end(&iter); - + RNA_PROP_END; } @@ -838,15 +1227,25 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA * self) RNA_pointer_create(NULL, &RNA_Struct, self->ptr.type, &tptr); iterprop= RNA_struct_find_property(&tptr, "functions"); - RNA_property_collection_begin(&tptr, iterprop, &iter); + RNA_PROP_BEGIN(&tptr, itemptr, iterprop) { + pystring = PyUnicode_FromString(RNA_function_identifier(itemptr.data)); + PyList_Append(ret, pystring); + Py_DECREF(pystring); + } + RNA_PROP_END; + } - for(; iter.valid; RNA_property_collection_next(&iter)) { - pystring = PyUnicode_FromString(RNA_function_identifier(iter.ptr.data)); + if(self->ptr.type == &RNA_Context) { + ListBase lb = CTX_data_dir_get(self->ptr.data); + LinkData *link; + + for(link=lb.first; link; link=link->next) { + pystring = PyUnicode_FromString(link->data); PyList_Append(ret, pystring); Py_DECREF(pystring); } - RNA_property_collection_end(&iter); + BLI_freelistN(&lb); } return ret; @@ -875,7 +1274,7 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) ret = pyrna_prop_to_py(&self->ptr, prop); } else if ((func = RNA_struct_find_function(&self->ptr, name))) { - ret = pyrna_func_to_py(&self->ptr, func); + ret = pyrna_func_to_py(self, func); } else if (self->ptr.type == &RNA_Context) { PointerRNA newptr; @@ -906,7 +1305,7 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) BLI_freelistN(&newlb); } else { - PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%s\" not found", name); + PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" not found", name); ret = NULL; } @@ -924,13 +1323,13 @@ static int pyrna_struct_setattro( BPy_StructRNA * self, PyObject *pyname, PyObje return 0; } else { - PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%s\" not found", name); + PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" not found", name); return -1; } } if (!RNA_property_editable(&self->ptr, prop)) { - PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%s\" from \"%s\" is read-only", RNA_property_identifier(prop), RNA_struct_identifier(self->ptr.type) ); + PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" from \"%.200s\" is read-only", RNA_property_identifier(prop), RNA_struct_identifier(self->ptr.type) ); return -1; } @@ -938,7 +1337,7 @@ static int pyrna_struct_setattro( BPy_StructRNA * self, PyObject *pyname, PyObje return pyrna_py_to_prop(&self->ptr, prop, NULL, value); } -PyObject *pyrna_prop_keys(BPy_PropertyRNA *self) +static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self) { PyObject *ret; if (RNA_property_type(self->prop) != PROP_COLLECTION) { @@ -946,34 +1345,31 @@ PyObject *pyrna_prop_keys(BPy_PropertyRNA *self) ret = NULL; } else { PyObject *item; - CollectionPropertyIterator iter; - PropertyRNA *nameprop; char name[256], *nameptr; ret = PyList_New(0); - RNA_property_collection_begin(&self->ptr, self->prop, &iter); - for(; iter.valid; RNA_property_collection_next(&iter)) { - if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) { - nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name)); - + RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) { + nameptr= RNA_struct_name_get_alloc(&itemptr, name, sizeof(name)); + + if(nameptr) { /* add to python list */ item = PyUnicode_FromString( nameptr ); PyList_Append(ret, item); Py_DECREF(item); /* done */ - if ((char *)&name != nameptr) + if(name != nameptr) MEM_freeN(nameptr); } } - RNA_property_collection_end(&iter); + RNA_PROP_END; } return ret; } -PyObject *pyrna_prop_items(BPy_PropertyRNA *self) +static PyObject *pyrna_prop_items(BPy_PropertyRNA *self) { PyObject *ret; if (RNA_property_type(self->prop) != PROP_COLLECTION) { @@ -981,61 +1377,316 @@ PyObject *pyrna_prop_items(BPy_PropertyRNA *self) ret = NULL; } else { PyObject *item; - CollectionPropertyIterator iter; - PropertyRNA *nameprop; char name[256], *nameptr; + int i= 0; ret = PyList_New(0); - RNA_property_collection_begin(&self->ptr, self->prop, &iter); - for(; iter.valid; RNA_property_collection_next(&iter)) { - if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) { - nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name)); - + RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) { + if(itemptr.data) { /* add to python list */ - item = Py_BuildValue("(NN)", PyUnicode_FromString( nameptr ), pyrna_struct_CreatePyObject(&iter.ptr)); + item= PyTuple_New(2); + nameptr= RNA_struct_name_get_alloc(&itemptr, name, sizeof(name)); + if(nameptr) { + PyTuple_SET_ITEM(item, 0, PyUnicode_FromString( nameptr )); + if(name != nameptr) + MEM_freeN(nameptr); + } + else { + PyTuple_SET_ITEM(item, 0, PyLong_FromSsize_t(i)); /* a bit strange but better then returning an empty list */ + } + PyTuple_SET_ITEM(item, 1, pyrna_struct_CreatePyObject(&itemptr)); + PyList_Append(ret, item); Py_DECREF(item); - /* done */ - if ((char *)&name != nameptr) - MEM_freeN(nameptr); + i++; } } - RNA_property_collection_end(&iter); + RNA_PROP_END; } return ret; } -PyObject *pyrna_prop_values(BPy_PropertyRNA *self) +static PyObject *pyrna_prop_values(BPy_PropertyRNA *self) { PyObject *ret; + if (RNA_property_type(self->prop) != PROP_COLLECTION) { PyErr_SetString( PyExc_TypeError, "values() is only valid for collection types" ); ret = NULL; } else { PyObject *item; - CollectionPropertyIterator iter; - PropertyRNA *nameprop; - ret = PyList_New(0); - RNA_property_collection_begin(&self->ptr, self->prop, &iter); - for(; iter.valid; RNA_property_collection_next(&iter)) { - if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) { - item = pyrna_struct_CreatePyObject(&iter.ptr); - PyList_Append(ret, item); - Py_DECREF(item); - } + RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) { + item = pyrna_struct_CreatePyObject(&itemptr); + PyList_Append(ret, item); + Py_DECREF(item); } - RNA_property_collection_end(&iter); + RNA_PROP_END; } return ret; } +static PyObject *pyrna_prop_get(BPy_PropertyRNA *self, PyObject *args) +{ + PointerRNA newptr; + + char *key; + PyObject* def = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) + return NULL; + + if(RNA_property_collection_lookup_string(&self->ptr, self->prop, key, &newptr)) + return pyrna_struct_CreatePyObject(&newptr); + + Py_INCREF(def); + return def; +} + + +#if (PY_VERSION_HEX >= 0x03000000) /* foreach needs py3 */ +static void foreach_attr_type( BPy_PropertyRNA *self, char *attr, + /* values to assign */ + RawPropertyType *raw_type, int *attr_tot, int *attr_signed ) +{ + PropertyRNA *prop; + *raw_type= -1; + *attr_tot= 0; + *attr_signed= 0; + + RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) { + prop = RNA_struct_find_property(&itemptr, attr); + *raw_type= RNA_property_raw_type(prop); + *attr_tot = RNA_property_array_length(prop); + *attr_signed= (RNA_property_subtype(prop)==PROP_UNSIGNED) ? 0:1; + break; + } + RNA_PROP_END; +} + +/* pyrna_prop_foreach_get/set both use this */ +static int foreach_parse_args( + BPy_PropertyRNA *self, PyObject *args, + + /*values to assign */ + char **attr, PyObject **seq, int *tot, int *size, RawPropertyType *raw_type, int *attr_tot, int *attr_signed) +{ +#if 0 + int array_tot; + int target_tot; +#endif + + *size= *raw_type= *attr_tot= *attr_signed= 0; + + if(!PyArg_ParseTuple(args, "sO", attr, seq) || (!PySequence_Check(*seq) && PyObject_CheckBuffer(*seq))) { + PyErr_SetString( PyExc_TypeError, "foreach_get(attr, sequence) expects a string and a sequence" ); + return -1; + } + + *tot= PySequence_Length(*seq); // TODO - buffer may not be a sequence! array.array() is tho. + + if(*tot>0) { + foreach_attr_type(self, *attr, raw_type, attr_tot, attr_signed); + *size= RNA_raw_type_sizeof(*raw_type); + +#if 0 // works fine but not strictly needed, we could allow RNA_property_collection_raw_* to do the checks + if((*attr_tot) < 1) + *attr_tot= 1; + + if (RNA_property_type(self->prop) == PROP_COLLECTION) + array_tot = RNA_property_collection_length(&self->ptr, self->prop); + else + array_tot = RNA_property_array_length(self->prop); + + + target_tot= array_tot * (*attr_tot); + + /* rna_access.c - rna_raw_access(...) uses this same method */ + if(target_tot != (*tot)) { + PyErr_Format( PyExc_TypeError, "foreach_get(attr, sequence) sequence length mismatch given %d, needed %d", *tot, target_tot); + return -1; + } +#endif + } + + return 0; +} + +static int foreach_compat_buffer(RawPropertyType raw_type, int attr_signed, const char *format) +{ + char f = format ? *format:'B'; /* B is assumed when not set */ + + switch(raw_type) { + case PROP_RAW_CHAR: + if (attr_signed) return (f=='b') ? 1:0; + else return (f=='B') ? 1:0; + case PROP_RAW_SHORT: + if (attr_signed) return (f=='h') ? 1:0; + else return (f=='H') ? 1:0; + case PROP_RAW_INT: + if (attr_signed) return (f=='i') ? 1:0; + else return (f=='I') ? 1:0; + case PROP_RAW_FLOAT: + return (f=='f') ? 1:0; + case PROP_RAW_DOUBLE: + return (f=='d') ? 1:0; + } + + return 0; +} + +static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set) +{ + PyObject *item; + int i=0, ok, buffer_is_compat; + void *array= NULL; + + /* get/set both take the same args currently */ + char *attr; + PyObject *seq; + int tot, size, attr_tot, attr_signed; + RawPropertyType raw_type; + + if(foreach_parse_args(self, args, &attr, &seq, &tot, &size, &raw_type, &attr_tot, &attr_signed) < 0) + return NULL; + + if(tot==0) + Py_RETURN_NONE; + + + + if(set) { /* get the array from python */ + buffer_is_compat = 0; + if(PyObject_CheckBuffer(seq)) { + Py_buffer buf; + PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT); + + /* check if the buffer matches */ + + buffer_is_compat = foreach_compat_buffer(raw_type, attr_signed, buf.format); + + if(buffer_is_compat) { + ok = RNA_property_collection_raw_set(NULL, &self->ptr, self->prop, attr, buf.buf, raw_type, tot); + } + + PyBuffer_Release(&buf); + } + + /* could not use the buffer, fallback to sequence */ + if(!buffer_is_compat) { + array= PyMem_Malloc(size * tot); + + for( ; iptr, self->prop, attr, array, raw_type, tot); + } + } + else { + buffer_is_compat = 0; + if(PyObject_CheckBuffer(seq)) { + Py_buffer buf; + PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT); + + /* check if the buffer matches, TODO - signed/unsigned types */ + + buffer_is_compat = foreach_compat_buffer(raw_type, attr_signed, buf.format); + + if(buffer_is_compat) { + ok = RNA_property_collection_raw_get(NULL, &self->ptr, self->prop, attr, buf.buf, raw_type, tot); + } + + PyBuffer_Release(&buf); + } + + /* could not use the buffer, fallback to sequence */ + if(!buffer_is_compat) { + array= PyMem_Malloc(size * tot); + + ok = RNA_property_collection_raw_get(NULL, &self->ptr, self->prop, attr, array, raw_type, tot); + + if(!ok) i= tot; /* skip the loop */ + + for( ; i= 0x03000000) */ + /* A bit of a kludge, make a list out of a collection or array, * then return the lists iter function, not especially fast but convenient for now */ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self) @@ -1070,14 +1721,26 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self) } static struct PyMethodDef pyrna_struct_methods[] = { - {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, ""}, + + /* maybe this become and ID function */ + {"keyframe_insert", (PyCFunction)pyrna_struct_keyframe_insert, METH_VARARGS, NULL}, + + {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL} }; static struct PyMethodDef pyrna_prop_methods[] = { - {"keys", (PyCFunction)pyrna_prop_keys, METH_NOARGS, ""}, - {"items", (PyCFunction)pyrna_prop_items, METH_NOARGS, ""}, - {"values", (PyCFunction)pyrna_prop_values, METH_NOARGS, ""}, + {"keys", (PyCFunction)pyrna_prop_keys, METH_NOARGS, NULL}, + {"items", (PyCFunction)pyrna_prop_items, METH_NOARGS,NULL}, + {"values", (PyCFunction)pyrna_prop_values, METH_NOARGS, NULL}, + + {"get", (PyCFunction)pyrna_prop_get, METH_VARARGS, NULL}, + +#if (PY_VERSION_HEX >= 0x03000000) + /* array accessor function */ + {"foreach_get", (PyCFunction)pyrna_prop_foreach_get, METH_VARARGS, NULL}, + {"foreach_set", (PyCFunction)pyrna_prop_foreach_set, METH_VARARGS, NULL}, +#endif {NULL, NULL, 0, NULL} }; @@ -1171,11 +1834,17 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) const char *identifier; int val = *(int*)data; - if (RNA_property_enum_identifier(ptr, prop, val, &identifier)) { + if (RNA_property_enum_identifier(BPy_GetContext(), ptr, prop, val, &identifier)) { ret = PyUnicode_FromString( identifier ); } else { - PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val); - ret = NULL; + /* prefer not fail silently incase of api errors, maybe disable it later */ + char error_str[128]; + sprintf(error_str, "RNA Warning: Current value \"%d\" matches no enum", val); + PyErr_Warn(PyExc_RuntimeWarning, error_str); + + ret = PyUnicode_FromString( "" ); + /*PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val); + ret = NULL;*/ } break; @@ -1184,8 +1853,9 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) { PointerRNA newptr; StructRNA *type= RNA_property_pointer_type(ptr, prop); + int flag = RNA_property_flag(prop); - if(type == &RNA_AnyType) { + if(flag & PROP_RNAPTR) { /* in this case we get the full ptr */ newptr= *(PointerRNA*)data; } @@ -1203,10 +1873,21 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) break; } case PROP_COLLECTION: - /* XXX not supported yet - * ret = pyrna_prop_CreatePyObject(ptr, prop); */ - ret = NULL; + { + ListBase *lb= (ListBase*)data; + CollectionPointerLink *link; + PyObject *linkptr; + + ret = PyList_New(0); + + for(link=lb->first; link; link=link->next) { + linkptr= pyrna_struct_CreatePyObject(&link->ptr); + PyList_Append(ret, linkptr); + Py_DECREF(linkptr); + } + break; + } default: PyErr_Format(PyExc_AttributeError, "RNA Error: unknown type \"%d\" (pyrna_param_to_py)", type); ret = NULL; @@ -1265,7 +1946,7 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw) tid= RNA_struct_identifier(self_ptr->type); fid= RNA_function_identifier(self_func); - PyErr_Format(PyExc_AttributeError, "%s.%s(): required parameter \"%s\" not specified", tid, fid, pid); + PyErr_Format(PyExc_AttributeError, "%.200s.%.200s(): required parameter \"%.200s\" not specified", tid, fid, pid); err= -1; break; } @@ -1282,11 +1963,19 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw) ret= NULL; if (err==0) { /* call function */ - RNA_function_call(self_ptr, self_func, parms); + ReportList reports; + bContext *C= BPy_GetContext(); + + BKE_reports_init(&reports, RPT_STORE); + RNA_function_call(C, &reports, self_ptr, self_func, parms); + + err= (BPy_reports_to_error(&reports))? -1: 0; + BKE_reports_clear(&reports); /* return value */ - if(pret) - ret= pyrna_param_to_py(&funcptr, pret, retdata); + if(err==0) + if(pret) + ret= pyrna_param_to_py(&funcptr, pret, retdata); } /* cleanup */ @@ -1375,7 +2064,7 @@ PyTypeObject pyrna_struct_Type = { NULL, /* allocfunc tp_alloc; */ pyrna_struct_new, /* newfunc tp_new; */ /* Low-level free-memory routine */ - NULL, //MEM_freeN, /* freefunc tp_free; */ + NULL, /* freefunc tp_free; */ /* For PyObject_IS_GC */ NULL, /* inquiry tp_is_gc; */ NULL, /* PyObject *tp_bases; */ @@ -1401,7 +2090,7 @@ PyTypeObject pyrna_prop_Type = { sizeof( BPy_PropertyRNA ), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - NULL, /* tp_dealloc */ + NULL, /* tp_dealloc */ NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ @@ -1411,7 +2100,7 @@ PyTypeObject pyrna_prop_Type = { /* Method suites for standard classes */ NULL, /* PyNumberMethods *tp_as_number; */ - NULL, /* PySequenceMethods *tp_as_sequence; */ + &pyrna_prop_as_sequence, /* PySequenceMethods *tp_as_sequence; */ &pyrna_prop_as_mapping, /* PyMappingMethods *tp_as_mapping; */ /* More standard operations (here for binary compatibility) */ @@ -1461,7 +2150,7 @@ PyTypeObject pyrna_prop_Type = { NULL, /* allocfunc tp_alloc; */ pyrna_prop_new, /* newfunc tp_new; */ /* Low-level free-memory routine */ - NULL, //MEM_freeN, /* freefunc tp_free; */ + NULL, /* freefunc tp_free; */ /* For PyObject_IS_GC */ NULL, /* inquiry tp_is_gc; */ NULL, /* PyObject *tp_bases; */ @@ -1496,43 +2185,52 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna) /* done with rna instance */ } -PyObject* pyrna_struct_Subtype(PointerRNA *ptr) +PyObject* pyrna_srna_Subtype(StructRNA *srna) { PyObject *newclass = NULL; - PropertyRNA *nameprop; - if (ptr->type==NULL) { + if (srna == NULL) { newclass= NULL; /* Nothing to do */ - } else if ((newclass= RNA_struct_py_type_get(ptr->data))) { + } else if ((newclass= RNA_struct_py_type_get(srna))) { Py_INCREF(newclass); - } else if ((nameprop = RNA_struct_name_property(ptr->type))) { + } else { + StructRNA *base; + /* for now, return the base RNA type rather then a real module */ - /* Assume RNA_struct_py_type_get(ptr->data) was alredy checked */ + /* Assume RNA_struct_py_type_get(srna) was alredy checked */ /* subclass equivelents - class myClass(myBase): some='value' # or ... - - myClass = type(name='myClass', bases=(myBase,), dict={'some':'value'}) + - myClass = type(name='myClass', bases=(myBase,), dict={'__module__':'bpy.types'}) */ - char name[256], *nameptr; - const char *descr= RNA_struct_ui_description(ptr->type); + const char *descr= RNA_struct_ui_description(srna); PyObject *args = PyTuple_New(3); PyObject *bases = PyTuple_New(1); + PyObject *py_base= NULL; PyObject *dict = PyDict_New(); PyObject *item; - - - nameptr= RNA_property_string_get_alloc(ptr, nameprop, name, sizeof(name)); + // arg 1 //PyTuple_SET_ITEM(args, 0, PyUnicode_FromString(tp_name)); - PyTuple_SET_ITEM(args, 0, PyUnicode_FromString(nameptr)); + PyTuple_SET_ITEM(args, 0, PyUnicode_FromString(RNA_struct_identifier(srna))); // arg 2 - PyTuple_SET_ITEM(bases, 0, (PyObject *)&pyrna_struct_Type); - Py_INCREF(&pyrna_struct_Type); + base= RNA_struct_base(srna); + if(base && base != srna) { + /*/printf("debug subtype %s %p\n", RNA_struct_identifier(srna), srna); */ + py_base= pyrna_srna_Subtype(base); + } + + if(py_base==NULL) { + py_base= (PyObject *)&pyrna_struct_Type; + Py_INCREF(py_base); + } + + PyTuple_SET_ITEM(bases, 0, py_base); PyTuple_SET_ITEM(args, 1, bases); @@ -1543,6 +2241,13 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) Py_DECREF(item); } + /* this isnt needed however its confusing if we get python script names in blender types, + * because the __module__ is used when printing the class */ + item= PyUnicode_FromString("bpy.types"); /* just to know its an internal type */ + PyDict_SetItemString(dict, "__module__", item); + Py_DECREF(item); + + PyTuple_SET_ITEM(args, 2, dict); // fill with useful subclass things! if (PyErr_Occurred()) { @@ -1553,16 +2258,25 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) newclass = PyObject_CallObject((PyObject *)&PyType_Type, args); Py_DECREF(args); - if (newclass) - pyrna_subtype_set_rna(newclass, ptr->data); - - if (name != nameptr) - MEM_freeN(nameptr); + if (newclass) { + pyrna_subtype_set_rna(newclass, srna); + // PyObSpit("NewStructRNA Type: ", (PyObject *)newclass); + } + else { + /* this should not happen */ + PyErr_Print(); + PyErr_Clear(); + } } return newclass; } +PyObject* pyrna_struct_Subtype(PointerRNA *ptr) +{ + return pyrna_srna_Subtype((ptr->type == &RNA_Struct) ? ptr->data : ptr->type); +} + /*-----------------------CreatePyObject---------------------------------*/ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) { @@ -1571,8 +2285,7 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) if (ptr->data==NULL && ptr->type==NULL) { /* Operator RNA has NULL data */ Py_RETURN_NONE; } - - if (ptr->type == &RNA_Struct) { /* always return a python subtype from rna struct types */ + else { PyTypeObject *tp = (PyTypeObject *)pyrna_struct_Subtype(ptr); if (tp) { @@ -1580,13 +2293,11 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) } else { fprintf(stderr, "Could not make type\n"); - pyrna = ( BPy_StructRNA * ) bpy_PyObject_New( BPy_StructRNA, &pyrna_struct_Type ); + pyrna = ( BPy_StructRNA * ) PyObject_NEW( BPy_StructRNA, &pyrna_struct_Type ); + Py_INCREF(pyrna); } } - else { - pyrna = ( BPy_StructRNA * ) bpy_PyObject_New( BPy_StructRNA, &pyrna_struct_Type ); - } - + if( !pyrna ) { PyErr_SetString( PyExc_MemoryError, "couldn't create BPy_StructRNA object" ); return NULL; @@ -1594,6 +2305,9 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) pyrna->ptr= *ptr; pyrna->freeptr= 0; + + // PyObSpit("NewStructRNA: ", (PyObject *)pyrna); + return ( PyObject * ) pyrna; } @@ -1601,7 +2315,8 @@ PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop ) { BPy_PropertyRNA *pyrna; - pyrna = ( BPy_PropertyRNA * ) bpy_PyObject_New( BPy_PropertyRNA, &pyrna_prop_Type ); + pyrna = ( BPy_PropertyRNA * ) PyObject_NEW( BPy_PropertyRNA, &pyrna_prop_Type ); + Py_INCREF(pyrna); if( !pyrna ) { PyErr_SetString( PyExc_MemoryError, "couldn't create BPy_rna object" ); @@ -1618,6 +2333,11 @@ PyObject *BPY_rna_module( void ) { PointerRNA ptr; +#ifdef USE_MATHUTILS // register mathutils callbacks, ok to run more then once. + mathutils_rna_array_cb_index= Mathutils_RegisterCallback(&mathutils_rna_array_cb); + mathutils_rna_matrix_cb_index= Mathutils_RegisterCallback(&mathutils_rna_matrix_cb); +#endif + /* This can't be set in the pytype struct because some compilers complain */ pyrna_prop_Type.tp_getattro = PyObject_GenericGetAttr; pyrna_prop_Type.tp_setattro = PyObject_GenericSetAttr; @@ -1664,12 +2384,12 @@ static PyObject *pyrna_basetype_getattro( BPy_BaseTypeRNA * self, PyObject *pyna if (RNA_property_collection_lookup_string(&self->ptr, self->prop, _PyUnicode_AsString(pyname), &newptr)) { ret= pyrna_struct_Subtype(&newptr); if (ret==NULL) { - PyErr_Format(PyExc_SystemError, "bpy.types.%s subtype could not be generated, this is a bug!", _PyUnicode_AsString(pyname)); + PyErr_Format(PyExc_SystemError, "bpy.types.%.200s subtype could not be generated, this is a bug!", _PyUnicode_AsString(pyname)); } return ret; } else { /* Override the error */ - PyErr_Format(PyExc_AttributeError, "bpy.types.%s not a valid RNA_Struct", _PyUnicode_AsString(pyname)); + PyErr_Format(PyExc_AttributeError, "bpy.types.%.200s not a valid RNA_Struct", _PyUnicode_AsString(pyname)); return NULL; } } @@ -1710,14 +2430,14 @@ PyObject *BPY_rna_types(void) pyrna_basetype_Type.tp_getattro = ( getattrofunc )pyrna_basetype_getattro; pyrna_basetype_Type.tp_flags = Py_TPFLAGS_DEFAULT; pyrna_basetype_Type.tp_methods = pyrna_basetype_methods; - //pyrna_basetype_Type.tp_free = MEM_freeN; if( PyType_Ready( &pyrna_basetype_Type ) < 0 ) return NULL; } - self= (BPy_BaseTypeRNA *)bpy_PyObject_New( BPy_BaseTypeRNA, &pyrna_basetype_Type ); - + self= (BPy_BaseTypeRNA *)PyObject_NEW( BPy_BaseTypeRNA, &pyrna_basetype_Type ); + Py_INCREF(self); + /* avoid doing this lookup for every getattr */ RNA_blender_rna_pointer_create(&self->ptr); self->prop = RNA_struct_find_property(&self->ptr, "structs"); @@ -1725,7 +2445,44 @@ PyObject *BPY_rna_types(void) return (PyObject *)self; } +static struct PyMethodDef props_methods[] = { + {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {NULL, NULL, 0, NULL} +}; +#if PY_VERSION_HEX >= 0x03000000 +static struct PyModuleDef props_module = { + PyModuleDef_HEAD_INIT, + "bpyprops", + "", + -1,/* multiple "initialization" just copies the module dict. */ + props_methods, + NULL, NULL, NULL, NULL +}; +#endif + +PyObject *BPY_rna_props( void ) +{ + PyObject *submodule, *mod; +#if PY_VERSION_HEX >= 0x03000000 + submodule= PyModule_Create(&props_module); +#else /* Py2.x */ + submodule= Py_InitModule3( "bpy.props", props_methods, "" ); +#endif + + mod = PyModule_New("props"); + PyModule_AddObject( submodule, "props", mod ); + + /* INCREF since its its assumed that all these functions return the + * module with a new ref like PyDict_New, since they are passed to + * PyModule_AddObject which steals a ref */ + Py_INCREF(submodule); + + return submodule; +} /* Orphan functions, not sure where they should go */ @@ -1745,7 +2502,7 @@ PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; } - if (self) { + if (self && PyCObject_Check(self)) { StructRNA *srna = PyCObject_AsVoidPtr(self); RNA_def_float(srna, id, def, min, max, name, description, soft_min, soft_max); Py_RETURN_NONE; @@ -1772,7 +2529,7 @@ PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; } - if (self) { + if (self && PyCObject_Check(self)) { StructRNA *srna = PyCObject_AsVoidPtr(self); RNA_def_int(srna, id, def, min, max, name, description, soft_min, soft_max); Py_RETURN_NONE; @@ -1791,7 +2548,7 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) char *id, *name="", *description=""; int def=0; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssi:IntProperty", kwlist, &id, &name, &description, &def)) + if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssi:BoolProperty", kwlist, &id, &name, &description, &def)) return NULL; if (PyTuple_Size(args) > 0) { @@ -1799,13 +2556,40 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; } - if (self) { + if (self && PyCObject_Check(self)) { StructRNA *srna = PyCObject_AsVoidPtr(self); RNA_def_boolean(srna, id, def, name, description); Py_RETURN_NONE; } else { PyObject *ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_IntProperty, NULL)); + PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_BoolProperty, NULL)); + PyTuple_SET_ITEM(ret, 1, kw); + Py_INCREF(kw); + return ret; + } +} + +PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) +{ + static char *kwlist[] = {"attr", "name", "description", "maxlen", "default", NULL}; + char *id, *name="", *description="", *def=""; + int maxlen=0; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssis:StringProperty", kwlist, &id, &name, &description, &maxlen, &def)) + return NULL; + + if (PyTuple_Size(args) > 0) { + PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this. + return NULL; + } + + if (self && PyCObject_Check(self)) { + StructRNA *srna = PyCObject_AsVoidPtr(self); + RNA_def_string(srna, id, def, maxlen, name, description); + Py_RETURN_NONE; + } else { + PyObject *ret = PyTuple_New(2); + PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_StringProperty, NULL)); PyTuple_SET_ITEM(ret, 1, kw); Py_INCREF(kw); return ret; @@ -1848,7 +2632,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun if (base_class) { if (!PyObject_IsSubclass(py_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):""); + PyErr_Format( PyExc_AttributeError, "expected %.200s subclass of class \"%.200s\"", class_type, name ? _PyUnicode_AsString(name):""); Py_XDECREF(name); return -1; } @@ -1871,7 +2655,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun if (item==NULL) { if ((flag & FUNC_REGISTER_OPTIONAL)==0) { - PyErr_Format( PyExc_AttributeError, "expected %s class to have an \"%s\" attribute", class_type, RNA_function_identifier(func)); + PyErr_Format( PyExc_AttributeError, "expected %.200s class to have an \"%.200s\" attribute", class_type, RNA_function_identifier(func)); return -1; } @@ -1886,7 +2670,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun 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, RNA_function_identifier(func)); + PyErr_Format( PyExc_AttributeError, "expected %.200s class \"%.200s\" attribute to be a function", class_type, RNA_function_identifier(func)); return -1; } @@ -1898,7 +2682,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun Py_DECREF(py_arg_count); if (arg_count != func_arg_count) { - PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" function to have %d args", class_type, RNA_function_identifier(func), func_arg_count); + PyErr_Format( PyExc_AttributeError, "expected %.200s class \"%.200s\" function to have %d args", class_type, RNA_function_identifier(func), func_arg_count); return -1; } } @@ -1930,7 +2714,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun } if (item==NULL && (flag & PROP_REGISTER_OPTIONAL)==0) { - PyErr_Format( PyExc_AttributeError, "expected %s class to have an \"%s\" attribute", class_type, identifier); + PyErr_Format( PyExc_AttributeError, "expected %.200s class to have an \"%.200s\" attribute", class_type, identifier); return -1; } @@ -2014,12 +2798,12 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par } else { Py_DECREF(py_class_instance); - PyErr_Format(PyExc_AttributeError, "could not find function %s in %s to execute callback.", RNA_function_identifier(func), RNA_struct_identifier(ptr->type)); + PyErr_Format(PyExc_AttributeError, "could not find function %.200s in %.200s to execute callback.", RNA_function_identifier(func), RNA_struct_identifier(ptr->type)); err= -1; } } else { - PyErr_Format(PyExc_AttributeError, "could not create instance of %s to call callback function %s.", RNA_struct_identifier(ptr->type), RNA_function_identifier(func)); + PyErr_Format(PyExc_AttributeError, "could not create instance of %.200s to call callback function %.200s.", RNA_struct_identifier(ptr->type), RNA_function_identifier(func)); err= -1; } @@ -2094,7 +2878,7 @@ PyObject *pyrna_basetype_register(PyObject *self, PyObject *args) C= BPy_GetContext(); /* call the register callback */ - BKE_reports_init(&reports, RPT_PRINT); + BKE_reports_init(&reports, RPT_STORE); srna= reg(C, &reports, py_class, bpy_class_validate, bpy_class_call, bpy_class_free); if(!srna) { diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index a2a3015912b..cea6993cce5 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: bpy_rna.h 21094 2009-06-23 00:09:26Z gsrb3d $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -63,6 +63,7 @@ typedef struct { PyObject *BPY_rna_module( void ); /*PyObject *BPY_rna_doc( void );*/ PyObject *BPY_rna_types( void ); +PyObject *BPY_rna_props( void ); PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ); PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop ); @@ -76,6 +77,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop); PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw); PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw); PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw); +PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw); /* function for registering types */ PyObject *pyrna_basetype_register(PyObject *self, PyObject *args); diff --git a/source/blender/python/intern/bpy_ui.c b/source/blender/python/intern/bpy_ui.c index c15315ca350..453a9c748b8 100644 --- a/source/blender/python/intern/bpy_ui.c +++ b/source/blender/python/intern/bpy_ui.c @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: bpy_ui.c 21611 2009-07-16 00:50:27Z campbellbarton $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -373,7 +373,7 @@ static struct PyMethodDef ui_methods[] = { #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef ui_module = { PyModuleDef_HEAD_INIT, - "bpyui", + "bpy.ui", "", -1,/* multiple "initialization" just copies the module dict. */ ui_methods, @@ -557,6 +557,7 @@ PyObject *BPY_ui_module( void ) PyModule_AddObject( mod, "SCRIPT", PyLong_FromSsize_t(SPACE_SCRIPT) ); PyModule_AddObject( mod, "TIME", PyLong_FromSsize_t(SPACE_TIME) ); PyModule_AddObject( mod, "NODE", PyLong_FromSsize_t(SPACE_NODE) ); + //PyModule_AddObject( mod, "CONSOLE", PyLong_FromSsize_t(SPACE_CONSOLE) ); /* INCREF since its its assumed that all these functions return the * module with a new ref like PyDict_New, since they are passed to diff --git a/source/blender/python/intern/bpy_ui.h b/source/blender/python/intern/bpy_ui.h index 4182a32d3f0..95afa1f08c8 100644 --- a/source/blender/python/intern/bpy_ui.h +++ b/source/blender/python/intern/bpy_ui.h @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: bpy_ui.h 21094 2009-06-23 00:09:26Z gsrb3d $ * * ***** BEGIN GPL LICENSE BLOCK ***** * diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index c447e7de982..82516dd657a 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: bpy_util.c 21526 2009-07-11 13:57:56Z campbellbarton $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -81,6 +81,7 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag) char *cstring; PyObject *item; BPY_flag_def *fd; + *flag = 0; if (PySequence_Check(seq)) { i= PySequence_Length(seq); @@ -108,6 +109,9 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag) error_val= 1; } + if (*flag == 0) + error_val = 1; + if (error_val) { char *buf = bpy_flag_error_str(flagdef); PyErr_SetString(PyExc_AttributeError, buf); @@ -167,7 +171,13 @@ void PyObSpit(char *name, PyObject *var) { else { PyObject_Print(var, stderr, 0); fprintf(stderr, " ref:%d ", var->ob_refcnt); - fprintf(stderr, " ptr:%ld", (long)var); + fprintf(stderr, " ptr:%p", (void *)var); + + fprintf(stderr, " type:"); + if(Py_TYPE(var)) + fprintf(stderr, "%s", Py_TYPE(var)->tp_name); + else + fprintf(stderr, ""); } fprintf(stderr, "\n"); } @@ -329,6 +339,81 @@ int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_c return 0; } + + +/* returns the exception string as a new PyUnicode object, depends on external StringIO module */ +PyObject *BPY_exception_buffer(void) +{ + PyObject *stdout_backup = PySys_GetObject("stdout"); /* borrowed */ + PyObject *stderr_backup = PySys_GetObject("stderr"); /* borrowed */ + PyObject *string_io = NULL; + PyObject *string_io_buf = NULL; + PyObject *string_io_mod= NULL; + PyObject *string_io_getvalue= NULL; + + PyObject *error_type, *error_value, *error_traceback; + + if (!PyErr_Occurred()) + return NULL; + + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + PyErr_Clear(); + + /* import StringIO / io + * string_io = StringIO.StringIO() + */ + +#if PY_VERSION_HEX < 0x03000000 + if(! (string_io_mod= PyImport_ImportModule("StringIO")) ) { +#else + if(! (string_io_mod= PyImport_ImportModule("io")) ) { +#endif + goto error_cleanup; + } else if (! (string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) { + goto error_cleanup; + } else if (! (string_io_getvalue= PyObject_GetAttrString(string_io, "getvalue"))) { + goto error_cleanup; + } + + Py_INCREF(stdout_backup); // since these were borrowed we dont want them freed when replaced. + Py_INCREF(stderr_backup); + + PySys_SetObject("stdout", string_io); // both of these are free'd when restoring + PySys_SetObject("stderr", string_io); + + PyErr_Restore(error_type, error_value, error_traceback); + PyErr_Print(); /* print the error */ + PyErr_Clear(); + + string_io_buf = PyObject_CallObject(string_io_getvalue, NULL); + + PySys_SetObject("stdout", stdout_backup); + PySys_SetObject("stderr", stderr_backup); + + Py_DECREF(stdout_backup); /* now sys owns the ref again */ + Py_DECREF(stderr_backup); + + Py_DECREF(string_io_mod); + Py_DECREF(string_io_getvalue); + Py_DECREF(string_io); /* free the original reference */ + + PyErr_Clear(); + return string_io_buf; + + +error_cleanup: + /* could not import the module so print the error and close */ + Py_XDECREF(string_io_mod); + Py_XDECREF(string_io); + + PyErr_Restore(error_type, error_value, error_traceback); + PyErr_Print(); /* print the error */ + PyErr_Clear(); + + return NULL; +} + char *BPy_enum_as_string(EnumPropertyItem *item) { DynStr *dynstr= BLI_dynstr_new(); @@ -336,7 +421,8 @@ char *BPy_enum_as_string(EnumPropertyItem *item) char *cstring; for (e= item; item->identifier; item++) { - BLI_dynstr_appendf(dynstr, (e==item)?"'%s'":", '%s'", item->identifier); + if(item->identifier[0]) + BLI_dynstr_appendf(dynstr, (e==item)?"'%s'":", '%s'", item->identifier); } cstring = BLI_dynstr_get_cstring(dynstr); @@ -358,3 +444,33 @@ int BPy_reports_to_error(ReportList *reports) return (report_str != NULL); } + +int BPy_errors_to_report(ReportList *reports) +{ + PyObject *pystring; + char *cstring; + + if (!PyErr_Occurred()) + return 1; + + /* less hassle if we allow NULL */ + if(reports==NULL) { + PyErr_Print(); + PyErr_Clear(); + return 1; + } + + pystring= BPY_exception_buffer(); + + if(pystring==NULL) { + BKE_report(reports, RPT_ERROR, "unknown py-exception, could not convert"); + return 0; + } + + cstring= _PyUnicode_AsString(pystring); + + BKE_report(reports, RPT_ERROR, cstring); + fprintf(stderr, "%s\n", cstring); // not exactly needed. just for testing + Py_DECREF(pystring); + return 1; +} diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h index 49f48802249..c6547665fd6 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_util.h @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: bpy_util.h 21094 2009-06-23 00:09:26Z gsrb3d $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -47,6 +47,8 @@ void PyObSpit(char *name, PyObject *var); void PyLineSpit(void); void BPY_getFileAndNum(char **filename, int *lineno); +PyObject *BPY_exception_buffer(void); + /* own python like utility function */ PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...); @@ -73,6 +75,7 @@ char *BPy_enum_as_string(struct EnumPropertyItem *item); /* error reporting */ int BPy_reports_to_error(struct ReportList *reports); +int BPy_errors_to_report(struct ReportList *reports); /* TODO - find a better solution! */ struct bContext *BPy_GetContext(void);