Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/editors/mesh/bmesh_tools.c3
-rw-r--r--source/blender/gpu/gpu_buffers.h157
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c1262
-rw-r--r--source/blender/makesrna/intern/rna_action_api.c80
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c101
-rw-r--r--source/blender/makesrna/intern/rna_material_api.c126
-rw-r--r--source/blender/makesrna/intern/rna_pose_api.c56
-rw-r--r--source/gameengine/Converter/BL_ArmatureActuator.cpp267
-rw-r--r--source/gameengine/Converter/BL_ArmatureActuator.h93
-rw-r--r--source/gameengine/Converter/BL_ArmatureChannel.cpp469
-rw-r--r--source/gameengine/Converter/BL_ArmatureChannel.h95
-rw-r--r--source/gameengine/Converter/BL_ArmatureConstraint.cpp454
-rw-r--r--source/gameengine/Converter/BL_ArmatureConstraint.h118
-rw-r--r--source/gameengine/GameLogic/SCA_BasicEventManager.cpp61
-rw-r--r--source/gameengine/GameLogic/SCA_BasicEventManager.h57
-rw-r--r--source/gameengine/Ketsji/KX_ArmatureSensor.cpp208
-rw-r--r--source/gameengine/Ketsji/KX_ArmatureSensor.h89
17 files changed, 3695 insertions, 1 deletions
diff --git a/source/blender/editors/mesh/bmesh_tools.c b/source/blender/editors/mesh/bmesh_tools.c
index 9b31a06edb3..ad1654d2f3a 100644
--- a/source/blender/editors/mesh/bmesh_tools.c
+++ b/source/blender/editors/mesh/bmesh_tools.c
@@ -2990,9 +2990,10 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
then rip the two adjacent edges in the vert fan.*/
if (em->bm->totvertsel == 1 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) {
/*find selected vert*/
- BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
if (BM_TestHFlag(v, BM_SELECT))
break;
+ }
/*this should be impossible, but sanity checks are a good thing*/
if (!v)
diff --git a/source/blender/gpu/gpu_buffers.h b/source/blender/gpu/gpu_buffers.h
new file mode 100644
index 00000000000..7377046ee63
--- /dev/null
+++ b/source/blender/gpu/gpu_buffers.h
@@ -0,0 +1,157 @@
+/**
+ * $Id: gpu_buffers.h 23816 2009-10-13 19:02:30Z nicholasbishop $
+ *
+ * ***** 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __GPU_BUFFERS_H__
+#define __GPU_BUFFERS_H__
+
+#define MAX_FREE_GPU_BUFFERS 8
+
+#ifdef _DEBUG
+/*#define DEBUG_VBO(X) printf(X)*/
+#define DEBUG_VBO(X)
+#else
+#define DEBUG_VBO(X)
+#endif
+
+struct DerivedMesh;
+
+/* V - vertex, N - normal, T - uv, C - color
+ F - float, UB - unsigned byte */
+#define GPU_BUFFER_INTER_V3F 1
+#define GPU_BUFFER_INTER_N3F 2
+#define GPU_BUFFER_INTER_T2F 3
+#define GPU_BUFFER_INTER_C3UB 4
+#define GPU_BUFFER_INTER_C4UB 5
+#define GPU_BUFFER_INTER_END -1
+
+typedef struct GPUBuffer
+{
+ int size; /* in bytes */
+ void *pointer; /* used with vertex arrays */
+ unsigned int id; /* used with vertex buffer objects */
+} GPUBuffer;
+
+typedef struct GPUBufferPool
+{
+ int size; /* number of allocated buffers stored */
+ int start; /* for a queue like structure */
+ /* when running out of space for storing buffers,
+ the last one used will be thrown away */
+
+ GPUBuffer* buffers[MAX_FREE_GPU_BUFFERS];
+} GPUBufferPool;
+
+typedef struct GPUBufferMaterial
+{
+ int start; /* at which vertex in the buffer the material starts */
+ int end; /* at which vertex it ends */
+ char mat_nr;
+} GPUBufferMaterial;
+
+typedef struct IndexLink {
+ int element;
+ struct IndexLink *next;
+} IndexLink;
+
+typedef struct GPUDrawObject
+{
+ GPUBuffer *vertices;
+ GPUBuffer *normals;
+ GPUBuffer *uv;
+ GPUBuffer *colors;
+ GPUBuffer *edges;
+ GPUBuffer *uvedges;
+
+ int *faceRemap; /* at what index was the face originally in DerivedMesh */
+ IndexLink *indices; /* given an index, find all elements using it */
+ IndexLink *indexMem; /* for faster memory allocation/freeing */
+ int indexMemUsage; /* how many are already allocated */
+ int colType;
+
+ GPUBufferMaterial *materials;
+
+ int nmaterials;
+ int nelements; /* (number of faces) * 3 */
+ int nlooseverts;
+ int nedges;
+ int nindices;
+ int legacy; /* if there was a failure allocating some buffer, use old rendering code */
+
+} GPUDrawObject;
+
+typedef struct GPUAttrib
+{
+ int index;
+ int size;
+ int type;
+} GPUAttrib;
+
+GPUBufferPool *GPU_buffer_pool_new();
+void GPU_buffer_pool_free( GPUBufferPool *pool ); /* TODO: Find a place where to call this function on exit */
+
+GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool );
+void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool );
+
+GPUDrawObject *GPU_drawobject_new( struct DerivedMesh *dm );
+void GPU_drawobject_free( struct DerivedMesh *dm );
+
+/* called before drawing */
+void GPU_vertex_setup( struct DerivedMesh *dm );
+void GPU_normal_setup( struct DerivedMesh *dm );
+void GPU_uv_setup( struct DerivedMesh *dm );
+void GPU_color_setup( struct DerivedMesh *dm );
+void GPU_edge_setup( struct DerivedMesh *dm ); /* does not mix with other data */
+void GPU_uvedge_setup( struct DerivedMesh *dm );
+void GPU_interleaved_setup( GPUBuffer *buffer, int data[] );
+int GPU_attrib_element_size( GPUAttrib data[], int numdata );
+void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numdata );
+
+/* can't lock more than one buffer at once */
+void *GPU_buffer_lock( GPUBuffer *buffer );
+void *GPU_buffer_lock_stream( GPUBuffer *buffer );
+void GPU_buffer_unlock( GPUBuffer *buffer );
+
+/* upload three unsigned chars, representing RGB colors, for each vertex. Resets dm->drawObject->colType to -1 */
+void GPU_color3_upload( struct DerivedMesh *dm, unsigned char *data );
+/* upload four unsigned chars, representing RGBA colors, for each vertex. Resets dm->drawObject->colType to -1 */
+void GPU_color4_upload( struct DerivedMesh *dm, unsigned char *data );
+/* switch color rendering on=1/off=0 */
+void GPU_color_switch( int mode );
+
+void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count );
+
+/* called after drawing */
+void GPU_buffer_unbind();
+
+int GPU_buffer_legacy( struct DerivedMesh *dm );
+
+#endif
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
new file mode 100644
index 00000000000..6b465b64590
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -0,0 +1,1262 @@
+/**
+ * $Id: gpu_buffers.c 23816 2009-10-13 19:02:30Z nicholasbishop $
+ *
+ * ***** 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#include "GL/glew.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_userdef_types.h"
+
+#include "gpu_buffers.h"
+
+#define GPU_BUFFER_VERTEX_STATE 1
+#define GPU_BUFFER_NORMAL_STATE 2
+#define GPU_BUFFER_TEXCOORD_STATE 4
+#define GPU_BUFFER_COLOR_STATE 8
+#define GPU_BUFFER_ELEMENT_STATE 16
+
+#define MAX_GPU_ATTRIB_DATA 32
+
+/* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
+int useVBOs = -1;
+GPUBufferPool *globalPool = 0;
+int GLStates = 0;
+GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
+
+GPUBufferPool *GPU_buffer_pool_new()
+{
+ GPUBufferPool *pool;
+
+ DEBUG_VBO("GPU_buffer_pool_new\n");
+
+ if( useVBOs < 0 ) {
+ if( GL_ARB_vertex_buffer_object ) {
+ DEBUG_VBO( "Vertex Buffer Objects supported.\n" );
+ useVBOs = 1;
+ }
+ else {
+ DEBUG_VBO( "Vertex Buffer Objects NOT supported.\n" );
+ useVBOs = 0;
+ }
+ }
+
+ pool = MEM_callocN(sizeof(GPUBufferPool), "GPU_buffer_pool_new");
+
+ return pool;
+}
+
+void GPU_buffer_pool_free(GPUBufferPool *pool)
+{
+ int i;
+
+ DEBUG_VBO("GPU_buffer_pool_free\n");
+
+ if( pool == 0 )
+ pool = globalPool;
+ if( pool == 0 )
+ return;
+
+ while( pool->start < 0 )
+ pool->start += MAX_FREE_GPU_BUFFERS;
+
+ for( i = 0; i < pool->size; i++ ) {
+ if( useVBOs ) {
+ glDeleteBuffersARB( 1, &pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]->id );
+ }
+ else {
+ MEM_freeN( pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]->pointer );
+ }
+ MEM_freeN(pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]);
+ }
+ MEM_freeN(pool);
+}
+
+void GPU_buffer_pool_remove( int index, GPUBufferPool *pool )
+{
+ int i;
+
+ DEBUG_VBO("GPU_buffer_pool_remove\n");
+
+ while( pool->start < 0 )
+ pool->start += MAX_FREE_GPU_BUFFERS;
+ for( i = index; i < pool->size-1; i++ ) {
+ pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS] = pool->buffers[(pool->start+i+1)%MAX_FREE_GPU_BUFFERS];
+ }
+ pool->size--;
+}
+
+void GPU_buffer_pool_delete_last( GPUBufferPool *pool )
+{
+ int last;
+
+ DEBUG_VBO("GPU_buffer_pool_delete_last\n");
+
+ if( pool->size == 0 )
+ return;
+
+ last = pool->start+pool->size-1;
+ while( last < 0 )
+ last += MAX_FREE_GPU_BUFFERS;
+ last = (last+MAX_FREE_GPU_BUFFERS)%MAX_FREE_GPU_BUFFERS;
+
+ if( useVBOs ) {
+ glDeleteBuffersARB(1,&pool->buffers[last]->id);
+ MEM_freeN( pool->buffers[last] );
+ }
+ else {
+ MEM_freeN( pool->buffers[last]->pointer );
+ MEM_freeN( pool->buffers[last] );
+ }
+ pool->size--;
+}
+
+GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool )
+{
+ char buffer[60];
+ int i;
+ int cursize;
+ GPUBuffer *allocated;
+ int bestfit = -1;
+
+ DEBUG_VBO("GPU_buffer_alloc\n");
+
+ if( pool == 0 ) {
+ if( globalPool == 0 )
+ globalPool = GPU_buffer_pool_new();
+ pool = globalPool;
+ }
+
+ while( pool->start < 0 )
+ pool->start += MAX_FREE_GPU_BUFFERS;
+
+ for( i = 0; i < pool->size; i++ ) {
+ int actuali = (pool->start+i)%MAX_FREE_GPU_BUFFERS;
+ cursize = pool->buffers[actuali]->size;
+ if( cursize == size ) {
+ allocated = pool->buffers[actuali];
+ GPU_buffer_pool_remove(i,pool);
+ DEBUG_VBO("free buffer of exact size found\n");
+ return allocated;
+ }
+ /* smaller buffers won't fit data and buffers at least twice as big are a waste of memory */
+ else if( cursize > size && size > cursize/2 ) {
+ /* is it closer to the required size than the last appropriate buffer found. try to save memory */
+ if( bestfit == -1 || pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS]->size > cursize ) {
+ bestfit = i;
+ }
+ }
+ }
+ if( bestfit == -1 ) {
+ DEBUG_VBO("allocating a new buffer\n");
+
+ allocated = MEM_mallocN(sizeof(GPUBuffer), "GPU_buffer_alloc");
+ allocated->size = size;
+ if( useVBOs == 1 ) {
+ glGenBuffersARB( 1, &allocated->id );
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, allocated->id );
+ glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, 0, GL_STATIC_DRAW_ARB );
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
+ }
+ else {
+ allocated->pointer = MEM_mallocN(size, "GPU_buffer_alloc_vertexarray");
+ while( allocated->pointer == 0 && pool->size > 0 ) {
+ GPU_buffer_pool_delete_last(pool);
+ allocated->pointer = MEM_mallocN(size, "GPU_buffer_alloc_vertexarray");
+ }
+ if( allocated->pointer == 0 && pool->size == 0 ) {
+ return 0;
+ }
+ }
+ }
+ else {
+ sprintf(buffer,"free buffer found. Wasted %d bytes\n", pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS]->size-size);
+ DEBUG_VBO(buffer);
+
+ allocated = pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS];
+ GPU_buffer_pool_remove(bestfit,pool);
+ }
+ return allocated;
+}
+
+void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool )
+{
+ int place;
+
+ DEBUG_VBO("GPU_buffer_free\n");
+
+ if( buffer == 0 )
+ return;
+ if( pool == 0 )
+ pool = globalPool;
+ if( pool == 0 )
+ globalPool = GPU_buffer_pool_new();
+
+ while( pool->start < 0 )
+ pool->start += MAX_FREE_GPU_BUFFERS;
+ place = (pool->start-1 + MAX_FREE_GPU_BUFFERS)%MAX_FREE_GPU_BUFFERS;
+
+ /* free the last used buffer in the queue if no more space */
+ if( pool->size == MAX_FREE_GPU_BUFFERS ) {
+ GPU_buffer_pool_delete_last( pool );
+ }
+
+ pool->size++;
+ pool->start = place;
+ pool->buffers[place] = buffer;
+}
+
+GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
+{
+ GPUDrawObject *object;
+ MVert *mvert;
+ MFace *mface;
+ int numverts[32768]; /* material number is an 16-bit short so there's at most 32768 materials */
+ int redir[32768]; /* material number is an 16-bit short so there's at most 32768 materials */
+ int *index;
+ int i;
+ int curmat, curverts, numfaces;
+
+ DEBUG_VBO("GPU_drawobject_new\n");
+
+ object = MEM_callocN(sizeof(GPUDrawObject),"GPU_drawobject_new_object");
+ object->nindices = dm->getNumVerts(dm);
+ object->indices = MEM_mallocN(sizeof(IndexLink)*object->nindices, "GPU_drawobject_new_indices");
+ object->nedges = dm->getNumEdges(dm);
+
+ for( i = 0; i < object->nindices; i++ ) {
+ object->indices[i].element = -1;
+ object->indices[i].next = 0;
+ }
+ /*object->legacy = 1;*/
+ memset(numverts,0,sizeof(int)*32768);
+
+ mvert = dm->getVertArray(dm);
+ mface = dm->getTessFaceArray(dm);
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ if( mface[i].v4 )
+ numverts[mface[i].mat_nr+16383] += 6; /* split every quad into two triangles */
+ else
+ numverts[mface[i].mat_nr+16383] += 3;
+ }
+
+ for( i = 0; i < 32768; i++ ) {
+ if( numverts[i] > 0 ) {
+ object->nmaterials++;
+ object->nelements += numverts[i];
+ }
+ }
+ object->materials = MEM_mallocN(sizeof(GPUBufferMaterial)*object->nmaterials,"GPU_drawobject_new_materials");
+ index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_drawobject_new_index");
+
+ curmat = curverts = 0;
+ for( i = 0; i < 32768; i++ ) {
+ if( numverts[i] > 0 ) {
+ object->materials[curmat].mat_nr = i-16383;
+ object->materials[curmat].start = curverts;
+ index[curmat] = curverts/3;
+ object->materials[curmat].end = curverts+numverts[i];
+ curverts += numverts[i];
+ curmat++;
+ }
+ }
+ object->faceRemap = MEM_mallocN(sizeof(int)*object->nelements/3,"GPU_drawobject_new_faceRemap");
+ for( i = 0; i < object->nmaterials; i++ ) {
+ redir[object->materials[i].mat_nr+16383] = i; /* material number -> material index */
+ }
+
+ object->indexMem = MEM_callocN(sizeof(IndexLink)*object->nelements,"GPU_drawobject_new_indexMem");
+ object->indexMemUsage = 0;
+
+#define ADDLINK( INDEX, ACTUAL ) \
+ if( object->indices[INDEX].element == -1 ) { \
+ object->indices[INDEX].element = ACTUAL; \
+ } else { \
+ IndexLink *lnk = &object->indices[INDEX], *lnk2; \
+ lnk2 = &object->indexMem[object->indexMemUsage]; \
+ lnk2->element = ACTUAL; \
+ SWAP(IndexLink, *lnk, *lnk2); \
+ lnk->next = lnk2; \
+ object->indexMemUsage++; \
+ }
+
+ for( i=0; i < numfaces; i++ ) {
+ int curInd = index[redir[mface[i].mat_nr+16383]];
+ object->faceRemap[curInd] = i;
+ ADDLINK( mface[i].v1, curInd*3 );
+ ADDLINK( mface[i].v2, curInd*3+1 );
+ ADDLINK( mface[i].v3, curInd*3+2 );
+ if( mface[i].v4 ) {
+ object->faceRemap[curInd+1] = i;
+ ADDLINK( mface[i].v3, curInd*3+3 );
+ ADDLINK( mface[i].v4, curInd*3+4 );
+ ADDLINK( mface[i].v1, curInd*3+5 );
+
+ index[redir[mface[i].mat_nr+16383]]+=2;
+ }
+ else {
+ index[redir[mface[i].mat_nr+16383]]++;
+ }
+ }
+
+ for( i = 0; i < object->nindices; i++ ) {
+ if( object->indices[i].element == -1 ) {
+ object->indices[i].element = object->nelements + object->nlooseverts;
+ object->nlooseverts++;
+ }
+ }
+#undef ADDLINK
+
+ MEM_freeN(index);
+ return object;
+}
+
+void GPU_drawobject_free( DerivedMesh *dm )
+{
+ GPUDrawObject *object;
+
+ DEBUG_VBO("GPU_drawobject_free\n");
+
+ if( dm == 0 )
+ return;
+ object = dm->drawObject;
+ if( object == 0 )
+ return;
+
+ MEM_freeN(object->materials);
+ MEM_freeN(object->faceRemap);
+ MEM_freeN(object->indices);
+ MEM_freeN(object->indexMem);
+ GPU_buffer_free( object->vertices, globalPool );
+ GPU_buffer_free( object->normals, globalPool );
+ GPU_buffer_free( object->uv, globalPool );
+ GPU_buffer_free( object->colors, globalPool );
+ GPU_buffer_free( object->edges, globalPool );
+ GPU_buffer_free( object->uvedges, globalPool );
+
+ MEM_freeN(object);
+ dm->drawObject = 0;
+}
+
+GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int size, GLenum target, void *user, void (*copy_f)(DerivedMesh *, float *, int *, int *, void *) )
+{
+ GPUBuffer *buffer;
+ float *varray;
+ int redir[32768];
+ int *index;
+ int i;
+ int success;
+ GLboolean uploaded;
+
+ DEBUG_VBO("GPU_buffer_setup\n");
+
+ if( globalPool == 0 ) {
+ globalPool = GPU_buffer_pool_new();
+
+ /* somehow GL_NORMAL_ARRAY is enabled on startup and causes edge drawing code to crash */
+ glDisableClientState( GL_VERTEX_ARRAY );
+ glDisableClientState( GL_NORMAL_ARRAY );
+ glDisableClientState( GL_TEXTURE_COORD_ARRAY );
+ glDisableClientState( GL_COLOR_ARRAY );
+ }
+ buffer = GPU_buffer_alloc(size,globalPool);
+ if( buffer == 0 ) {
+ dm->drawObject->legacy = 1;
+ }
+ if( dm->drawObject->legacy ) {
+ return 0;
+ }
+
+ index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_buffer_setup");
+ for( i = 0; i < object->nmaterials; i++ ) {
+ index[i] = object->materials[i].start*3;
+ redir[object->materials[i].mat_nr+16383] = i;
+ }
+
+ if( useVBOs ) {
+ success = 0;
+ while( success == 0 ) {
+ glBindBufferARB( target, buffer->id );
+ glBufferDataARB( target, buffer->size, 0, GL_STATIC_DRAW_ARB ); /* discard previous data, avoid stalling gpu */
+ varray = glMapBufferARB( target, GL_WRITE_ONLY_ARB );
+ if( varray == 0 ) {
+ DEBUG_VBO( "Failed to map buffer to client address space\n" );
+ GPU_buffer_free( buffer, globalPool );
+ GPU_buffer_pool_delete_last( globalPool );
+ if( globalPool->size > 0 ) {
+ GPU_buffer_pool_delete_last( globalPool );
+ buffer = GPU_buffer_alloc( size, globalPool );
+ if( buffer == 0 ) {
+ dm->drawObject->legacy = 1;
+ success = 1;
+ }
+ }
+ else {
+ dm->drawObject->legacy = 1;
+ success = 1;
+ }
+ }
+ else {
+ success = 1;
+ }
+ }
+
+ if( dm->drawObject->legacy == 0 ) {
+ uploaded = GL_FALSE;
+ while( !uploaded ) {
+ (*copy_f)( dm, varray, index, redir, user );
+ uploaded = glUnmapBufferARB( target ); /* returns false if data got corruped during transfer */
+ }
+ }
+ glBindBufferARB(target, 0);
+ }
+ else {
+ if( buffer->pointer != 0 ) {
+ varray = buffer->pointer;
+ (*copy_f)( dm, varray, index, redir, user );
+ }
+ else {
+ dm->drawObject->legacy = 1;
+ }
+ }
+
+ MEM_freeN(index);
+
+ return buffer;
+}
+
+void GPU_buffer_copy_vertex( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+ int start;
+ int i, j, numfaces;
+
+ MVert *mvert;
+ MFace *mface;
+
+ DEBUG_VBO("GPU_buffer_copy_vertex\n");
+
+ mvert = dm->getVertArray(dm);
+ mface = dm->getTessFaceArray(dm);
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ start = index[redir[mface[i].mat_nr+16383]];
+ if( mface[i].v4 )
+ index[redir[mface[i].mat_nr+16383]] += 18;
+ else
+ index[redir[mface[i].mat_nr+16383]] += 9;
+
+ /* v1 v2 v3 */
+ VECCOPY(&varray[start],mvert[mface[i].v1].co);
+ VECCOPY(&varray[start+3],mvert[mface[i].v2].co);
+ VECCOPY(&varray[start+6],mvert[mface[i].v3].co);
+
+ if( mface[i].v4 ) {
+ /* v3 v4 v1 */
+ VECCOPY(&varray[start+9],mvert[mface[i].v3].co);
+ VECCOPY(&varray[start+12],mvert[mface[i].v4].co);
+ VECCOPY(&varray[start+15],mvert[mface[i].v1].co);
+ }
+ }
+ j = dm->drawObject->nelements*3;
+ for( i = 0; i < dm->drawObject->nindices; i++ ) {
+ if( dm->drawObject->indices[i].element >= dm->drawObject->nelements ) {
+ VECCOPY(&varray[j],mvert[i].co);
+ j+=3;
+ }
+ }
+}
+
+GPUBuffer *GPU_buffer_vertex( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_buffer_vertex\n");
+
+ return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*(dm->drawObject->nelements+dm->drawObject->nlooseverts), GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_vertex);
+}
+
+void GPU_buffer_copy_normal( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+ int i, numfaces;
+ int start;
+ float norm[3];
+
+ float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
+ MVert *mvert = dm->getVertArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
+
+ DEBUG_VBO("GPU_buffer_copy_normal\n");
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ start = index[redir[mface[i].mat_nr+16383]];
+ if( mface[i].v4 )
+ index[redir[mface[i].mat_nr+16383]] += 18;
+ else
+ index[redir[mface[i].mat_nr+16383]] += 9;
+
+ /* v1 v2 v3 */
+ if( mface[i].flag & ME_SMOOTH ) {
+ VECCOPY(&varray[start],mvert[mface[i].v1].no);
+ VECCOPY(&varray[start+3],mvert[mface[i].v2].no);
+ VECCOPY(&varray[start+6],mvert[mface[i].v3].no);
+ }
+ else {
+ if( nors ) {
+ VECCOPY(&varray[start],&nors[i*3]);
+ VECCOPY(&varray[start+3],&nors[i*3]);
+ VECCOPY(&varray[start+6],&nors[i*3]);
+ }
+ if( mface[i].v4 )
+ CalcNormFloat4(mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, mvert[mface[i].v4].co, norm);
+ else
+ CalcNormFloat(mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, norm);
+ VECCOPY(&varray[start],norm);
+ VECCOPY(&varray[start+3],norm);
+ VECCOPY(&varray[start+6],norm);
+ }
+
+ if( mface[i].v4 ) {
+ /* v3 v4 v1 */
+ if( mface[i].flag & ME_SMOOTH ) {
+ VECCOPY(&varray[start+9],mvert[mface[i].v3].no);
+ VECCOPY(&varray[start+12],mvert[mface[i].v4].no);
+ VECCOPY(&varray[start+15],mvert[mface[i].v1].no);
+ }
+ else {
+ VECCOPY(&varray[start+9],norm);
+ VECCOPY(&varray[start+12],norm);
+ VECCOPY(&varray[start+15],norm);
+ }
+ }
+ }
+}
+
+GPUBuffer *GPU_buffer_normal( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_buffer_normal\n");
+
+ return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_normal);
+}
+
+void GPU_buffer_copy_uv( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+ int start;
+ int i, numfaces;
+
+ MTFace *mtface;
+ MFace *mface;
+
+ DEBUG_VBO("GPU_buffer_copy_uv\n");
+
+ mface = dm->getTessFaceArray(dm);
+ mtface = DM_get_face_data_layer(dm, CD_MTFACE);
+
+ if( mtface == 0 ) {
+ DEBUG_VBO("Texture coordinates do not exist for this mesh");
+ return;
+ }
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ start = index[redir[mface[i].mat_nr+16383]];
+ if( mface[i].v4 )
+ index[redir[mface[i].mat_nr+16383]] += 12;
+ else
+ index[redir[mface[i].mat_nr+16383]] += 6;
+
+ /* v1 v2 v3 */
+ VECCOPY2D(&varray[start],mtface[i].uv[0]);
+ VECCOPY2D(&varray[start+2],mtface[i].uv[1]);
+ VECCOPY2D(&varray[start+4],mtface[i].uv[2]);
+
+ if( mface[i].v4 ) {
+ /* v3 v4 v1 */
+ VECCOPY2D(&varray[start+6],mtface[i].uv[2]);
+ VECCOPY2D(&varray[start+8],mtface[i].uv[3]);
+ VECCOPY2D(&varray[start+10],mtface[i].uv[0]);
+ }
+ }
+}
+
+GPUBuffer *GPU_buffer_uv( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_buffer_uv\n");
+ if( DM_get_face_data_layer(dm, CD_MTFACE) != 0 )
+ return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uv);
+ else
+ return 0;
+}
+
+void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
+{
+ int i, numfaces;
+ unsigned char *varray = (unsigned char *)varray_;
+ unsigned char *mcol = (unsigned char *)user;
+ MFace *mface = dm->getTessFaceArray(dm);
+
+ DEBUG_VBO("GPU_buffer_copy_color3\n");
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ int start = index[redir[mface[i].mat_nr+16383]];
+ if( mface[i].v4 )
+ index[redir[mface[i].mat_nr+16383]] += 18;
+ else
+ index[redir[mface[i].mat_nr+16383]] += 9;
+
+ /* v1 v2 v3 */
+ VECCOPY(&varray[start],&mcol[i*12]);
+ VECCOPY(&varray[start+3],&mcol[i*12+3]);
+ VECCOPY(&varray[start+6],&mcol[i*12+6]);
+ if( mface[i].v4 ) {
+ /* v3 v4 v1 */
+ VECCOPY(&varray[start+9],&mcol[i*12+6]);
+ VECCOPY(&varray[start+12],&mcol[i*12+9]);
+ VECCOPY(&varray[start+15],&mcol[i*12]);
+ }
+ }
+}
+
+void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
+{
+ int i, numfaces;
+ unsigned char *varray = (unsigned char *)varray_;
+ unsigned char *mcol = (unsigned char *)user;
+ MFace *mface = dm->getTessFaceArray(dm);
+
+ DEBUG_VBO("GPU_buffer_copy_color4\n");
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ int start = index[redir[mface[i].mat_nr+16383]];
+ if( mface[i].v4 )
+ index[redir[mface[i].mat_nr+16383]] += 18;
+ else
+ index[redir[mface[i].mat_nr+16383]] += 9;
+
+ /* v1 v2 v3 */
+ VECCOPY(&varray[start],&mcol[i*16]);
+ VECCOPY(&varray[start+3],&mcol[i*16+4]);
+ VECCOPY(&varray[start+6],&mcol[i*16+8]);
+ if( mface[i].v4 ) {
+ /* v3 v4 v1 */
+ VECCOPY(&varray[start+9],&mcol[i*16+8]);
+ VECCOPY(&varray[start+12],&mcol[i*16+12]);
+ VECCOPY(&varray[start+15],&mcol[i*16]);
+ }
+ }
+}
+
+GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
+{
+ unsigned char *colors;
+ int i, numfaces;
+ MCol *mcol;
+ GPUBuffer *result;
+ DEBUG_VBO("GPU_buffer_color\n");
+
+ mcol = DM_get_face_data_layer(dm, CD_ID_MCOL);
+ dm->drawObject->colType = CD_ID_MCOL;
+ if(!mcol) {
+ mcol = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
+ dm->drawObject->colType = CD_WEIGHT_MCOL;
+ }
+ if(!mcol) {
+ mcol = DM_get_face_data_layer(dm, CD_MCOL);
+ dm->drawObject->colType = CD_MCOL;
+ }
+
+ numfaces= dm->getNumTessFaces(dm);
+ colors = MEM_mallocN(numfaces*12*sizeof(unsigned char), "GPU_buffer_color");
+ for( i=0; i < numfaces*4; i++ ) {
+ colors[i*3] = mcol[i].b;
+ colors[i*3+1] = mcol[i].g;
+ colors[i*3+2] = mcol[i].r;
+ }
+
+ result = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, colors, GPU_buffer_copy_color3 );
+
+ MEM_freeN(colors);
+ return result;
+}
+
+void GPU_buffer_copy_edge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+ int i;
+
+ MVert *mvert;
+ MEdge *medge;
+ unsigned int *varray_ = (unsigned int *)varray;
+ int numedges;
+
+ DEBUG_VBO("GPU_buffer_copy_edge\n");
+
+ mvert = dm->getVertArray(dm);
+ medge = dm->getEdgeArray(dm);
+
+ numedges= dm->getNumEdges(dm);
+ for(i = 0; i < numedges; i++) {
+ varray_[i*2] = (unsigned int)dm->drawObject->indices[medge[i].v1].element;
+ varray_[i*2+1] = (unsigned int)dm->drawObject->indices[medge[i].v2].element;
+ }
+}
+
+GPUBuffer *GPU_buffer_edge( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_buffer_edge\n");
+
+ return GPU_buffer_setup( dm, dm->drawObject, sizeof(int)*2*dm->drawObject->nedges, GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_edge);
+}
+
+void GPU_buffer_copy_uvedge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+ MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ int i, j=0;
+
+ DEBUG_VBO("GPU_buffer_copy_uvedge\n");
+
+ if(tf) {
+ for(i = 0; i < dm->numFaceData; i++, tf++) {
+ MFace mf;
+ dm->getTessFace(dm,i,&mf);
+
+ VECCOPY2D(&varray[j],tf->uv[0]);
+ VECCOPY2D(&varray[j+2],tf->uv[1]);
+
+ VECCOPY2D(&varray[j+4],tf->uv[1]);
+ VECCOPY2D(&varray[j+6],tf->uv[2]);
+
+ if(!mf.v4) {
+ VECCOPY2D(&varray[j+8],tf->uv[2]);
+ VECCOPY2D(&varray[j+10],tf->uv[0]);
+ j+=12;
+ } else {
+ VECCOPY2D(&varray[j+8],tf->uv[2]);
+ VECCOPY2D(&varray[j+10],tf->uv[3]);
+
+ VECCOPY2D(&varray[j+12],tf->uv[3]);
+ VECCOPY2D(&varray[j+14],tf->uv[0]);
+ j+=16;
+ }
+ }
+ }
+ else {
+ DEBUG_VBO("Could not get MTFACE data layer");
+ }
+}
+
+GPUBuffer *GPU_buffer_uvedge( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_buffer_uvedge\n");
+
+ return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*(dm->drawObject->nelements/3)*2, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uvedge);
+}
+
+
+void GPU_vertex_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_vertex_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->vertices == 0 )
+ dm->drawObject->vertices = GPU_buffer_vertex( dm );
+ if( dm->drawObject->vertices == 0 ) {
+ DEBUG_VBO( "Failed to setup vertices\n" );
+ return;
+ }
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
+ glVertexPointer( 3, GL_FLOAT, 0, 0 );
+ }
+ else {
+ glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_VERTEX_STATE;
+}
+
+void GPU_normal_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_normal_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->normals == 0 )
+ dm->drawObject->normals = GPU_buffer_normal( dm );
+ if( dm->drawObject->normals == 0 ) {
+ DEBUG_VBO( "Failed to setup normals\n" );
+ return;
+ }
+ glEnableClientState( GL_NORMAL_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id );
+ glNormalPointer( GL_FLOAT, 0, 0 );
+ }
+ else {
+ glNormalPointer( GL_FLOAT, 0, dm->drawObject->normals->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_NORMAL_STATE;
+}
+
+void GPU_uv_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_uv_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->uv == 0 )
+ dm->drawObject->uv = GPU_buffer_uv( dm );
+
+ if( dm->drawObject->uv != 0 ) {
+ glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id );
+ glTexCoordPointer( 2, GL_FLOAT, 0, 0 );
+ }
+ else {
+ glTexCoordPointer( 2, GL_FLOAT, 0, dm->drawObject->uv->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_TEXCOORD_STATE;
+ }
+}
+
+void GPU_color_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_color_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->colors == 0 )
+ dm->drawObject->colors = GPU_buffer_color( dm );
+ if( dm->drawObject->colors == 0 ) {
+ DEBUG_VBO( "Failed to setup colors\n" );
+ return;
+ }
+ glEnableClientState( GL_COLOR_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id );
+ glColorPointer( 3, GL_UNSIGNED_BYTE, 0, 0 );
+ }
+ else {
+ glColorPointer( 3, GL_UNSIGNED_BYTE, 0, dm->drawObject->colors->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+}
+
+void GPU_edge_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_edge_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->edges == 0 )
+ dm->drawObject->edges = GPU_buffer_edge( dm );
+ if( dm->drawObject->edges == 0 ) {
+ DEBUG_VBO( "Failed to setup edges\n" );
+ return;
+ }
+ if( dm->drawObject->vertices == 0 )
+ dm->drawObject->vertices = GPU_buffer_vertex( dm );
+ if( dm->drawObject->vertices == 0 ) {
+ DEBUG_VBO( "Failed to setup vertices\n" );
+ return;
+ }
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
+ glVertexPointer( 3, GL_FLOAT, 0, 0 );
+ }
+ else {
+ glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_VERTEX_STATE;
+
+ if( useVBOs ) {
+ glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id );
+ }
+
+ GLStates |= GPU_BUFFER_ELEMENT_STATE;
+}
+
+void GPU_uvedge_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_uvedge_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->uvedges == 0 )
+ dm->drawObject->uvedges = GPU_buffer_uvedge( dm );
+ if( dm->drawObject->uvedges == 0 ) {
+ DEBUG_VBO( "Failed to setup UV edges\n" );
+ return;
+ }
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id );
+ glVertexPointer( 2, GL_FLOAT, 0, 0 );
+ }
+ else {
+ glVertexPointer( 2, GL_FLOAT, 0, dm->drawObject->uvedges->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_VERTEX_STATE;
+}
+
+void GPU_interleaved_setup( GPUBuffer *buffer, int data[] ) {
+ int i;
+ int elementsize = 0;
+ intptr_t offset = 0;
+
+ DEBUG_VBO("GPU_interleaved_setup\n");
+
+ for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
+ switch( data[i] ) {
+ case GPU_BUFFER_INTER_V3F:
+ elementsize += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_N3F:
+ elementsize += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_T2F:
+ elementsize += 2*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_C3UB:
+ elementsize += 3*sizeof(unsigned char);
+ break;
+ case GPU_BUFFER_INTER_C4UB:
+ elementsize += 4*sizeof(unsigned char);
+ break;
+ default:
+ DEBUG_VBO( "Unknown element in data type array in GPU_interleaved_setup\n" );
+ }
+ }
+
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
+ for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
+ switch( data[i] ) {
+ case GPU_BUFFER_INTER_V3F:
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glVertexPointer( 3, GL_FLOAT, elementsize, (void *)offset );
+ GLStates |= GPU_BUFFER_VERTEX_STATE;
+ offset += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_N3F:
+ glEnableClientState( GL_NORMAL_ARRAY );
+ glNormalPointer( GL_FLOAT, elementsize, (void *)offset );
+ GLStates |= GPU_BUFFER_NORMAL_STATE;
+ offset += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_T2F:
+ glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ glTexCoordPointer( 2, GL_FLOAT, elementsize, (void *)offset );
+ GLStates |= GPU_BUFFER_TEXCOORD_STATE;
+ offset += 2*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_C3UB:
+ glEnableClientState( GL_COLOR_ARRAY );
+ glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+ offset += 3*sizeof(unsigned char);
+ break;
+ case GPU_BUFFER_INTER_C4UB:
+ glEnableClientState( GL_COLOR_ARRAY );
+ glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+ offset += 4*sizeof(unsigned char);
+ break;
+ }
+ }
+ }
+ else {
+ for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
+ switch( data[i] ) {
+ case GPU_BUFFER_INTER_V3F:
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glVertexPointer( 3, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
+ GLStates |= GPU_BUFFER_VERTEX_STATE;
+ offset += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_N3F:
+ glEnableClientState( GL_NORMAL_ARRAY );
+ glNormalPointer( GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
+ GLStates |= GPU_BUFFER_NORMAL_STATE;
+ offset += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_T2F:
+ glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ glTexCoordPointer( 2, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
+ GLStates |= GPU_BUFFER_TEXCOORD_STATE;
+ offset += 2*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_C3UB:
+ glEnableClientState( GL_COLOR_ARRAY );
+ glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+ offset += 3*sizeof(unsigned char);
+ break;
+ case GPU_BUFFER_INTER_C4UB:
+ glEnableClientState( GL_COLOR_ARRAY );
+ glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+ offset += 4*sizeof(unsigned char);
+ break;
+ }
+ }
+ }
+}
+
+static int GPU_typesize( int type ) {
+ switch( type ) {
+ case GL_FLOAT:
+ return sizeof(float);
+ case GL_INT:
+ return sizeof(int);
+ case GL_UNSIGNED_INT:
+ return sizeof(unsigned int);
+ case GL_BYTE:
+ return sizeof(char);
+ case GL_UNSIGNED_BYTE:
+ return sizeof(unsigned char);
+ default:
+ return 0;
+ }
+}
+
+int GPU_attrib_element_size( GPUAttrib data[], int numdata ) {
+ int i, elementsize = 0;
+
+ for( i = 0; i < numdata; i++ ) {
+ int typesize = GPU_typesize(data[i].type);
+ if( typesize == 0 )
+ DEBUG_VBO( "Unknown element in data type array in GPU_attrib_element_size\n" );
+ else {
+ elementsize += typesize*data[i].size;
+ }
+ }
+ return elementsize;
+}
+
+void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numdata ) {
+ int i;
+ int elementsize;
+ intptr_t offset = 0;
+
+ DEBUG_VBO("GPU_interleaved_attrib_setup\n");
+
+ for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
+ if( attribData[i].index != -1 ) {
+ glDisableVertexAttribArrayARB( attribData[i].index );
+ }
+ else
+ break;
+ }
+ elementsize = GPU_attrib_element_size( data, numdata );
+
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
+ for( i = 0; i < numdata; i++ ) {
+ glEnableVertexAttribArrayARB( data[i].index );
+ glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (void *)offset );
+ offset += data[i].size*GPU_typesize(data[i].type);
+
+ attribData[i].index = data[i].index;
+ attribData[i].size = data[i].size;
+ attribData[i].type = data[i].type;
+ }
+ attribData[numdata].index = -1;
+ }
+ else {
+ for( i = 0; i < numdata; i++ ) {
+ glEnableVertexAttribArrayARB( data[i].index );
+ glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (char *)buffer->pointer + offset );
+ offset += data[i].size*GPU_typesize(data[i].type);
+ }
+ }
+}
+
+
+void GPU_buffer_unbind()
+{
+ int i;
+ DEBUG_VBO("GPU_buffer_unbind\n");
+
+ if( GLStates & GPU_BUFFER_VERTEX_STATE )
+ glDisableClientState( GL_VERTEX_ARRAY );
+ if( GLStates & GPU_BUFFER_NORMAL_STATE )
+ glDisableClientState( GL_NORMAL_ARRAY );
+ if( GLStates & GPU_BUFFER_TEXCOORD_STATE )
+ glDisableClientState( GL_TEXTURE_COORD_ARRAY );
+ if( GLStates & GPU_BUFFER_COLOR_STATE )
+ glDisableClientState( GL_COLOR_ARRAY );
+ if( GLStates & GPU_BUFFER_ELEMENT_STATE ) {
+ if( useVBOs ) {
+ glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
+ }
+ }
+ GLStates &= !(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE);
+
+ for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
+ if( attribData[i].index != -1 ) {
+ glDisableVertexAttribArrayARB( attribData[i].index );
+ }
+ else
+ break;
+ }
+ if( GLStates != 0 )
+ DEBUG_VBO( "Some weird OpenGL state is still set. Why?" );
+ if( useVBOs )
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
+}
+
+void GPU_color3_upload( DerivedMesh *dm, unsigned char *data )
+{
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new(dm);
+ GPU_buffer_free(dm->drawObject->colors,globalPool);
+ dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3 );
+}
+void GPU_color4_upload( DerivedMesh *dm, unsigned char *data )
+{
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new(dm);
+ GPU_buffer_free(dm->drawObject->colors,globalPool);
+ dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4 );
+}
+
+void GPU_color_switch( int mode )
+{
+ if( mode ) {
+ if( !GLStates & GPU_BUFFER_COLOR_STATE )
+ glEnableClientState( GL_COLOR_ARRAY );
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+ }
+ else {
+ if( GLStates & GPU_BUFFER_COLOR_STATE )
+ glDisableClientState( GL_COLOR_ARRAY );
+ GLStates &= (!GPU_BUFFER_COLOR_STATE);
+ }
+}
+
+int GPU_buffer_legacy( DerivedMesh *dm )
+{
+ int test= (U.gameflags & USER_DISABLE_VBO);
+ if( test )
+ return 1;
+
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new(dm);
+ return dm->drawObject->legacy;
+}
+
+void *GPU_buffer_lock( GPUBuffer *buffer )
+{
+ float *varray;
+
+ DEBUG_VBO("GPU_buffer_lock\n");
+ if( buffer == 0 ) {
+ DEBUG_VBO( "Failed to lock NULL buffer\n" );
+ return 0;
+ }
+
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
+ varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
+ if( varray == 0 ) {
+ DEBUG_VBO( "Failed to map buffer to client address space\n" );
+ }
+ return varray;
+ }
+ else {
+ return buffer->pointer;
+ }
+}
+
+void *GPU_buffer_lock_stream( GPUBuffer *buffer )
+{
+ float *varray;
+
+ DEBUG_VBO("GPU_buffer_lock_stream\n");
+ if( buffer == 0 ) {
+ DEBUG_VBO( "Failed to lock NULL buffer\n" );
+ return 0;
+ }
+
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
+ glBufferDataARB( GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB ); /* discard previous data, avoid stalling gpu */
+ varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
+ if( varray == 0 ) {
+ DEBUG_VBO( "Failed to map buffer to client address space\n" );
+ }
+ return varray;
+ }
+ else {
+ return buffer->pointer;
+ }
+}
+
+void GPU_buffer_unlock( GPUBuffer *buffer )
+{
+ DEBUG_VBO( "GPU_buffer_unlock\n" );
+ if( useVBOs ) {
+ if( buffer != 0 ) {
+ if( glUnmapBufferARB( GL_ARRAY_BUFFER_ARB ) == 0 ) {
+ DEBUG_VBO( "Failed to copy new data\n" );
+ }
+ }
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ }
+}
+
+void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count )
+{
+ if( useVBOs ) {
+ glDrawElements( mode, count, GL_UNSIGNED_INT, (void *)(start*sizeof(unsigned int)) );
+ }
+ else {
+ glDrawElements( mode, count, GL_UNSIGNED_INT, ((int *)elements->pointer)+start );
+ }
+}
diff --git a/source/blender/makesrna/intern/rna_action_api.c b/source/blender/makesrna/intern/rna_action_api.c
new file mode 100644
index 00000000000..991a8251cc5
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_action_api.c
@@ -0,0 +1,80 @@
+/**
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Arystanbek Dyussenov
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#include "DNA_action_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_action.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_curve_types.h"
+
+/* XXX disabled until RNA allows returning arrays */
+#if 0
+/* return frame range of all curves (min, max) or (0, 1) if there are no keys */
+int *rna_Action_get_frame_range(bAction *act, int *ret_length)
+{
+ int *ret;
+ float start, end;
+
+ calc_action_range(act, &start, &end, 1);
+
+ *ret_length= 2;
+ ret= MEM_callocN(*ret_length * sizeof(int), "rna_Action_get_frame_range");
+
+ ret[0]= (int)start;
+ ret[1]= (int)end;
+
+ return ret;
+}
+#endif
+
+#else
+
+void RNA_api_action(StructRNA *srna)
+{
+#if 0
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func= RNA_def_function(srna, "get_frame_range", "rna_Action_get_frame_range");
+ RNA_def_function_ui_description(func, "Get action frame range as a (min, max) tuple.");
+ parm= RNA_def_int_array(func, "frame_range", 1, NULL, 0, 0, "", "Action frame range.", 0, 0);
+ RNA_def_property_flag(parm, PROP_DYNAMIC_ARRAY);
+ RNA_def_function_return(func, parm);
+#endif
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
new file mode 100644
index 00000000000..4ac6b98b167
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -0,0 +1,101 @@
+/**
+ * $Id: rna_image_api.c 23507 2009-09-27 09:19:29Z kazanbas $
+ *
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Arystanbek Dyussenov
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_image_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+/*
+ User should check if returned path exists before copying a file there.
+
+ TODO: it would be better to return a (abs, rel) tuple.
+*/
+static char *rna_Image_get_export_path(Image *image, char *dest_dir, int rel)
+{
+ int length = FILE_MAX;
+ char *path= MEM_callocN(length, "image file path");
+
+ if (!BKE_get_image_export_path(image, dest_dir, rel ? NULL : path, length, rel ? path : NULL, length )) {
+ MEM_freeN(path);
+ return NULL;
+ }
+
+ return path;
+}
+
+char *rna_Image_get_abs_filename(Image *image, bContext *C)
+{
+ char *filename= MEM_callocN(FILE_MAX, "Image.get_abs_filename()");
+
+ BLI_strncpy(filename, image->name, FILE_MAXDIR + FILE_MAXFILE);
+ BLI_convertstringcode(filename, CTX_data_main(C)->name);
+ BLI_convertstringframe(filename, CTX_data_scene(C)->r.cfra);
+
+ return filename;
+}
+
+#else
+
+void RNA_api_image(StructRNA *srna)
+{
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func= RNA_def_function(srna, "get_export_path", "rna_Image_get_export_path");
+ RNA_def_function_ui_description(func, "Produce image export path.");
+ parm= RNA_def_string(func, "dest_dir", "", 0, "", "Destination directory.");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm= RNA_def_boolean(func, "get_rel_path", 1, "", "Return relative path if True.");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm= RNA_def_string(func, "path", "", 0, "", "Absolute export path.");
+ RNA_def_function_return(func, parm);
+
+ func= RNA_def_function(srna, "get_abs_filename", "rna_Image_get_abs_filename");
+ RNA_def_function_ui_description(func, "Get absolute filename.");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ parm= RNA_def_string_file_path(func, "abs_filename", NULL, 0, "", "Image/movie absolute filename.");
+ RNA_def_function_return(func, parm);
+}
+
+#endif
+
diff --git a/source/blender/makesrna/intern/rna_material_api.c b/source/blender/makesrna/intern/rna_material_api.c
new file mode 100644
index 00000000000..aa28b6b923c
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_material_api.c
@@ -0,0 +1,126 @@
+/**
+ *
+ *
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#include "DNA_material_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_material.h"
+#include "BKE_texture.h"
+
+/*
+ Adds material to the first free texture slot.
+ If all slots are busy, replaces the first.
+*/
+static void rna_Material_add_texture(Material *ma, Tex *tex, int mapto, int texco)
+{
+ int i;
+ MTex *mtex;
+ int slot= -1;
+
+ for (i= 0; i < MAX_MTEX; i++) {
+ if (!ma->mtex[i]) {
+ slot= i;
+ break;
+ }
+ }
+
+ if (slot == -1)
+ slot= 0;
+
+ if (ma->mtex[slot]) {
+ ma->mtex[slot]->tex->id.us--;
+ }
+ else {
+ ma->mtex[slot]= add_mtex();
+ }
+
+ mtex= ma->mtex[slot];
+
+ mtex->tex= tex;
+ id_us_plus(&tex->id);
+
+ mtex->texco= mapto;
+ mtex->mapto= texco;
+}
+
+#else
+
+void RNA_api_material(StructRNA *srna)
+{
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ /* copied from rna_def_material_mtex (rna_material.c) */
+ static EnumPropertyItem prop_texture_coordinates_items[] = {
+ {TEXCO_GLOB, "GLOBAL", 0, "Global", "Uses global coordinates for the texture coordinates."},
+ {TEXCO_OBJECT, "OBJECT", 0, "Object", "Uses linked object's coordinates for texture coordinates."},
+ {TEXCO_UV, "UV", 0, "UV", "Uses UV coordinates for texture coordinates."},
+ {TEXCO_ORCO, "ORCO", 0, "Generated", "Uses the original undeformed coordinates of the object."},
+ {TEXCO_STRAND, "STRAND", 0, "Strand", "Uses normalized strand texture coordinate (1D)."},
+ {TEXCO_STICKY, "STICKY", 0, "Sticky", "Uses mesh's sticky coordinates for the texture coordinates."},
+ {TEXCO_WINDOW, "WINDOW", 0, "Window", "Uses screen coordinates as texture coordinates."},
+ {TEXCO_NORM, "NORMAL", 0, "Normal", "Uses normal vector as texture coordinates."},
+ {TEXCO_REFL, "REFLECTION", 0, "Reflection", "Uses reflection vector as texture coordinates."},
+ {TEXCO_STRESS, "STRESS", 0, "Stress", "Uses the difference of edge lengths compared to original coordinates of the mesh."},
+ {TEXCO_TANGENT, "TANGENT", 0, "Tangent", "Uses the optional tangent vector as texture coordinates."},
+
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem prop_texture_mapto_items[] = {
+ {MAP_COL, "COLOR", 0, "Color", "Causes the texture to affect basic color of the material"},
+ {MAP_NORM, "NORMAL", 0, "Normal", "Causes the texture to affect the rendered normal"},
+ {MAP_COLSPEC, "SPECULAR_COLOR", 0, "Specularity Color", "Causes the texture to affect the specularity color"},
+ {MAP_COLMIR, "MIRROR", 0, "Mirror", "Causes the texture to affect the mirror color"},
+ {MAP_REF, "REFLECTION", 0, "Reflection", "Causes the texture to affect the value of the materials reflectivity"},
+ {MAP_SPEC, "SPECULARITY", 0, "Specularity", "Causes the texture to affect the value of specularity"},
+ {MAP_EMIT, "EMIT", 0, "Emit", "Causes the texture to affect the emit value"},
+ {MAP_ALPHA, "ALPHA", 0, "Alpha", "Causes the texture to affect the alpha value"},
+ {MAP_HAR, "HARDNESS", 0, "Hardness", "Causes the texture to affect the hardness value"},
+ {MAP_RAYMIRR, "RAY_MIRROR", 0, "Ray-Mirror", "Causes the texture to affect the ray-mirror value"},
+ {MAP_TRANSLU, "TRANSLUCENCY", 0, "Translucency", "Causes the texture to affect the translucency value"},
+ {MAP_AMB, "AMBIENT", 0, "Ambient", "Causes the texture to affect the value of ambient"},
+ {MAP_DISPLACE, "DISPLACEMENT", 0, "Displacement", "Let the texture displace the surface"},
+ {MAP_WARP, "WARP", 0, "Warp", "Let the texture warp texture coordinates of next channels"},
+ {0, NULL, 0, NULL, NULL}};
+
+ func= RNA_def_function(srna, "add_texture", "rna_Material_add_texture");
+ RNA_def_function_ui_description(func, "Add a texture to material's free texture slot.");
+ parm= RNA_def_pointer(func, "texture", "Texture", "", "Texture to add.");
+ parm= RNA_def_enum(func, "texture_coordinates", prop_texture_coordinates_items, TEXCO_UV, "", "Source of texture coordinate information."); /* optional */
+ parm= RNA_def_enum(func, "map_to", prop_texture_mapto_items, MAP_COL, "", "Controls which material property the texture affects."); /* optional */
+}
+
+#endif
+
diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c
new file mode 100644
index 00000000000..c6791405109
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_pose_api.c
@@ -0,0 +1,56 @@
+/**
+ * $Id: rna_pose_api.c 23425 2009-09-22 19:09:04Z 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#include "DNA_object_types.h"
+
+/* #include "BLO_sys_types.h" */
+
+#ifdef RNA_RUNTIME
+
+/* #include "DNA_anim_types.h" */
+#include "DNA_action_types.h" /* bPose */
+
+#else
+
+void RNA_api_pose(StructRNA *srna)
+{
+ /* FunctionRNA *func; */
+ /* PropertyRNA *parm; */
+
+}
+
+#endif
+
diff --git a/source/gameengine/Converter/BL_ArmatureActuator.cpp b/source/gameengine/Converter/BL_ArmatureActuator.cpp
new file mode 100644
index 00000000000..4105eb57d5f
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureActuator.cpp
@@ -0,0 +1,267 @@
+/**
+ * $Id: BL_ArmatureActuator.cpp 23562 2009-09-29 21:42:40Z 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_actuator_types.h"
+#include "BKE_constraint.h"
+#include "BLI_arithb.h"
+#include "BL_ArmatureActuator.h"
+#include "BL_ArmatureObject.h"
+
+/**
+ * This class is the conversion of the Pose channel constraint.
+ * It makes a link between the pose constraint and the KX scene.
+ * The main purpose is to give access to the constraint target
+ * to link it to a game object.
+ * It also allows to activate/deactivate constraints during the game.
+ * Later it will also be possible to create constraint on the fly
+ */
+
+BL_ArmatureActuator::BL_ArmatureActuator(SCA_IObject* obj,
+ int type,
+ const char *posechannel,
+ const char *constraintname,
+ KX_GameObject* targetobj,
+ KX_GameObject* subtargetobj,
+ float weight) :
+ SCA_IActuator(obj, KX_ACT_ARMATURE),
+ m_constraint(NULL),
+ m_gametarget(targetobj),
+ m_gamesubtarget(subtargetobj),
+ m_posechannel(posechannel),
+ m_constraintname(constraintname),
+ m_weight(weight),
+ m_type(type)
+{
+ if (m_gametarget)
+ m_gametarget->RegisterActuator(this);
+ if (m_gamesubtarget)
+ m_gamesubtarget->RegisterActuator(this);
+ FindConstraint();
+}
+
+BL_ArmatureActuator::~BL_ArmatureActuator()
+{
+ if (m_gametarget)
+ m_gametarget->UnregisterActuator(this);
+ if (m_gamesubtarget)
+ m_gamesubtarget->UnregisterActuator(this);
+}
+
+void BL_ArmatureActuator::ProcessReplica()
+{
+ // the replica is tracking the same object => register it (this may be changed in Relnk())
+ if (m_gametarget)
+ m_gametarget->RegisterActuator(this);
+ if (m_gamesubtarget)
+ m_gamesubtarget->UnregisterActuator(this);
+ SCA_IActuator::ProcessReplica();
+}
+
+void BL_ArmatureActuator::ReParent(SCA_IObject* parent)
+{
+ SCA_IActuator::ReParent(parent);
+ // must remap the constraint
+ FindConstraint();
+}
+
+bool BL_ArmatureActuator::UnlinkObject(SCA_IObject* clientobj)
+{
+ bool res=false;
+ if (clientobj == m_gametarget)
+ {
+ // this object is being deleted, we cannot continue to track it.
+ m_gametarget = NULL;
+ res = true;
+ }
+ if (clientobj == m_gamesubtarget)
+ {
+ // this object is being deleted, we cannot continue to track it.
+ m_gamesubtarget = NULL;
+ res = true;
+ }
+ return res;
+}
+
+void BL_ArmatureActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
+{
+ void **h_obj = (*obj_map)[m_gametarget];
+ if (h_obj) {
+ if (m_gametarget)
+ m_gametarget->UnregisterActuator(this);
+ m_gametarget = (KX_GameObject*)(*h_obj);
+ m_gametarget->RegisterActuator(this);
+ }
+ h_obj = (*obj_map)[m_gamesubtarget];
+ if (h_obj) {
+ if (m_gamesubtarget)
+ m_gamesubtarget->UnregisterActuator(this);
+ m_gamesubtarget = (KX_GameObject*)(*h_obj);
+ m_gamesubtarget->RegisterActuator(this);
+ }
+}
+
+void BL_ArmatureActuator::FindConstraint()
+{
+ m_constraint = NULL;
+
+ if (m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) {
+ BL_ArmatureObject* armobj = (BL_ArmatureObject*)m_gameobj;
+ m_constraint = armobj->GetConstraint(m_posechannel, m_constraintname);
+ }
+}
+
+bool BL_ArmatureActuator::Update(double curtime, bool frame)
+{
+ // the only role of this actuator is to ensure that the armature pose will be evaluated
+ bool result = false;
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (!bNegativeEvent) {
+ BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent();
+ switch (m_type) {
+ case ACT_ARM_RUN:
+ result = true;
+ obj->SetActiveAction(NULL, 0, curtime);
+ break;
+ case ACT_ARM_ENABLE:
+ if (m_constraint)
+ m_constraint->ClrConstraintFlag(CONSTRAINT_OFF);
+ break;
+ case ACT_ARM_DISABLE:
+ if (m_constraint)
+ m_constraint->SetConstraintFlag(CONSTRAINT_OFF);
+ break;
+ case ACT_ARM_SETTARGET:
+ if (m_constraint) {
+ m_constraint->SetTarget(m_gametarget);
+ m_constraint->SetSubtarget(m_gamesubtarget);
+ }
+ break;
+ case ACT_ARM_SETWEIGHT:
+ if (m_constraint)
+ m_constraint->SetWeight(m_weight);
+ break;
+ }
+ }
+ return result;
+}
+
+#ifndef DISABLE_PYTHON
+
+/* ------------------------------------------------------------------------- */
+/* Python Integration Hooks */
+/* ------------------------------------------------------------------------- */
+
+PyTypeObject BL_ArmatureActuator::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
+ "BL_ArmatureActuator",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_base_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &SCA_IActuator::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+
+PyMethodDef BL_ArmatureActuator::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+PyAttributeDef BL_ArmatureActuator::Attributes[] = {
+ KX_PYATTRIBUTE_RO_FUNCTION("constraint", BL_ArmatureActuator, pyattr_get_constraint),
+ KX_PYATTRIBUTE_RW_FUNCTION("target", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object),
+ KX_PYATTRIBUTE_RW_FUNCTION("subtarget", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object),
+ KX_PYATTRIBUTE_FLOAT_RW("weight",0.0f,1.0f,BL_ArmatureActuator,m_weight),
+ KX_PYATTRIBUTE_INT_RW("type",0,ACT_ARM_MAXTYPE,false,BL_ArmatureActuator,m_type),
+ { NULL } //Sentinel
+};
+
+PyObject* BL_ArmatureActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self);
+ KX_GameObject *target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget;
+ if (!target)
+ Py_RETURN_NONE;
+ else
+ return target->GetProxy();
+}
+
+int BL_ArmatureActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self);
+ KX_GameObject* &target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget;
+ KX_GameObject *gameobj;
+
+ if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: BL_ArmatureActuator"))
+ return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
+
+ if (target != NULL)
+ target->UnregisterActuator(actuator);
+
+ target = gameobj;
+
+ if (target)
+ target->RegisterActuator(actuator);
+
+ return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject* BL_ArmatureActuator::pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self);
+ BL_ArmatureConstraint* constraint = actuator->m_constraint;
+ if (!constraint)
+ Py_RETURN_NONE;
+ else
+ return constraint->GetProxy();
+}
+
+#endif // DISABLE_PYTHON
+
diff --git a/source/gameengine/Converter/BL_ArmatureActuator.h b/source/gameengine/Converter/BL_ArmatureActuator.h
new file mode 100644
index 00000000000..29b07b16d52
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureActuator.h
@@ -0,0 +1,93 @@
+/**
+ * $Id: BL_ArmatureActuator.h 23562 2009-09-29 21:42:40Z 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef BL_ARMATUREACTUATOR
+#define BL_ARMATUREACTUATOR
+
+#include "SCA_IActuator.h"
+#include "BL_ArmatureConstraint.h"
+
+/**
+ * This class is the conversion of the Pose channel constraint.
+ * It makes a link between the pose constraint and the KX scene.
+ * The main purpose is to give access to the constraint target
+ * to link it to a game object.
+ * It also allows to activate/deactivate constraints during the game.
+ * Later it will also be possible to create constraint on the fly
+ */
+
+class BL_ArmatureActuator : public SCA_IActuator
+{
+ Py_Header;
+public:
+ BL_ArmatureActuator(SCA_IObject* gameobj,
+ int type,
+ const char *posechannel,
+ const char *constraintname,
+ KX_GameObject* targetobj,
+ KX_GameObject* subtargetobj,
+ float weight);
+
+ virtual ~BL_ArmatureActuator();
+
+ virtual CValue* GetReplica() {
+ BL_ArmatureActuator* replica = new BL_ArmatureActuator(*this);
+ replica->ProcessReplica();
+ return replica;
+ };
+ virtual void ProcessReplica();
+ virtual bool UnlinkObject(SCA_IObject* clientobj);
+ virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
+ virtual bool Update(double curtime, bool frame);
+ virtual void ReParent(SCA_IObject* parent);
+
+#ifndef DISABLE_PYTHON
+
+ /* These are used to get and set m_target */
+ static PyObject* pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject* pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+
+#endif // DISABLE_PYTHON
+
+private:
+ // identify the constraint that this actuator controls
+ void FindConstraint();
+
+ BL_ArmatureConstraint* m_constraint;
+ KX_GameObject* m_gametarget;
+ KX_GameObject* m_gamesubtarget;
+ STR_String m_posechannel;
+ STR_String m_constraintname;
+ float m_weight;
+ int m_type;
+};
+
+#endif //BL_ARMATUREACTUATOR
+
+
diff --git a/source/gameengine/Converter/BL_ArmatureChannel.cpp b/source/gameengine/Converter/BL_ArmatureChannel.cpp
new file mode 100644
index 00000000000..817049c6977
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureChannel.cpp
@@ -0,0 +1,469 @@
+/**
+ * $Id: BL_ArmatureChannel.cpp 23562 2009-09-29 21:42:40Z 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_armature_types.h"
+#include "BL_ArmatureChannel.h"
+#include "BL_ArmatureObject.h"
+#include "BL_ArmatureConstraint.h"
+#include "BLI_arithb.h"
+#include "BLI_string.h"
+
+#ifndef DISABLE_PYTHON
+
+PyTypeObject BL_ArmatureChannel::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BL_ArmatureChannel",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_base_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &CValue::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+PyObject* BL_ArmatureChannel::py_repr(void)
+{
+ return PyUnicode_FromString(m_posechannel->name);
+}
+
+PyObject *BL_ArmatureChannel::GetProxy()
+{
+ return GetProxyPlus_Ext(this, &Type, m_posechannel);
+}
+
+PyObject *BL_ArmatureChannel::NewProxy(bool py_owns)
+{
+ return NewProxyPlus_Ext(this, &Type, m_posechannel, py_owns);
+}
+
+#endif // DISABLE_PYTHON
+
+BL_ArmatureChannel::BL_ArmatureChannel(
+ BL_ArmatureObject *armature,
+ bPoseChannel *posechannel)
+ : PyObjectPlus(), m_posechannel(posechannel), m_armature(armature)
+{
+}
+
+BL_ArmatureChannel::~BL_ArmatureChannel()
+{
+}
+
+#ifndef DISABLE_PYTHON
+
+// PYTHON
+
+PyMethodDef BL_ArmatureChannel::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+// order of definition of attributes, must match Attributes[] array
+#define BCA_BONE 0
+#define BCA_PARENT 1
+
+PyAttributeDef BL_ArmatureChannel::Attributes[] = {
+ // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr
+ KX_PYATTRIBUTE_RO_FUNCTION("bone",BL_ArmatureChannel,py_attr_getattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureChannel,py_attr_getattr),
+
+ { NULL } //Sentinel
+};
+
+/* attributes directly taken from bPoseChannel */
+PyAttributeDef BL_ArmatureChannel::AttributesPtr[] = {
+ KX_PYATTRIBUTE_CHAR_RO("name",bPoseChannel,name),
+ KX_PYATTRIBUTE_FLAG_RO("has_ik",bPoseChannel,flag, POSE_CHAIN),
+ KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_x",bPoseChannel,ikflag, BONE_IK_NO_XDOF),
+ KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_y",bPoseChannel,ikflag, BONE_IK_NO_YDOF),
+ KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_z",bPoseChannel,ikflag, BONE_IK_NO_ZDOF),
+ KX_PYATTRIBUTE_FLAG_RO("ik_limit_x",bPoseChannel,ikflag, BONE_IK_XLIMIT),
+ KX_PYATTRIBUTE_FLAG_RO("ik_limit_y",bPoseChannel,ikflag, BONE_IK_YLIMIT),
+ KX_PYATTRIBUTE_FLAG_RO("ik_limit_z",bPoseChannel,ikflag, BONE_IK_ZLIMIT),
+ KX_PYATTRIBUTE_FLAG_RO("ik_rot_control",bPoseChannel,ikflag, BONE_IK_ROTCTL),
+ KX_PYATTRIBUTE_FLAG_RO("ik_lin_control",bPoseChannel,ikflag, BONE_IK_LINCTL),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RW("location",-FLT_MAX,FLT_MAX,bPoseChannel,loc,3),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RW("scale",-FLT_MAX,FLT_MAX,bPoseChannel,size,3),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_quaternion",-1.0f,1.0f,bPoseChannel,quat,4),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotaion_euler",-10.f,10.f,bPoseChannel,eul,3),
+ KX_PYATTRIBUTE_SHORT_RW("rotation_mode",0,ROT_MODE_MAX-1,false,bPoseChannel,rotmode),
+ KX_PYATTRIBUTE_FLOAT_MATRIX_RO("channel_matrix",bPoseChannel,chan_mat,4),
+ KX_PYATTRIBUTE_FLOAT_MATRIX_RO("pose_matrix",bPoseChannel,pose_mat,4),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_head",bPoseChannel,pose_head,3),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_tail",bPoseChannel,pose_tail,3),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_min_x",bPoseChannel,limitmin[0]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_max_x",bPoseChannel,limitmax[0]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_min_y",bPoseChannel,limitmin[1]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_max_y",bPoseChannel,limitmax[1]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_min_z",bPoseChannel,limitmin[2]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_max_z",bPoseChannel,limitmax[2]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_x",bPoseChannel,stiffness[0]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_y",bPoseChannel,stiffness[1]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_z",bPoseChannel,stiffness[2]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_stretch",bPoseChannel,ikstretch),
+ KX_PYATTRIBUTE_FLOAT_RW("ik_rot_weight",0,1.0f,bPoseChannel,ikrotweight),
+ KX_PYATTRIBUTE_FLOAT_RW("ik_lin_weight",0,1.0f,bPoseChannel,iklinweight),
+ KX_PYATTRIBUTE_RW_FUNCTION("joint_rotation",BL_ArmatureChannel,py_attr_get_joint_rotation,py_attr_set_joint_rotation),
+ { NULL } //Sentinel
+};
+
+PyObject* BL_ArmatureChannel::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
+ bPoseChannel* channel = self->m_posechannel;
+ int attr_order = attrdef-Attributes;
+
+ if (!channel) {
+ PyErr_SetString(PyExc_AttributeError, "channel is NULL");
+ return NULL;
+ }
+
+ switch (attr_order) {
+ case BCA_BONE:
+ // bones are standalone proxy
+ return NewProxyPlus_Ext(NULL,&BL_ArmatureBone::Type,channel->bone,false);
+ case BCA_PARENT:
+ {
+ BL_ArmatureChannel* parent = self->m_armature->GetChannel(channel->parent);
+ if (parent)
+ return parent->GetProxy();
+ else
+ Py_RETURN_NONE;
+ }
+ }
+ PyErr_SetString(PyExc_AttributeError, "channel unknown attribute");
+ return NULL;
+}
+
+int BL_ArmatureChannel::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
+ bPoseChannel* channel = self->m_posechannel;
+ int attr_order = attrdef-Attributes;
+
+ int ival;
+ double dval;
+ char* sval;
+ KX_GameObject *oval;
+
+ if (!channel) {
+ PyErr_SetString(PyExc_AttributeError, "channel is NULL");
+ return PY_SET_ATTR_FAIL;
+ }
+
+ switch (attr_order) {
+ default:
+ break;
+ }
+
+ PyErr_SetString(PyExc_AttributeError, "channel unknown attribute");
+ return PY_SET_ATTR_FAIL;
+}
+
+PyObject* BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
+ bPoseChannel* pchan = self->m_posechannel;
+ // decompose the pose matrix in euler rotation
+ float rest_mat[3][3];
+ float pose_mat[3][3];
+ float joint_mat[3][3];
+ float joints[3];
+ float norm;
+ double sa, ca;
+ // get rotation in armature space
+ Mat3CpyMat4(pose_mat, pchan->pose_mat);
+ Mat3Ortho(pose_mat);
+ if (pchan->parent) {
+ // bone has a parent, compute the rest pose of the bone taking actual pose of parent
+ Mat3IsMat3MulMat4(rest_mat, pchan->bone->bone_mat, pchan->parent->pose_mat);
+ Mat3Ortho(rest_mat);
+ } else {
+ // otherwise, the bone matrix in armature space is the rest pose
+ Mat3CpyMat4(rest_mat, pchan->bone->arm_mat);
+ }
+ // remove the rest pose to get the joint movement
+ Mat3Transp(rest_mat);
+ Mat3MulMat3(joint_mat, rest_mat, pose_mat);
+ joints[0] = joints[1] = joints[2] = 0.f;
+ // returns a 3 element list that gives corresponding joint
+ int flag = 0;
+ if (!(pchan->ikflag & BONE_IK_NO_XDOF))
+ flag |= 1;
+ if (!(pchan->ikflag & BONE_IK_NO_YDOF))
+ flag |= 2;
+ if (!(pchan->ikflag & BONE_IK_NO_ZDOF))
+ flag |= 4;
+ switch (flag) {
+ case 0: // fixed joint
+ break;
+ case 1: // X only
+ Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ);
+ joints[1] = joints[2] = 0.f;
+ break;
+ case 2: // Y only
+ Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ);
+ joints[0] = joints[2] = 0.f;
+ break;
+ case 3: // X+Y
+ Mat3ToEulO(joint_mat, joints, EULER_ORDER_ZYX);
+ joints[2] = 0.f;
+ break;
+ case 4: // Z only
+ Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ);
+ joints[0] = joints[1] = 0.f;
+ break;
+ case 5: // X+Z
+ // decompose this as an equivalent rotation vector in X/Z plane
+ joints[0] = joint_mat[1][2];
+ joints[2] = -joint_mat[1][0];
+ norm = Normalize(joints);
+ if (norm < FLT_EPSILON) {
+ norm = (joint_mat[1][1] < 0.f) ? M_PI : 0.f;
+ } else {
+ norm = acos(joint_mat[1][1]);
+ }
+ VecMulf(joints, norm);
+ break;
+ case 6: // Y+Z
+ Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ);
+ joints[0] = 0.f;
+ break;
+ case 7: // X+Y+Z
+ // equivalent axis
+ joints[0] = (joint_mat[1][2]-joint_mat[2][1])*0.5f;
+ joints[1] = (joint_mat[2][0]-joint_mat[0][2])*0.5f;
+ joints[2] = (joint_mat[0][1]-joint_mat[1][0])*0.5f;
+ sa = VecLength(joints);
+ ca = (joint_mat[0][0]+joint_mat[1][1]+joint_mat[1][1]-1.0f)*0.5f;
+ if (sa > FLT_EPSILON) {
+ norm = atan2(sa,ca)/sa;
+ } else {
+ if (ca < 0.0) {
+ norm = M_PI;
+ VecMulf(joints,0.f);
+ if (joint_mat[0][0] > 0.f) {
+ joints[0] = 1.0f;
+ } else if (joint_mat[1][1] > 0.f) {
+ joints[1] = 1.0f;
+ } else {
+ joints[2] = 1.0f;
+ }
+ } else {
+ norm = 0.0;
+ }
+ }
+ VecMulf(joints,norm);
+ break;
+ }
+ return newVectorObject(joints, 3, Py_NEW, NULL);
+}
+
+int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
+ bPoseChannel* pchan = self->m_posechannel;
+ PyObject *item;
+ float joints[3];
+ float quat[4];
+
+ if (!PySequence_Check(value) || PySequence_Size(value) != 3) {
+ PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats");
+ return PY_SET_ATTR_FAIL;
+ }
+ for (int i=0; i<3; i++) {
+ item = PySequence_GetItem(value, i); /* new ref */
+ joints[i] = PyFloat_AsDouble(item);
+ Py_DECREF(item);
+ if (joints[i] == -1.0f && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats");
+ return PY_SET_ATTR_FAIL;
+ }
+ }
+
+ int flag = 0;
+ if (!(pchan->ikflag & BONE_IK_NO_XDOF))
+ flag |= 1;
+ if (!(pchan->ikflag & BONE_IK_NO_YDOF))
+ flag |= 2;
+ if (!(pchan->ikflag & BONE_IK_NO_ZDOF))
+ flag |= 4;
+ QuatOne(quat);
+ switch (flag) {
+ case 0: // fixed joint
+ break;
+ case 1: // X only
+ joints[1] = joints[2] = 0.f;
+ EulOToQuat(joints, EULER_ORDER_XYZ, quat);
+ break;
+ case 2: // Y only
+ joints[0] = joints[2] = 0.f;
+ EulOToQuat(joints, EULER_ORDER_XYZ, quat);
+ break;
+ case 3: // X+Y
+ joints[2] = 0.f;
+ EulOToQuat(joints, EULER_ORDER_ZYX, quat);
+ break;
+ case 4: // Z only
+ joints[0] = joints[1] = 0.f;
+ EulOToQuat(joints, EULER_ORDER_XYZ, quat);
+ break;
+ case 5: // X+Z
+ // X and Z are components of an equivalent rotation axis
+ joints[1] = 0;
+ VecRotToQuat(joints, VecLength(joints), quat);
+ break;
+ case 6: // Y+Z
+ joints[0] = 0.f;
+ EulOToQuat(joints, EULER_ORDER_XYZ, quat);
+ break;
+ case 7: // X+Y+Z
+ // equivalent axis
+ VecRotToQuat(joints, VecLength(joints), quat);
+ break;
+ }
+ if (pchan->rotmode > 0) {
+ QuatToEulO(quat, joints, pchan->rotmode);
+ VecCopyf(pchan->eul, joints);
+ } else
+ QuatCopy(pchan->quat, quat);
+ return PY_SET_ATTR_SUCCESS;
+}
+
+// *************************
+// BL_ArmatureBone
+//
+// Access to Bone structure
+PyTypeObject BL_ArmatureBone::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BL_ArmatureBone",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_bone_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &CValue::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+// not used since this class is never instantiated
+PyObject *BL_ArmatureBone::GetProxy()
+{
+ return NULL;
+}
+PyObject *BL_ArmatureBone::NewProxy(bool py_owns)
+{
+ return NULL;
+}
+
+PyObject *BL_ArmatureBone::py_bone_repr(PyObject *self)
+{
+ Bone* bone = static_cast<Bone*>BGE_PROXY_PTR(self);
+ return PyUnicode_FromString(bone->name);
+}
+
+PyMethodDef BL_ArmatureBone::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+/* no attributes on C++ class since it is never instantiated */
+PyAttributeDef BL_ArmatureBone::Attributes[] = {
+ { NULL } //Sentinel
+};
+
+// attributes that work on proxy ptr (points to a Bone structure)
+PyAttributeDef BL_ArmatureBone::AttributesPtr[] = {
+ KX_PYATTRIBUTE_CHAR_RO("name",Bone,name),
+ KX_PYATTRIBUTE_FLAG_RO("connected",Bone,flag, BONE_CONNECTED),
+ KX_PYATTRIBUTE_FLAG_RO("hinge",Bone,flag, BONE_HINGE),
+ KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("inherit_scale",Bone,flag, BONE_NO_SCALE),
+ KX_PYATTRIBUTE_SHORT_RO("bbone_segments",Bone,segments),
+ KX_PYATTRIBUTE_FLOAT_RO("roll",Bone,roll),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("head",Bone,head,3),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("tail",Bone,tail,3),
+ KX_PYATTRIBUTE_FLOAT_RO("length",Bone,length),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_head",Bone,arm_head,3),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_tail",Bone,arm_tail,3),
+ KX_PYATTRIBUTE_FLOAT_MATRIX_RO("arm_mat",Bone,arm_mat,4),
+ KX_PYATTRIBUTE_FLOAT_MATRIX_RO("bone_mat",Bone,bone_mat,4),
+ KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureBone,py_bone_get_parent),
+ KX_PYATTRIBUTE_RO_FUNCTION("children",BL_ArmatureBone,py_bone_get_parent),
+ { NULL } //Sentinel
+};
+
+PyObject *BL_ArmatureBone::py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ Bone* bone = reinterpret_cast<Bone*>BGE_PROXY_PTR(self);
+ if (bone->parent) {
+ // create a proxy unconnected to any GE object
+ return NewProxyPlus_Ext(NULL,&Type,bone->parent,false);
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject *BL_ArmatureBone::py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ Bone* bone = reinterpret_cast<Bone*>BGE_PROXY_PTR(self);
+ Bone* child;
+ int count = 0;
+ for (child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next)
+ count++;
+
+ PyObject* childrenlist = PyList_New(count);
+
+ for (count = 0, child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next, ++count)
+ PyList_SET_ITEM(childrenlist,count,NewProxyPlus_Ext(NULL,&Type,child,false));
+
+ return childrenlist;
+}
+
+#endif // DISABLE_PYTHON
diff --git a/source/gameengine/Converter/BL_ArmatureChannel.h b/source/gameengine/Converter/BL_ArmatureChannel.h
new file mode 100644
index 00000000000..249fa4c8ac7
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureChannel.h
@@ -0,0 +1,95 @@
+/**
+ * $Id: BL_ArmatureChannel.h 23562 2009-09-29 21:42:40Z 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BL_ARMATURECHANNEL
+#define __BL_ARMATURECHANNEL
+
+#include "DNA_action_types.h"
+#include "GEN_HashedPtr.h"
+#include "GEN_Map.h"
+#include "PyObjectPlus.h"
+
+class SCA_IObject;
+class KX_GameObject;
+class BL_ArmatureObject;
+struct bConstraint;
+struct bPoseChannel;
+struct Object;
+struct bPose;
+
+class BL_ArmatureChannel : public PyObjectPlus
+{
+ // use Py_HeaderPtr since we use generic pointer in proxy
+ Py_HeaderPtr;
+
+private:
+ friend class BL_ArmatureObject;
+ struct bPoseChannel* m_posechannel;
+ BL_ArmatureObject* m_armature;
+
+public:
+ BL_ArmatureChannel(class BL_ArmatureObject *armature,
+ struct bPoseChannel *posechannel);
+ virtual ~BL_ArmatureChannel();
+
+#ifndef DISABLE_PYTHON
+ // Python access
+ virtual PyObject* py_repr(void);
+
+ static PyObject* py_attr_getattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static int py_attr_setattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ static PyObject* py_attr_get_joint_rotation(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static int py_attr_set_joint_rotation(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+#endif // DISABLE_PYTHON
+};
+
+/* this is a factory class to access bBone data field in the GE.
+ It's not supposed to be instantiated, we only need it for the Attributes and Method array.
+ The actual proxy object will be manually created using NewProxyPtr */
+class BL_ArmatureBone : public PyObjectPlus
+{
+ // use Py_HeaderPtr since we use generic pointer in proxy
+ Py_HeaderPtr;
+private:
+ // make constructor private to make sure no one tries to instantiate this class
+ BL_ArmatureBone() {}
+ virtual ~BL_ArmatureBone() {}
+
+public:
+
+#ifndef DISABLE_PYTHON
+ static PyObject *py_bone_repr(PyObject *self);
+ static PyObject *py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+#endif
+
+};
+
+
+#endif //__BL_ARMATURECHANNEL
+
diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.cpp b/source/gameengine/Converter/BL_ArmatureConstraint.cpp
new file mode 100644
index 00000000000..4c470b67387
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureConstraint.cpp
@@ -0,0 +1,454 @@
+/**
+ * $Id: BL_ArmatureConstraint.cpp 23562 2009-09-29 21:42:40Z 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_constraint_types.h"
+#include "DNA_action_types.h"
+#include "BL_ArmatureConstraint.h"
+#include "BL_ArmatureObject.h"
+#include "BLI_arithb.h"
+#include "BLI_string.h"
+
+#ifndef DISABLE_PYTHON
+
+PyTypeObject BL_ArmatureConstraint::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BL_ArmatureConstraint",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_base_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &CValue::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+PyObject* BL_ArmatureConstraint::py_repr(void)
+{
+ return PyUnicode_FromString(m_name);
+}
+
+#endif // DISABLE_PYTHON
+
+BL_ArmatureConstraint::BL_ArmatureConstraint(
+ BL_ArmatureObject *armature,
+ bPoseChannel *posechannel,
+ bConstraint *constraint,
+ KX_GameObject* target,
+ KX_GameObject* subtarget)
+ : PyObjectPlus(), m_armature(armature), m_constraint(constraint), m_posechannel(posechannel)
+{
+ m_target = target;
+ m_blendtarget = (target) ? target->GetBlenderObject() : NULL;
+ m_subtarget = subtarget;
+ m_blendsubtarget = (subtarget) ? subtarget->GetBlenderObject() : NULL;
+ m_pose = m_subpose = NULL;
+ if (m_blendtarget) {
+ Mat4CpyMat4(m_blendmat, m_blendtarget->obmat);
+ if (m_blendtarget->type == OB_ARMATURE)
+ m_pose = m_blendtarget->pose;
+ }
+ if (m_blendsubtarget) {
+ Mat4CpyMat4(m_blendsubmat, m_blendsubtarget->obmat);
+ if (m_blendsubtarget->type == OB_ARMATURE)
+ m_subpose = m_blendsubtarget->pose;
+ }
+ if (m_target)
+ m_target->RegisterObject(m_armature);
+ if (m_subtarget)
+ m_subtarget->RegisterObject(m_armature);
+ BLI_snprintf(m_name, sizeof(m_name), "%s:%s", m_posechannel->name, m_constraint->name);
+}
+
+BL_ArmatureConstraint::~BL_ArmatureConstraint()
+{
+ if (m_target)
+ m_target->UnregisterObject(m_armature);
+ if (m_subtarget)
+ m_subtarget->UnregisterObject(m_armature);
+}
+
+BL_ArmatureConstraint* BL_ArmatureConstraint::GetReplica() const
+{
+ BL_ArmatureConstraint* replica = new BL_ArmatureConstraint(*this);
+ replica->ProcessReplica();
+ return replica;
+}
+
+void BL_ArmatureConstraint::ReParent(BL_ArmatureObject* armature)
+{
+ m_armature = armature;
+ if (m_target)
+ m_target->RegisterObject(armature);
+ if (m_subtarget)
+ m_subtarget->RegisterObject(armature);
+ // find the corresponding constraint in the new armature object
+ if (m_constraint) {
+ bPose* newpose = armature->GetOrigPose();
+ char* constraint = m_constraint->name;
+ char* posechannel = m_posechannel->name;
+ bPoseChannel* pchan;
+ bConstraint* pcon;
+ m_constraint = NULL;
+ m_posechannel = NULL;
+ // and locate the constraint
+ for (pchan = (bPoseChannel*)newpose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) {
+ if (!strcmp(pchan->name, posechannel)) {
+ // now locate the constraint
+ for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) {
+ if (!strcmp(pcon->name, constraint)) {
+ m_constraint = pcon;
+ m_posechannel = pchan;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+void BL_ArmatureConstraint::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
+{
+ void **h_obj = (*obj_map)[m_target];
+ if (h_obj) {
+ m_target->UnregisterObject(m_armature);
+ m_target = (KX_GameObject*)(*h_obj);
+ m_target->RegisterObject(m_armature);
+ }
+ h_obj = (*obj_map)[m_subtarget];
+ if (h_obj) {
+ m_subtarget->UnregisterObject(m_armature);
+ m_subtarget = (KX_GameObject*)(*h_obj);
+ m_subtarget->RegisterObject(m_armature);
+ }
+}
+
+bool BL_ArmatureConstraint::UnlinkObject(SCA_IObject* clientobj)
+{
+ bool res=false;
+ if (clientobj == m_target) {
+ m_target = NULL;
+ res = true;
+ }
+ if (clientobj == m_subtarget) {
+ m_subtarget = NULL;
+ res = true;
+ }
+ return res;
+}
+
+void BL_ArmatureConstraint::UpdateTarget()
+{
+ if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) {
+ if (m_blendtarget) {
+ // external target, must be updated
+ m_target->UpdateBlenderObjectMatrix(m_blendtarget);
+ if (m_pose && m_target->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
+ // update the pose in case a bone is specified in the constraint target
+ m_blendtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose();
+ }
+ if (m_blendsubtarget && m_subtarget) {
+ m_subtarget->UpdateBlenderObjectMatrix(m_blendsubtarget);
+ if (m_subpose && m_subtarget->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
+ m_blendsubtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose();
+ }
+ }
+}
+
+void BL_ArmatureConstraint::RestoreTarget()
+{
+ if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) {
+ if (m_blendtarget) {
+ Mat4CpyMat4(m_blendtarget->obmat, m_blendmat);
+ if (m_pose)
+ m_blendtarget->pose = m_pose;
+ }
+ if (m_blendsubtarget && m_subtarget) {
+ Mat4CpyMat4(m_blendsubtarget->obmat, m_blendsubmat);
+ if (m_subpose)
+ m_blendsubtarget->pose = m_subpose;
+ }
+ }
+}
+
+bool BL_ArmatureConstraint::Match(const char* posechannel, const char* constraint)
+{
+ return (!strcmp(m_posechannel->name, posechannel) && !strcmp(m_constraint->name, constraint));
+}
+
+void BL_ArmatureConstraint::SetTarget(KX_GameObject* target)
+{
+ if (m_blendtarget) {
+ if (target != m_target) {
+ m_target->UnregisterObject(m_armature);
+ m_target = target;
+ if (m_target)
+ m_target->RegisterObject(m_armature);
+ }
+ }
+
+}
+
+void BL_ArmatureConstraint::SetSubtarget(KX_GameObject* subtarget)
+{
+ if (m_blendsubtarget) {
+ if (subtarget != m_subtarget) {
+ m_subtarget->UnregisterObject(m_armature);
+ m_subtarget = subtarget;
+ if (m_subtarget)
+ m_subtarget->RegisterObject(m_armature);
+ }
+ }
+
+}
+
+#ifndef DISABLE_PYTHON
+
+// PYTHON
+
+PyMethodDef BL_ArmatureConstraint::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+// order of definition of attributes, must match Attributes[] array
+#define BCA_TYPE 0
+#define BCA_NAME 1
+#define BCA_ENFORCE 2
+#define BCA_HEADTAIL 3
+#define BCA_LINERROR 4
+#define BCA_ROTERROR 5
+#define BCA_TARGET 6
+#define BCA_SUBTARGET 7
+#define BCA_ACTIVE 8
+#define BCA_IKWEIGHT 9
+#define BCA_IKTYPE 10
+#define BCA_IKFLAG 11
+#define BCA_IKDIST 12
+#define BCA_IKMODE 13
+
+PyAttributeDef BL_ArmatureConstraint::Attributes[] = {
+ // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr
+ KX_PYATTRIBUTE_RO_FUNCTION("type",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("name",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("enforce",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("headtail",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("lin_error",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("rot_error",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("target",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("subtarget",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("active",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("ik_weight",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("ik_type",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("ik_flag",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("ik_dist",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("ik_mode",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+
+ { NULL } //Sentinel
+};
+
+
+PyObject* BL_ArmatureConstraint::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ BL_ArmatureConstraint* self= static_cast<BL_ArmatureConstraint*>(self_v);
+ bConstraint* constraint = self->m_constraint;
+ bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL;
+ int attr_order = attrdef-Attributes;
+
+ if (!constraint) {
+ PyErr_SetString(PyExc_AttributeError, "constraint is NULL");
+ return NULL;
+ }
+
+ switch (attr_order) {
+ case BCA_TYPE:
+ return PyLong_FromLong(constraint->type);
+ case BCA_NAME:
+ return PyUnicode_FromString(constraint->name);
+ case BCA_ENFORCE:
+ return PyFloat_FromDouble(constraint->enforce);
+ case BCA_HEADTAIL:
+ return PyFloat_FromDouble(constraint->headtail);
+ case BCA_LINERROR:
+ return PyFloat_FromDouble(constraint->lin_error);
+ case BCA_ROTERROR:
+ return PyFloat_FromDouble(constraint->rot_error);
+ case BCA_TARGET:
+ if (!self->m_target)
+ Py_RETURN_NONE;
+ else
+ return self->m_target->GetProxy();
+ case BCA_SUBTARGET:
+ if (!self->m_subtarget)
+ Py_RETURN_NONE;
+ else
+ return self->m_subtarget->GetProxy();
+ case BCA_ACTIVE:
+ return PyBool_FromLong(constraint->flag & CONSTRAINT_OFF);
+ case BCA_IKWEIGHT:
+ case BCA_IKTYPE:
+ case BCA_IKFLAG:
+ case BCA_IKDIST:
+ case BCA_IKMODE:
+ if (!ikconstraint) {
+ PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type");
+ return NULL;
+ }
+ switch (attr_order) {
+ case BCA_IKWEIGHT:
+ return PyFloat_FromDouble((ikconstraint)?ikconstraint->weight:0.0);
+ case BCA_IKTYPE:
+ return PyLong_FromLong(ikconstraint->type);
+ case BCA_IKFLAG:
+ return PyLong_FromLong(ikconstraint->flag);
+ case BCA_IKDIST:
+ return PyFloat_FromDouble(ikconstraint->dist);
+ case BCA_IKMODE:
+ return PyLong_FromLong(ikconstraint->mode);
+ }
+ // should not come here
+ break;
+ }
+ PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute");
+ return NULL;
+}
+
+int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ BL_ArmatureConstraint* self= static_cast<BL_ArmatureConstraint*>(self_v);
+ bConstraint* constraint = self->m_constraint;
+ bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL;
+ int attr_order = attrdef-Attributes;
+ int ival;
+ double dval;
+ char* sval;
+ KX_GameObject *oval;
+
+ if (!constraint) {
+ PyErr_SetString(PyExc_AttributeError, "constraint is NULL");
+ return PY_SET_ATTR_FAIL;
+ }
+
+ switch (attr_order) {
+ case BCA_ENFORCE:
+ dval = PyFloat_AsDouble(value);
+ if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */
+ PyErr_SetString(PyExc_AttributeError, "constraint.enforce = float: BL_ArmatureConstraint, expected a float between 0 and 1");
+ return PY_SET_ATTR_FAIL;
+ }
+ constraint->enforce = dval;
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_HEADTAIL:
+ dval = PyFloat_AsDouble(value);
+ if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */
+ PyErr_SetString(PyExc_AttributeError, "constraint.headtail = float: BL_ArmatureConstraint, expected a float between 0 and 1");
+ return PY_SET_ATTR_FAIL;
+ }
+ constraint->headtail = dval;
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_TARGET:
+ if (!ConvertPythonToGameObject(value, &oval, true, "constraint.target = value: BL_ArmatureConstraint"))
+ return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
+ self->SetTarget(oval);
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_SUBTARGET:
+ if (!ConvertPythonToGameObject(value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint"))
+ return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
+ self->SetSubtarget(oval);
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_ACTIVE:
+ ival = PyObject_IsTrue( value );
+ if (ival == -1) {
+ PyErr_SetString(PyExc_AttributeError, "constraint.active = bool: BL_ArmatureConstraint, expected True or False");
+ return PY_SET_ATTR_FAIL;
+ }
+ self->m_constraint->flag = (self->m_constraint->flag & ~CONSTRAINT_OFF) | ((ival)?0:CONSTRAINT_OFF);
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_IKWEIGHT:
+ case BCA_IKDIST:
+ case BCA_IKMODE:
+ if (!ikconstraint) {
+ PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type");
+ return PY_SET_ATTR_FAIL;
+ }
+ switch (attr_order) {
+ case BCA_IKWEIGHT:
+ dval = PyFloat_AsDouble(value);
+ if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */
+ PyErr_SetString(PyExc_AttributeError, "constraint.weight = float: BL_ArmatureConstraint, expected a float between 0 and 1");
+ return PY_SET_ATTR_FAIL;
+ }
+ ikconstraint->weight = dval;
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_IKDIST:
+ dval = PyFloat_AsDouble(value);
+ if (dval < 0.0f) { /* also accounts for non float */
+ PyErr_SetString(PyExc_AttributeError, "constraint.ik_dist = float: BL_ArmatureConstraint, expected a positive float");
+ return PY_SET_ATTR_FAIL;
+ }
+ ikconstraint->dist = dval;
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_IKMODE:
+ ival = PyLong_AsLong(value);
+ if (ival < 0) {
+ PyErr_SetString(PyExc_AttributeError, "constraint.ik_mode = integer: BL_ArmatureConstraint, expected a positive integer");
+ return PY_SET_ATTR_FAIL;
+ }
+ ikconstraint->mode = ival;
+ return PY_SET_ATTR_SUCCESS;
+ }
+ // should not come here
+ break;
+
+ }
+
+ PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute");
+ return PY_SET_ATTR_FAIL;
+}
+
+#endif // DISABLE_PYTHON
diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.h b/source/gameengine/Converter/BL_ArmatureConstraint.h
new file mode 100644
index 00000000000..c1510b3c56a
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureConstraint.h
@@ -0,0 +1,118 @@
+/**
+ * $Id: BL_ArmatureConstraint.h 23562 2009-09-29 21:42:40Z 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BL_ARMATURECONSTRAINT
+#define __BL_ARMATURECONSTRAINT
+
+#include "DNA_constraint_types.h"
+#include "GEN_HashedPtr.h"
+#include "GEN_Map.h"
+#include "PyObjectPlus.h"
+
+class SCA_IObject;
+class KX_GameObject;
+class BL_ArmatureObject;
+struct bConstraint;
+struct bPoseChannel;
+struct Object;
+struct bPose;
+
+/**
+ * SG_DList : element of controlled constraint list
+ * head = BL_ArmatureObject::m_controlledConstraints
+ * SG_QList : not used
+ */
+class BL_ArmatureConstraint : public PyObjectPlus
+{
+ Py_Header;
+
+private:
+ struct bConstraint* m_constraint;
+ struct bPoseChannel* m_posechannel;
+ class BL_ArmatureObject* m_armature;
+ char m_name[64];
+ KX_GameObject* m_target;
+ KX_GameObject* m_subtarget;
+ struct Object* m_blendtarget;
+ struct Object* m_blendsubtarget;
+ float m_blendmat[4][4];
+ float m_blendsubmat[4][4];
+ struct bPose* m_pose;
+ struct bPose* m_subpose;
+
+public:
+ BL_ArmatureConstraint(class BL_ArmatureObject *armature,
+ struct bPoseChannel *posechannel,
+ struct bConstraint *constraint,
+ KX_GameObject* target,
+ KX_GameObject* subtarget);
+ virtual ~BL_ArmatureConstraint();
+
+ BL_ArmatureConstraint* GetReplica() const;
+ void ReParent(BL_ArmatureObject* armature);
+ void Relink(GEN_Map<GEN_HashedPtr, void*> *map);
+ bool UnlinkObject(SCA_IObject* clientobj);
+
+ void UpdateTarget();
+ void RestoreTarget();
+
+ bool Match(const char* posechannel, const char* constraint);
+ const char* GetName() { return m_name; }
+
+ void SetConstraintFlag(int flag)
+ {
+ if (m_constraint)
+ m_constraint->flag |= flag;
+ }
+ void ClrConstraintFlag(int flag)
+ {
+ if (m_constraint)
+ m_constraint->flag &= ~flag;
+ }
+ void SetWeight(float weight)
+ {
+ if (m_constraint && m_constraint->type == CONSTRAINT_TYPE_KINEMATIC && m_constraint->data) {
+ bKinematicConstraint* con = (bKinematicConstraint*)m_constraint->data;
+ con->weight = weight;
+ }
+ }
+ void SetTarget(KX_GameObject* target);
+ void SetSubtarget(KX_GameObject* subtarget);
+
+#ifndef DISABLE_PYTHON
+
+ // Python access
+ virtual PyObject* py_repr(void);
+
+ static PyObject* py_attr_getattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static int py_attr_setattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+#endif // DISABLE_PYTHON
+};
+
+#endif //__BL_ARMATURECONSTRAINT
+
diff --git a/source/gameengine/GameLogic/SCA_BasicEventManager.cpp b/source/gameengine/GameLogic/SCA_BasicEventManager.cpp
new file mode 100644
index 00000000000..6d81784338e
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_BasicEventManager.cpp
@@ -0,0 +1,61 @@
+/**
+ * Manager for 'always' events. Since always sensors can operate in pulse
+ * mode, they need to be activated.
+ *
+ * $Id: SCA_BasicEventManager.cpp 23490 2009-09-25 16:30:15Z 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "SCA_BasicEventManager.h"
+#include "SCA_LogicManager.h"
+#include <vector>
+#include "SCA_ISensor.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+using namespace std;
+
+SCA_BasicEventManager::SCA_BasicEventManager(class SCA_LogicManager* logicmgr)
+ : SCA_EventManager(logicmgr, BASIC_EVENTMGR)
+{
+}
+
+SCA_BasicEventManager::~SCA_BasicEventManager()
+{
+}
+
+void SCA_BasicEventManager::NextFrame()
+{
+ SG_DList::iterator<SCA_ISensor> it(m_sensors);
+ for (it.begin();!it.end();++it)
+ {
+ (*it)->Activate(m_logicmgr);
+ }
+}
+
diff --git a/source/gameengine/GameLogic/SCA_BasicEventManager.h b/source/gameengine/GameLogic/SCA_BasicEventManager.h
new file mode 100644
index 00000000000..6b68cfcbe16
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_BasicEventManager.h
@@ -0,0 +1,57 @@
+/**
+ * Manager for sensor that only need to call Update
+ *
+ * $Id: SCA_BasicEventManager.h 23499 2009-09-26 20:03:01Z nexyon $
+ *
+ * ***** 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 *****
+ */
+
+#ifndef __SCA_BASICEVENTMGR
+#define __SCA_BASICEVENTMGR
+
+#include "SCA_EventManager.h"
+#include <vector>
+
+using namespace std;
+
+class SCA_BasicEventManager : public SCA_EventManager
+{
+public:
+ SCA_BasicEventManager(class SCA_LogicManager* logicmgr);
+ ~SCA_BasicEventManager();
+
+ virtual void NextFrame();
+
+
+#ifdef WITH_CXX_GUARDEDALLOC
+public:
+ void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_BasicEventManager"); }
+ void operator delete( void *mem ) { MEM_freeN(mem); }
+#endif
+};
+
+#endif //__SCA_BASICEVENTMGR
+
diff --git a/source/gameengine/Ketsji/KX_ArmatureSensor.cpp b/source/gameengine/Ketsji/KX_ArmatureSensor.cpp
new file mode 100644
index 00000000000..007dc459793
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ArmatureSensor.cpp
@@ -0,0 +1,208 @@
+/**
+ * Armature sensor
+ *
+ * $Id: KX_ArmatureSensor.cpp 23562 2009-09-29 21:42:40Z 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "BKE_constraint.h"
+#include "DNA_sensor_types.h"
+
+#include "BL_ArmatureObject.h"
+#include "KX_ArmatureSensor.h"
+#include "SCA_EventManager.h"
+#include "SCA_LogicManager.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_ArmatureSensor::KX_ArmatureSensor(class SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ const char *posechannel,
+ const char *constraintname,
+ int type,
+ float value)
+ : SCA_ISensor(gameobj,eventmgr),
+ m_constraint(NULL),
+ m_posechannel(posechannel),
+ m_constraintname(constraintname),
+ m_type(type),
+ m_value(value)
+{
+ FindConstraint();
+}
+
+void KX_ArmatureSensor::Init()
+{
+ m_lastresult = m_invert?true:false;
+ m_result = false;
+ m_reset = true;
+}
+
+void KX_ArmatureSensor::FindConstraint()
+{
+ m_constraint = NULL;
+
+ if (m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) {
+ BL_ArmatureObject* armobj = (BL_ArmatureObject*)m_gameobj;
+ // get the persistent pose structure
+ bPose* pose = armobj->GetOrigPose();
+ bPoseChannel* pchan;
+ bConstraint* pcon;
+ // and locate the constraint
+ for (pchan = (bPoseChannel*)pose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) {
+ if (!strcmp(pchan->name, m_posechannel)) {
+ // now locate the constraint
+ for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) {
+ if (!strcmp(pcon->name, m_constraintname)) {
+ if (pcon->flag & CONSTRAINT_DISABLE)
+ /* this constraint is not valid, can't use it */
+ break;
+ m_constraint = pcon;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+CValue* KX_ArmatureSensor::GetReplica()
+{
+ KX_ArmatureSensor* replica = new KX_ArmatureSensor(*this);
+ // m_range_expr must be recalculated on replica!
+ replica->ProcessReplica();
+ return replica;
+}
+
+void KX_ArmatureSensor::ReParent(SCA_IObject* parent)
+{
+ SCA_ISensor::ReParent(parent);
+ // must remap the constraint
+ FindConstraint();
+}
+
+bool KX_ArmatureSensor::IsPositiveTrigger()
+{
+ return (m_invert) ? !m_result : m_result;
+}
+
+
+KX_ArmatureSensor::~KX_ArmatureSensor()
+{
+}
+
+bool KX_ArmatureSensor::Evaluate()
+{
+ bool reset = m_reset && m_level;
+
+ m_reset = false;
+ if (!m_constraint)
+ return false;
+ switch (m_type) {
+ case SENS_ARM_STATE_CHANGED:
+ m_result = !(m_constraint->flag & CONSTRAINT_OFF);
+ break;
+ case SENS_ARM_LIN_ERROR_BELOW:
+ m_result = (m_constraint->lin_error < m_value);
+ break;
+ case SENS_ARM_LIN_ERROR_ABOVE:
+ m_result = (m_constraint->lin_error > m_value);
+ break;
+ case SENS_ARM_ROT_ERROR_BELOW:
+ m_result = (m_constraint->rot_error < m_value);
+ break;
+ case SENS_ARM_ROT_ERROR_ABOVE:
+ m_result = (m_constraint->rot_error > m_value);
+ break;
+ }
+ if (m_lastresult!=m_result)
+ {
+ m_lastresult = m_result;
+ return true;
+ }
+ return (reset) ? true : false;
+}
+
+#ifndef DISABLE_PYTHON
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_ArmatureSensor::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "KX_ArmatureSensor",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_base_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &SCA_ISensor::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+PyMethodDef KX_ArmatureSensor::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+PyAttributeDef KX_ArmatureSensor::Attributes[] = {
+ KX_PYATTRIBUTE_RO_FUNCTION("constraint", KX_ArmatureSensor, pyattr_get_constraint),
+ KX_PYATTRIBUTE_FLOAT_RW("value",-FLT_MAX,FLT_MAX,KX_ArmatureSensor,m_value),
+ KX_PYATTRIBUTE_INT_RW("type",0,SENS_ARM_MAXTYPE,false,KX_ArmatureSensor,m_type),
+ { NULL } //Sentinel
+};
+
+PyObject* KX_ArmatureSensor::pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_ArmatureSensor* sensor = static_cast<KX_ArmatureSensor*>(self);
+ if (sensor->m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) {
+ BL_ArmatureObject* armobj = (BL_ArmatureObject*)sensor->m_gameobj;
+ BL_ArmatureConstraint* constraint = armobj->GetConstraint(sensor->m_posechannel, sensor->m_constraintname);
+ if (constraint)
+ return constraint->GetProxy();
+ }
+ Py_RETURN_NONE;
+}
+
+#endif // DISABLE_PYTHON
diff --git a/source/gameengine/Ketsji/KX_ArmatureSensor.h b/source/gameengine/Ketsji/KX_ArmatureSensor.h
new file mode 100644
index 00000000000..710fbe1b7bc
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ArmatureSensor.h
@@ -0,0 +1,89 @@
+/**
+ * Property sensor
+ *
+ * $Id: KX_ArmatureSensor.h 23562 2009-09-29 21:42:40Z 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __KX_ARMATURESENSOR
+#define __KX_ARMATURESENSOR
+
+struct bConstraint;
+
+#include "SCA_ISensor.h"
+#include "DNA_sensor_types.h"
+
+class KX_ArmatureSensor : public SCA_ISensor
+{
+ Py_Header;
+ //class CExpression* m_rightexpr;
+
+protected:
+
+public:
+ KX_ArmatureSensor(class SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ const char *posechannel,
+ const char *constraintname,
+ int type,
+ float value);
+
+ /**
+ * For property sensor, it is used to release the pre-calculated expression
+ * so that self references are removed before the sensor itself is released
+ */
+ virtual ~KX_ArmatureSensor();
+ virtual CValue* GetReplica();
+ virtual void ReParent(SCA_IObject* parent);
+ virtual void Init();
+ virtual bool Evaluate();
+ virtual bool IsPositiveTrigger();
+
+ // identify the constraint that this actuator controls
+ void FindConstraint();
+
+#ifndef DISABLE_PYTHON
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+ static PyObject* pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+
+#endif // DISABLE_PYTHON
+
+private:
+ struct bConstraint* m_constraint;
+ STR_String m_posechannel;
+ STR_String m_constraintname;
+ int m_type;
+ float m_value;
+ bool m_result;
+ bool m_lastresult;
+};
+
+#endif
+