merged changes to revision 24446
authorMaxime Curioni <maxime.curioni@gmail.com>
Tue, 10 Nov 2009 12:08:02 +0000 (12:08 +0000)
committerMaxime Curioni <maxime.curioni@gmail.com>
Tue, 10 Nov 2009 12:08:02 +0000 (12:08 +0000)
254 files changed:
CMakeLists.txt
config/darwin-config.py
extern/Makefile
extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp
extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h
extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h
extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp
extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h
extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp
extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp
extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h
extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp
intern/bsp/SConscript
intern/decimation/SConscript
intern/ghost/intern/GHOST_WindowCocoa.mm
intern/smoke/intern/Makefile
projectfiles_vc9/blender/blender.vcproj
projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj
release/datafiles/datatoc.py
release/scripts/io/export_3ds.py
release/scripts/io/export_fbx.py
release/scripts/io/export_mdd.py
release/scripts/io/export_obj.py
release/scripts/io/export_ply.py
release/scripts/io/export_x3d.py
release/scripts/io/import_anim_bvh.py [new file with mode: 0644]
release/scripts/io/import_scene_3ds.py [moved from release/scripts/io/import_3ds.py with 99% similarity]
release/scripts/io/import_scene_obj.py [moved from release/scripts/io/import_obj.py with 99% similarity]
release/scripts/io/netrender/client.py
release/scripts/modules/bpy_ext/Mesh.py [new file with mode: 0644]
release/scripts/modules/bpy_ext/Object.py
release/scripts/modules/bpy_ext/__init__.py
release/scripts/modules/bpy_ops.py
release/scripts/modules/bpy_types.py [new file with mode: 0644]
release/scripts/modules/bpy_utils.py [moved from release/scripts/modules/bpy_sys.py with 92% similarity]
release/scripts/modules/console/complete_calltip.py [new file with mode: 0644]
release/scripts/modules/console/intellisense.py
release/scripts/modules/dynamic_menu.py
release/scripts/op/add_mesh_torus.py [moved from release/scripts/io/add_mesh_torus.py with 95% similarity]
release/scripts/op/console_python.py [new file with mode: 0644]
release/scripts/op/console_shell.py [new file with mode: 0644]
release/scripts/op/mesh.py [new file with mode: 0644]
release/scripts/op/mesh_skin.py [moved from release/scripts/io/mesh_skin.py with 96% similarity]
release/scripts/op/uvcalc_smart_project.py [new file with mode: 0644]
release/scripts/op/vertexpaint_dirt.py [moved from release/scripts/io/vertexpaint_dirt.py with 99% similarity]
release/scripts/op/wm.py [new file with mode: 0644]
release/scripts/templates/gamelogic.py
release/scripts/templates/gamelogic_basic.py
release/scripts/templates/gamelogic_module.py
release/scripts/templates/operator.py
release/scripts/templates/operator_simple.py
release/scripts/ui/properties_data_mesh.py
release/scripts/ui/properties_object.py
release/scripts/ui/properties_object_constraint.py
release/scripts/ui/properties_particle.py
release/scripts/ui/properties_physics_field.py
release/scripts/ui/properties_physics_softbody.py
release/scripts/ui/properties_render.py
release/scripts/ui/space_console.py
release/scripts/ui/space_image.py
release/scripts/ui/space_info.py
release/scripts/ui/space_sequencer.py
release/scripts/ui/space_userpref.py
release/scripts/ui/space_view3d.py
release/scripts/ui/space_view3d_toolbar.py
source/Makefile
source/blender/blenkernel/BKE_deform.h
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/intern/action.c
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/blender.c
source/blender/blenkernel/intern/booleanops.c
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/deform.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/node.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/softbody.c
source/blender/blenkernel/intern/texture.c
source/blender/blenlib/BLI_math.h [new file with mode: 0644]
source/blender/blenlib/BLI_math_base.h [new file with mode: 0644]
source/blender/blenlib/BLI_math_color.h [new file with mode: 0644]
source/blender/blenlib/BLI_math_geom.h [new file with mode: 0644]
source/blender/blenlib/BLI_math_matrix.h [new file with mode: 0644]
source/blender/blenlib/BLI_math_rotation.h [new file with mode: 0644]
source/blender/blenlib/BLI_math_vector.h [new file with mode: 0644]
source/blender/blenlib/intern/math_base.c [new file with mode: 0644]
source/blender/blenlib/intern/math_color.c [new file with mode: 0644]
source/blender/blenlib/intern/math_geom.c [new file with mode: 0644]
source/blender/blenlib/intern/math_matrix.c [new file with mode: 0644]
source/blender/blenlib/intern/math_rotation.c [new file with mode: 0644]
source/blender/blenlib/intern/math_vector.c [new file with mode: 0644]
source/blender/blenlib/intern/util.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/collada/DocumentExporter.cpp
source/blender/collada/DocumentImporter.cpp
source/blender/collada/SConscript
source/blender/editors/animation/anim_channels_defines.c
source/blender/editors/animation/anim_channels_edit.c
source/blender/editors/animation/anim_ipo_utils.c
source/blender/editors/animation/anim_markers.c
source/blender/editors/animation/drivers.c
source/blender/editors/animation/keyframing.c
source/blender/editors/armature/armature_intern.h
source/blender/editors/armature/armature_ops.c
source/blender/editors/armature/editarmature.c
source/blender/editors/armature/editarmature_retarget.c
source/blender/editors/armature/meshlaplacian.c
source/blender/editors/armature/meshlaplacian.h
source/blender/editors/armature/poselib.c
source/blender/editors/armature/poseobject.c
source/blender/editors/datafiles/B.blend.c
source/blender/editors/gpencil/drawgpencil.c
source/blender/editors/gpencil/gpencil_edit.c
source/blender/editors/include/ED_anim_api.h
source/blender/editors/include/ED_armature.h
source/blender/editors/include/ED_gpencil.h
source/blender/editors/include/ED_mesh.h
source/blender/editors/include/ED_object.h
source/blender/editors/include/ED_transform.h
source/blender/editors/interface/interface_draw.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_icons.c
source/blender/editors/interface/interface_layout.c
source/blender/editors/interface/interface_widgets.c
source/blender/editors/mesh/editmesh.c
source/blender/editors/mesh/editmesh_add.c
source/blender/editors/mesh/editmesh_tools.c
source/blender/editors/mesh/mesh_data.c
source/blender/editors/mesh/mesh_intern.h
source/blender/editors/mesh/mesh_ops.c
source/blender/editors/mesh/meshtools.c
source/blender/editors/object/object_add.c
source/blender/editors/object/object_edit.c
source/blender/editors/object/object_hook.c
source/blender/editors/object/object_intern.h
source/blender/editors/object/object_modifier.c
source/blender/editors/object/object_ops.c
source/blender/editors/object/object_relations.c
source/blender/editors/object/object_shapekey.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/physics/particle_object.c
source/blender/editors/physics/physics_intern.h
source/blender/editors/physics/physics_ops.c
source/blender/editors/screen/area.c
source/blender/editors/screen/screen_context.c
source/blender/editors/screen/screen_edit.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/space_action/action_select.c
source/blender/editors/space_buttons/buttons_context.c
source/blender/editors/space_console/console_report.c
source/blender/editors/space_console/space_console.c
source/blender/editors/space_file/file_ops.c
source/blender/editors/space_graph/graph_buttons.c
source/blender/editors/space_graph/graph_draw.c
source/blender/editors/space_graph/graph_select.c
source/blender/editors/space_nla/nla_select.c
source/blender/editors/space_node/drawnode.c
source/blender/editors/space_node/node_draw.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_node/node_select.c
source/blender/editors/space_outliner/outliner.c
source/blender/editors/space_sequencer/sequencer_edit.c
source/blender/editors/space_sequencer/sequencer_intern.h
source/blender/editors/space_sequencer/sequencer_ops.c
source/blender/editors/space_sequencer/sequencer_select.c
source/blender/editors/space_view3d/drawarmature.c
source/blender/editors/space_view3d/view3d_buttons.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_ops.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_manipulator.c
source/blender/editors/transform/transform_orientations.c
source/blender/editors/util/editmode_undo.c
source/blender/editors/uvedit/uvedit_intern.h
source/blender/editors/uvedit/uvedit_ops.c
source/blender/editors/uvedit/uvedit_unwrap_ops.c
source/blender/gpu/intern/gpu_shader_material.glsl
source/blender/gpu/intern/gpu_shader_material.glsl.c
source/blender/imbuf/intern/Makefile
source/blender/makesdna/DNA_armature_types.h
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_node_types.h
source/blender/makesdna/DNA_particle_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_space_types.h
source/blender/makesdna/DNA_texture_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/RNA_define.h
source/blender/makesrna/RNA_enum_types.h
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_armature.c
source/blender/makesrna/intern/rna_boid.c
source/blender/makesrna/intern/rna_cloth.c
source/blender/makesrna/intern/rna_constraint.c
source/blender/makesrna/intern/rna_curve.c
source/blender/makesrna/intern/rna_define.c
source/blender/makesrna/intern/rna_fcurve.c
source/blender/makesrna/intern/rna_fcurve_api.c [new file with mode: 0644]
source/blender/makesrna/intern/rna_fluidsim.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_internal_types.h
source/blender/makesrna/intern/rna_material.c
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_meta.c
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_nodetree.c
source/blender/makesrna/intern/rna_nodetree_types.h
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_object_force.c
source/blender/makesrna/intern/rna_particle.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_smoke.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_texture.c
source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c
source/blender/nodes/intern/SHD_nodes/SHD_curves.c
source/blender/python/epy_doc_gen.py
source/blender/python/intern/bpy_interface.c
source/blender/python/intern/bpy_operator_wrap.c
source/blender/python/intern/bpy_rna.c
source/blender/python/intern/bpy_rna.h
source/blender/python/intern/bpy_util.c
source/blender/quicktime/apple/quicktime_export.c
source/blender/quicktime/quicktime_export.h
source/blender/render/CMakeLists.txt
source/blender/render/SConscript
source/blender/render/intern/source/pipeline.c
source/blender/render/intern/source/pointdensity.c
source/blender/render/intern/source/shadeoutput.c
source/blender/render/intern/source/texture.c
source/blender/render/intern/source/volume_precache.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_gesture.c
source/blender/windowmanager/intern/wm_operators.c
source/blender/windowmanager/wm.h
source/blender/windowmanager/wm_event_types.h
source/creator/CMakeLists.txt
source/creator/creator.c
source/gameengine/Converter/BL_ArmatureChannel.cpp
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/nan_definitions.mk
source/nan_link.mk

index 7c5ba143b5264f239ca343cd8ff9304c7f741a89..4e02ea20fb0cadbf001f3d7f642271ac9476d393 100644 (file)
@@ -555,6 +555,16 @@ IF(APPLE)
        SET(TIFF_INC ${TIFF}/include)
 
        SET(EXETYPE MACOSX_BUNDLE)
+
+
+       IF(CMAKE_OSX_ARCHITECTURES MATCHES "i386")
+               SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -ftree-vectorize -msse -msse2 -fvariable-expansion-in-unroller")
+               SET(CMAKE_C_FLAGS_RELEASE "-O3 -ftree-vectorize -msse -msse2 -fvariable-expansion-in-unroller")
+       ELSEIF(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
+               SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -ftree-vectorize -msse -msse2 -msse3 -mssse3 -fvariable-expansion-in-unroller")
+               SET(CMAKE_C_FLAGS_RELEASE "-O3 -ftree-vectorize -msse -msse2 -msse3 -mssse3 -fvariable-expansion-in-unroller")
+       ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES "i386")
+
 ENDIF(APPLE)
 
 IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
index 8a1b0eff6c12d1f168e608a022c1ad0c86a96753..03cc4eb1f8cdbb3a1450ab1be2125bb747263fb0 100644 (file)
@@ -31,7 +31,7 @@ elif cmd_res[0]=='9':
 elif cmd_res[0]=='10':
        MAC_CUR_VER='10.6'
 
-if MAC_PROC == 'powerpc':
+if MACOSX_ARCHITECTURE == 'ppc':
        LCGDIR = '#../lib/darwin-6.1-powerpc'
 else :
        LCGDIR = '#../lib/darwin-9.x.universal'
@@ -39,7 +39,7 @@ LIBDIR = '${LCGDIR}'
 
 BF_PYTHON_VERSION = '3.1'
 
-if MAC_PROC == 'powerpc' and BF_PYTHON_VERSION == '2.3':
+if MACOSX_ARCHITECTURE == 'ppc' and BF_PYTHON_VERSION == '2.3':
        MAC_MIN_VERS = '10.3'
        MACOSX_SDK='/Developer/SDKs/MacOSX10.3.9.sdk'
        CC = 'gcc'
@@ -247,7 +247,20 @@ BF_OPENGL_LIBPATH = '/System/Library/Frameworks/OpenGL.framework/Libraries'
 BF_OPENGL_LINKFLAGS = ['-framework', 'OpenGL']
 
 #OpenCollada flags
-WITH_BF_COLLADA = False
+WITH_BF_COLLADA = True
+BF_COLLADA = '#source/blender/collada'
+BF_COLLADA_INC = '${BF_COLLADA}'
+BF_COLLADA_LIB = 'bf_collada'
+BF_OPENCOLLADA = LIBDIR + '/opencollada'
+BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include'
+BF_OPENCOLLADA_LIB = 'OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils OpenCOLLADAStreamWriter MathMLSolver GeneratedSaxParser UTF xml2'
+BF_OPENCOLLADA_LIBPATH = LIBDIR + '/opencollada'
+BF_PCRE = LIBDIR + '/opencollada'
+BF_PCRE_LIB = 'pcre'
+BF_PCRE_LIBPATH = '${BF_PCRE}/lib'
+#BF_EXPAT = '/usr'
+#BF_EXPAT_LIB = 'expat'
+#BF_EXPAT_LIBPATH = '/usr/lib'
 
 #############################################################################
 ###################  various compile settings and flags    ##################
index a30cd1d7ca3ccacc3a5f7ac55ca93c1b10aa874d..4a2e7a6d59b321850014a2f1f4ee350dc427c42f 100644 (file)
@@ -34,7 +34,7 @@ DIRS = glew/src
 
 # Cloth requires it
 ifeq ($(NAN_USE_BULLET), true)
-       DIRS += bullet2
+    DIRS += bullet2
 endif
 
 ifeq ($(WITH_BINRELOC), true)
@@ -42,7 +42,9 @@ ifeq ($(WITH_BINRELOC), true)
 endif
 
 ifeq ($(WITH_OPENJPEG), true)
-    DIRS += libopenjpeg
+    ifndef BF_OPENJPEG
+        DIRS += libopenjpeg
+    endif
 endif
 
 ifeq ($(WITH_LZO), true)
index 274c5f5bdc6b03bec294ca6ceb87544c458c2d79..496fd996f8c78e381e80c17811ba4d33db5171e0 100644 (file)
@@ -202,7 +202,6 @@ void btConvexConvexAlgorithm ::processCollision (btCollisionObject* body0,btColl
                input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared;
        }
 
-       input.m_stackAlloc = dispatchInfo.m_stackAllocator;
        input.m_transformA = body0->getWorldTransform();
        input.m_transformB = body1->getWorldTransform();
 
index 412aace21146e85a388c332ce886e963ecb86589..2989daeb44edfdf42afc3949163fa607709c2dc9 100644 (file)
@@ -33,7 +33,7 @@ public:
                const btConvexShape* convexA,const btConvexShape* convexB,
                                        const btTransform& transA,const btTransform& transB,
                                btVector3& v, btVector3& pa, btVector3& pb,
-                               class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc
+                               class btIDebugDraw* debugDraw
                                ) = 0;
 
 
index db797d5141ffd9f0049c88100f6c99e1cd998bd0..b011bb9ae588899011fa818828d28a157f000dd1 100644 (file)
@@ -41,15 +41,13 @@ struct btDiscreteCollisionDetectorInterface
        struct ClosestPointInput
        {
                ClosestPointInput()
-                       :m_maximumDistanceSquared(btScalar(1e30)),
-                       m_stackAlloc(0)
+                       :m_maximumDistanceSquared(btScalar(1e30))
                {
                }
 
                btTransform m_transformA;
                btTransform m_transformB;
                btScalar        m_maximumDistanceSquared;
-               btStackAlloc* m_stackAlloc;
        };
 
        virtual ~btDiscreteCollisionDetectorInterface() {};
index 05573c7cfceed4c0eb220a098681b3c2869b3bb4..55c23ee854965bebf143c1795db9b31dce886c2c 100644 (file)
@@ -25,7 +25,7 @@ bool btGjkEpaPenetrationDepthSolver::calcPenDepth( btSimplexSolverInterface& sim
                                                                                          const btConvexShape* pConvexA, const btConvexShape* pConvexB,
                                                                                          const btTransform& transformA, const btTransform& transformB,
                                                                                          btVector3& v, btVector3& wWitnessOnA, btVector3& wWitnessOnB,
-                                                                                         class btIDebugDraw* debugDraw, btStackAlloc* stackAlloc )
+                                                                                         class btIDebugDraw* debugDraw )
 {
 
        (void)debugDraw;
index 68dbc56651817365f996c86f3fee99d4809dc702..4db18628021bbd9fade3aa75136eb02716cdf977 100644 (file)
@@ -29,7 +29,7 @@ class btGjkEpaPenetrationDepthSolver : public btConvexPenetrationDepthSolver
                                                                          const btConvexShape* pConvexA, const btConvexShape* pConvexB,
                                                                          const btTransform& transformA, const btTransform& transformB,
                                                                          btVector3& v, btVector3& wWitnessOnA, btVector3& wWitnessOnB,
-                                                                         class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc );
+                                                                         class btIDebugDraw* debugDraw );
 
        private :
 
index 0856332d1ca2f2416a7aa2bba91b850edf889dda..331d25623df1e11359d367e864ee8b943efd2369 100644 (file)
@@ -293,7 +293,7 @@ void btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result&
                                        m_minkowskiA,m_minkowskiB,
                                        localTransA,localTransB,
                                        m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB,
-                                       debugDraw,input.m_stackAlloc
+                                       debugDraw
                                        );
 
                                if (isValid2)
index 581b4258f03aaef70b15e2858e51d473b6e85091..1fdbb2457d17973e324eea726f5192d84f57c4c4 100644 (file)
@@ -71,11 +71,10 @@ bool btMinkowskiPenetrationDepthSolver::calcPenDepth(btSimplexSolverInterface& s
                                                                                                   const btConvexShape* convexA,const btConvexShape* convexB,
                                                                                                   const btTransform& transA,const btTransform& transB,
                                                                                                   btVector3& v, btVector3& pa, btVector3& pb,
-                                                                                                  class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc
+                                                                                                  class btIDebugDraw* debugDraw
                                                                                                   )
 {
 
-       (void)stackAlloc;
        (void)v;
        
 
index 23cbd57ac7ef95dec5aa01888e38cdc065a6800f..e93e4e4bb4efb493051b32526949134424cce131 100644 (file)
@@ -28,7 +28,7 @@ public:
        const btConvexShape* convexA,const btConvexShape* convexB,
                                const btTransform& transA,const btTransform& transB,
                        btVector3& v, btVector3& pa, btVector3& pb,
-                       class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc
+                       class btIDebugDraw* debugDraw
                        );
 };
 
index 47addbac45b8e5cf9d3c740fe6b360fdf2c02128..20d6975832b838d1cba910b630ae2058071522d4 100644 (file)
@@ -365,10 +365,6 @@ double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float
        btPointCollector gjkOutput;
        btGjkPairDetector::ClosestPointInput input;
        
-       btStackAlloc gStackAlloc(1024*1024*2);
-       input.m_stackAlloc = &gStackAlloc;
-       
        btTransform tr;
        tr.setIdentity();
        
index 2ecc280f1358111de78c9d3c352e83be8d2cef31..ff5a213d7b80bfe7617aebbdf0b64b2f1aeca256 100644 (file)
@@ -5,8 +5,5 @@ sources = env.Glob('intern/*.cpp')
 
 incs = 'intern ../container ../moto/include ../memutil'
 
-if (env['OURPLATFORM'] == 'win32-mingw'):
-    env.BlenderLib ('blender_BSP', sources, Split(incs), [], libtype='core', priority=26 )
-else:
-    env.BlenderLib ('blender_BSP', sources, Split(incs), [], libtype='core', priority=20 )
+env.BlenderLib ('blender_BSP', sources, Split(incs), [], libtype='core', priority=200 )
 
index ef95a79592824600923a3d446debbd1ba85dda75..2dd86c44cf1b60620c9426d87d707e9389fa2110 100644 (file)
@@ -5,4 +5,4 @@ sources = env.Glob('intern/*.cpp')
 
 incs = '. ../moto/include ../container ../memutil'
 
-env.BlenderLib ('bf_decimation', sources, Split(incs) , [], libtype=['core'], priority = [10] )
+env.BlenderLib ('bf_decimation', sources, Split(incs) , [], libtype=['core'], priority = [200] )
index 7716175b9f631a3c3b04563c3e27ff323a187a20..6d6829f392534ee20822e9dcaef13e3efe0f67db 100644 (file)
@@ -68,7 +68,7 @@ extern "C" {
 - (void)windowWillClose:(NSNotification *)notification;
 - (void)windowDidBecomeKey:(NSNotification *)notification;
 - (void)windowDidResignKey:(NSNotification *)notification;
-- (void)windowDidUpdate:(NSNotification *)notification;
+- (void)windowDidExpose:(NSNotification *)notification;
 - (void)windowDidResize:(NSNotification *)notification;
 @end
 
@@ -91,13 +91,10 @@ extern "C" {
 
 - (void)windowDidResignKey:(NSNotification *)notification
 {
-       //The window is no more key when its own view becomes fullscreen
-       //but ghost doesn't know the view/window difference, so hide this fact
-       if (associatedWindow->getState() != GHOST_kWindowStateFullScreen)
-               systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow);
+       systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow);
 }
 
-- (void)windowDidUpdate:(NSNotification *)notification
+- (void)windowDidExpose:(NSNotification *)notification
 {
        systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow);
 }
@@ -622,6 +619,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
                                //Make window normal and resize it
                                [m_window setStyleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)];
                                [m_window setFrame:[[m_window screen] visibleFrame] display:YES];
+                               //TODO for 10.6 only : window title is forgotten after the style change
                                [m_window makeFirstResponder:m_openGLView];
 #else
                                //With 10.5, we need to create a new window to change its style to borderless
@@ -686,10 +684,18 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
 {
        GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid")
     if (order == GHOST_kWindowOrderTop) {
-               [m_window orderFront:nil];
+               [m_window makeKeyAndOrderFront:nil];
     }
     else {
+               NSArray *windowsList;
+               
                [m_window orderBack:nil];
+               
+               //Check for other blender opened windows and make the frontmost key
+               windowsList = [NSApp orderedWindows];
+               if ([windowsList count]) {
+                       [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
+               }
     }
     return GHOST_kSuccess;
 }
index 2cdd7d3853e8990a65f87513b74fa8db545d0239..760b1627a91b0d8853f915a851f80b47b0f5b9a5 100644 (file)
@@ -41,6 +41,11 @@ ifeq ($(WITH_BF_OPENMP),true)
    CPPFLAGS += -DPARALLEL
 endif
 
+ifeq ($(WITH_FFTW3),true)
+    CPPFLAGS += -DFFTW3=1
+    CPPFLAGS += $(BF_FFTW3_INC)
+endif
+
 CPPFLAGS += -I.
 CPPFLAGS += -I../extern
 CPPFLAGS += -I$(NAN_PNG)/include
index 538afaf950c72576c5c4810653a1eb2ef25760f2..a5203aa8edba57164b28699402d3d94d32b1b317 100644 (file)
@@ -74,7 +74,7 @@
                        <Tool\r
                                Name="VCLinkerTool"\r
                                AdditionalOptions="/MACHINE:I386"\r
-                               AdditionalDependencies="libsamplerate.lib SDL.lib freetype2ST.lib gnu_gettext.lib qtmlClient.lib OpenAL32.lib wrap_oal.lib ws2_32.lib dxguid.lib opengl32.lib libjpeg.lib glu32.lib vfw32.lib winmm.lib libpng_st.lib zlib.lib python31.lib pthreadVSE2.lib pthreadVC2.lib libtiff.lib Half.lib Iex.lib IlmImf.lib Imath.lib IlmThread.lib avcodec-52.lib avformat-52.lib avutil-50.lib swscale-0.lib avdevice-52.lib libsndfile-1.lib opencollada.lib"\r
+                               AdditionalDependencies="libsamplerate.lib SDL.lib freetype2ST.lib gnu_gettext.lib qtmlClient.lib OpenAL32.lib wrap_oal.lib ws2_32.lib dxguid.lib opengl32.lib libjpeg.lib glu32.lib vfw32.lib winmm.lib libpng_st.lib zlib.lib python31.lib pthreadVSE2.lib pthreadVC2.lib libtiff.lib Half.lib Iex.lib IlmImf.lib Imath.lib IlmThread.lib avcodec-52.lib avformat-52.lib avutil-50.lib swscale-0.lib avdevice-52.lib libsndfile-1.lib OpenCOLLADABaseUtils.lib OpenCOLLADAFramework.lib OpenCOLLADAStreamWriter.lib OpenCOLLADASaxFrameworkLoader.lib pcre.lib UTF.lib GeneratedSaxParser.lib MathMLSolver.lib xml2.lib"\r
                                ShowProgress="0"\r
                                OutputFile="..\..\..\install\msvc_9\blender.exe"\r
                                LinkIncremental="1"\r
                        <Tool\r
                                Name="VCLinkerTool"\r
                                AdditionalOptions="/MACHINE:I386&#x0D;&#x0A;"\r
-                               AdditionalDependencies="libsamplerate.lib SDL.lib freetype2ST.lib gnu_gettext.lib qtmlClient.lib OpenAL32.lib wrap_oal.lib ws2_32.lib dxguid.lib opengl32.lib libjpeg.lib glu32.lib vfw32.lib winmm.lib libpng_st.lib zlib.lib python31_d.lib pthreadVSE2.lib pthreadVC2.lib libtiff.lib Half_d.lib Iex_d.lib Imath_d.lib IlmImf_d.lib IlmThread_d.lib avcodec-52.lib avformat-52.lib avdevice-52.lib avutil-50.lib swscale-0.lib libsndfile-1.lib opencollada.lib"\r
+                               AdditionalDependencies="libsamplerate.lib SDL.lib freetype2ST.lib gnu_gettext.lib qtmlClient.lib OpenAL32.lib wrap_oal.lib ws2_32.lib dxguid.lib opengl32.lib libjpeg.lib glu32.lib vfw32.lib winmm.lib libpng_st.lib zlib.lib python31_d.lib pthreadVSE2.lib pthreadVC2.lib libtiff.lib Half_d.lib Iex_d.lib Imath_d.lib IlmImf_d.lib IlmThread_d.lib avcodec-52.lib avformat-52.lib avdevice-52.lib avutil-50.lib swscale-0.lib libsndfile-1.lib OpenCOLLADABaseUtils.lib OpenCOLLADAFramework.lib OpenCOLLADAStreamWriter.lib OpenCOLLADASaxFrameworkLoader.lib pcre.lib UTF.lib GeneratedSaxParser.lib MathMLSolver.lib xml2.lib"\r
                                ShowProgress="0"\r
                                OutputFile="..\..\..\install\msvc_9d\blender.exe"\r
                                LinkIncremental="2"\r
index f52dd193150cdeb76e4ea09dd295c33d4b265bab..c0a13bbe26bd8f72dfd26c24557bb668a565e34f 100644 (file)
                                RelativePath="..\..\..\source\blender\makesrna\intern\rna_fcurve.c"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\..\..\source\blender\makesrna\intern\rna_fcurve_api.c"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="..\..\..\source\blender\makesrna\intern\rna_fluidsim.c"\r
                                >\r
index 70bb348ad02efe4c61a1216593a1e3f5fabecbd5..a78b64c5095a3cc92fbfa13ecea7a4946a1ce04d 100755 (executable)
@@ -48,6 +48,7 @@ if filename[0] == ".":
 cname = filename + ".c"
 sys.stdout.write("Making C file <%s>\n" % cname)
 
+filename = filename.split("/")[-1].split("\\")[-1]
 filename = filename.replace(".", "_")
 sys.stdout.write(str(size))
 sys.stdout.write("\n")
index 3e5d64a3e35e666daa273f8e2278d427b72724c9..a96abb502154e80afd0680d11d529450b9eaea90 100644 (file)
@@ -1109,7 +1109,7 @@ def save_3ds(filename, context):
 #         Blender.Draw.PupMenu("Error%t|This script requires a full python installation")
 # # save_3ds('/test_b.3ds')
 from bpy.props import *
-class EXPORT_OT_autodesk_3ds(bpy.types.Operator):
+class Export3DS(bpy.types.Operator):
        '''Export to 3DS file format (.3ds).'''
        bl_idname = "export.autodesk_3ds"
        bl_label = 'Export 3DS'
@@ -1135,9 +1135,13 @@ class EXPORT_OT_autodesk_3ds(bpy.types.Operator):
                print("Poll")
                return context.active_object != None
 
-bpy.ops.add(EXPORT_OT_autodesk_3ds)
+bpy.ops.add(Export3DS)
 
 # Add to a menu
 import dynamic_menu
-menu_func = lambda self, context: self.layout.itemO("export.autodesk_3ds", text="Autodesk 3DS...")
+
+def menu_func(self, context):
+    default_path = bpy.data.filename.replace(".blend", ".3ds")
+    self.layout.item_stringO(Export3DS.bl_idname, "path", default_path, text="Autodesk 3DS...")
+
 menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
index b303e536b99dc22f34e248e2c46cbe2c94f38348..ec2d2791b5233dd35afadc97fa4d2163aed4705c 100644 (file)
@@ -237,14 +237,14 @@ def sane_groupname(data): return sane_name(data, sane_name_mapping_group)
 #      FORCE_CWD - dont use the basepath, just add a ./ to the filename.
 #              use when we know the file will be in the basepath.
 #      '''
-#      fname = bpy.sys.expandpath(fname_orig)
+#      fname = bpy.utils.expandpath(fname_orig)
 # #    fname = Blender.sys.expandpath(fname_orig)
 #      fname_strip = os.path.basename(fname)
 # #    fname_strip = strip_path(fname)
 #      if FORCE_CWD:
 #              fname_rel = '.' + os.sep + fname_strip
 #      else:
-#              fname_rel = bpy.sys.relpath(fname, basepath)
+#              fname_rel = bpy.utils.relpath(fname, basepath)
 # #            fname_rel = Blender.sys.relpath(fname, basepath)
 #      if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:]
 #      return fname, fname_strip, fname_rel
@@ -349,7 +349,7 @@ def write(filename, batch_objects = None, \
                fbxpath = filename
                
                # get the path component of filename
-               tmp_exists = bpy.sys.exists(fbxpath)
+               tmp_exists = bpy.utils.exists(fbxpath)
 #              tmp_exists = Blender.sys.exists(fbxpath)
                
                if tmp_exists != 2: # a file, we want a path
@@ -363,7 +363,7 @@ def write(filename, batch_objects = None, \
 #                              Draw.PupMenu('Error%t|Directory does not exist!')
                                return
 
-                       tmp_exists = bpy.sys.exists(fbxpath)
+                       tmp_exists = bpy.utils.exists(fbxpath)
 #                      tmp_exists = Blender.sys.exists(fbxpath)
                
                if tmp_exists != 2:
@@ -398,7 +398,7 @@ def write(filename, batch_objects = None, \
                                # path may alredy exist
                                # TODO - might exist but be a file. unlikely but should probably account for it.
 
-                               if bpy.sys.exists(new_fbxpath) == 0:
+                               if bpy.utils.exists(new_fbxpath) == 0:
 #                              if Blender.sys.exists(new_fbxpath) == 0:
                                        os.mkdir(new_fbxpath)
                                
@@ -3351,7 +3351,7 @@ def write_ui():
        
        # GLOBALS.clear()
 from bpy.props import *
-class EXPORT_OT_fbx(bpy.types.Operator):
+class ExportFBX(bpy.types.Operator):
        '''Selection to an ASCII Autodesk FBX'''
        bl_idname = "export.fbx"
        bl_label = "Export FBX"
@@ -3433,7 +3433,7 @@ class EXPORT_OT_fbx(bpy.types.Operator):
                return ('RUNNING_MODAL',)
 
 
-bpy.ops.add(EXPORT_OT_fbx)
+bpy.ops.add(ExportFBX)
 
 # if __name__ == "__main__":
 #      bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply")
@@ -3456,7 +3456,7 @@ bpy.ops.add(EXPORT_OT_fbx)
 # - bpy.data.remove_scene: line 366
 # - bpy.sys.time move to bpy.sys.util?
 # - new scene creation, activation: lines 327-342, 368
-# - uses bpy.sys.expandpath, *.relpath - replace at least relpath
+# - uses bpy.utils.expandpath, *.relpath - replace at least relpath
 
 # SMALL or COSMETICAL
 # - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version')
@@ -3464,6 +3464,10 @@ bpy.ops.add(EXPORT_OT_fbx)
 
 # Add to a menu
 import dynamic_menu
-menu_func = lambda self, context: self.layout.itemO("export.fbx", text="Autodesk FBX...")
+
+def menu_func(self, context):
+    default_path = bpy.data.filename.replace(".blend", ".fbx")
+    self.layout.item_stringO(ExportFBX.bl_idname, "path", default_path, text="Autodesk FBX...")
+
 menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
 
index 677361f33927ff56b7ddb3db9fbfcb33e3e82dbc..2b3e1681449fc043fdc9705ca6020f17bfdc8663 100644 (file)
@@ -54,148 +54,148 @@ import os
 #from Blender import *
 #import BPyMessages
 try:
-       from struct import pack
+    from struct import pack
 except:
-       pack = None
+    pack = None
 
 def zero_file(filepath):
-       '''
-       If a file fails, this replaces it with 1 char, better not remove it?
-       '''
-       file = open(filepath, 'w')
-       file.write('\n') # apparently macosx needs some data in a blank file?
-       file.close()
+    '''
+    If a file fails, this replaces it with 1 char, better not remove it?
+    '''
+    file = open(filepath, 'w')
+    file.write('\n') # apparently macosx needs some data in a blank file?
+    file.close()
 
 def check_vertcount(mesh,vertcount):
-       '''
-       check and make sure the vertcount is consistent throughout the frame range
-       '''
-       if len(mesh.verts) != vertcount:
-               raise Exception('Error, number of verts has changed during animation, cannot export')
-               f.close()
-               zero_file(filepath)
-               return
-       
-       
+    '''
+    check and make sure the vertcount is consistent throughout the frame range
+    '''
+    if len(mesh.verts) != vertcount:
+        raise Exception('Error, number of verts has changed during animation, cannot export')
+        f.close()
+        zero_file(filepath)
+        return
+    
+    
 def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
-       if not pack:
-               raise Exception('Error, this script requires the "pack" module')
-       
-       if ob.type != 'MESH':
-               raise Exception('Error, active object is not a mesh')
-       """
-       Window.EditMode(0)
-       Blender.Window.WaitCursor(1)
-
-       mesh_orig = Mesh.New()
-       mesh_orig.getFromObject(ob.name)
-       """
-       orig_frame = sce.current_frame
-       sce.set_frame(PREF_STARTFRAME)
-       me = ob.create_mesh(True, 'PREVIEW')
-
-       #Flip y and z
-       mat_flip= Mathutils.Matrix(\
-       [1.0, 0.0, 0.0, 0.0],\
-       [0.0, 0.0, 1.0, 0.0],\
-       [0.0, 1.0, 0.0, 0.0],\
-       [0.0, 0.0, 0.0, 1.0],\
-       )
-
-       numverts = len(me.verts)
-
-       numframes = PREF_ENDFRAME-PREF_STARTFRAME+1
-       PREF_FPS= float(PREF_FPS)
-       f = open(filename, 'wb') #no Errors yet:Safe to create file
-       
-       # Write the header
-       f.write(pack(">2i", numframes, numverts))
-       
-       # Write the frame times (should we use the time IPO??)
-       f.write( pack(">%df" % (numframes), *[frame/PREF_FPS for frame in range(numframes)]) ) # seconds
-       
-       #rest frame needed to keep frames in sync
-       """
-       Blender.Set('curframe', PREF_STARTFRAME)
-       me_tmp.getFromObject(ob.name)
-       """
-
-       check_vertcount(me,numverts)
-       me.transform(mat_flip * ob.matrix)
-       f.write(pack(">%df" % (numverts*3), *[axis for v in me.verts for axis in v.co]))
-               
-       for frame in range(PREF_STARTFRAME,PREF_ENDFRAME+1):#in order to start at desired frame
-               """
-               Blender.Set('curframe', frame)
-               me_tmp.getFromObject(ob.name)
-               """
-
-               sce.set_frame(frame)
-               me = ob.create_mesh(True, 'PREVIEW')
-               check_vertcount(me,numverts)
-               me.transform(mat_flip * ob.matrix)
-               
-               # Write the vertex data
-               f.write(pack(">%df" % (numverts*3), *[axis for v in me.verts for axis in v.co]))
-       
-       """
-       me_tmp.verts= None
-       """
-       f.close()
-       
-       print ('MDD Exported: %s frames:%d\n'% (filename, numframes-1))
-       """
-       Blender.Window.WaitCursor(0)
-       Blender.Set('curframe', orig_frame)
-       """
-       sce.set_frame(orig_frame)
+    """
+    Blender.Window.WaitCursor(1)
+
+    mesh_orig = Mesh.New()
+    mesh_orig.getFromObject(ob.name)
+    """
+
+    bpy.ops.object.mode_set(mode='OBJECT')
+
+    orig_frame = sce.current_frame
+    sce.set_frame(PREF_STARTFRAME)
+    me = ob.create_mesh(True, 'PREVIEW')
+
+    #Flip y and z
+    mat_flip= Mathutils.Matrix(\
+    [1.0, 0.0, 0.0, 0.0],\
+    [0.0, 0.0, 1.0, 0.0],\
+    [0.0, 1.0, 0.0, 0.0],\
+    [0.0, 0.0, 0.0, 1.0],\
+    )
+
+    numverts = len(me.verts)
+
+    numframes = PREF_ENDFRAME-PREF_STARTFRAME+1
+    PREF_FPS= float(PREF_FPS)
+    f = open(filename, 'wb') #no Errors yet:Safe to create file
+    
+    # Write the header
+    f.write(pack(">2i", numframes, numverts))
+    
+    # Write the frame times (should we use the time IPO??)
+    f.write( pack(">%df" % (numframes), *[frame/PREF_FPS for frame in range(numframes)]) ) # seconds
+    
+    #rest frame needed to keep frames in sync
+    """
+    Blender.Set('curframe', PREF_STARTFRAME)
+    me_tmp.getFromObject(ob.name)
+    """
+
+    check_vertcount(me,numverts)
+    me.transform(mat_flip * ob.matrix)
+    f.write(pack(">%df" % (numverts*3), *[axis for v in me.verts for axis in v.co]))
+        
+    for frame in range(PREF_STARTFRAME,PREF_ENDFRAME+1):#in order to start at desired frame
+        """
+        Blender.Set('curframe', frame)
+        me_tmp.getFromObject(ob.name)
+        """
+
+        sce.set_frame(frame)
+        me = ob.create_mesh(True, 'PREVIEW')
+        check_vertcount(me,numverts)
+        me.transform(mat_flip * ob.matrix)
+        
+        # Write the vertex data
+        f.write(pack(">%df" % (numverts*3), *[axis for v in me.verts for axis in v.co]))
+    
+    """
+    me_tmp.verts= None
+    """
+    f.close()
+    
+    print ('MDD Exported: %s frames:%d\n'% (filename, numframes-1))
+    """
+    Blender.Window.WaitCursor(0)
+    Blender.Set('curframe', orig_frame)
+    """
+    sce.set_frame(orig_frame)
 
 from bpy.props import *
 
-class EXPORT_OT_mdd(bpy.types.Operator):
-       '''Animated mesh to MDD vertex keyframe file.'''
-       bl_idname = "export.mdd"
-       bl_label = "Export MDD"
-
-       # get first scene to get min and max properties for frames, fps
-
-       sce = bpy.data.scenes[bpy.data.scenes.keys()[0]]
-       minframe = sce.rna_type.properties["current_frame"].soft_min
-       maxframe = sce.rna_type.properties["current_frame"].soft_max
-       minfps = sce.render_data.rna_type.properties["fps"].soft_min
-       maxfps = sce.render_data.rna_type.properties["fps"].soft_max
-
-       # List of operator properties, the attributes will be assigned
-       # to the class instance from the operator settings before calling.
-       path = StringProperty(name="File Path", description="File path used for exporting the MDD file", maxlen= 1024, default= "tmp.mdd")
-       fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default= 25)
-       start_frame = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe,max=maxframe,default=1)
-       end_frame = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default= 250)
-
-       def poll(self, context):
-               return context.active_object != None
-
-       def execute(self, context):
-               if not self.path:
-                       raise Exception("filename not set")
-               write(self.path, context.scene, context.active_object,
-                       self.start_frame, self.end_frame, self.fps )
-               return ('FINISHED',)
-       
-       def invoke(self, context, event):       
-               wm = context.manager
-               wm.add_fileselect(self)
-               return ('RUNNING_MODAL',)
-
-bpy.ops.add(EXPORT_OT_mdd)
+class ExportMDD(bpy.types.Operator):
+    '''Animated mesh to MDD vertex keyframe file.'''
+    bl_idname = "export.mdd"
+    bl_label = "Export MDD"
+
+    # get first scene to get min and max properties for frames, fps
+
+    sce = bpy.data.scenes[bpy.data.scenes.keys()[0]]
+    minframe = sce.rna_type.properties["current_frame"].soft_min
+    maxframe = sce.rna_type.properties["current_frame"].soft_max
+    minfps = sce.render_data.rna_type.properties["fps"].soft_min
+    maxfps = sce.render_data.rna_type.properties["fps"].soft_max
+
+    # List of operator properties, the attributes will be assigned
+    # to the class instance from the operator settings before calling.
+    path = StringProperty(name="File Path", description="File path used for exporting the MDD file", maxlen= 1024, default= "tmp.mdd")
+    fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default= 25)
+    start_frame = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe,max=maxframe,default=1)
+    end_frame = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default= 250)
+
+    def poll(self, context):
+        ob = context.active_object
+        return (ob and ob.type=='MESH')
+
+    def execute(self, context):
+        if not self.path:
+            raise Exception("filename not set")
+        write(self.path, context.scene, context.active_object,
+            self.start_frame, self.end_frame, self.fps )
+        return ('FINISHED',)
+    
+    def invoke(self, context, event):
+        wm = context.manager
+        wm.add_fileselect(self)
+        return ('RUNNING_MODAL',)
+
+bpy.ops.add(ExportMDD)
 
 # Add to a menu
 import dynamic_menu
-menu_func = lambda self, context: self.layout.itemO("export.mdd", text="Vertex Keyframe Animation (.mdd)...")
+
+def menu_func(self, context):
+    default_path = bpy.data.filename.replace(".blend", ".mdd")
+    self.layout.item_stringO(ExportMDD.bl_idname, "path", default_path, text="Vertex Keyframe Animation (.mdd)...")
+
 menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
 
 if __name__=='__main__':
-       #if not pack:
-#              Draw.PupMenu('Error%t|This script requires a full python install')
-       #Blender.Window.FileSelector(mdd_export_ui, 'EXPORT MDD', sys.makename(ext='.mdd'))
-       bpy.ops.EXPORT_OT_mdd(path="/tmp/test.mdd")
+    #Blender.Window.FileSelector(mdd_export_ui, 'EXPORT MDD', sys.makename(ext='.mdd'))
+    bpy.ops.EXPORT_OT_mdd(path="/tmp/test.mdd")
index 72f1835fea8abd8f0b7d690a86e16ee7b420c352..2c77cbd702afe17dad133b89a68ceb7a30b1198e 100644 (file)
@@ -223,11 +223,11 @@ def copy_images(dest_dir):
        copyCount = 0
        
 #      for bImage in uniqueImages.values():
-#              image_path = bpy.sys.expandpath(bImage.filename)
+#              image_path = bpy.utils.expandpath(bImage.filename)
 #              if bpy.sys.exists(image_path):
 #                      # Make a name for the target path.
 #                      dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
-#                      if not bpy.sys.exists(dest_image_path): # Image isnt alredy there
+#                      if not bpy.utils.exists(dest_image_path): # Image isnt alredy there
 #                              print('\tCopying "%s" > "%s"' % (image_path, dest_image_path))
 #                              copy_file(image_path, dest_image_path)
 #                              copyCount+=1
@@ -932,7 +932,7 @@ Currently the exporter lacks these features:
 
 from bpy.props import *
 
-class EXPORT_OT_obj(bpy.types.Operator):
+class ExportOBJ(bpy.types.Operator):
        '''Save a Wavefront OBJ File'''
        
        bl_idname = "export.obj"
@@ -1002,10 +1002,14 @@ class EXPORT_OT_obj(bpy.types.Operator):
                print("Poll")
                return context.active_object != None
 
-bpy.ops.add(EXPORT_OT_obj)
+bpy.ops.add(ExportOBJ)
 
 import dynamic_menu
-menu_func = lambda self, context: self.layout.itemO("export.obj", text="Wavefront (.obj)...")
+
+def menu_func(self, context):
+    default_path = bpy.data.filename.replace(".blend", ".obj")
+    self.layout.item_stringO(ExportOBJ.bl_idname, "path", default_path, text="Wavefront (.obj)...")
+
 menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
 
 if __name__ == "__main__":
index 7235d51450e28792623966fe1b6c947f962ce083..99fa3233278105c10e2cdf14b78f267b94bbbb94 100644 (file)
@@ -252,7 +252,7 @@ def write(filename, scene, ob, \
 from bpy.props import *
 
 
-class EXPORT_OT_ply(bpy.types.Operator):
+class ExportPLY(bpy.types.Operator):
        '''Export a single object as a stanford PLY with normals, colours and texture coordinates.'''
        bl_idname = "export.ply"
        bl_label = "Export PLY"
@@ -292,10 +292,14 @@ class EXPORT_OT_ply(bpy.types.Operator):
                return ('RUNNING_MODAL',)
 
 
-bpy.ops.add(EXPORT_OT_ply)
+bpy.ops.add(ExportPLY)
 
 import dynamic_menu
-menu_func = lambda self, context: self.layout.itemO("export.ply", text="Stanford (.ply)...")
+
+def menu_func(self, context):
+    default_path = bpy.data.filename.replace(".blend", ".ply")
+    self.layout.item_stringO(ExportPLY.bl_idname, "path", default_path, text="Stanford (.ply)...")
+
 menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
 
 if __name__ == "__main__":
index 6de6725267650ccaf2f40756a3f977dedfc3ffa0..c8c5f71f6fff3513de437a76cf3c5af061b510a5 100644 (file)
@@ -1215,7 +1215,7 @@ def x3d_export_ui(filename):
 
 from bpy.props import *
 
-class EXPORT_OT_x3d(bpy.types.Operator):
+class ExportX3D(bpy.types.Operator):
        '''Export selection to Extensible 3D file (.x3d)'''
        bl_idname = "export.x3d"
        bl_label = 'Export X3D'
@@ -1238,10 +1238,14 @@ class EXPORT_OT_x3d(bpy.types.Operator):
                wm.add_fileselect(self)
                return ('RUNNING_MODAL',)
 
-bpy.ops.add(EXPORT_OT_x3d)
+bpy.ops.add(ExportX3D)
 
 import dynamic_menu
-menu_func = lambda self, context: self.layout.itemO("export.x3d", text="X3D Extensible 3D (.x3d)...")
+
+def menu_func(self, context):
+    default_path = bpy.data.filename.replace(".blend", ".x3d")
+    self.layout.item_stringO(ExportX3D.bl_idname, "path", default_path, text="X3D Extensible 3D (.x3d)...")
+
 menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
 
 # NOTES
diff --git a/release/scripts/io/import_anim_bvh.py b/release/scripts/io/import_anim_bvh.py
new file mode 100644 (file)
index 0000000..dff9a3a
--- /dev/null
@@ -0,0 +1,881 @@
+import math
+
+# import Blender
+import bpy
+# import BPyMessages
+import Mathutils
+Vector= Mathutils.Vector
+Euler= Mathutils.Euler
+Matrix= Mathutils.Matrix
+RotationMatrix= Mathutils.RotationMatrix
+TranslationMatrix= Mathutils.TranslationMatrix
+
+# NASTY GLOBAL
+ROT_STYLE = 'QUAT'
+
+DEG2RAD = 0.017453292519943295
+
+class bvh_node_class(object):
+       __slots__=(\
+       'name',# bvh joint name
+       'parent',# bvh_node_class type or None for no parent
+       'children',# a list of children of this type.
+       'rest_head_world',# worldspace rest location for the head of this node
+       'rest_head_local',# localspace rest location for the head of this node
+       'rest_tail_world',# # worldspace rest location for the tail of this node
+       'rest_tail_local',# # worldspace rest location for the tail of this node
+       'channels',# list of 6 ints, -1 for an unused channel, otherwise an index for the BVH motion data lines, lock triple then rot triple
+       'rot_order',# a triple of indicies as to the order rotation is applied. [0,1,2] is x/y/z - [None, None, None] if no rotation.
+       'anim_data',# a list one tuple's one for each frame. (locx, locy, locz, rotx, roty, rotz)
+       'has_loc',# Conveinience function, bool, same as (channels[0]!=-1 or channels[1]!=-1 channels[2]!=-1)
+       'has_rot',# Conveinience function, bool, same as (channels[3]!=-1 or channels[4]!=-1 channels[5]!=-1)
+       'temp')# use this for whatever you want
+       
+       def __init__(self, name, rest_head_world, rest_head_local, parent, channels, rot_order):
+               self.name= name
+               self.rest_head_world= rest_head_world
+               self.rest_head_local= rest_head_local
+               self.rest_tail_world= None
+               self.rest_tail_local= None
+               self.parent= parent
+               self.channels= channels
+               self.rot_order= rot_order
+               
+               # convenience functions
+               self.has_loc= channels[0] != -1 or channels[1] != -1 or channels[2] != -1
+               self.has_rot= channels[3] != -1 or channels[4] != -1 or channels[5] != -1
+               
+               
+               self.children= []
+               
+               # list of 6 length tuples: (lx,ly,lz, rx,ry,rz)
+               # even if the channels arnt used they will just be zero
+               # 
+               self.anim_data= [(0,0,0,0,0,0)] 
+               
+       
+       def __repr__(self):
+               return 'BVH name:"%s", rest_loc:(%.3f,%.3f,%.3f), rest_tail:(%.3f,%.3f,%.3f)' %\
+               (self.name,\
+               self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z,\
+               self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z)
+       
+
+
+# Change the order rotation is applied.
+MATRIX_IDENTITY_3x3 = Matrix([1,0,0],[0,1,0],[0,0,1])
+MATRIX_IDENTITY_4x4 = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1])
+
+def eulerRotate(x,y,z, rot_order): 
+       
+       # Clamp all values between 0 and 360, values outside this raise an error.
+       mats=[RotationMatrix(math.radians(x%360),3,'x'), RotationMatrix(math.radians(y%360),3,'y'), RotationMatrix(math.radians(z%360),3,'z')]
+       # print rot_order
+       # Standard BVH multiplication order, apply the rotation in the order Z,X,Y
+       
+       #XXX, order changes???
+       #eul = (mats[rot_order[2]]*(mats[rot_order[1]]* (mats[rot_order[0]]* MATRIX_IDENTITY_3x3))).toEuler()   
+       eul = (MATRIX_IDENTITY_3x3*mats[rot_order[0]]*(mats[rot_order[1]]* (mats[rot_order[2]]))).toEuler()     
+       
+       eul = math.degrees(eul.x), math.degrees(eul.y), math.degrees(eul.z) 
+       
+       return eul
+
+def read_bvh(context, file_path, GLOBAL_SCALE=1.0):
+       # File loading stuff
+       # Open the file for importing
+       file = open(file_path, 'rU')    
+       
+       # Seperate into a list of lists, each line a list of words.
+       file_lines = file.readlines()
+       # Non standard carrage returns?
+       if len(file_lines) == 1:
+               file_lines = file_lines[0].split('\r')
+       
+       # Split by whitespace.
+       file_lines =[ll for ll in [ l.split() for l in file_lines] if ll]
+       
+       
+       # Create Hirachy as empties
+       
+       if file_lines[0][0].lower() == 'hierarchy':
+               #print 'Importing the BVH Hierarchy for:', file_path
+               pass
+       else:
+               raise 'ERROR: This is not a BVH file'
+       
+       bvh_nodes= {None:None}
+       bvh_nodes_serial = [None]
+       
+       channelIndex = -1
+       
+
+       lineIdx = 0 # An index for the file.
+       while lineIdx < len(file_lines) -1:
+               #...
+               if file_lines[lineIdx][0].lower() == 'root' or file_lines[lineIdx][0].lower() == 'joint':
+                       
+                       # Join spaces into 1 word with underscores joining it.
+                       if len(file_lines[lineIdx]) > 2:
+                               file_lines[lineIdx][1] = '_'.join(file_lines[lineIdx][1:])
+                               file_lines[lineIdx] = file_lines[lineIdx][:2]
+                       
+                       # MAY NEED TO SUPPORT MULTIPLE ROOT's HERE!!!, Still unsure weather multiple roots are possible.??
+                       
+                       # Make sure the names are unique- Object names will match joint names exactly and both will be unique.
+                       name = file_lines[lineIdx][1]
+                       
+                       #print '%snode: %s, parent: %s' % (len(bvh_nodes_serial) * '  ', name,  bvh_nodes_serial[-1])
+                       
+                       lineIdx += 2 # Incriment to the next line (Offset)
+                       rest_head_local = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) )
+                       lineIdx += 1 # Incriment to the next line (Channels)
+                       
+                       # newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation]
+                       # newChannel references indecies to the motiondata,
+                       # if not assigned then -1 refers to the last value that will be added on loading at a value of zero, this is appended 
+                       # We'll add a zero value onto the end of the MotionDATA so this is always refers to a value.
+                       my_channel = [-1, -1, -1, -1, -1, -1] 
+                       my_rot_order= [None, None, None]
+                       rot_count= 0
+                       for channel in file_lines[lineIdx][2:]:
+                               channel= channel.lower()
+                               channelIndex += 1 # So the index points to the right channel
+                               if   channel == 'xposition':    my_channel[0] = channelIndex
+                               elif channel == 'yposition':    my_channel[1] = channelIndex
+                               elif channel == 'zposition':    my_channel[2] = channelIndex
+                               
+                               elif channel == 'xrotation':
+                                       my_channel[3] = channelIndex
+                                       my_rot_order[rot_count]= 0
+                                       rot_count+=1
+                               elif channel == 'yrotation':
+                                       my_channel[4] = channelIndex
+                                       my_rot_order[rot_count]= 1
+                                       rot_count+=1
+                               elif channel == 'zrotation':
+                                       my_channel[5] = channelIndex
+                                       my_rot_order[rot_count]= 2
+                                       rot_count+=1
+                       
+                       channels = file_lines[lineIdx][2:]
+                       
+                       my_parent= bvh_nodes_serial[-1] # account for none
+                       
+                       
+                       # Apply the parents offset accumletivly
+                       if my_parent==None:
+                               rest_head_world= Vector(rest_head_local)
+                       else:
+                               rest_head_world= my_parent.rest_head_world + rest_head_local
+                       
+                       bvh_node= bvh_nodes[name]= bvh_node_class(name, rest_head_world, rest_head_local, my_parent, my_channel, my_rot_order)
+                       
+                       # If we have another child then we can call ourselves a parent, else 
+                       bvh_nodes_serial.append(bvh_node)
+
+               # Account for an end node
+               if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is somtimes a name after 'End Site' but we will ignore it.
+                       lineIdx += 2 # Incriment to the next line (Offset)
+                       rest_tail = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) )
+                       
+                       bvh_nodes_serial[-1].rest_tail_world= bvh_nodes_serial[-1].rest_head_world + rest_tail
+                       bvh_nodes_serial[-1].rest_tail_local= rest_tail
+                       
+                       
+                       # Just so we can remove the Parents in a uniform way- End end never has kids
+                       # so this is a placeholder
+                       bvh_nodes_serial.append(None)
+               
+               if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0] == '}': # == ['}']
+                       bvh_nodes_serial.pop() # Remove the last item
+               
+               if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0].lower() == 'motion':
+                       #print '\nImporting motion data'
+                       lineIdx += 3 # Set the cursor to the first frame
+                       break
+                       
+               lineIdx += 1
+       
+       
+       # Remove the None value used for easy parent reference
+       del bvh_nodes[None]
+       # Dont use anymore
+       del bvh_nodes_serial
+       
+       bvh_nodes_list= bvh_nodes.values()
+       
+       while lineIdx < len(file_lines):
+               line= file_lines[lineIdx]
+               for bvh_node in bvh_nodes_list:
+                       #for bvh_node in bvh_nodes_serial:
+                       lx= ly= lz= rx= ry= rz= 0.0
+                       channels= bvh_node.channels
+                       anim_data= bvh_node.anim_data
+                       if channels[0] != -1:
+                               lx= GLOBAL_SCALE * float(  line[channels[0]] )
+                               
+                       if channels[1] != -1:
+                               ly= GLOBAL_SCALE * float(  line[channels[1]] )
+                       
+                       if channels[2] != -1:
+                               lz= GLOBAL_SCALE * float(  line[channels[2]] )
+                       
+                       if channels[3] != -1 or channels[4] != -1 or channels[5] != -1:
+                               rx, ry, rz = float( line[channels[3]] ), float( line[channels[4]] ), float( line[channels[5]] )
+                               
+                               if ROT_STYLE != 'NATIVE':
+                                       rx, ry, rz = eulerRotate(rx, ry, rz, bvh_node.rot_order)
+                               
+                               #x,y,z = x/10.0, y/10.0, z/10.0 # For IPO's 36 is 360d
+                               
+                               # Make interpolation not cross between 180d, thjis fixes sub frame interpolation and time scaling.
+                               # Will go from (355d to 365d) rather then to (355d to 5d) - inbetween these 2 there will now be a correct interpolation.
+                               
+                               while anim_data[-1][3] - rx >  180: rx+=360
+                               while anim_data[-1][3] - rx < -180: rx-=360
+                               
+                               while anim_data[-1][4] - ry >  180: ry+=360
+                               while anim_data[-1][4] - ry < -180: ry-=360
+                               
+                               while anim_data[-1][5] - rz >  180: rz+=360
+                               while anim_data[-1][5] - rz < -180: rz-=360
+                               
+                       # Done importing motion data #
+                       anim_data.append( (lx, ly, lz, rx, ry, rz) )
+               lineIdx += 1
+       
+       # Assign children
+       for bvh_node in bvh_nodes.values():             
+               bvh_node_parent= bvh_node.parent
+               if bvh_node_parent:
+                       bvh_node_parent.children.append(bvh_node)
+       
+       # Now set the tip of each bvh_node
+       for bvh_node in bvh_nodes.values():
+               
+               if not bvh_node.rest_tail_world:
+                       if len(bvh_node.children)==0:
+                               # could just fail here, but rare BVH files have childless nodes
+                               bvh_node.rest_tail_world = Vector(bvh_node.rest_head_world)
+                               bvh_node.rest_tail_local = Vector(bvh_node.rest_head_local)
+                       elif len(bvh_node.children)==1:
+                               bvh_node.rest_tail_world= Vector(bvh_node.children[0].rest_head_world)
+                               bvh_node.rest_tail_local= Vector(bvh_node.children[0].rest_head_local)
+                       else:
+                               # allow this, see above
+                               #if not bvh_node.children:
+                               #       raise 'error, bvh node has no end and no children. bad file'
+                                       
+                               # Removed temp for now
+                               rest_tail_world= Vector(0,0,0)
+                               rest_tail_local= Vector(0,0,0)
+                               for bvh_node_child in bvh_node.children:
+                                       rest_tail_world += bvh_node_child.rest_head_world
+                                       rest_tail_local += bvh_node_child.rest_head_local
+                               
+                               bvh_node.rest_tail_world= rest_tail_world * (1.0/len(bvh_node.children))
+                               bvh_node.rest_tail_local= rest_tail_local * (1.0/len(bvh_node.children))
+
+               # Make sure tail isnt the same location as the head.
+               if (bvh_node.rest_tail_local-bvh_node.rest_head_local).length <= 0.001*GLOBAL_SCALE:
+                       
+                       bvh_node.rest_tail_local.y= bvh_node.rest_tail_local.y + GLOBAL_SCALE/10
+                       bvh_node.rest_tail_world.y= bvh_node.rest_tail_world.y + GLOBAL_SCALE/10
+                       
+               
+               
+       return bvh_nodes
+
+
+
+def bvh_node_dict2objects(context, bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False):
+       
+       if IMPORT_START_FRAME<1:
+               IMPORT_START_FRAME= 1
+               
+       scn= context.scene
+       scn.objects.selected = []
+       
+       objects= []
+       
+       def add_ob(name):
+               ob = scn.objects.new('Empty')
+               objects.append(ob)
+               return ob
+       
+       # Add objects
+       for name, bvh_node in bvh_nodes.items():
+               bvh_node.temp= add_ob(name)
+       
+       # Parent the objects
+       for bvh_node in bvh_nodes.values():
+               bvh_node.temp.makeParent([ bvh_node_child.temp for bvh_node_child in bvh_node.children ], 1, 0) # ojbs, noninverse, 1 = not fast.
+       
+       # Offset
+       for bvh_node in bvh_nodes.values():
+               # Make relative to parents offset
+               bvh_node.temp.loc= bvh_node.rest_head_local
+       
+       # Add tail objects
+       for name, bvh_node in bvh_nodes.items():
+               if not bvh_node.children:
+                       ob_end= add_ob(name + '_end')
+                       bvh_node.temp.makeParent([ob_end], 1, 0) # ojbs, noninverse, 1 = not fast.
+                       ob_end.loc= bvh_node.rest_tail_local
+       
+       
+       # Animate the data, the last used bvh_node will do since they all have the same number of frames
+       for current_frame in range(len(bvh_node.anim_data)):
+               Blender.Set('curframe', current_frame+IMPORT_START_FRAME)
+               
+               for bvh_node in bvh_nodes.values():
+                       lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame]
+                       
+                       rest_head_local= bvh_node.rest_head_local
+                       bvh_node.temp.loc= rest_head_local.x+lx, rest_head_local.y+ly, rest_head_local.z+lz
+                       
+                       bvh_node.temp.rot= rx*DEG2RAD,ry*DEG2RAD,rz*DEG2RAD
+                       
+                       bvh_node.temp.insertIpoKey(Blender.Object.IpoKeyTypes.LOCROT)
+       
+       scn.update(1)
+       return objects
+
+
+
+def bvh_node_dict2armature(context, bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False):
+       
+       if IMPORT_START_FRAME<1:
+               IMPORT_START_FRAME= 1
+               
+       
+       # Add the new armature, 
+       scn = context.scene
+#XXX   scn.objects.selected = []
+       for ob in scn.objects:
+               ob.selected = False
+       
+       
+#XXX   arm_data= bpy.data.armatures.new()
+#XXX   arm_ob = scn.objects.new(arm_data)
+       bpy.ops.object.armature_add()
+       arm_ob= scn.objects[-1]
+       arm_data= arm_ob.data
+
+       
+       
+       
+#XXX   scn.objects.context = [arm_ob]
+#XXX   scn.objects.active = arm_ob
+       arm_ob.selected= True
+       scn.objects.active= arm_ob
+       print(scn.objects.active)
+       
+       
+       # Put us into editmode
+#XXX   arm_data.makeEditable()
+       
+       bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+       bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+
+       
+       
+       # Get the average bone length for zero length bones, we may not use this.
+       average_bone_length= 0.0
+       nonzero_count= 0
+       for bvh_node in bvh_nodes.values():
+               l= (bvh_node.rest_head_local-bvh_node.rest_tail_local).length
+               if l:
+                       average_bone_length+= l
+                       nonzero_count+=1
+       
+       # Very rare cases all bones couldbe zero length???
+       if not average_bone_length:
+               average_bone_length = 0.1
+       else:
+               # Normal operation
+               average_bone_length = average_bone_length/nonzero_count
+       
+       
+#XXX - sloppy operator code
+       
+       bpy.ops.armature.delete()
+       bpy.ops.armature.select_all_toggle()
+       bpy.ops.armature.delete()
+
+       ZERO_AREA_BONES= []
+       for name, bvh_node in bvh_nodes.items():
+               # New editbone
+               bpy.ops.armature.bone_primitive_add(name="Bone")
+               
+#XXX           bone= bvh_node.temp= Blender.Armature.Editbone()
+               bone= bvh_node.temp= arm_data.edit_bones[-1]
+
+               bone.name= name
+#              arm_data.bones[name]= bone
+               
+               bone.head= bvh_node.rest_head_world
+               bone.tail= bvh_node.rest_tail_world
+               
+               # ZERO AREA BONES.
+               if (bone.head-bone.tail).length < 0.001:
+                       if bvh_node.parent:
+                               ofs= bvh_node.parent.rest_head_local- bvh_node.parent.rest_tail_local
+                               if ofs.length: # is our parent zero length also?? unlikely
+                                       bone.tail= bone.tail+ofs
+                               else:
+                                       bone.tail.y= bone.tail.y+average_bone_length
+                       else:
+                               bone.tail.y= bone.tail.y+average_bone_length
+                       
+                       ZERO_AREA_BONES.append(bone.name)
+       
+       
+       for bvh_node in bvh_nodes.values():
+               if bvh_node.parent:
+                       # bvh_node.temp is the Editbone
+                       
+                       # Set the bone parent
+                       bvh_node.temp.parent= bvh_node.parent.temp
+                       
+                       # Set the connection state
+                       if not bvh_node.has_loc and\
+                       bvh_node.parent and\
+                       bvh_node.parent.temp.name not in ZERO_AREA_BONES and\
+                       bvh_node.parent.rest_tail_local == bvh_node.rest_head_local:
+                               bvh_node.temp.connected= True
+       
+       # Replace the editbone with the editbone name,
+       # to avoid memory errors accessing the editbone outside editmode
+       for bvh_node in bvh_nodes.values():
+               bvh_node.temp= bvh_node.temp.name
+       
+#XXX   arm_data.update()
+       
+       # Now Apply the animation to the armature
+       
+       # Get armature animation data
+       bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+       bpy.ops.object.mode_set(mode='POSE', toggle=False)
+       
+       pose= arm_ob.pose
+       pose_bones= pose.pose_channels
+       
+       
+       if ROT_STYLE=='NATIVE':
+               eul_order_lookup = {\
+                       (0,1,2):'XYZ',
+                       (0,2,1):'XZY',
+                       (1,0,2):'YXZ',
+                       (1,2,0):'YZX',
+                       (2,0,1):'ZXY',
+                       (2,1,0):'ZYZ'
+               }
+               
+               for bvh_node in bvh_nodes.values():
+                       bone_name= bvh_node.temp # may not be the same name as the bvh_node, could have been shortened.
+                       pose_bone= pose_bones[bone_name]
+                       pose_bone.rotation_mode  = eul_order_lookup[tuple(bvh_node.rot_order)]
+               
+       elif ROT_STYLE=='XYZ':
+               for pose_bone in pose_bones:
+                       pose_bone.rotation_mode  = 'XYZ'
+       else:
+               # Quats default
+               pass 
+       
+       
+       bpy.ops.pose.select_all_toggle() # set
+       bpy.ops.anim.insert_keyframe_menu(type=-4) # XXX -     -4 ???
+       
+
+       
+       
+       
+       #for p in pose_bones:
+       #       print(p)
+       
+       
+#XXX   action = Blender.Armature.NLA.NewAction("Action") 
+#XXX   action.setActive(arm_ob)
+       
+       #bpy.ops.act.new()
+       #action = bpy.data.actions[-1]
+       
+       # arm_ob.animation_data.action = action
+       action = arm_ob.animation_data.action
+       
+       
+       
+       
+       #xformConstants= [ Blender.Object.Pose.LOC, Blender.Object.Pose.ROT ]
+       
+       # Replace the bvh_node.temp (currently an editbone)
+       # With a tuple  (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv)
+       for bvh_node in bvh_nodes.values():
+               bone_name= bvh_node.temp # may not be the same name as the bvh_node, could have been shortened.
+               pose_bone= pose_bones[bone_name]
+               rest_bone= arm_data.bones[bone_name]
+#XXX           bone_rest_matrix = rest_bone.matrix['ARMATURESPACE'].rotationPart()
+               bone_rest_matrix = rest_bone.matrix.rotationPart()
+               
+               
+               bone_rest_matrix_inv= Matrix(bone_rest_matrix)
+               bone_rest_matrix_inv.invert()
+               
+               bone_rest_matrix_inv.resize4x4()
+               bone_rest_matrix.resize4x4()
+               bvh_node.temp= (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv)
+               
+       
+       # Make a dict for fast access without rebuilding a list all the time.
+       '''
+       xformConstants_dict={
+       (True,True):    [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT],\
+       (False,True):   [Blender.Object.Pose.ROT],\
+       (True,False):   [Blender.Object.Pose.LOC],\
+       (False,False):  [],\
+       }
+       '''
+       
+       # KEYFRAME METHOD, SLOW, USE IPOS DIRECT
+       
+       # Animate the data, the last used bvh_node will do since they all have the same number of frames
+       for current_frame in range(len(bvh_node.anim_data)-1): # skip the first frame (rest frame)
+               # print current_frame
+               
+               #if current_frame==150: # debugging
+               #       break
+               
+               # Dont neet to set the current frame
+               for bvh_node in bvh_nodes.values():
+                       pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp
+                       lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame+1]
+                       
+                       if bvh_node.has_rot:
+                               
+                               if ROT_STYLE=='QUAT':
+                                       # Set the rotation, not so simple
+                                       bone_rotation_matrix= Euler(math.radians(rx), math.radians(ry), math.radians(rz)).toMatrix()
+                                       
+                                       bone_rotation_matrix.resize4x4()
+                                       #XXX ORDER CHANGE???
+                                       #pose_bone.rotation_quaternion= (bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat() # ORIGINAL
+                                       # pose_bone.rotation_quaternion= (bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix).toQuat()
+                                       # pose_bone.rotation_quaternion= (bone_rotation_matrix * bone_rest_matrix).toQuat() # BAD
+                                       # pose_bone.rotation_quaternion= bone_rotation_matrix.toQuat() # NOT GOOD
+                                       # pose_bone.rotation_quaternion= bone_rotation_matrix.toQuat() # NOT GOOD
+                                       
+                                       #pose_bone.rotation_quaternion= (bone_rotation_matrix * bone_rest_matrix_inv * bone_rest_matrix).toQuat()
+                                       #pose_bone.rotation_quaternion= (bone_rest_matrix_inv * bone_rest_matrix * bone_rotation_matrix).toQuat()
+                                       #pose_bone.rotation_quaternion= (bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat()
+                                       
+                                       #pose_bone.rotation_quaternion= ( bone_rest_matrix* bone_rest_matrix_inv * bone_rotation_matrix).toQuat()
+                                       #pose_bone.rotation_quaternion= (bone_rotation_matrix * bone_rest_matrix  * bone_rest_matrix_inv).toQuat()
+                                       #pose_bone.rotation_quaternion= (bone_rest_matrix_inv * bone_rotation_matrix  * bone_rest_matrix ).toQuat()
+                                       
+                                       pose_bone.rotation_quaternion= (bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix).toQuat()
+                                       
+                               else:
+                                       bone_rotation_matrix= Euler(math.radians(rx), math.radians(ry), math.radians(rz)).toMatrix()
+                                       bone_rotation_matrix.resize4x4()
+                                       
+                                       eul= (bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toEuler()
+                                       
+                                       #pose_bone.rotation_euler = math.radians(rx), math.radians(ry), math.radians(rz)
+                                       pose_bone.rotation_euler = eul
+                               
+                               print("ROTATION" + str(Euler(math.radians(rx), math.radians(ry), math.radians(rz))))
+                       
+                       if bvh_node.has_loc:
+                               # Set the Location, simple too
+                               
+                               #XXX ORDER CHANGE
+                               # pose_bone.location= (TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local ) * bone_rest_matrix_inv).translationPart() # WHY * 10? - just how pose works
+                               # pose_bone.location= (bone_rest_matrix_inv * TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local )).translationPart()
+                               # pose_bone.location= lx, ly, lz
+                               pose_bone.location= Vector(lx, ly, lz) - bvh_node.rest_head_local
+                               
+
+#XXX           # TODO- add in 2.5
+                       if 0:
+                               # Get the transform 
+                               xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot]
+                               
+                               if xformConstants:
+                                       # Insert the keyframe from the loc/quat
+                                       pose_bone.insertKey(arm_ob, current_frame+IMPORT_START_FRAME, xformConstants, True )
+                       else:
+                               
+                               if bvh_node.has_loc:
+                                       pose_bone.keyframe_insert("location")
+                               if bvh_node.has_rot:
+                                       if ROT_STYLE=='QUAT':
+                                               pose_bone.keyframe_insert("rotation_quaternion")
+                                       else:
+                                               pose_bone.keyframe_insert("rotation_euler")
+                               
+                               
+                       
+               # bpy.ops.anim.insert_keyframe_menu(type=-4) # XXX -     -4 ???
+               bpy.ops.screen.frame_offset(delta=1)
+               
+               # First time, set the IPO's to linear
+#XXX   #TODO
+               if 0:
+                       if current_frame==0:
+                               for ipo in action.getAllChannelIpos().values():
+                                       if ipo:
+                                               for cur in ipo:
+                                                       cur.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
+                                                       if IMPORT_LOOP:
+                                                               cur.extend = Blender.IpoCurve.ExtendTypes.CYCLIC
+                                                       
+                                               
+               else:
+                       for cu in action.fcurves:
+                               for bez in cu.keyframe_points:
+                                       bez.interpolation = 'CONSTANT'
+               
+       # END KEYFRAME METHOD
+       
+       
+       """
+       # IPO KEYFRAME SETTING
+       # Add in the IPOs by adding keyframes, AFAIK theres no way to add IPOs to an action so I do this :/
+       for bvh_node in bvh_nodes.values():
+               pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp
+               
+               # Get the transform 
+               xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot]
+               if xformConstants:
+                       pose_bone.loc[:]= 0,0,0
+                       pose_bone.quat[:]= 0,0,1,0
+                       # Insert the keyframe from the loc/quat
+                       pose_bone.insertKey(arm_ob, IMPORT_START_FRAME, xformConstants)
+
+       
+       action_ipos= action.getAllChannelIpos()
+       
+       
+       for bvh_node in bvh_nodes.values():
+               has_loc= bvh_node.has_loc
+               has_rot= bvh_node.has_rot
+               
+               if not has_rot and not has_loc:
+                       # No animation data
+                       continue
+               
+               ipo= action_ipos[bvh_node.temp[0].name] # posebones name as key
+               
+               if has_loc:
+                       curve_xloc= ipo[Blender.Ipo.PO_LOCX]
+                       curve_yloc= ipo[Blender.Ipo.PO_LOCY]
+                       curve_zloc= ipo[Blender.Ipo.PO_LOCZ]
+                       
+                       curve_xloc.interpolation= \
+                       curve_yloc.interpolation= \
+                       curve_zloc.interpolation= \
+                       Blender.IpoCurve.InterpTypes.LINEAR
+                       
+               
+               if has_rot:
+                       curve_wquat= ipo[Blender.Ipo.PO_QUATW]
+                       curve_xquat= ipo[Blender.Ipo.PO_QUATX]
+                       curve_yquat= ipo[Blender.Ipo.PO_QUATY]
+                       curve_zquat= ipo[Blender.Ipo.PO_QUATZ]
+                       
+                       curve_wquat.interpolation= \
+                       curve_xquat.interpolation= \
+                       curve_yquat.interpolation= \
+                       curve_zquat.interpolation= \
+                       Blender.IpoCurve.InterpTypes.LINEAR
+               
+               # Get the bone 
+               pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp
+               
+               
+               def pose_rot(anim_data):
+                       bone_rotation_matrix= Euler(anim_data[3], anim_data[4], anim_data[5]).toMatrix()
+                       bone_rotation_matrix.resize4x4()
+                       return tuple((bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat()) # qw,qx,qy,qz
+               
+               def pose_loc(anim_data):
+                       return tuple((TranslationMatrix(Vector(anim_data[0], anim_data[1], anim_data[2])) * bone_rest_matrix_inv).translationPart())
+               
+               
+               last_frame= len(bvh_node.anim_data)+IMPORT_START_FRAME-1
+               
+               if has_loc:
+                       pose_locations= [pose_loc(anim_key) for anim_key in bvh_node.anim_data]
+                       
+                       # Add the start at the end, we know the start is just 0,0,0 anyway
+                       curve_xloc.append((last_frame, pose_locations[-1][0]))
+                       curve_yloc.append((last_frame, pose_locations[-1][1]))
+                       curve_zloc.append((last_frame, pose_locations[-1][2]))
+                       
+                       if len(pose_locations) > 1:
+                               ox,oy,oz= pose_locations[0]
+                               x,y,z= pose_locations[1]
+                               
+                               for i in range(1, len(pose_locations)-1): # from second frame to second last frame
+                                       
+                                       nx,ny,nz= pose_locations[i+1]
+                                       xset= yset= zset= True # we set all these by default
+                                       if abs((ox+nx)/2 - x) < 0.00001:        xset= False
+                                       if abs((oy+ny)/2 - y) < 0.00001:        yset= False
+                                       if abs((oz+nz)/2 - z) < 0.00001:        zset= False
+                                       
+                                       if xset: curve_xloc.append((i+IMPORT_START_FRAME, x))
+                                       if yset: curve_yloc.append((i+IMPORT_START_FRAME, y))
+                                       if zset: curve_zloc.append((i+IMPORT_START_FRAME, z))
+                                       
+                                       # Set the old and use the new
+                                       ox,oy,oz=       x,y,z
+                                       x,y,z=          nx,ny,nz
+               
+               
+               if has_rot:
+                       pose_rotations= [pose_rot(anim_key) for anim_key in bvh_node.anim_data]
+                       
+                       # Add the start at the end, we know the start is just 0,0,0 anyway
+                       curve_wquat.append((last_frame, pose_rotations[-1][0]))
+                       curve_xquat.append((last_frame, pose_rotations[-1][1]))
+                       curve_yquat.append((last_frame, pose_rotations[-1][2]))
+                       curve_zquat.append((last_frame, pose_rotations[-1][3]))
+                       
+                       
+                       if len(pose_rotations) > 1:
+                               ow,ox,oy,oz= pose_rotations[0]
+                               w,x,y,z= pose_rotations[1]
+                               
+                               for i in range(1, len(pose_rotations)-1): # from second frame to second last frame
+                                       
+                                       nw, nx,ny,nz= pose_rotations[i+1]
+                                       wset= xset= yset= zset= True # we set all these by default
+                                       if abs((ow+nw)/2 - w) < 0.00001:        wset= False
+                                       if abs((ox+nx)/2 - x) < 0.00001:        xset= False
+                                       if abs((oy+ny)/2 - y) < 0.00001:        yset= False
+                                       if abs((oz+nz)/2 - z) < 0.00001:        zset= False
+                                       
+                                       if wset: curve_wquat.append((i+IMPORT_START_FRAME, w))
+                                       if xset: curve_xquat.append((i+IMPORT_START_FRAME, x))
+                                       if yset: curve_yquat.append((i+IMPORT_START_FRAME, y))
+                                       if zset: curve_zquat.append((i+IMPORT_START_FRAME, z))
+                                       
+                                       # Set the old and use the new
+                                       ow,ox,oy,oz=    w,x,y,z
+                                       w,x,y,z=                nw,nx,ny,nz
+
+       # IPO KEYFRAME SETTING
+       """
+       
+# XXX NOT NEEDED NOW?
+       # pose.update()
+       return arm_ob
+
+
+#=============#
+# TESTING     #
+#=============#
+
+#('/metavr/mocap/bvh/boxer.bvh')
+#('/d/staggered_walk.bvh')
+#('/metavr/mocap/bvh/dg-306-g.bvh') # Incompleate EOF
+#('/metavr/mocap/bvh/wa8lk.bvh') # duplicate joint names, \r line endings.
+#('/metavr/mocap/bvh/walk4.bvh') # 0 channels
+
+'''
+import os
+DIR = '/metavr/mocap/bvh/'
+for f in ('/d/staggered_walk.bvh',):
+       #for f in os.listdir(DIR)[5:6]:
+       #for f in os.listdir(DIR):
+       if f.endswith('.bvh'):
+               s = Blender.Scene.New(f)
+               s.makeCurrent()
+               #file= DIR + f
+               file= f
+               print f
+               bvh_nodes= read_bvh(file, 1.0)
+               bvh_node_dict2armature(bvh_nodes, 1)
+'''
+
+def load_bvh_ui(context, file, PREF_UI= False):
+       
+#XXX   if BPyMessages.Error_NoFile(file):
+#XXX           return
+       
+#XXX   Draw= Blender.Draw
+       
+       IMPORT_SCALE = 0.1
+       IMPORT_START_FRAME = 1
+       IMPORT_AS_ARMATURE = 1
+       IMPORT_AS_EMPTIES = 0
+       IMPORT_LOOP = 0
+       
+       # Get USER Options
+       if PREF_UI:
+               pup_block = [\
+               ('As Armature', IMPORT_AS_ARMATURE, 'Imports the BVH as an armature'),\
+               ('As Empties', IMPORT_AS_EMPTIES, 'Imports the BVH as empties'),\
+               ('Scale: ', IMPORT_SCALE, 0.001, 100.0, 'Scale the BVH, Use 0.01 when 1.0 is 1 metre'),\
+               ('Start Frame: ', IMPORT_START_FRAME, 1, 30000, 'Frame to start BVH motion'),\
+               ('Loop Animation', IMPORT_LOOP, 'Enable cyclic IPOs'),\
+               ]
+               
+#XXX           if not Draw.PupBlock('BVH Import...', pup_block):
+#XXX                   return
+       
+       # print('Attempting import BVH', file)
+       
+       if not IMPORT_AS_ARMATURE and not IMPORT_AS_EMPTIES:
+               raise('No import option selected')
+
+#XXX   Blender.Window.WaitCursor(1)
+       # Get the BVH data and act on it.
+       import time
+       t1= time.time()
+       print('\tparsing bvh...', end= "")
+       bvh_nodes= read_bvh(context, file, IMPORT_SCALE)
+       print('%.4f' % (time.time()-t1))
+       t1= time.time()
+       print('\timporting to blender...', end="")
+       if IMPORT_AS_ARMATURE:  bvh_node_dict2armature(context, bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP)
+       if IMPORT_AS_EMPTIES:   bvh_node_dict2objects(context, bvh_nodes,  IMPORT_START_FRAME, IMPORT_LOOP)
+       
+       print('Done in %.4f\n' % (time.time()-t1))
+#XXX   Blender.Window.WaitCursor(0)
+
+def main():
+       Blender.Window.FileSelector(load_bvh_ui, 'Import BVH', '*.bvh')
+
+from bpy.props import *
+
+class BvhImporter(bpy.types.Operator):
+       '''Load a Wavefront OBJ File.'''
+       bl_idname = "import_anim.bvh"
+       bl_label = "Import BVH"
+       
+       path = StringProperty(name="File Path", description="File path used for importing the OBJ file", maxlen= 1024, default= "")
+       
+       def execute(self, context):
+               # print("Selected: " + context.active_object.name)
+
+               read_bvh(context, self.path)
+
+               return ('FINISHED',)
+       
+       def invoke(self, context, event):       
+               wm = context.manager
+               wm.add_fileselect(self)
+               return ('RUNNING_MODAL',)
+
+
+bpy.ops.add(BvhImporter)
+
+
+import dynamic_menu
+menu_func = lambda self, context: self.layout.itemO(BvhImporter.bl_idname, text="Motion Capture (.bvh)...")
+menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_import, menu_func)
similarity index 99%
rename from release/scripts/io/import_3ds.py
rename to release/scripts/io/import_scene_3ds.py
index 62612cc79d4ea03e174b63a4b084beaa7138be13..cd351ccb99e20bf863e5e933a4fbd7965ddd3656 100644 (file)
@@ -139,7 +139,7 @@ import os
 import time
 import struct
 
-from import_obj import unpack_face_list, load_image
+from import_scene_obj import unpack_face_list, load_image
 
 import bpy
 import Mathutils
@@ -1143,7 +1143,7 @@ from bpy.props import *
 
 class IMPORT_OT_autodesk_3ds(bpy.types.Operator):
        '''Import from 3DS file format (.3ds)'''
-       bl_idname = "import.autodesk_3ds"
+       bl_idname = "import_scene.autodesk_3ds"
        bl_label = 'Import 3DS'
        
        # List of operator properties, the attributes will be assigned
@@ -1167,7 +1167,7 @@ class IMPORT_OT_autodesk_3ds(bpy.types.Operator):
 bpy.ops.add(IMPORT_OT_autodesk_3ds)
 
 import dynamic_menu
-menu_func = lambda self, context: self.layout.itemO("import.autodesk_3ds", text="3D Studio (.3ds)...")
+menu_func = lambda self, context: self.layout.itemO(IMPORT_OT_autodesk_3ds.bl_idname, text="3D Studio (.3ds)...")
 menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_import, menu_func)
 
 # NOTES:
similarity index 99%
rename from release/scripts/io/import_obj.py
rename to release/scripts/io/import_scene_obj.py
index e5e0dc35995db7e529de402fbaf2b4ff520de830..d1b29a3024da96f7e61d48cfeae118f05f1e109f 100644 (file)
@@ -1574,7 +1574,7 @@ from bpy.props import *
 
 class IMPORT_OT_obj(bpy.types.Operator):
        '''Load a Wavefront OBJ File.'''
-       bl_idname = "import.obj"
+       bl_idname = "import_scene.obj"
        bl_label = "Import OBJ"
        
        # List of operator properties, the attributes will be assigned
@@ -1626,7 +1626,7 @@ bpy.ops.add(IMPORT_OT_obj)
 
 
 import dynamic_menu
-menu_func = lambda self, context: self.layout.itemO("import.obj", text="Wavefront (.obj)...")
+menu_func = lambda self, context: self.layout.itemO(IMPORT_OT_obj.bl_idname, text="Wavefront (.obj)...")
 menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_import, menu_func)
 
 
index 8694d7782aece3d1332269f15f8aaed1847a86b8..9cb176972e60d7df2833899aac71cc10248d5766 100644 (file)
@@ -34,7 +34,9 @@ def addFluidFiles(job, path):
                        match = pattern.match(fluid_file)
                        
                        if match:
-                               current_frame = int(match.groups()[1])
+                               # fluid frames starts at 0, which explains the +1
+                               # This is stupid
+                               current_frame = int(match.groups()[1]) + 1 
                                job.addFile(path + fluid_file, current_frame, current_frame)
 
 def addPointCache(job, ob, point_cache, default_path):
@@ -46,7 +48,7 @@ def addPointCache(job, ob, point_cache, default_path):
        if name == "":
                name = "".join(["%02X" % ord(c) for c in ob.name])
        
-       cache_path = bpy.sys.expandpath(point_cache.filepath) if point_cache.external else default_path
+       cache_path = bpy.utils.expandpath(point_cache.filepath) if point_cache.external else default_path
        
        index = "%02i" % point_cache.index
        
@@ -111,14 +113,14 @@ def clientSendJob(conn, scene, anim = False):
        # LIBRARIES
        ###########################
        for lib in bpy.data.libraries:
-               job.addFile(bpy.sys.expandpath(lib_path))
+               job.addFile(bpy.utils.expandpath(lib_path))
                
        ###########################
        # IMAGES
        ###########################
        for image in bpy.data.images:
                if image.source == "FILE" and not image.packed_file:
-                       job.addFile(bpy.sys.expandpath(image.filename))
+                       job.addFile(bpy.utils.expandpath(image.filename))
        
        ###########################
        # FLUID + POINT CACHE
@@ -129,7 +131,7 @@ def clientSendJob(conn, scene, anim = False):
        for object in bpy.data.objects:
                for modifier in object.modifiers:
                        if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
-                               addFluidFiles(job, bpy.sys.expandpath(modifier.settings.path))
+                               addFluidFiles(job, bpy.utils.expandpath(modifier.settings.path))
                        elif modifier.type == "CLOTH":
                                addPointCache(job, object, modifier.point_cache, default_path)
                        elif modifier.type == "SOFT_BODY":
@@ -253,3 +255,15 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
                        
                        conn.close()
 
+def compatible(module):
+       exec("import " + module)
+       module = eval(module)
+       for member in dir(module):
+               subclass = getattr(module, member)
+               try:            subclass.COMPAT_ENGINES.add('NET_RENDER')
+               except: pass
+       del module
+
+compatible("properties_render")
+compatible("properties_world")
+compatible("properties_material")
diff --git a/release/scripts/modules/bpy_ext/Mesh.py b/release/scripts/modules/bpy_ext/Mesh.py
new file mode 100644 (file)
index 0000000..e69de29
index 203e50bdef74434a1f2ea05f329f761e67a00da3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,22 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-# 
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-# 
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-import bpy
-class_obj = bpy.types.Object
-
-class_obj.getChildren = lambda ob: [child for child in bpy.data.objects if child.parent == ob]
index 4198205e54272f7c41c1b6f03f9f5a80f43f3877..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,19 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-# 
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-# 
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-import bpy_ext.Object
index c30869669cc20b1ebb22e4f9c5ccbbda51ba2c25..35d986fe09db78e386e78127f56f53acf779be4b 100644 (file)
@@ -4,12 +4,12 @@
 #  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.
@@ -128,6 +128,12 @@ class bpy_ops_submodule_op(object):
 
     __keys__ = ('module', 'func')
 
+
+    def _get_doc(self):
+        return op_as_string(self.idname())
+
+    __doc__ = property(_get_doc)
+
     def __init__(self, module, func):
         self.module = module
         self.func = func
@@ -186,365 +192,3 @@ class bpy_ops_submodule_op(object):
 
 import bpy
 bpy.ops = bpy_ops()
-
-# TODO, C macro's cant define settings :|
-
-from bpy.props import *
-
-
-class MESH_OT_delete_edgeloop(bpy.types.Operator):
-    '''Export a single object as a stanford PLY with normals,
-    colours and texture coordinates.'''
-    bl_idname = "mesh.delete_edgeloop"
-    bl_label = "Delete Edge Loop"
-
-    def execute(self, context):
-        bpy.ops.tfm.edge_slide(value=1.0)
-        bpy.ops.mesh.select_more()
-        bpy.ops.mesh.remove_doubles()
-        return ('FINISHED',)
-
-rna_path_prop = StringProperty(name="Context Attributes",
-        description="rna context string", maxlen=1024, default="")
-
-rna_reverse_prop = BoolProperty(name="Reverse",
-        description="Cycle backwards", default=False)
-
-
-class NullPathMember:
-    pass
-
-
-def context_path_validate(context, path):
-    import sys
-    try:
-        value = eval("context.%s" % path)
-    except AttributeError:
-        if "'NoneType'" in str(sys.exc_info()[1]):
-            # One of the items in the rna path is None, just ignore this
-            value = NullPathMember
-        else:
-            # We have a real error in the rna path, dont ignore that
-            raise
-
-    return value
-
-
-def execute_context_assign(self, context):
-    if context_path_validate(context, self.path) == NullPathMember:
-        return ('PASS_THROUGH',)
-
-    exec("context.%s=self.value" % self.path)
-    return ('FINISHED',)
-
-
-class WM_OT_context_set_boolean(bpy.types.Operator):
-    '''Set a context value.'''
-    bl_idname = "wm.context_set_boolean"
-    bl_label = "Context Set"
-
-    path = rna_path_prop
-    value = BoolProperty(name="Value",
-            description="Assignment value", default=True)
-
-    execute = execute_context_assign
-
-
-class WM_OT_context_set_int(bpy.types.Operator): # same as enum
-    '''Set a context value.'''
-    bl_idname = "wm.context_set_int"
-    bl_label = "Context Set"
-
-    path = rna_path_prop
-    value = IntProperty(name="Value", description="Assign value", default=0)
-
-    execute = execute_context_assign
-
-
-class WM_OT_context_set_float(bpy.types.Operator): # same as enum
-    '''Set a context value.'''
-    bl_idname = "wm.context_set_int"
-    bl_label = "Context Set"
-
-    path = rna_path_prop
-    value = FloatProperty(name="Value",
-            description="Assignment value", default=0.0)
-
-    execute = execute_context_assign
-
-
-class WM_OT_context_set_string(bpy.types.Operator): # same as enum
-    '''Set a context value.'''
-    bl_idname = "wm.context_set_string"
-    bl_label = "Context Set"
-
-    path = rna_path_prop
-    value = StringProperty(name="Value",
-            description="Assign value", maxlen=1024, default="")
-
-    execute = execute_context_assign
-
-
-class WM_OT_context_set_enum(bpy.types.Operator):
-    '''Set a context value.'''
-    bl_idname = "wm.context_set_enum"
-    bl_label = "Context Set"
-
-    path = rna_path_prop
-    value = StringProperty(name="Value",
-            description="Assignment value (as a string)",
-            maxlen=1024, default="")
-
-    execute = execute_context_assign
-
-
-class WM_OT_context_toggle(bpy.types.Operator):
-    '''Toggle a context value.'''
-    bl_idname = "wm.context_toggle"
-    bl_label = "Context Toggle"
-    path = rna_path_prop
-
-    def execute(self, context):
-
-        if context_path_validate(context, self.path) == NullPathMember:
-            return ('PASS_THROUGH',)
-
-        exec("context.%s=not (context.%s)" % (self.path, self.path))
-        return ('FINISHED',)
-
-
-class WM_OT_context_toggle_enum(bpy.types.Operator):
-    '''Toggle a context value.'''
-    bl_idname = "wm.context_toggle_enum"
-    bl_label = "Context Toggle Values"
-
-    path = rna_path_prop
-    value_1 = StringProperty(name="Value", \
-                description="Toggle enum", maxlen=1024, default="")
-
-    value_2 = StringProperty(name="Value", \
-                description="Toggle enum", maxlen=1024, default="")
-
-    def execute(self, context):
-
-        if context_path_validate(context, self.path) == NullPathMember:
-            return ('PASS_THROUGH',)
-
-        exec("context.%s = ['%s', '%s'][context.%s!='%s']" % \
-            (self.path, self.value_1, self.value_2, self.path, self.value_2))
-
-        return ('FINISHED',)
-
-
-class WM_OT_context_cycle_int(bpy.types.Operator):
-    '''Set a context value. Useful for cycling active material,
-    vertex keys, groups' etc.'''
-    bl_idname = "wm.context_cycle_int"
-    bl_label = "Context Int Cycle"
-    path = rna_path_prop
-    reverse = rna_reverse_prop
-
-    def execute(self, context):
-
-        value = context_path_validate(context, self.path)
-        if value == NullPathMember:
-            return ('PASS_THROUGH',)
-
-        self.value = value
-        if self.reverse:
-            self.value -= 1
-        else:
-            self.value += 1
-        execute_context_assign(self, context)
-
-        if self.value != eval("context.%s" % self.path):
-            # relies on rna clamping int's out of the range
-            if self.reverse:
-                self.value = (1 << 32)
-            else:
-                self.value = - (1 << 32)
-            execute_context_assign(self, context)
-
-        return ('FINISHED',)
-
-
-class WM_OT_context_cycle_enum(bpy.types.Operator):
-    '''Toggle a context value.'''
-    bl_idname = "wm.context_cycle_enum"
-    bl_label = "Context Enum Cycle"
-
-    path = rna_path_prop
-    reverse = rna_reverse_prop
-
-    def execute(self, context):
-
-        value = context_path_validate(context, self.path)
-        if value == NullPathMember:
-            return ('PASS_THROUGH',)
-
-        orig_value = value
-
-        # Have to get rna enum values
-        rna_struct_str, rna_prop_str = self.path.rsplit('.', 1)
-        i = rna_prop_str.find('[')
-
-        # just incse we get "context.foo.bar[0]"
-        if i != -1:
-            rna_prop_str = rna_prop_str[0:i]
-
-        rna_struct = eval("context.%s.rna_type" % rna_struct_str)
-
-        rna_prop = rna_struct.properties[rna_prop_str]
-
-        if type(rna_prop) != bpy.types.EnumProperty:
-            raise Exception("expected an enum property")
-
-        enums = rna_struct.properties[rna_prop_str].items.keys()
-        orig_index = enums.index(orig_value)
-
-        # Have the info we need, advance to the next item
-        if self.reverse:
-            if orig_index == 0:
-                advance_enum = enums[-1]
-            else:
-                advance_enum = enums[orig_index-1]
-        else:
-            if orig_index == len(enums) - 1:
-                advance_enum = enums[0]
-            else:
-                advance_enum = enums[orig_index + 1]
-
-        # set the new value
-        exec("context.%s=advance_enum" % self.path)
-        return ('FINISHED',)
-
-doc_id = StringProperty(name="Doc ID",
-        description="ID for the documentation", maxlen=1024, default="")
-
-doc_new = StringProperty(name="Doc New",
-        description="", maxlen=1024, default="")
-
-
-class WM_OT_doc_view(bpy.types.Operator):
-    '''Load online reference docs'''
-    bl_idname = "wm.doc_view"
-    bl_label = "View Documentation"
-
-    doc_id = doc_id
-    _prefix = 'http://www.blender.org/documentation/250PythonDoc'
-
-    def _nested_class_string(self, class_string):
-        ls = []
-        class_obj = getattr(bpy.types, class_string, None).bl_rna
-        while class_obj:
-            ls.insert(0, class_obj)
-            class_obj = class_obj.nested
-        return '.'.join([class_obj.identifier for class_obj in ls])
-
-    def execute(self, context):
-        id_split = self.doc_id.split('.')
-        if len(id_split) == 1: # rna, class
-            url = '%s/bpy.types.%s-class.html' % (self._prefix, id_split[0])
-        elif len(id_split) == 2: # rna, class.prop
-            class_name, class_prop = id_split
-
-            # It so happens that epydoc nests these
-            class_name_full = self._nested_class_string(class_name)
-
-            if hasattr(bpy.types, class_name.upper() + '_OT_' + class_prop):
-                url = '%s/bpy.ops.%s-module.html#%s' % \
-                        (self._prefix, class_name_full, class_prop)
-            else:
-                url = '%s/bpy.types.%s-class.html#%s' % \
-                        (self._prefix, class_name_full, class_prop)
-
-        else:
-            return ('PASS_THROUGH',)
-
-        import webbrowser
-        webbrowser.open(url)
-
-        return ('FINISHED',)
-
-
-class WM_OT_doc_edit(bpy.types.Operator):
-    '''Load online reference docs'''
-    bl_idname = "wm.doc_edit"
-    bl_label = "Edit Documentation"
-
-    doc_id = doc_id
-    doc_new = doc_new
-
-    _url = "http://www.mindrones.com/blender/svn/xmlrpc.php"
-
-    def _send_xmlrpc(self, data_dict):
-        print("sending data:", data_dict)
-
-        import xmlrpc.client
-        user = 'blenderuser'
-        pwd = 'blender>user'
-
-        docblog = xmlrpc.client.ServerProxy(self._url)
-        docblog.metaWeblog.newPost(1, user, pwd, data_dict, 1)
-
-    def execute(self, context):
-
-        class_name, class_prop = self.doc_id.split('.')
-
-        if not self.doc_new:
-            return 'OPERATOR_CANCELLED'
-
-        # check if this is an operator
-        op_name = class_name.upper() + '_OT_' + class_prop
-        op_class = getattr(bpy.types, op_name, None)
-
-        # Upload this to the web server
-        upload = {}
-
-        if op_class:
-            rna = op_class.bl_rna
-            doc_orig = rna.description
-            if doc_orig == self.doc_new:
-                return 'OPERATOR_CANCELLED'
-
-            print("op - old:'%s' -> new:'%s'" % (doc_orig, self.doc_new))
-            upload["title"] = 'OPERATOR %s:%s' % (self.doc_id, doc_orig)
-            upload["description"] = self.doc_new
-
-            self._send_xmlrpc(upload)
-
-        else:
-            rna = getattr(bpy.types, class_name).bl_rna
-            doc_orig = rna.properties[class_prop].description
-            if doc_orig == self.doc_new:
-                return 'OPERATOR_CANCELLED'
-
-            print("rna - old:'%s' -> new:'%s'" % (doc_orig, self.doc_new))
-            upload["title"] = 'RNA %s:%s' % s(self.doc_id, doc_orig)
-
-        upload["description"] = self.doc_new
-
-        self._send_xmlrpc(upload)
-
-        return ('FINISHED',)
-
-    def invoke(self, context, event):
-        wm = context.manager
-        wm.invoke_props_popup(self, event)
-        return ('RUNNING_MODAL',)
-
-
-bpy.ops.add(MESH_OT_delete_edgeloop)
-
-bpy.ops.add(WM_OT_context_set_boolean)
-bpy.ops.add(WM_OT_context_set_int)
-bpy.ops.add(WM_OT_context_set_float)
-bpy.ops.add(WM_OT_context_set_string)
-bpy.ops.add(WM_OT_context_set_enum)
-bpy.ops.add(WM_OT_context_toggle)
-bpy.ops.add(WM_OT_context_toggle_enum)
-bpy.ops.add(WM_OT_context_cycle_enum)
-bpy.ops.add(WM_OT_context_cycle_int)
-
-bpy.ops.add(WM_OT_doc_view)
-bpy.ops.add(WM_OT_doc_edit)
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
new file mode 100644 (file)
index 0000000..d2bed9f
--- /dev/null
@@ -0,0 +1,82 @@
+# ##### 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+
+StructRNA = bpy.types.Struct.__bases__[0]
+# StructRNA = bpy.types.Struct
+
+
+class Object(bpy.types.ID):
+
+    def _get_children(self):
+        return [child for child in bpy.data.objects if child.parent == self]
+
+    children = property(_get_children)
+
+
+def ord_ind(i1,i2):
+    if i1<i2: return i1,i2
+    return i2,i1
+
+class Mesh(bpy.types.ID):
+    
+    def _get_edge_keys(self):
+        return [edge_key for face in self.faces for edge_key in face.edge_keys]
+
+    edge_keys = property(_get_edge_keys)
+
+    def _get_edge_face_count_dict(self):
+        face_edge_keys = [face.edge_keys for face in self.faces]
+        face_edge_count = {}
+        for face_keys in face_edge_keys:
+            for key in face_keys:
+                try:
+                    face_edge_count[key] += 1
+                except:
+                    face_edge_count[key] = 1
+
+        return face_edge_count
+
+    edge_face_count_dict = property(_get_edge_face_count_dict)
+
+    def _get_edge_face_count(self):
+        edge_face_count_dict = self.edge_face_count_dict
+        return [edge_face_count_dict.get(ed.key, 0) for ed in mesh.edges]
+
+    edge_face_count = property(_get_edge_face_count)
+
+
+class MeshEdge(StructRNA):
+
+    def _get_key(self):
+        return ord_ind(*tuple(self.verts))
+
+    key = property(_get_key)
+
+
+class MeshFace(StructRNA):
+
+    def _get_edge_keys(self):
+        verts = tuple(self.verts)
+        if len(verts)==3:
+            return ord_ind(verts[0], verts[1]),  ord_ind(verts[1], verts[2]),  ord_ind(verts[2], verts[0])
+
+        return ord_ind(verts[0], verts[1]),  ord_ind(verts[1], verts[2]),  ord_ind(verts[2], verts[3]),  ord_ind(verts[3], verts[0])
+
+    edge_keys = property(_get_edge_keys)
similarity index 92%
rename from release/scripts/modules/bpy_sys.py
rename to release/scripts/modules/bpy_utils.py
index 86f9c9d63a204a8230ddb3e7c221d214a2384491..5a73364c1b1593b80aef38943b320912559ee810 100644 (file)
@@ -4,12 +4,12 @@
 #  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.
@@ -26,5 +26,5 @@ def expandpath(path):
     return path
 
 import types
-bpy.sys = types.ModuleType("bpy.sys")
-bpy.sys.expandpath = expandpath
+bpy.utils = types.ModuleType("bpy.utils")
+bpy.utils.expandpath = expandpath
diff --git a/release/scripts/modules/console/complete_calltip.py b/release/scripts/modules/console/complete_calltip.py
new file mode 100644 (file)
index 0000000..486f946
--- /dev/null
@@ -0,0 +1,190 @@
+# Copyright (c) 2009 www.stani.be (GPL license)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import inspect
+import re
+
+
+# regular expression constants
+DEF_DOC = '%s\s*(\(.*?\))'
+DEF_SOURCE = 'def\s+%s\s*(\(.*?\)):'
+RE_EMPTY_LINE = re.compile('^\s*\n')
+RE_FLAG = re.MULTILINE | re.DOTALL
+RE_NEWLINE = re.compile('\n+')
+RE_SPACE = re.compile('\s+')
+RE_DEF_COMPLETE = re.compile(
+    # don't start with a quote
+    '''(?:^|[^"'a-zA-Z0-9_])'''
+    # start with a \w = [a-zA-Z0-9_]
+    '''((\w+'''
+    # allow also dots and closed bracket pairs []
+    '''(?:\w|[.]|\[.+?\])*'''
+    # allow empty string
+    '''|)'''
+    # allow opening bracket(s)
+    '''(?:\(|\s)*)$''')
+
+
+def reduce_newlines(text):
+    """Reduces multiple newlines to a single newline.
+
+    :param text: text with multiple newlines
+    :type text: str
+    :returns: text with single newlines
+    :rtype: str
+
+    >>> reduce_newlines('hello\\n\\nworld')
+    'hello\\nworld'
+    """
+    return RE_NEWLINE.sub('\n', text)
+
+
+def reduce_spaces(text):
+    """Reduces multiple whitespaces to a single space.
+
+    :param text: text with multiple spaces
+    :type text: str
+    :returns: text with single spaces
+    :rtype: str
+
+    >>> reduce_spaces('hello    \\nworld')
+    'hello world'
+    """
+    return RE_SPACE.sub(' ', text)
+
+
+def get_doc(object):
+    """Get the doc string or comments for an object.
+
+    :param object: object
+    :returns: doc string
+    :rtype: str
+
+    >>> get_doc(abs)
+    'abs(number) -> number\\n\\nReturn the absolute value of the argument.'
+    """
+    result = inspect.getdoc(object) or inspect.getcomments(object)
+    return result and RE_EMPTY_LINE.sub('', result.rstrip()) or ''
+
+
+def get_argspec(func, strip_self=True, doc=None, source=None):
+    """Get argument specifications.
+
+    :param strip_self: strip `self` from argspec
+    :type strip_self: bool
+    :param doc: doc string of func (optional)
+    :type doc: str
+    :param source: source code of func (optional)
+    :type source: str
+    :returns: argument specification
+    :rtype: str
+
+    >>> get_argspec(inspect.getclasstree)
+    '(classes, unique=0)'
+    >>> get_argspec(abs)
+    '(number)'
+    """
+    # get the function object of the class
+    try:
+        func = func.__func__
+    except AttributeError:
+        try:
+            # py 2.X
+            func = func.im_func
+        except AttributeError:
+            pass
+    # is callable?
+    if not hasattr(func, '__call__'):
+        return ''
+    # func should have a name
+    try:
+        func_name = func.__name__
+    except AttributeError:
+        return ''
+    # from docstring
+    if doc is None:
+        doc = get_doc(func)
+    match = re.search(DEF_DOC % func_name, doc, RE_FLAG)
+    # from source code
+    if not match:
+        if source is None:
+            try:
+                source = inspect.getsource(func)
+            except TypeError:
+                source = ''
+        if source:
+            match = re.search(DEF_SOURCE % func_name, source, RE_FLAG)
+    if match:
+        argspec = reduce_spaces(match.group(1))
+    else:
+        # try with the inspect.getarg* functions
+        try:
+            argspec = inspect.formatargspec(*inspect.getfullargspec(func))
+        except:
+            try:
+                # py 2.X
+                argspec = inspect.formatargspec(*inspect.getargspec(func))
+            except:
+                try:
+                    argspec = inspect.formatargvalues(
+                        *inspect.getargvalues(func))
+                except:
+                    argspec = ''
+        if strip_self:
+            argspec = argspec.replace('self, ', '')
+    return argspec
+
+
+def complete(line, cursor, namespace):
+    """Complete callable with calltip.
+
+    :param line: incomplete text line
+    :type line: str
+    :param cursor: current character position
+    :type cursor: int
+    :param namespace: namespace
+    :type namespace: dict
+    :returns: (matches, world, scrollback)
+    :rtype: (list of str, str, str)
+
+    >>> import os
+    >>> complete('os.path.isdir(', 14, {'os': os})[-1]
+    'isdir(s)\\nReturn true if the pathname refers to an existing directory.'
+    >>> complete('abs(', 4, {})[-1]
+    'abs(number) -> number\\nReturn the absolute value of the argument.'
+    """
+    matches = []
+    match = RE_DEF_COMPLETE.search(line[:cursor])
+    if match:
+        word = match.group(1)
+        func_word = match.group(2)
+        try:
+            func = eval(func_word, namespace)
+        except Exception:
+            func = None
+            scrollback = ''
+        if func:
+            doc = get_doc(func)
+            argspec = get_argspec(func, doc=doc)
+            scrollback = func_word.split('.')[-1] + (argspec or '()')
+            if doc.startswith(scrollback):
+                scrollback = doc
+            elif doc:
+                scrollback += '\n' + doc
+            scrollback = reduce_newlines(scrollback)
+    else:
+        word = ''
+        scrollback = ''
+    return matches, word, scrollback
index eda34c9ff6bc1f1cf2813fe80f5552ce7a570e62..686b3e7294bf8ef00cb9129c4a89b78cb0e86a76 100644 (file)
 """This module provides intellisense features such as:
 
 * autocompletion
-* calltips (not yet implemented)
+* calltips
 
 It unifies all completion plugins and only loads them on demand.
 """
+
 # TODO: file complete if startswith quotes
 import os
 import re
@@ -63,6 +64,9 @@ def complete(line, cursor, namespace, private=True):
     :type private: bool
     :returns: list of completions, word
     :rtype: list, str
+
+    >>> complete('re.sr', 5, {'re': re})
+    (['re.sre_compile', 're.sre_parse'], 're.sr')
     """
     re_unquoted_word = RE_UNQUOTED_WORD.search(line[:cursor])
     if re_unquoted_word:
@@ -99,14 +103,28 @@ def expand(line, cursor, namespace, private=True):
         current expanded line, updated cursor position and scrollback
 
     :rtype: str, int, str
+
+    >>> expand('os.path.isdir(', 14, {'os': os})[-1]
+    'isdir(s)\\nReturn true if the pathname refers to an existing directory.'
+    >>> expand('abs(', 4, {})[-1]
+    'abs(number) -> number\\nReturn the absolute value of the argument.'
     """
-    matches, word = complete(line, cursor, namespace, private)
+    if line[:cursor].strip().endswith('('):
+        import complete_calltip
+        matches, word, scrollback = complete_calltip.complete(line,
+            cursor, namespace)
+        no_calltip = False
+    else:
+        matches, word = complete(line, cursor, namespace, private)
+        if len(matches) == 1:
+            scrollback = ''
+        else:
+            scrollback = '  '.join([m.split('.')[-1] for m in matches])
+        no_calltip = True
     prefix = os.path.commonprefix(matches)[len(word):]
     if prefix:
         line = line[:cursor] + prefix + line[cursor:]
         cursor += len(prefix)
-    if len(matches) == 1:
-        scrollback = ''
-    else:
-        scrollback = '  '.join([m.split('.')[-1] for m in matches])
+        if no_calltip and prefix.endswith('('):
+            return expand(line, cursor, namespace, private)
     return line, cursor, scrollback
index 8d124f222a1eccaf6036af2185d5ee951655db10..e176626aac34d9b78faf78029546f4a08886dbd9 100644 (file)
@@ -4,12 +4,12 @@
 #  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.
similarity index 95%
rename from release/scripts/io/add_mesh_torus.py
rename to release/scripts/op/add_mesh_torus.py
index 8a6a3a58ed60ca86f9b1209e96c45b3857786681..ddc4f0b977002a2f33aa714a860f2a697a6cfa74 100644 (file)
@@ -74,7 +74,7 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg):
 from bpy.props import *
 
 
-class AddTorusPrimitive(bpy.types.Operator):
+class AddTorus(bpy.types.Operator):
     '''Add a torus mesh.'''
     bl_idname = "mesh.primitive_torus_add"
     bl_label = "Add Torus"
@@ -117,7 +117,7 @@ class AddTorusPrimitive(bpy.types.Operator):
         ob_new = bpy.data.add_object('MESH', "Torus")
         ob_new.data = mesh
         scene.add_object(ob_new)
-        scene.active_object = ob_new
+        scene.objects.active = ob_new
         ob_new.selected = True
 
         ob_new.location = tuple(context.scene.cursor_location)
@@ -125,12 +125,12 @@ class AddTorusPrimitive(bpy.types.Operator):
         return ('FINISHED',)
 
 # Register the operator
-bpy.ops.add(AddTorusPrimitive)
+bpy.ops.add(AddTorus)
 
 # Add to a menu
 import dynamic_menu
 
-menu_func = (lambda self, context: self.layout.itemO("mesh.primitive_torus_add",
+menu_func = (lambda self, context: self.layout.itemO(AddTorus.bl_idname,
                                         text="Torus", icon='ICON_MESH_DONUT'))
 
 menu_item = dynamic_menu.add(bpy.types.INFO_MT_mesh_add, menu_func)
diff --git a/release/scripts/op/console_python.py b/release/scripts/op/console_python.py
new file mode 100644 (file)
index 0000000..d3b745c
--- /dev/null
@@ -0,0 +1,225 @@
+# ##### 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import sys
+import bpy
+
+language_id = 'python'
+
+def add_scrollback(text, text_type):
+    for l in text.split('\n'):
+        bpy.ops.console.scrollback_append(text=l.replace('\t', '    '),
+            type=text_type)
+
+def get_console(console_id):
+    '''
+    helper function for console operators
+    currently each text datablock gets its own
+    console - bpython_code.InteractiveConsole()
+    ...which is stored in this function.
+
+    console_id can be any hashable type
+    '''
+    from code import InteractiveConsole
+
+    try:
+        consoles = get_console.consoles
+    except:
+        consoles = get_console.consoles = {}
+
+    # clear all dead consoles, use text names as IDs
+    # TODO, find a way to clear IDs
+    '''
+    for console_id in list(consoles.keys()):
+        if console_id not in bpy.data.texts:
+            del consoles[id]
+    '''
+
+    try:
+        console, stdout, stderr = consoles[console_id]
+    except:
+        namespace = {'__builtins__': __builtins__, 'bpy': bpy}
+        console = InteractiveConsole(namespace)
+
+        import io
+        stdout = io.StringIO()
+        stderr = io.StringIO()
+
+        consoles[console_id] = console, stdout, stderr
+
+    return console, stdout, stderr
+
+
+class PyConsoleExec(bpy.types.Operator):
+    '''Execute the current console line as a python expression.'''
+    bl_idname = "console.execute_" + language_id
+    bl_label = "Console Execute"
+    bl_register = False
+
+    # Both prompts must be the same length
+    PROMPT = '>>> '
+    PROMPT_MULTI = '... '
+
+    # is this working???
+    '''
+    def poll(self, context):
+        return (context.space_data.type == 'PYTHON')
+    '''
+    # its not :|
+
+    def execute(self, context):
+        sc = context.space_data
+
+        try:
+            line = sc.history[-1].line
+        except:
+            return ('CANCELLED',)
+
+        if sc.console_type != 'PYTHON':
+            return ('CANCELLED',)
+
+        console, stdout, stderr = get_console(hash(context.region))
+
+        # Hack, useful but must add some other way to access
+        #if "C" not in console.locals:
+        console.locals["C"] = context
+
+        # redirect output
+        sys.stdout = stdout
+        sys.stderr = stderr
+
+        # run the console
+        if not line.strip():
+            line_exec = '\n'  # executes a multiline statement
+        else:
+            line_exec = line
+
+        is_multiline = console.push(line_exec)
+
+        stdout.seek(0)
+        stderr.seek(0)
+
+        output = stdout.read()
+        output_err = stderr.read()
+
+        # cleanup
+        sys.stdout = sys.__stdout__
+        sys.stderr = sys.__stderr__
+        sys.last_traceback = None
+
+        # So we can reuse, clear all data
+        stdout.truncate(0)
+        stderr.truncate(0)
+
+        bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT')
+
+        if is_multiline:
+            sc.prompt = self.PROMPT_MULTI
+        else:
+            sc.prompt = self.PROMPT
+
+        # insert a new blank line
+        bpy.ops.console.history_append(text="", current_character=0,
+            remove_duplicates=True)
+
+        # Insert the output into the editor
+        # not quite correct because the order might have changed,
+        # but ok 99% of the time.
+        if output:
+            add_scrollback(output, 'OUTPUT')
+        if output_err:
+            add_scrollback(output_err, 'ERROR')
+
+        return ('FINISHED',)
+
+
+class PyConsoleAutocomplete(bpy.types.Operator):
+    '''Evaluate the namespace up until the cursor and give a list of
+    options or complete the name if there is only one.'''
+    bl_idname = "console.autocomplete_" + language_id
+    bl_label = "Python Console Autocomplete"
+    bl_register = False
+
+    def poll(self, context):
+        return context.space_data.console_type == 'PYTHON'
+
+    def execute(self, context):
+        from console import intellisense
+
+        sc = context.space_data
+
+        console = get_console(hash(context.region))[0]
+        
+        current_line = sc.history[-1]
+        line = current_line.line
+
+        if not console:
+            return ('CANCELLED',)
+
+        if sc.console_type != 'PYTHON':
+            return ('CANCELLED',)
+
+        # This function isnt aware of the text editor or being an operator
+        # just does the autocomp then copy its results back
+        current_line.line, current_line.current_character, scrollback = \
+            intellisense.expand(
+                line=current_line.line,
+                cursor=current_line.current_character,
+                namespace=console.locals,
+                private='-d' in sys.argv)
+
+        # Now we need to copy back the line from blender back into the
+        # text editor. This will change when we dont use the text editor
+        # anymore
+        if scrollback:
+            add_scrollback(scrollback, 'INFO')
+
+        context.area.tag_redraw()
+
+        return ('FINISHED',)
+
+
+class PyConsoleBanner(bpy.types.Operator):
+    bl_idname = "console.banner_" + language_id
+
+    def execute(self, context):
+        sc = context.space_data
+        version_string = sys.version.strip().replace('\n', ' ')
+
+        add_scrollback(" * Python Interactive Console %s *" % version_string, 'OUTPUT')
+        add_scrollback("Command History:  Up/Down Arrow", 'OUTPUT')
+        add_scrollback("Cursor:           Left/Right Home/End", 'OUTPUT')
+        add_scrollback("Remove:           Backspace/Delete", 'OUTPUT')
+        add_scrollback("Execute:          Enter", 'OUTPUT')
+        add_scrollback("Autocomplete:     Ctrl+Space", 'OUTPUT')
+        add_scrollback("Ctrl +/-  Wheel:  Zoom", 'OUTPUT')
+        add_scrollback("Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, Mathutils, Geometry, BGL", 'OUTPUT')
+        add_scrollback("", 'OUTPUT')
+        add_scrollback("", 'OUTPUT')
+        sc.prompt = PyConsoleExec.PROMPT
+
+        # Add context into the namespace for quick access
+        console = get_console(hash(context.region))[0]
+        console.locals["C"] = bpy.context
+
+        return ('FINISHED',)
+
+bpy.ops.add(PyConsoleExec)
+bpy.ops.add(PyConsoleAutocomplete)
+bpy.ops.add(PyConsoleBanner)
diff --git a/release/scripts/op/console_shell.py b/release/scripts/op/console_shell.py
new file mode 100644 (file)
index 0000000..874101d
--- /dev/null
@@ -0,0 +1,113 @@
+# ##### 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import sys
+import os
+
+import bpy
+
+
+language_id = 'shell'
+
+def add_scrollback(text, text_type):
+    for l in text.split('\n'):
+        bpy.ops.console.scrollback_append(text=l.replace('\t', '    '),
+            type=text_type)
+
+def shell_run(text):
+    import subprocess
+    val, output= subprocess.getstatusoutput(text)
+
+    if not val:
+        style= 'OUTPUT'
+    else:
+        style= 'ERROR'
+
+    add_scrollback(output, style)
+
+
+class ShellConsoleExec(bpy.types.Operator):
+    '''Execute the current console line as a python expression.'''
+    bl_idname = "console.execute_" + language_id
+    bl_label = "Console Execute"
+    bl_register = False
+
+    # Both prompts must be the same length
+    PROMPT = '$ '
+
+    # is this working???
+    '''
+    def poll(self, context):
+        return (context.space_data.type == 'PYTHON')
+    '''
+    # its not :|
+
+    def execute(self, context):
+        sc = context.space_data
+
+        try:
+            line = sc.history[-1].line
+        except:
+            return ('CANCELLED',)
+            
+        bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT')
+        
+        shell_run(line)
+        
+        # insert a new blank line
+        bpy.ops.console.history_append(text="", current_character=0,
+            remove_duplicates=True)
+
+        sc.prompt = os.getcwd()+ShellConsoleExec.PROMPT
+        return ('FINISHED',)
+
+
+class ShellConsoleAutocomplete(bpy.types.Operator):
+    '''Evaluate the namespace up until the cursor and give a list of
+    options or complete the name if there is only one.'''
+    bl_idname = "console.autocomplete_" + language_id
+    bl_label = "Python Console Autocomplete"
+    bl_register = False
+
+    def poll(self, context):
+        return context.space_data.console_type == 'PYTHON'
+
+    def execute(self, context):
+        from console import intellisense
+
+        sc = context.space_data
+        
+        # TODO
+        return ('CANCELLED',)
+
+
+class ShellConsoleBanner(bpy.types.Operator):
+    bl_idname = "console.banner_" + language_id
+
+    def execute(self, context):
+        sc = context.space_data
+        
+        shell_run("bash --version")
+        sc.prompt = os.getcwd()+ShellConsoleExec.PROMPT
+
+        return ('FINISHED',)
+
+bpy.ops.add(ShellConsoleExec)
+bpy.ops.add(ShellConsoleAutocomplete)
+bpy.ops.add(ShellConsoleBanner)
diff --git a/release/scripts/op/mesh.py b/release/scripts/op/mesh.py
new file mode 100644 (file)
index 0000000..f78e337
--- /dev/null
@@ -0,0 +1,71 @@
+# ##### 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+
+def main(context):
+    ob = context.active_object
+    bpy.ops.mesh.selection_type(type='FACE')
+    is_editmode = (ob.mode=='EDIT')
+    if is_editmode:
+        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+    mesh = ob.data
+    
+    face_list = [face for face in mesh.faces]
+    face_edge_keys = [face.edge_keys for face in face_list]
+
+    edge_face_count = mesh.edge_face_count_dict
+    
+    def test_interior(index):
+        for key in face_edge_keys[index]:
+            if edge_face_count[key] < 3:
+                return False
+        return True
+
+    for index, face in enumerate(face_list):
+        if(test_interior(index)):
+            face.selected = True
+        else:
+            face.selected = False
+
+    if is_editmode:
+        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+
+class MeshSelectInteriorFaces(bpy.types.Operator):
+    '''Select faces where all edges have more then 2 face users.'''
+
+    bl_idname = "mesh.faces_select_interior"
+    bl_label = "Select Interior Faces"
+    bl_register = True
+    bl_undo = True
+
+    def poll(self, context):
+        ob = context.active_object
+        return (ob and ob.type == 'MESH')
+
+    def execute(self, context):
+        main(context)
+        return ('FINISHED',)
+
+
+# Register the operator
+bpy.ops.add(MeshSelectInteriorFaces)
+
+if __name__ == "__main__":
+    bpy.ops.mesh.faces_select_interior()
similarity index 96%
rename from release/scripts/io/mesh_skin.py
rename to release/scripts/op/mesh_skin.py
index 04543cbef3a670d879226bda80ee7da6d553e8e0..f9a92c8cd82225d26a04c531e8d1f918dc85b75a 100644 (file)
@@ -222,22 +222,6 @@ class edgeLoop(object):
 
 # Returns face edges.
 # face must have edge data.
-
-# Utility funcs for 2.5, make into a module??
-def ord_ind(i1,i2):
-       if i1<i2: return i1,i2
-       return i2,i1
-       
-def edge_key(ed):
-       v1,v2 = tuple(ed.verts)
-       return ord_ind(v1, v2)
-
-def face_edge_keys(f):
-       verts  = tuple(f.verts)
-       if len(verts)==3:
-               return ord_ind(verts[0], verts[1]),  ord_ind(verts[1], verts[2]),  ord_ind(verts[2], verts[0])
-       
-       return ord_ind(verts[0], verts[1]),  ord_ind(verts[1], verts[2]),  ord_ind(verts[2], verts[3]),  ord_ind(verts[3], verts[0])
        
 def mesh_faces_extend(me, faces, mat_idx = 0):
        orig_facetot = len(me.faces)
@@ -272,15 +256,15 @@ def getSelectedEdges(context, me, ob):
        if MESH_MODE == 'FACE':
                context.scene.tool_settings.mesh_selection_mode = 'EDGE'
                # value is [edge, face_sel_user_in]
-               edge_dict=  dict((edge_key(ed), [ed, 0]) for ed in me.edges)
+               edge_dict=  dict((ed.key, [ed, 0]) for ed in me.edges)
                
                for f in me.faces:
-                       if f.sel:
-                               for edkey in face_edge_keys(f):
+                       if f.selected:
+                               for edkey in f.edge_keys:
                                        edge_dict[edkey][1] += 1
                
                context.scene.tool_settings.mesh_selection_mode = MESH_MODE
-               return [ ed_data[0] for ed_data in edge_dict.itervalues() if ed_data[1] == 1 ]
+               return [ ed_data[0] for ed_data in edge_dict.values() if ed_data[1] == 1 ]
        
        
 
@@ -296,7 +280,7 @@ def getVertLoops(selEdges, me):
        vert_used = [False] * tot
        
        for ed in selEdges:
-               i1, i2 = edge_key(ed)
+               i1, i2 = ed.key
                vert_siblings[i1].append(i2)
                vert_siblings[i2].append(i1)
        
diff --git a/release/scripts/op/uvcalc_smart_project.py b/release/scripts/op/uvcalc_smart_project.py
new file mode 100644 (file)
index 0000000..1120232
--- /dev/null
@@ -0,0 +1,1146 @@
+# -------------------------------------------------------------------------- 
+# Smart Projection UV Projection Unwrapper v1.2 by Campbell Barton (AKA Ideasman) 
+# -------------------------------------------------------------------------- 
+# ***** 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. 
+# 
+# ***** END GPL LICENCE BLOCK ***** 
+# -------------------------------------------------------------------------- 
+
+
+#from Blender import Object, Draw, Window, sys, Mesh, Geometry
+from Mathutils import Matrix, Vector, RotationMatrix
+import time
+import Geometry
+import bpy
+from math import cos, degrees, radians
+
+DEG_TO_RAD = 0.017453292519943295 # pi/180.0
+SMALL_NUM = 0.000000001
+BIG_NUM = 1e15
+
+global USER_FILL_HOLES
+global USER_FILL_HOLES_QUALITY
+USER_FILL_HOLES = None
+USER_FILL_HOLES_QUALITY = None
+
+dict_matrix = {}
+
+def pointInTri2D(v, v1, v2, v3):
+       global dict_matrix
+       
+       key = v1.x, v1.y, v2.x, v2.y, v3.x, v3.y
+       
+       # Commented because its slower to do teh bounds check, we should realy cache the bounds info for each face.
+       '''
+       # BOUNDS CHECK
+       xmin= 1000000
+       ymin= 1000000
+       
+       xmax= -1000000
+       ymax= -1000000
+       
+       for i in (0,2,4):
+               x= key[i]
+               y= key[i+1]
+               
+               if xmax<x:      xmax= x
+               if ymax<y:      ymax= y
+               if xmin>x:      xmin= x
+               if ymin>y:      ymin= y 
+       
+       x= v.x
+       y= v.y
+       
+       if x<xmin or x>xmax or y < ymin or y > ymax:
+               return False
+       # Done with bounds check
+       '''
+       try:
+               mtx = dict_matrix[key]
+               if not mtx:
+                       return False
+       except:
+               side1 = v2 - v1
+               side2 = v3 - v1
+               
+               nor = side1.cross(side2)
+               
+               l1 = [side1[0], side1[1], side1[2]]
+               l2 = [side2[0], side2[1], side2[2]]
+               l3 = [nor[0], nor[1], nor[2]]
+               
+               mtx = Matrix(l1, l2, l3)
+               
+               # Zero area 2d tri, even tho we throw away zerop area faces
+               # the projection UV can result in a zero area UV.
+               if not mtx.determinant():
+                       dict_matrix[key] = None
+                       return False
+               
+               mtx.invert()
+               
+               dict_matrix[key] = mtx
+       
+       uvw = (v - v1) * mtx
+       return 0 <= uvw[0] and 0 <= uvw[1] and uvw[0] + uvw[1] <= 1
+
+       
+def boundsIsland(faces):
+       minx = maxx = faces[0].uv[0][0] # Set initial bounds.
+       miny = maxy = faces[0].uv[0][1]
+       # print len(faces), minx, maxx, miny , maxy
+       for f in faces:
+               for uv in f.uv:
+                       x= uv.x
+                       y= uv.y
+                       if x<minx: minx= x
+                       if y<miny: miny= y
+                       if x>maxx: maxx= x
+                       if y>maxy: maxy= y
+       
+       return minx, miny, maxx, maxy
+
+"""
+def boundsEdgeLoop(edges):
+       minx = maxx = edges[0][0] # Set initial bounds.
+       miny = maxy = edges[0][1]
+       # print len(faces), minx, maxx, miny , maxy
+       for ed in edges:
+               for pt in ed:
+                       print 'ass'
+                       x= pt[0]
+                       y= pt[1]
+                       if x<minx: x= minx
+                       if y<miny: y= miny
+                       if x>maxx: x= maxx
+                       if y>maxy: y= maxy
+       
+       return minx, miny, maxx, maxy
+"""
+
+# Turns the islands into a list of unpordered edges (Non internal)
+# Onlt for UV's
+# only returns outline edges for intersection tests. and unique points.
+
+def island2Edge(island):
+       
+       # Vert index edges
+       edges = {}
+       
+       unique_points= {}
+       
+       for f in island:
+               f_uvkey= map(tuple, f.uv)
+               
+               
+               for vIdx, edkey in enumerate(f.edge_keys):
+                       unique_points[f_uvkey[vIdx]] = f.uv[vIdx]
+                       
+                       if f.v[vIdx].index > f.v[vIdx-1].index:
+                               i1= vIdx-1;     i2= vIdx
+                       else:           
+                               i1= vIdx;       i2= vIdx-1
+                       
+                       try:    edges[ f_uvkey[i1], f_uvkey[i2] ] *= 0 # sets eny edge with more then 1 user to 0 are not returned.
+                       except: edges[ f_uvkey[i1], f_uvkey[i2] ] = (f.uv[i1] - f.uv[i2]).length, 
+       
+       # If 2 are the same then they will be together, but full [a,b] order is not correct.
+       
+       # Sort by length
+       
+               
+       length_sorted_edges = [(Vector(key[0]), Vector(key[1]), value) for key, value in edges.items() if value != 0]
+       
+       try:    length_sorted_edges.sort(key = lambda A: -A[2]) # largest first
+       except: length_sorted_edges.sort(lambda A, B: cmp(B[2], A[2]))
+       
+       # Its okay to leave the length in there.
+       #for e in length_sorted_edges:
+       #       e.pop(2)
+       
+       # return edges and unique points
+       return length_sorted_edges, [v.__copy__().resize3D() for v in unique_points.values()]
+       
+# ========================= NOT WORKING????
+# Find if a points inside an edge loop, un-orderd.
+# pt is and x/y
+# edges are a non ordered loop of edges.
+# #offsets are the edge x and y offset.
+"""
+def pointInEdges(pt, edges):
+       #
+       x1 = pt[0] 
+       y1 = pt[1]
+       
+       # Point to the left of this line.
+       x2 = -100000
+       y2 = -10000
+       intersectCount = 0
+       for ed in edges:
+               xi, yi = lineIntersection2D(x1,y1, x2,y2, ed[0][0], ed[0][1], ed[1][0], ed[1][1])
+               if xi != None: # Is there an intersection.
+                       intersectCount+=1
+       
+       return intersectCount % 2
+"""
+
+def pointInIsland(pt, island):
+       vec1 = Vector(); vec2 = Vector(); vec3 = Vector()       
+       for f in island:
+               vec1.x, vec1.y = f.uv[0]
+               vec2.x, vec2.y = f.uv[1]
+               vec3.x, vec3.y = f.uv[2]
+
+               if pointInTri2D(pt, vec1, vec2, vec3):
+                       return True
+               
+               if len(f.v) == 4:
+                       vec1.x, vec1.y = f.uv[0]
+                       vec2.x, vec2.y = f.uv[2]
+                       vec3.x, vec3.y = f.uv[3]                        
+                       if pointInTri2D(pt, vec1, vec2, vec3):
+                               return True
+       return False
+
+
+# box is (left,bottom, right, top)
+def islandIntersectUvIsland(source, target, SourceOffset):
+       # Is 1 point in the box, inside the vertLoops
+       edgeLoopsSource = source[6] # Pretend this is offset
+       edgeLoopsTarget = target[6]
+       
+       # Edge intersect test   
+       for ed in edgeLoopsSource:
+               for seg in edgeLoopsTarget:
+                       i = Geometry.LineIntersect2D(\
+                       seg[0], seg[1], SourceOffset+ed[0], SourceOffset+ed[1])
+                       if i:
+                               return 1 # LINE INTERSECTION
+       
+       # 1 test for source being totally inside target
+       SourceOffset.resize3D()
+       for pv in source[7]:
+               if pointInIsland(pv+SourceOffset, target[0]):
+                       return 2 # SOURCE INSIDE TARGET
+       
+       # 2 test for a part of the target being totaly inside the source.
+       for pv in target[7]:
+               if pointInIsland(pv-SourceOffset, source[0]):
+                       return 3 # PART OF TARGET INSIDE SOURCE.
+
+       return 0 # NO INTERSECTION
+
+
+
+
+# Returns the X/y Bounds of a list of vectors.
+def testNewVecLs2DRotIsBetter(vecs, mat=-1, bestAreaSoFar = -1):
+       
+       # UV's will never extend this far.
+       minx = miny = BIG_NUM
+       maxx = maxy = -BIG_NUM
+       
+       for i, v in enumerate(vecs):
+               
+               # Do this allong the way
+               if mat != -1:
+                       v = vecs[i] = v*mat
+                       x= v.x
+                       y= v.y
+                       if x<minx: minx= x
+                       if y<miny: miny= y
+                       if x>maxx: maxx= x
+                       if y>maxy: maxy= y
+               
+               # Spesific to this algo, bail out if we get bigger then the current area
+               if bestAreaSoFar != -1 and (maxx-minx) * (maxy-miny) > bestAreaSoFar:
+                       return (BIG_NUM, None), None
+       w = maxx-minx
+       h = maxy-miny
+       return (w*h, w,h), vecs # Area, vecs
+       
+# Takes a list of faces that make up a UV island and rotate
+# until they optimally fit inside a square.
+ROTMAT_2D_POS_90D = RotationMatrix( radians(90.0), 2)
+ROTMAT_2D_POS_45D = RotationMatrix( radians(45.0), 2)
+
+RotMatStepRotation = []
+rot_angle = 22.5 #45.0/2
+while rot_angle > 0.1:
+       RotMatStepRotation.append([\
+        RotationMatrix( radians(rot_angle), 2),\
+        RotationMatrix( radians(-rot_angle), 2)])
+       
+       rot_angle = rot_angle/2.0
+       
+
+def optiRotateUvIsland(faces):
+       global currentArea
+       
+       # Bestfit Rotation
+       def best2dRotation(uvVecs, MAT1, MAT2):
+               global currentArea
+               
+               newAreaPos, newfaceProjectionGroupListPos =\
+               testNewVecLs2DRotIsBetter(uvVecs[:], MAT1, currentArea[0])
+               
+               
+               # Why do I use newpos here? May as well give the best area to date for an early bailout
+               # some slight speed increase in this.
+               # If the new rotation is smaller then the existing, we can 
+               # avoid copying a list and overwrite the old, crappy one.
+               
+               if newAreaPos[0] < currentArea[0]:
+                       newAreaNeg, newfaceProjectionGroupListNeg =\
+                       testNewVecLs2DRotIsBetter(uvVecs, MAT2, newAreaPos[0])  # Reuse the old bigger list.
+               else:
+                       newAreaNeg, newfaceProjectionGroupListNeg =\
+                       testNewVecLs2DRotIsBetter(uvVecs[:], MAT2, currentArea[0])  # Cant reuse, make a copy.
+               
+               
+               # Now from the 3 options we need to discover which to use
+               # we have cerrentArea/newAreaPos/newAreaNeg
+               bestArea = min(currentArea[0], newAreaPos[0], newAreaNeg[0])
+               
+               if currentArea[0] == bestArea:
+                       return uvVecs
+               elif newAreaPos[0] == bestArea:
+                       uvVecs = newfaceProjectionGroupListPos
+                       currentArea = newAreaPos                
+               elif newAreaNeg[0] == bestArea:
+                       uvVecs = newfaceProjectionGroupListNeg
+                       currentArea = newAreaNeg
+               
+               return uvVecs
+               
+       
+       # Serialized UV coords to Vectors
+       uvVecs = [uv for f in faces  for uv in f.uv]
+       
+       # Theres a small enough number of these to hard code it
+       # rather then a loop.
+       
+       # Will not modify anything
+       currentArea, dummy =\
+       testNewVecLs2DRotIsBetter(uvVecs)
+       
+       
+       # Try a 45d rotation
+       newAreaPos, newfaceProjectionGroupListPos = testNewVecLs2DRotIsBetter(uvVecs[:], ROTMAT_2D_POS_45D, currentArea[0])
+       
+       if newAreaPos[0] < currentArea[0]:
+               uvVecs = newfaceProjectionGroupListPos
+               currentArea = newAreaPos
+       # 45d done
+       
+       # Testcase different rotations and find the onfe that best fits in a square
+       for ROTMAT in RotMatStepRotation:
+               uvVecs = best2dRotation(uvVecs, ROTMAT[0], ROTMAT[1])
+       
+       # Only if you want it, make faces verticle!
+       if currentArea[1] > currentArea[2]:
+               # Rotate 90d
+               # Work directly on the list, no need to return a value.
+               testNewVecLs2DRotIsBetter(uvVecs, ROTMAT_2D_POS_90D)
+       
+       
+       # Now write the vectors back to the face UV's
+       i = 0 # count the serialized uv/vectors
+       for f in faces:
+               #f.uv = [uv for uv in uvVecs[i:len(f)+i] ]
+               for j, k in enumerate(range(i, len(f.v)+i)):
+                       f.uv[j][:] = uvVecs[k]
+               i += len(f.v)
+
+
+# Takes an island list and tries to find concave, hollow areas to pack smaller islands into.
+def mergeUvIslands(islandList):
+       global USER_FILL_HOLES
+       global USER_FILL_HOLES_QUALITY
+       
+       
+       # Pack islands to bottom LHS
+       # Sync with island
+       
+       #islandTotFaceArea = [] # A list of floats, each island area
+       #islandArea = [] # a list of tuples ( area, w,h)
+       
+       
+       decoratedIslandList = []
+       
+       islandIdx = len(islandList)
+       while islandIdx:
+               islandIdx-=1
+               minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx])
+               w, h = maxx-minx, maxy-miny
+               
+               totFaceArea = 0
+               offset= Vector(minx, miny)
+               for f in islandList[islandIdx]:
+                       for uv in f.uv:
+                               uv -= offset
+                       
+                       totFaceArea += f.area
+               
+               islandBoundsArea = w*h
+               efficiency = abs(islandBoundsArea - totFaceArea)
+               
+               # UV Edge list used for intersections as well as unique points.
+               edges, uniqueEdgePoints = island2Edge(islandList[islandIdx])
+               
+               decoratedIslandList.append([islandList[islandIdx], totFaceArea, efficiency, islandBoundsArea, w,h, edges, uniqueEdgePoints]) 
+               
+       
+       # Sort by island bounding box area, smallest face area first.
+       # no.. chance that to most simple edge loop first.
+       decoratedIslandListAreaSort =decoratedIslandList[:]
+       
+       decoratedIslandListAreaSort.sort(key = lambda A: A[3])
+       
+       # sort by efficiency, Least Efficient first.
+       decoratedIslandListEfficSort = decoratedIslandList[:]
+       # decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2]))
+
+       decoratedIslandListEfficSort.sort(key = lambda A: -A[2])
+
+       # ================================================== THESE CAN BE TWEAKED.
+       # This is a quality value for the number of tests.
+       # from 1 to 4, generic quality value is from 1 to 100
+       USER_STEP_QUALITY =   ((USER_FILL_HOLES_QUALITY - 1) / 25.0) + 1
+       
+       # If 100 will test as long as there is enough free space.
+       # this is rarely enough, and testing takes a while, so lower quality speeds this up.
+       
+       # 1 means they have the same quality 
+       USER_FREE_SPACE_TO_TEST_QUALITY = 1 + (((100 - USER_FILL_HOLES_QUALITY)/100.0) *5)
+       
+       #print 'USER_STEP_QUALITY', USER_STEP_QUALITY
+       #print 'USER_FREE_SPACE_TO_TEST_QUALITY', USER_FREE_SPACE_TO_TEST_QUALITY
+       
+       removedCount = 0
+       
+       areaIslandIdx = 0
+       ctrl = Window.Qual.CTRL
+       BREAK= False
+       while areaIslandIdx < len(decoratedIslandListAreaSort) and not BREAK:
+               sourceIsland = decoratedIslandListAreaSort[areaIslandIdx]
+               # Alredy packed?
+               if not sourceIsland[0]:
+                       areaIslandIdx+=1
+               else:
+                       efficIslandIdx = 0
+                       while efficIslandIdx < len(decoratedIslandListEfficSort) and not BREAK:
+                               
+                               if Window.GetKeyQualifiers() & ctrl:
+                                       BREAK= True
+                                       break
+                               
+                               # Now we have 2 islands, is the efficience of the islands lowers theres an
+                               # increasing likely hood that we can fit merge into the bigger UV island.
+                               # this ensures a tight fit.
+                               
+                               # Just use figures we have about user/unused area to see if they might fit.
+                               
+                               targetIsland = decoratedIslandListEfficSort[efficIslandIdx]
+                               
+                               
+                               if sourceIsland[0] == targetIsland[0] or\
+                               not targetIsland[0] or\
+                               not sourceIsland[0]:
+                                       pass
+                               else:
+                                       
+                                       # ([island, totFaceArea, efficiency, islandArea, w,h])
+                                       # Waisted space on target is greater then UV bounding island area.
+                                       
+                                       
+                                       # if targetIsland[3] > (sourceIsland[2]) and\ #
+                                       # print USER_FREE_SPACE_TO_TEST_QUALITY, 'ass'
+                                       if targetIsland[2] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\
+                                       targetIsland[4] > sourceIsland[4] and\
+                                       targetIsland[5] > sourceIsland[5]:
+                                               
+                                               # DEBUG # print '%.10f  %.10f' % (targetIsland[3], sourceIsland[1])
+                                               
+                                               # These enough spare space lets move the box until it fits
+                                               
+                                               # How many times does the source fit into the target x/y
+                                               blockTestXUnit = targetIsland[4]/sourceIsland[4]
+                                               blockTestYUnit = targetIsland[5]/sourceIsland[5]
+                                               
+                                               boxLeft = 0
+                                               
+                                               
+                                               # Distllllance we can move between whilst staying inside the targets bounds.
+                                               testWidth = targetIsland[4] - sourceIsland[4]
+                                               testHeight = targetIsland[5] - sourceIsland[5]
+                                               
+                                               # Increment we move each test. x/y
+                                               xIncrement = (testWidth / (blockTestXUnit * ((USER_STEP_QUALITY/50)+0.1)))
+                                               yIncrement = (testHeight / (blockTestYUnit * ((USER_STEP_QUALITY/50)+0.1)))
+
+                                               # Make sure were not moving less then a 3rg of our width/height
+                                               if xIncrement<sourceIsland[4]/3:
+                                                       xIncrement= sourceIsland[4]
+                                               if yIncrement<sourceIsland[5]/3:
+                                                       yIncrement= sourceIsland[5]
+                                               
+                                               
+                                               boxLeft = 0 # Start 1 back so we can jump into the loop.
+                                               boxBottom= 0 #-yIncrement
+                                               
+                                               ##testcount= 0
+                                               
+                                               while boxBottom <= testHeight:
+                                                       # Should we use this? - not needed for now.
+                                                       #if Window.GetKeyQualifiers() & ctrl:
+                                                       #       BREAK= True
+                                                       #       break
+                                                       
+                                                       ##testcount+=1
+                                                       #print 'Testing intersect'
+                                                       Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, Vector(boxLeft, boxBottom))
+                                                       #print 'Done', Intersect
+                                                       if Intersect == 1:  # Line intersect, dont bother with this any more
+                                                               pass
+                                                       
+                                                       if Intersect == 2:  # Source inside target
+                                                               '''
+                                                               We have an intersection, if we are inside the target 
+                                                               then move us 1 whole width accross,
+                                                               Its possible this is a bad idea since 2 skinny Angular faces
+                                                               could join without 1 whole move, but its a lot more optimal to speed this up
+                                                               since we have alredy tested for it.
+                                                               
+                                                               It gives about 10% speedup with minimal errors.
+                                                               '''
+                                                               #print 'ass'
+                                                               # Move the test allong its width + SMALL_NUM
+                                                               #boxLeft += sourceIsland[4] + SMALL_NUM
+                                                               boxLeft += sourceIsland[4]
+                                                       elif Intersect == 0: # No intersection?? Place it.
+                                                               # Progress
+                                                               removedCount +=1
+#XXX                                                           Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount)
+                                                               
+                                                               # Move faces into new island and offset
+                                                               targetIsland[0].extend(sourceIsland[0])
+                                                               offset= Vector(boxLeft, boxBottom)
+                                                               
+                                                               for f in sourceIsland[0]:
+                                                                       for uv in f.uv:
+                                                                               uv+= offset
+                                                               
+                                                               sourceIsland[0][:] = [] # Empty
+                                                               
+
+                                                               # Move edge loop into new and offset.
+                                                               # targetIsland[6].extend(sourceIsland[6])
+                                                               #while sourceIsland[6]:
+                                                               targetIsland[6].extend( [ (\
+                                                                        (e[0]+offset, e[1]+offset, e[2])\
+                                                               ) for e in sourceIsland[6] ] )
+                                                               
+                                                               sourceIsland[6][:] = [] # Empty
+                                                               
+                                                               # Sort by edge length, reverse so biggest are first.
+                                                               
+                                                               try:     targetIsland[6].sort(key = lambda A: A[2])
+                                                               except: targetIsland[6].sort(lambda B,A: cmp(A[2], B[2] ))
+                                                               
+                                                               
+                                                               targetIsland[7].extend(sourceIsland[7])
+                                                               offset= Vector(boxLeft, boxBottom, 0)
+                                                               for p in sourceIsland[7]:
+                                                                       p+= offset
+                                                               
+                                                               sourceIsland[7][:] = []
+                                                               
+                                                               
+                                                               # Decrement the efficiency
+                                                               targetIsland[1]+=sourceIsland[1] # Increment totFaceArea
+                                                               targetIsland[2]-=sourceIsland[1] # Decrement efficiency
+                                                               # IF we ever used these again, should set to 0, eg
+                                                               sourceIsland[2] = 0 # No area if anyone wants to know
+                                                               
+                                                               break
+                                                       
+                                                       
+                                                       # INCREMENR NEXT LOCATION
+                                                       if boxLeft > testWidth:
+                                                               boxBottom += yIncrement
+                                                               boxLeft = 0.0
+                                                       else:
+                                                               boxLeft += xIncrement
+                                               ##print testcount
+                               
+                               efficIslandIdx+=1
+               areaIslandIdx+=1
+       
+       # Remove empty islands
+       i = len(islandList)
+       while i:
+               i-=1
+               if not islandList[i]:
+                       del islandList[i] # Can increment islands removed here.
+
+# Takes groups of faces. assumes face groups are UV groups.
+def getUvIslands(faceGroups, me):
+       
+       # Get seams so we dont cross over seams
+       edge_seams = {} # shoudl be a set
+       for ed in me.edges:
+               if ed.seam:
+                       edge_seams[ed.key] = None # dummy var- use sets!                        
+       # Done finding seams
+       
+       
+       islandList = []
+       
+#XXX   Window.DrawProgressBar(0.0, 'Splitting %d projection groups into UV islands:' % len(faceGroups))
+       #print '\tSplitting %d projection groups into UV islands:' % len(faceGroups),
+       # Find grouped faces
+       
+       faceGroupIdx = len(faceGroups)
+       
+       while faceGroupIdx:
+               faceGroupIdx-=1
+               faces = faceGroups[faceGroupIdx]
+               
+               if not faces:
+                       continue
+               
+               # Build edge dict
+               edge_users = {}
+               
+               for i, f in enumerate(faces):
+                       for ed_key in f.edge_keys:
+                               if ed_key in edge_seams: # DELIMIT SEAMS! ;)
+                                       edge_users[ed_key] = [] # so as not to raise an error
+                               else:
+                                       try:            edge_users[ed_key].append(i)
+                                       except:         edge_users[ed_key] = [i]
+               
+               # Modes
+               # 0 - face not yet touched.
+               # 1 - added to island list, and need to search
+               # 2 - touched and searched - dont touch again.
+               face_modes = [0] * len(faces) # initialize zero - untested.
+               
+               face_modes[0] = 1 # start the search with face 1
+               
+               newIsland = []
+               
+               newIsland.append(faces[0])
+               
+               
+               ok = True
+               while ok:
+                       
+                       ok = True
+                       while ok:
+                               ok= False
+                               for i in range(len(faces)):
+                                       if face_modes[i] == 1: # search
+                                               for ed_key in faces[i].edge_keys:
+                                                       for ii in edge_users[ed_key]:
+                                                               if i != ii and face_modes[ii] == 0:
+                                                                       face_modes[ii] = ok = 1 # mark as searched
+                                                                       newIsland.append(faces[ii])
+                                                               
+                                               # mark as searched, dont look again.
+                                               face_modes[i] = 2
+                       
+                       islandList.append(newIsland)
+                       
+                       ok = False
+                       for i in range(len(faces)):
+                               if face_modes[i] == 0:
+                                       newIsland = []
+                                       newIsland.append(faces[i])
+                                       
+                                       face_modes[i] = ok = 1
+                                       break
+                       # if not ok will stop looping
+       
+#XXX   Window.DrawProgressBar(0.1, 'Optimizing Rotation for %i UV Islands' % len(islandList))
+       
+       for island in islandList:
+               optiRotateUvIsland(island)
+       
+       return islandList
+       
+
+def packIslands(islandList):
+       if USER_FILL_HOLES:
+#XXX           Window.DrawProgressBar(0.1, 'Merging Islands (Ctrl: skip merge)...')
+               mergeUvIslands(islandList) # Modify in place
+               
+       
+       # Now we have UV islands, we need to pack them.
+       
+       # Make a synchronised list with the islands
+       # so we can box pak the islands.
+       packBoxes = []
+       
+       # Keep a list of X/Y offset so we can save time by writing the 
+       # uv's and packed data in one pass.
+       islandOffsetList = [] 
+       
+       islandIdx = 0
+       
+       while islandIdx < len(islandList):
+               minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx])
+               
+               w, h = maxx-minx, maxy-miny
+               
+               if USER_ISLAND_MARGIN:
+                       minx -= USER_ISLAND_MARGIN# *w
+                       miny -= USER_ISLAND_MARGIN# *h
+                       maxx += USER_ISLAND_MARGIN# *w
+                       maxy += USER_ISLAND_MARGIN# *h
+               
+                       # recalc width and height
+                       w, h = maxx-minx, maxy-miny
+               
+               if w < 0.00001 or h < 0.00001:
+                       del islandList[islandIdx]
+                       islandIdx -=1
+                       continue
+               
+               '''Save the offset to be applied later,
+               we could apply to the UVs now and allign them to the bottom left hand area
+               of the UV coords like the box packer imagines they are
+               but, its quicker just to remember their offset and
+               apply the packing and offset in 1 pass '''
+               islandOffsetList.append((minx, miny))
+               
+               # Add to boxList. use the island idx for the BOX id.
+               packBoxes.append([0, 0, w, h])
+               islandIdx+=1
+       
+       # Now we have a list of boxes to pack that syncs
+       # with the islands.
+       
+       #print '\tPacking UV Islands...'
+#XXX   Window.DrawProgressBar(0.7, 'Packing %i UV Islands...' % len(packBoxes) )
+       
+       time1 = time.time()
+       packWidth, packHeight = Geometry.BoxPack2D(packBoxes)
+       
+       # print 'Box Packing Time:', time.time() - time1
+       
+       #if len(pa      ckedLs) != len(islandList):
+       #       raise "Error packed boxes differes from original length"
+       
+       #print '\tWriting Packed Data to faces'
+#XXX   Window.DrawProgressBar(0.8, 'Writing Packed Data to faces')
+       
+       # Sort by ID, so there in sync again
+       islandIdx = len(islandList)
+       # Having these here avoids devide by 0
+       if islandIdx:
+               
+               if USER_STRETCH_ASPECT:
+                       # Maximize to uv area?? Will write a normalize function.
+                       xfactor = 1.0 / packWidth
+                       yfactor = 1.0 / packHeight      
+               else:
+                       # Keep proportions.
+                       xfactor = yfactor = 1.0 / max(packWidth, packHeight)
+       
+       while islandIdx:
+               islandIdx -=1
+               # Write the packed values to the UV's
+               
+               xoffset = packBoxes[islandIdx][0] - islandOffsetList[islandIdx][0]
+               yoffset = packBoxes[islandIdx][1] - islandOffsetList[islandIdx][1]
+               
+               for f in islandList[islandIdx]: # Offsetting the UV's so they fit in there packed box
+                       for uv in f.uv:
+                               uv.x= (uv.x+xoffset) * xfactor
+                               uv.y= (uv.y+yoffset) * yfactor
+                       
+                       
+
+def VectoMat(vec):
+       a3 = vec.__copy__().normalize()
+       
+       up = Vector(0,0,1)
+       if abs(a3.dot(up)) == 1.0:
+               up = Vector(0,1,0)
+       
+       a1 = a3.cross(up).normalize()
+       a2 = a3.cross(a1)
+       return Matrix([a1[0], a1[1], a1[2]], [a2[0], a2[1], a2[2]], [a3[0], a3[1], a3[2]])
+
+
+class thickface(object):
+       __slost__= 'v', 'uv', 'no', 'area', 'edge_keys'
+       def __init__(self, face, uvface, mesh_verts):
+               self.v = [mesh_verts[i] for i in face.verts]
+               if len(self.v)==4:
+                       self.uv = uvface.uv1, uvface.uv2, uvface.uv3, uvface.uv4
+               else:
+                       self.uv = uvface.uv1, uvface.uv2, uvface.uv3
+                       
+               self.no = face.normal
+               self.area = face.area
+               self.edge_keys = face.edge_keys
+
+global ob
+ob = None
+def main(context, island_margin, projection_limit):
+       global USER_FILL_HOLES
+       global USER_FILL_HOLES_QUALITY
+       global USER_STRETCH_ASPECT
+       global USER_ISLAND_MARGIN
+       
+#XXX objects= bpy.data.scenes.active.objects
+       objects = context.selected_editable_objects
+       
+       
+       # we can will tag them later.
+       obList =  [ob for ob in objects if ob.type == 'MESH']
+       
+       # Face select object may not be selected.
+#XXX   ob = objects.active
+       ob= objects[0]
+
+       if ob and ob.selected == 0 and ob.type == 'MESH':
+               # Add to the list
+               obList =[ob]
+       del objects
+       
+       if not obList:
+               raise('error, no selected mesh objects')
+       
+       # Create the variables.
+       USER_PROJECTION_LIMIT = projection_limit
+       USER_ONLY_SELECTED_FACES = (1)
+       USER_SHARE_SPACE = (1) # Only for hole filling.
+       USER_STRETCH_ASPECT = (1) # Only for hole filling.
+       USER_ISLAND_MARGIN = island_margin # Only for hole filling.
+       USER_FILL_HOLES = (0)
+       USER_FILL_HOLES_QUALITY = (50) # Only for hole filling.
+       USER_VIEW_INIT = (0) # Only for hole filling.
+       USER_AREA_WEIGHT = (1) # Only for hole filling.
+       
+       # Reuse variable
+       if len(obList) == 1:
+               ob = "Unwrap %i Selected Mesh"
+       else:
+               ob = "Unwrap %i Selected Meshes"
+       
+       # HACK, loop until mouse is lifted.
+       '''
+       while Window.GetMouseButtons() != 0:
+               time.sleep(10)
+       '''
+       
+#XXX   if not Draw.PupBlock(ob % len(obList), pup_block):
+#XXX           return
+#XXX   del ob
+       
+       # Convert from being button types
+       
+       USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD)
+       USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT/2) * DEG_TO_RAD)
+       
+       
+       # Toggle Edit mode
+       is_editmode = (context.active_object.mode == 'EDIT')
+       if is_editmode:
+               bpy.ops.object.mode_set(mode='OBJECT')
+       # Assume face select mode! an annoying hack to toggle face select mode because Mesh dosent like faceSelectMode.
+       
+       if USER_SHARE_SPACE:
+               # Sort by data name so we get consistant results
+               obList.sort(key = lambda ob: ob.data.name)
+               collected_islandList= []
+       
+#XXX   Window.WaitCursor(1)
+       
+       time1 = time.time()
+       
+       # Tag as False se we dont operate on teh same mesh twice.
+#XXX   bpy.data.meshes.tag = False 
+       for me in bpy.data.meshes:
+               me.tag = False
+
+       
+       for ob in obList:
+               me = ob.data
+               
+               if me.tag or me.library:
+                       continue
+               
+               # Tag as used
+               me.tag = True
+               
+               if len(me.uv_textures)==0: # Mesh has no UV Coords, dont bother.
+                       me.add_uv_texture()
+               
+               uv_layer = me.active_uv_texture.data
+               me_verts = list(me.verts)
+               
+               if USER_ONLY_SELECTED_FACES:
+                       meshFaces = [thickface(f, uv_layer[i], me_verts) for i, f in enumerate(me.faces) if f.selected]
+               #else:
+               #       meshFaces = map(thickface, me.faces)
+               
+               if not meshFaces:
+                       continue
+               
+#XXX           Window.DrawProgressBar(0.1, 'SmartProj UV Unwrapper, mapping "%s", %i faces.' % (me.name, len(meshFaces)))
+               
+               # =======
+               # Generate a projection list from face normals, this is ment to be smart :)
+               
+               # make a list of face props that are in sync with meshFaces             
+               # Make a Face List that is sorted by area.
+               # meshFaces = []
+               
+               # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first.
+               meshFaces.sort( key = lambda a: -a.area ) 
+                       
+               # remove all zero area faces
+               while meshFaces and meshFaces[-1].area <= SMALL_NUM:
+                       # Set their UV's to 0,0
+                       for uv in meshFaces[-1].uv:
+                               uv.zero()
+                       meshFaces.pop()
+               
+               # Smallest first is slightly more efficient, but if the user cancels early then its better we work on the larger data.
+               
+               # Generate Projection Vecs
+               # 0d is   1.0
+               # 180 IS -0.59846
+               
+               
+               # Initialize projectVecs
+               if USER_VIEW_INIT:
+                       # Generate Projection
+                       projectVecs = [Vector(Window.GetViewVector()) * ob.matrixWorld.copy().invert().rotationPart()] # We add to this allong the way
+               else:
+                       projectVecs = []
+               
+               newProjectVec = meshFaces[0].no
+               newProjectMeshFaces = []        # Popping stuffs it up.
+               
+               
+               # Predent that the most unique angke is ages away to start the loop off
+               mostUniqueAngle = -1.0
+               
+               # This is popped
+               tempMeshFaces = meshFaces[:]
+               
+               
+               
+               # This while only gathers projection vecs, faces are assigned later on.
+               while 1:
+                       # If theres none there then start with the largest face
+                       
+                       # add all the faces that are close.
+                       for fIdx in range(len(tempMeshFaces)-1, -1, -1):
+                               # Use half the angle limit so we dont overweight faces towards this
+                               # normal and hog all the faces.
+                               if newProjectVec.dot(tempMeshFaces[fIdx].no) > USER_PROJECTION_LIMIT_HALF_CONVERTED:
+                                       newProjectMeshFaces.append(tempMeshFaces.pop(fIdx))
+                       
+                       # Add the average of all these faces normals as a projectionVec
+                       averageVec = Vector(0,0,0)
+                       if USER_AREA_WEIGHT:
+                               for fprop in newProjectMeshFaces:
+                                       averageVec += (fprop.no * fprop.area)
+                       else:
+                               for fprop in newProjectMeshFaces:
+                                       averageVec += fprop.no
+                                       
+                       if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN
+                               projectVecs.append(averageVec.normalize())
+                       
+                       
+                       # Get the next vec!
+                       # Pick the face thats most different to all existing angles :)
+                       mostUniqueAngle = 1.0 # 1.0 is 0d. no difference.
+                       mostUniqueIndex = 0 # dummy
+                       
+                       for fIdx in range(len(tempMeshFaces)-1, -1, -1):
+                               angleDifference = -1.0 # 180d difference.
+                               
+                               # Get the closest vec angle we are to.
+                               for p in projectVecs:
+                                       temp_angle_diff= p.dot(tempMeshFaces[fIdx].no)
+                                       
+                                       if angleDifference < temp_angle_diff:
+                                               angleDifference= temp_angle_diff
+                               
+                               if angleDifference < mostUniqueAngle:
+                                       # We have a new most different angle
+                                       mostUniqueIndex = fIdx
+                                       mostUniqueAngle = angleDifference
+                       
+                       if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED:
+                               #print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces)
+                               # Now weight the vector to all its faces, will give a more direct projection
+                               # if the face its self was not representive of the normal from surrounding faces.
+                               
+                               newProjectVec = tempMeshFaces[mostUniqueIndex].no
+                               newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)]
+                               
+                       
+                       else:
+                               if len(projectVecs) >= 1: # Must have at least 2 projections
+                                       break
+               
+               
+               # If there are only zero area faces then its possible
+               # there are no projectionVecs
+               if not len(projectVecs):
+                       Draw.PupMenu('error, no projection vecs where generated, 0 area faces can cause this.')
+                       return
+               
+               faceProjectionGroupList =[[] for i in range(len(projectVecs)) ]
+               
+               # MAP and Arrange # We know there are 3 or 4 faces here 
+               
+               for fIdx in range(len(meshFaces)-1, -1, -1):
+                       fvec = meshFaces[fIdx].no
+                       i = len(projectVecs)
+                       
+                       # Initialize first
+                       bestAng = fvec.dot(projectVecs[0])
+                       bestAngIdx = 0
+                       
+                       # Cycle through the remaining, first alredy done
+                       while i-1:
+                               i-=1
+                               
+                               newAng = fvec.dot(projectVecs[i])
+                               if newAng > bestAng: # Reverse logic for dotvecs
+                                       bestAng = newAng
+                                       bestAngIdx = i
+                       
+                       # Store the area for later use.
+                       faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx])
+               
+               # Cull faceProjectionGroupList,
+               
+               
+               # Now faceProjectionGroupList is full of faces that face match the project Vecs list
+               for i in range(len(projectVecs)):
+                       # Account for projectVecs having no faces.
+                       if not faceProjectionGroupList[i]:
+                               continue
+                       
+                       # Make a projection matrix from a unit length vector.
+                       MatProj = VectoMat(projectVecs[i])
+                       
+                       # Get the faces UV's from the projected vertex.
+                       for f in faceProjectionGroupList[i]:
+                               f_uv = f.uv
+                               for j, v in enumerate(f.v):
+                                       # XXX - note, between Mathutils in 2.4 and 2.5 the order changed.
+                                       f_uv[j][:] = (v.co * MatProj)[:2]
+               
+               
+               if USER_SHARE_SPACE:
+                       # Should we collect and pack later?
+                       islandList = getUvIslands(faceProjectionGroupList, me)
+                       collected_islandList.extend(islandList)
+                       
+               else:
+                       # Should we pack the islands for this 1 object?
+                       islandList = getUvIslands(faceProjectionGroupList, me)
+                       packIslands(islandList)
+               
+               
+               # update the mesh here if we need to.
+       
+       # We want to pack all in 1 go, so pack now
+       if USER_SHARE_SPACE:
+#XXX           Window.DrawProgressBar(0.9, "Box Packing for all objects...")
+               packIslands(collected_islandList)
+       
+       print("Smart Projection time: %.2f" % (time.time() - time1))
+       # Window.DrawProgressBar(0.9, "Smart Projections done, time: %.2f sec." % (time.time() - time1))
+       
+       if is_editmode:
+               bpy.ops.object.mode_set(mode='EDIT')
+       
+#XXX   Window.DrawProgressBar(1.0, "")
+#XXX   Window.WaitCursor(0)
+#XXX   Window.RedrawAll()
+
+"""
+       pup_block = [\
+       'Projection',\
+*      ('Angle Limit:', USER_PROJECTION_LIMIT, 1, 89, ''),\
+       ('Selected Faces Only', USER_ONLY_SELECTED_FACES, 'Use only selected faces from all selected meshes.'),\
+       ('Init from view', USER_VIEW_INIT, 'The first projection will be from the view vector.'),\
+       ('Area Weight', USER_AREA_WEIGHT, 'Weight projections vector by face area.'),\
+       '',\
+       '',\
+       '',\
+       'UV Layout',\
+       ('Share Tex Space', USER_SHARE_SPACE, 'Objects Share texture space, map all objects into 1 uvmap.'),\
+       ('Stretch to bounds', USER_STRETCH_ASPECT, 'Stretch the final output to texture bounds.'),\
+*      ('Island Margin:', USER_ISLAND_MARGIN, 0.0, 0.5, ''),\
+       'Fill in empty areas',\
+       ('Fill Holes', USER_FILL_HOLES, 'Fill in empty areas reduced texture waistage (slow).'),\
+       ('Fill Quality:', USER_FILL_HOLES_QUALITY, 1, 100, 'Depends on fill holes, how tightly to fill UV holes, (higher is slower)'),\
+       ]
+"""
+
+from bpy.props import *
+class SmartProject(bpy.types.Operator):
+       '''This script projection unwraps the selected faces of a mesh. it operates on all selected mesh objects, and can be used unwrap selected faces, or all faces.'''
+       bl_idname = "uv.smart_project"
+       bl_label = "Smart UV Project"
+
+       bl_register = True
+       bl_undo = True
+
+       angle_limit = FloatProperty(name="Angle Limit",
+                       description="lower for more projection groups, higher for less distortion.",
+                       default=66.0, min=1.0, max=89.0)
+
+       island_margin = FloatProperty(name="Island Margin",
+                       description="Margin to reduce bleed from adjacent islands.",
+                       default=0.0, min=0.0, max=1.0)
+
+       def poll(self, context):
+               return context.active_object != None
+
+       def execute(self, context):
+               main(context, self.island_margin, self.angle_limit)
+               return ('FINISHED',)
+
+bpy.ops.add(SmartProject)
+
+# Add to a menu
+import dynamic_menu
+
+menu_func = (lambda self, context: self.layout.itemO(SmartProject.bl_idname,
+                                                                               text="Smart Project"))
+
+menu_item = dynamic_menu.add(bpy.types.VIEW3D_MT_uv_map, menu_func)
+
+if __name__ == '__main__':
+       bpy.ops.uv.smart_project()
+
similarity index 99%
rename from release/scripts/io/vertexpaint_dirt.py
rename to release/scripts/op/vertexpaint_dirt.py
index 7d32c153d0461c55e2d83408ee856d2fe95734d5..04398dfa8cec2a9bd45b310e366fb260b4c9e1cc 100644 (file)
@@ -117,7 +117,7 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
         active_col_layer = me.vertex_colors[0].data
 
     if not active_col_layer:
-        return("CANCELLED", )
+        return('CANCELLED', )
 
     for i, f in enumerate(me.faces):
         if not me.use_paint_mask or f.selected:
diff --git a/release/scripts/op/wm.py b/release/scripts/op/wm.py
new file mode 100644 (file)
index 0000000..e65002e
--- /dev/null
@@ -0,0 +1,378 @@
+# ##### 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8-80 compliant>
+
+import bpy
+
+from bpy.props import *
+
+class MESH_OT_delete_edgeloop(bpy.types.Operator):
+    '''Export a single object as a stanford PLY with normals,
+    colours and texture coordinates.'''
+    bl_idname = "mesh.delete_edgeloop"
+    bl_label = "Delete Edge Loop"
+
+    def execute(self, context):
+        bpy.ops.tfm.edge_slide(value=1.0)
+        bpy.ops.mesh.select_more()
+        bpy.ops.mesh.remove_doubles()
+        return ('FINISHED',)
+
+rna_path_prop = StringProperty(name="Context Attributes",
+        description="rna context string", maxlen=1024, default="")
+
+rna_reverse_prop = BoolProperty(name="Reverse",
+        description="Cycle backwards", default=False)
+
+class NullPathMember:
+    pass
+
+
+def context_path_validate(context, path):
+    import sys
+    try:
+        value = eval("context.%s" % path)
+    except AttributeError:
+        if "'NoneType'" in str(sys.exc_info()[1]):
+            # One of the items in the rna path is None, just ignore this
+            value = NullPathMember
+        else:
+            # We have a real error in the rna path, dont ignore that
+            raise
+
+    return value
+
+
+def execute_context_assign(self, context):
+    if context_path_validate(context, self.path) == NullPathMember:
+        return ('PASS_THROUGH',)
+
+    exec("context.%s=self.value" % self.path)
+    return ('FINISHED',)
+
+
+class WM_OT_context_set_boolean(bpy.types.Operator):
+    '''Set a context value.'''
+    bl_idname = "wm.context_set_boolean"
+    bl_label = "Context Set"
+
+    path = rna_path_prop
+    value = BoolProperty(name="Value",
+            description="Assignment value", default=True)
+
+    execute = execute_context_assign
+
+
+class WM_OT_context_set_int(bpy.types.Operator): # same as enum
+    '''Set a context value.'''
+    bl_idname = "wm.context_set_int"
+    bl_label = "Context Set"
+
+    path = rna_path_prop
+    value = IntProperty(name="Value", description="Assign value", default=0)
+
+    execute = execute_context_assign
+
+
+class WM_OT_context_set_float(bpy.types.Operator): # same as enum
+    '''Set a context value.'''
+    bl_idname = "wm.context_set_int"
+    bl_label = "Context Set"
+
+    path = rna_path_prop
+    value = FloatProperty(name="Value",
+            description="Assignment value", default=0.0)
+
+    execute = execute_context_assign
+
+
+class WM_OT_context_set_string(bpy.types.Operator): # same as enum
+    '''Set a context value.'''
+    bl_idname = "wm.context_set_string"
+    bl_label = "Context Set"
+
+    path = rna_path_prop
+    value = StringProperty(name="Value",
+            description="Assign value", maxlen=1024, default="")
+
+    execute = execute_context_assign
+
+
+class WM_OT_context_set_enum(bpy.types.Operator):
+    '''Set a context value.'''
+    bl_idname = "wm.context_set_enum"
+    bl_label = "Context Set"
+
+    path = rna_path_prop
+    value = StringProperty(name="Value",
+            description="Assignment value (as a string)",
+            maxlen=1024, default="")
+
+    execute = execute_context_assign
+
+
+class WM_OT_context_toggle(bpy.types.Operator):
+    '''Toggle a context value.'''
+    bl_idname = "wm.context_toggle"
+    bl_label = "Context Toggle"
+    path = rna_path_prop
+
+    def execute(self, context):
+
+        if context_path_validate(context, self.path) == NullPathMember:
+            return ('PASS_THROUGH',)
+
+        exec("context.%s=not (context.%s)" % (self.path, self.path))
+        return ('FINISHED',)
+
+
+class WM_OT_context_toggle_enum(bpy.types.Operator):
+    '''Toggle a context value.'''
+    bl_idname = "wm.context_toggle_enum"
+    bl_label = "Context Toggle Values"
+
+    path = rna_path_prop
+    value_1 = StringProperty(name="Value", \
+                description="Toggle enum", maxlen=1024, default="")
+
+    value_2 = StringProperty(name="Value", \
+                description="Toggle enum", maxlen=1024, default="")
+
+    def execute(self, context):
+
+        if context_path_validate(context, self.path) == NullPathMember:
+            return ('PASS_THROUGH',)
+
+        exec("context.%s = ['%s', '%s'][context.%s!='%s']" % \
+            (self.path, self.value_1, self.value_2, self.path, self.value_2))
+
+        return ('FINISHED',)
+
+
+class WM_OT_context_cycle_int(bpy.types.Operator):
+    '''Set a context value. Useful for cycling active material,
+    vertex keys, groups' etc.'''
+    bl_idname = "wm.context_cycle_int"
+    bl_label = "Context Int Cycle"
+    path = rna_path_prop
+    reverse = rna_reverse_prop
+
+    def execute(self, context):
+
+        value = context_path_validate(context, self.path)
+        if value == NullPathMember:
+            return ('PASS_THROUGH',)
+
+        self.value = value
+        if self.reverse:
+            self.value -= 1
+        else:
+            self.value += 1
+        execute_context_assign(self, context)
+
+        if self.value != eval("context.%s" % self.path):
+            # relies on rna clamping int's out of the range
+            if self.reverse:
+                self.value = (1 << 32)
+            else:
+                self.value = - (1 << 32)
+            execute_context_assign(self, context)
+
+        return ('FINISHED',)
+
+
+class WM_OT_context_cycle_enum(bpy.types.Operator):
+    '''Toggle a context value.'''
+    bl_idname = "wm.context_cycle_enum"
+    bl_label = "Context Enum Cycle"
+
+    path = rna_path_prop
+    reverse = rna_reverse_prop
+
+    def execute(self, context):
+
+        value = context_path_validate(context, self.path)
+        if value == NullPathMember:
+            return ('PASS_THROUGH',)
+
+        orig_value = value
+
+        # Have to get rna enum values
+        rna_struct_str, rna_prop_str = self.path.rsplit('.', 1)
+        i = rna_prop_str.find('[')
+
+        # just incse we get "context.foo.bar[0]"
+        if i != -1:
+            rna_prop_str = rna_prop_str[0:i]
+
+        rna_struct = eval("context.%s.rna_type" % rna_struct_str)
+
+        rna_prop = rna_struct.properties[rna_prop_str]
+
+        if type(rna_prop) != bpy.types.EnumProperty:
+            raise Exception("expected an enum property")
+
+        enums = rna_struct.properties[rna_prop_str].items.keys()
+        orig_index = enums.index(orig_value)
+
+        # Have the info we need, advance to the next item
+        if self.reverse:
+            if orig_index == 0:
+                advance_enum = enums[-1]
+            else:
+                advance_enum = enums[orig_index-1]
+        else:
+            if orig_index == len(enums) - 1:
+                advance_enum = enums[0]
+            else:
+                advance_enum = enums[orig_index + 1]
+
+        # set the new value
+        exec("context.%s=advance_enum" % self.path)
+        return ('FINISHED',)
+
+doc_id = StringProperty(name="Doc ID",
+        description="ID for the documentation", maxlen=1024, default="")
+
+doc_new = StringProperty(name="Doc New",
+        description="", maxlen=1024, default="")
+
+
+class WM_OT_doc_view(bpy.types.Operator):
+    '''Load online reference docs'''
+    bl_idname = "wm.doc_view"
+    bl_label = "View Documentation"
+
+    doc_id = doc_id
+    _prefix = 'http://www.blender.org/documentation/250PythonDoc'
+
+    def _nested_class_string(self, class_string):
+        ls = []
+        class_obj = getattr(bpy.types, class_string, None).bl_rna
+        while class_obj:
+            ls.insert(0, class_obj)
+            class_obj = class_obj.nested
+        return '.'.join([class_obj.identifier for class_obj in ls])
+
+    def execute(self, context):
+        id_split = self.doc_id.split('.')
+        if len(id_split) == 1: # rna, class
+            url = '%s/bpy.types.%s-class.html' % (self._prefix, id_split[0])
+        elif len(id_split) == 2: # rna, class.prop
+            class_name, class_prop = id_split
+
+            if hasattr(bpy.types, class_name.upper() + '_OT_' + class_prop):
+                url = '%s/bpy.ops.%s-module.html#%s' % \
+                        (self._prefix, class_name, class_prop)
+            else:
+                # It so happens that epydoc nests these
+                class_name_full = self._nested_class_string(class_name)
+                url = '%s/bpy.types.%s-class.html#%s' % \
+                        (self._prefix, class_name_full, class_prop)
+
+        else:
+            return ('PASS_THROUGH',)
+
+        import webbrowser
+        webbrowser.open(url)
+
+        return ('FINISHED',)
+
+
+class WM_OT_doc_edit(bpy.types.Operator):
+    '''Load online reference docs'''
+    bl_idname = "wm.doc_edit"
+    bl_label = "Edit Documentation"
+
+    doc_id = doc_id
+    doc_new = doc_new
+
+    _url = "http://www.mindrones.com/blender/svn/xmlrpc.php"
+
+    def _send_xmlrpc(self, data_dict):
+        print("sending data:", data_dict)
+
+        import xmlrpc.client
+        user = 'blenderuser'
+        pwd = 'blender>user'
+
+        docblog = xmlrpc.client.ServerProxy(self._url)
+        docblog.metaWeblog.newPost(1, user, pwd, data_dict, 1)
+
+    def execute(self, context):
+
+        class_name, class_prop = self.doc_id.split('.')
+
+        if not self.doc_new:
+            return ('RUNNING_MODAL',)
+
+        # check if this is an operator
+        op_name = class_name.upper() + '_OT_' + class_prop
+        op_class = getattr(bpy.types, op_name, None)
+
+        # Upload this to the web server
+        upload = {}
+
+        if op_class:
+            rna = op_class.bl_rna
+            doc_orig = rna.description
+            if doc_orig == self.doc_new:
+                return ('RUNNING_MODAL',)
+
+            print("op - old:'%s' -> new:'%s'" % (doc_orig, self.doc_new))
+            upload["title"] = 'OPERATOR %s:%s' % (self.doc_id, doc_orig)
+            upload["description"] = self.doc_new
+
+            self._send_xmlrpc(upload)
+
+        else:
+            rna = getattr(bpy.types, class_name).bl_rna
+            doc_orig = rna.properties[class_prop].description
+            if doc_orig == self.doc_new:
+                return ('RUNNING_MODAL',)
+
+            print("rna - old:'%s' -> new:'%s'" % (doc_orig, self.doc_new))
+            upload["title"] = 'RNA %s:%s' % (self.doc_id, doc_orig)
+
+        upload["description"] = self.doc_new
+
+        self._send_xmlrpc(upload)
+
+        return ('FINISHED',)
+
+    def invoke(self, context, event):
+        wm = context.manager
+        wm.invoke_props_popup(self, event)
+        return ('RUNNING_MODAL',)
+
+
+bpy.ops.add(MESH_OT_delete_edgeloop)
+
+bpy.ops.add(WM_OT_context_set_boolean)
+bpy.ops.add(WM_OT_context_set_int)
+bpy.ops.add(WM_OT_context_set_float)
+bpy.ops.add(WM_OT_context_set_string)
+bpy.ops.add(WM_OT_context_set_enum)
+bpy.ops.add(WM_OT_context_toggle)
+bpy.ops.add(WM_OT_context_toggle_enum)
+bpy.ops.add(WM_OT_context_cycle_enum)
+bpy.ops.add(WM_OT_context_cycle_int)
+
+bpy.ops.add(WM_OT_doc_view)
+bpy.ops.add(WM_OT_doc_edit)
index 203a693de5ac070ab15368211504cf7ccc05b968..37d354d0e6bb038a0877918a6236784cc30fb3e3 100644 (file)
@@ -4,12 +4,12 @@
 #  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.
index b3fe0a4a6cae30546d4f65bfade459ce7005d2bb..0accb57ccc26f14a9f53158acdbee48626ddb145 100644 (file)
@@ -4,12 +4,12 @@
 #  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.
index c19ec7d9116baeafbbecce331a0c70c8a08341de..8cb4fd7ca8dad01a600775807cf333a8743a5784 100644 (file)
@@ -4,12 +4,12 @@
 #  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.
index 88e6a3270962fa691ea73abbfc0c5c9fc59324f5..1ed45f3e2119f38db4e3b6633a39509157b6fb99 100644 (file)
@@ -4,12 +4,12 @@
 #  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.
@@ -19,6 +19,7 @@
 import bpy
 
 def write_some_data(context, path, use_some_setting):
+    print("running write_some_data...")
     pass
 
 from bpy.props import *
@@ -33,16 +34,18 @@ class ExportSomeData(bpy.types.Operator):
 
     # TODO, add better example props
     path = StringProperty(name="File Path", description="File path used for exporting the PLY file", maxlen= 1024, default= "")
-    use_some_setting = BoolProperty(name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default= True)
+    use_setting = BoolProperty(name="Example Boolean", description="Example Tooltip", default= True)
 
     def poll(self, context):
         return context.active_object != None
 
     def execute(self, context):
-        if not self.is_property_set("path"):
-            raise Exception("filename not set")
 
-        write(self.path, context, use_setting, SOME_SETTING = self.use_some_setting)
+        # # Bug, currently isnt working
+        #if not self.is_property_set("path"):
+        #    raise Exception("filename not set")
+
+        write_some_data(self.path, context, self.use_setting)
 
         return ('FINISHED',)
 
@@ -53,11 +56,11 @@ class ExportSomeData(bpy.types.Operator):
             # File selector
             wm.add_fileselect(self) # will run self.execute()
             return ('RUNNING_MODAL',)
-        else if 0:
+        elif 0:
             # Redo popup
             wm.invoke_props_popup(self, event) #
             return ('RUNNING_MODAL',)
-        else if 0:
+        elif 0:
             return self.execute(context)
 
 
index 6e166a3e97014856de890fb75cbde3761998712d..438df083d4de6bfec516a9dafd70d1c8f797132d 100644 (file)
@@ -4,12 +4,12 @@
 #  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.
index 20360fa5ee363e3351247083b0da7075160144ae..49e26a2e8c2fcd70d349280c55eca6b560385d09 100644 (file)
@@ -159,40 +159,42 @@ class DATA_PT_shape_keys(DataButtonsPanel):
 
         col = row.column()
 
-        subcol = col.column(align=True)
-        subcol.itemO("object.shape_key_add", icon='ICON_ZOOMIN', text="")
-        subcol.itemO("object.shape_key_remove", icon='ICON_ZOOMOUT', text="")
+        sub = col.column(align=True)
+        sub.itemO("object.shape_key_add", icon='ICON_ZOOMIN', text="")
+        sub.itemO("object.shape_key_remove", icon='ICON_ZOOMOUT', text="")
 
         if kb:
             col.itemS()
 
-            subcol = col.column(align=True)
-            subcol.item_enumO("object.shape_key_move", "type", 'UP', icon='ICON_TRIA_UP', text="")
-            subcol.item_enumO("object.shape_key_move", "type", 'DOWN', icon='ICON_TRIA_DOWN', text="")
+            sub = col.column(align=True)
+            sub.item_enumO("object.shape_key_move", "type", 'UP', icon='ICON_TRIA_UP', text="")
+            sub.item_enumO("object.shape_key_move", "type", 'DOWN', icon='ICON_TRIA_DOWN', text="")
 
             split = layout.split(percentage=0.4)
-            sub = split.row()
-            sub.enabled = enable_edit
-            sub.itemR(key, "relative")
+            row = split.row()
+            row.enabled = enable_edit
+            row.itemR(key, "relative")
 
-            sub = split.row()
-            sub.alignment = 'RIGHT'
+            row = split.row()
+            row.alignment = 'RIGHT'
 
-            subrow = sub.row(align=True)
-            subrow.active = enable_edit_value
+            sub = row.row(align=True)
+            subsub = sub.row(align=True)
+            subsub.active = enable_edit_value
             if ob.shape_key_lock:
-                subrow.itemR(ob, "shape_key_lock", icon='ICON_PINNED', text="")
+                subsub.itemR(ob, "shape_key_lock", icon='ICON_PINNED', text="")
             else:
-                subrow.itemR(ob, "shape_key_lock", icon='ICON_UNPINNED', text="")
+                subsub.itemR(ob, "shape_key_lock", icon='ICON_UNPINNED', text="")
             if kb.mute:
-                subrow.itemR(kb, "mute", icon='ICON_MUTE_IPO_ON', text="")
+                subsub.itemR(kb, "mute", icon='ICON_MUTE_IPO_ON', text="")
             else:
-                subrow.itemR(kb, "mute", icon='ICON_MUTE_IPO_OFF', text="")
-            subrow.itemO("object.shape_key_clear", icon='ICON_X', text="")
+                subsub.itemR(kb, "mute", icon='ICON_MUTE_IPO_OFF', text="")
+            sub.itemR(ob, "shape_key_edit_mode", text="")
 
-            sub.itemO("object.shape_key_mirror", icon='ICON_MOD_MIRROR', text="")
+            sub = row.row(align=True)
+            sub.itemO("object.shape_key_mirror", icon='ICON_ARROW_LEFTRIGHT', text="")
+            sub.itemO("object.shape_key_clear", icon='ICON_X', text="")
 
-            sub.itemR(ob, "shape_key_edit_mode", text="")
 
             row = layout.row()
             row.itemR(kb, "name")
@@ -204,17 +206,18 @@ class DATA_PT_shape_keys(DataButtonsPanel):
                     row.itemR(kb, "value")
 
                     split = layout.split()
-                    sub = split.column(align=True)
-                    sub.active = enable_edit_value
-                    sub.itemL(text="Range:")
-                    sub.itemR(kb, "slider_min", text="Min")
-                    sub.itemR(kb, "slider_max", text="Max")
-
-                    sub = split.column(align=True)
-                    sub.active = enable_edit_value
-                    sub.itemL(text="Blend:")
-                    sub.item_pointerR(kb, "vertex_group", ob, "vertex_groups", text="")
-                    sub.item_pointerR(kb, "relative_key", key, "keys", text="")
+
+                    col = split.column(align=True)
+                    col.active = enable_edit_value
+                    col.itemL(text="Range:")
+                    col.itemR(kb, "slider_min", text="Min")
+                    col.itemR(kb, "slider_max", text="Max")
+
+                    col = split.column(align=True)
+                    col.active = enable_edit_value
+                    col.itemL(text="Blend:")
+                    col.item_pointerR(kb, "vertex_group", ob, "vertex_groups", text="")
+                    col.item_pointerR(kb, "relative_key", key, "keys", text="")
 
             else:
                 row = layout.row()
index fe1458a080a8b6d22970c72e3dc8f267c3d85dae..f6f1cf0e03c9123b6dafb5691630a7153bb36001 100644 (file)
@@ -78,18 +78,18 @@ class OBJECT_PT_transform_locks(ObjectButtonsPanel):
         row = layout.row()
 
         col = row.column()
-        col.itemR(ob, "lock_location")
+        col.itemR(ob, "lock_location", text="Location")
 
         col = row.column()
         if ob.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'):
-            col.itemR(ob, "lock_rotations_4d", text="Lock Rotation")
+            col.itemR(ob, "lock_rotations_4d", text="Rotation")
             if ob.lock_rotations_4d:
                 col.itemR(ob, "lock_rotation_w", text="W")
             col.itemR(ob, "lock_rotation", text="")
         else:
             col.itemR(ob, "lock_rotation", text="Rotation")
 
-        row.column().itemR(ob, "lock_scale")
+        row.column().itemR(ob, "lock_scale", text="Scale")
 
 
 class OBJECT_PT_relations(ObjectButtonsPanel):
index 3857a59edafe1aa07f9e3d6a2385a42368e1cb57..c662706743c65c926ed768d9e3a3ae77b2708be1 100644 (file)
@@ -133,7 +133,7 @@ class ConstraintButtonsPanel(bpy.types.Panel):
     def IK(self, context, layout, con):
         if context.object.pose.ik_solver == "ITASC":
             layout.itemR(con, "ik_type")
-            getattr(self, "IK_" + con.ik_type)(context, layout, con)
+            getattr(self, 'IK_' + con.ik_type)(context, layout, con)
         else:
             # Legacy IK constraint
             self.target_template(layout, con)
@@ -438,7 +438,7 @@ class ConstraintButtonsPanel(bpy.types.Panel):
 
         row = layout.row()
         row.itemL(text="Convert:")
-        row.itemR(con, "owner_space", text="")
+        row.itemR(con, "target_space", text="")
 
     def LOCKED_TRACK(self, context, layout, con):
         self.target_template(layout, con)
@@ -607,7 +607,7 @@ class ConstraintButtonsPanel(bpy.types.Panel):
         col = layout.column()
         col.itemL(text="Chain Scaling:")
         col.itemR(con, "keep_max_length")
-        col.itemR(con, "radius_to_thickness")
+        col.itemR(con, "xz_scaling_mode")
 
 
 class OBJECT_PT_constraints(ConstraintButtonsPanel):
@@ -702,7 +702,7 @@ class BONE_PT_inverse_kinematics(ConstraintButtonsPanel):
         split.itemR(pchan, "ik_stretch", text="Stretch", slider=True)
         split.itemL()
 
-        if ob.pose.ik_solver == "ITASC":
+        if ob.pose.ik_solver == 'ITASC':
             row = layout.row()
             row.itemR(pchan, "ik_rot_control", text="Control Rotation")
             row.itemR(pchan, "ik_rot_weight", text="Weight", slider=True)
@@ -723,7 +723,7 @@ class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
 
         if ob and bone:
             pchan = ob.pose.pose_channels[bone.name]
-            return pchan.has_ik and ob.pose.ik_solver == "ITASC" and ob.pose.ik_param
+            return pchan.has_ik and ob.pose.ik_solver == 'ITASC' and ob.pose.ik_param
 
         return False
 
@@ -734,7 +734,7 @@ class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
         itasc = ob.pose.ik_param
 
         layout.itemR(itasc, "mode", expand=True)
-        simulation = itasc.mode == "SIMULATION"
+        simulation = itasc.mode == 'SIMULATION'
         if simulation:
             layout.itemL(text="Reiteration:")
             layout.itemR(itasc, "reiteration", expand=True)
@@ -742,7 +742,7 @@ class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
         flow = layout.column_flow()
         flow.itemR(itasc, "precision", text="Prec")
         flow.itemR(itasc, "num_iter", text="Iter")
-        flow.active = not simulation or itasc.reiteration != "NEVER"
+        flow.active = not simulation or itasc.reiteration != 'NEVER'
 
         if simulation:
             layout.itemR(itasc, "auto_step")
@@ -757,7 +757,7 @@ class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
         if simulation:
             layout.itemR(itasc, "feedback")
             layout.itemR(itasc, "max_velocity")
-        if itasc.solver == "DLS":
+        if itasc.solver == 'DLS':
             row = layout.row()
             row.itemR(itasc, "dampmax", text="Damp", slider=True)
             row.itemR(itasc, "dampeps", text="Eps", slider=True)
index eddf8158c239da351737f4ebaef7e5de9dd88104..e9cc541c807730ca593968e8e26d94b215ce5378 100644 (file)
@@ -930,63 +930,64 @@ class PARTICLE_PT_vertexgroups(ParticleButtonsPanel):
     def draw(self, context):
         layout = self.layout
 
+        ob = context.object
         psys = context.particle_system
         part = psys.settings
 
-        layout.itemL(text="Nothing here yet.")
+        layout.itemL(text="Nothing here yet.")
 
-        #row = layout.row()
-        #row.itemL(text="Vertex Group")
-        #row.itemL(text="Negate")
+        row = layout.row()
+        row.itemL(text="Vertex Group")
+        row.itemL(text="Negate")
 
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_density")
-        #row.itemR(psys, "vertex_group_density_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_density", ob, "vertex_groups", text="Density")
+        row.itemR(psys, "vertex_group_density_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_velocity")
-        #row.itemR(psys, "vertex_group_velocity_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_velocity", ob, "vertex_groups", text="Velocity")
+        row.itemR(psys, "vertex_group_velocity_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_length")
-        #row.itemR(psys, "vertex_group_length_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_length", ob, "vertex_groups", text="Length")
+        row.itemR(psys, "vertex_group_length_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_clump")
-        #row.itemR(psys, "vertex_group_clump_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_clump", ob, "vertex_groups", text="Clump")
+        row.itemR(psys, "vertex_group_clump_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_kink")
-        #row.itemR(psys, "vertex_group_kink_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_kink", ob, "vertex_groups", text="Kink")
+        row.itemR(psys, "vertex_group_kink_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_roughness1")
-        #row.itemR(psys, "vertex_group_roughness1_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_roughness1", ob, "vertex_groups", text="Roughness 1")
+        row.itemR(psys, "vertex_group_roughness1_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_roughness2")
-        #row.itemR(psys, "vertex_group_roughness2_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_roughness2", ob, "vertex_groups", text="Roughness 2")
+        row.itemR(psys, "vertex_group_roughness2_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_roughness_end")
-        #row.itemR(psys, "vertex_group_roughness_end_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_roughness_end", ob, "vertex_groups", text="Roughness End")
+        row.itemR(psys, "vertex_group_roughness_end_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_size")
-        #row.itemR(psys, "vertex_group_size_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_size", ob, "vertex_groups", text="Size")
+        row.itemR(psys, "vertex_group_size_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_tangent")
-        #row.itemR(psys, "vertex_group_tangent_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_tangent", ob, "vertex_groups", text="Tangent")
+        row.itemR(psys, "vertex_group_tangent_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_rotation")
-        #row.itemR(psys, "vertex_group_rotation_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_rotation", ob, "vertex_groups", text="Rotation")
+        row.itemR(psys, "vertex_group_rotation_negate", text="")
 
-        #row = layout.row()
-        #row.itemR(psys, "vertex_group_field")
-        #row.itemR(psys, "vertex_group_field_negate", text="")
+        row = layout.row()
+        row.item_pointerR(psys, "vertex_group_field", ob, "vertex_groups", text="Field")
+        row.itemR(psys, "vertex_group_field_negate", text="")
 
 bpy.types.register(PARTICLE_PT_particles)
 bpy.types.register(PARTICLE_PT_hair_dynamics)
index b61f2172d94b1a6daa2fce5cc9c80692af228c3c..3e2630e38f53b4c02141689d744472023c1712fd 100644 (file)
@@ -77,7 +77,7 @@ class PHYSICS_PT_field(PhysicButtonsPanel):
             layout.itemS()
 
             layout.itemR(field, "guide_kink_type")
-            if (field.guide_kink_type != "NONE"):
+            if (field.guide_kink_type != 'NONE'):
                 layout.itemR(field, "guide_kink_axis")
 
                 flow = layout.column_flow()
index 27c8e357608c10bbbcf09f6081f49fd0714437a4..f43d903d0c778be6f8bbfd0eb98fca348841fded 100644 (file)
@@ -73,8 +73,9 @@ class PHYSICS_PT_softbody(PhysicButtonsPanel):
 
             col = split.column()
             col.itemL(text="Object:")
-            col.itemR(softbody, "mass")
             col.itemR(softbody, "friction")
+            col.itemR(softbody, "mass")
+            col.item_pointerR(softbody, "mass_vertex_group", ob, "vertex_groups", text="Mass:")
 
             col = split.column()
             col.itemL(text="Simulation:")
@@ -167,6 +168,7 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel):
         col.itemR(softbody, "plastic")
         col.itemR(softbody, "bending")
         col.itemR(softbody, "spring_length", text="Length")
+        col.item_pointerR(softbody, "spring_vertex_group", ob, "vertex_groups", text="Springs:")
 
         col = split.column()
         col.itemR(softbody, "stiff_quads")
index 92d7712d8e3abf98e7e20131a7e8a18a88ee4d14..ddc0b552634040615239f79ab77d752735495d0e 100644 (file)
@@ -227,7 +227,7 @@ class RENDER_PT_performance(RenderButtonsPanel):
         sub.active = rd.render_raytracing
         sub.itemL(text="Acceleration structure:")
         sub.itemR(rd, "raytrace_structure", text="")
-        if rd.raytrace_structure == "OCTREE":
+        if rd.raytrace_structure == 'OCTREE':
             sub.itemR(rd, "octree_resolution", text="Resolution")
         else:
             sub.itemR(rd, "use_instances", text="Instances")
index 7cd5a0a903bdb5975014c7c66cec3c7ef377a69d..d5392645387c8edd0d64a17b5e2e4e097056b3b3 100644 (file)
@@ -19,6 +19,7 @@
 # <pep8 compliant>
 import sys
 import bpy
+from bpy.props import *
 
 
 class CONSOLE_HT_header(bpy.types.Header):
@@ -68,6 +69,7 @@ class CONSOLE_MT_console(bpy.types.Menu):
         layout.itemO("console.clear")
         layout.itemO("console.copy")
         layout.itemO("console.paste")
+        layout.itemM("CONSOLE_MT_language")
 
 
 class CONSOLE_MT_report(bpy.types.Menu):
@@ -81,6 +83,24 @@ class CONSOLE_MT_report(bpy.types.Menu):
         layout.itemO("console.report_delete")
         layout.itemO("console.report_copy")
 
+class CONSOLE_MT_language(bpy.types.Menu):
+    bl_label = "Languages..."
+
+    def draw(self, context):
+        layout = self.layout
+        layout.column()
+
+        mod = bpy.ops.console
+        languages = []
+        for opname in dir(mod):
+            # execute_python, execute_shell etc.
+            if opname.startswith("execute_"):
+                languages.append(opname.split('_', 1)[-1])
+
+        languages.sort()
+
+        for language in languages:
+            layout.item_stringO("console.language", "language", language, text=language[0].upper() + language[1:])
 
 def add_scrollback(text, text_type):
     for l in text.split('\n'):
@@ -88,166 +108,85 @@ def add_scrollback(text, text_type):
             type=text_type)
 
 
-def get_console(console_id):
-    '''
-    helper function for console operators
-    currently each text datablock gets its own
-    console - bpython_code.InteractiveConsole()
-    ...which is stored in this function.
-
-    console_id can be any hashable type
-    '''
-    from code import InteractiveConsole
-
-    try:
-        consoles = get_console.consoles
-    except:
-        consoles = get_console.consoles = {}
-
-    # clear all dead consoles, use text names as IDs
-    # TODO, find a way to clear IDs
-    '''
-    for console_id in list(consoles.keys()):
-        if console_id not in bpy.data.texts:
-            del consoles[id]
-    '''
+class ConsoleExec(bpy.types.Operator):
+    '''Execute the current console line as a python expression.'''
+    bl_idname = "console.execute"
+    bl_label = "Console Execute"
+    bl_register = False
 
-    try:
-        console, stdout, stderr = consoles[console_id]
-    except:
-        namespace = {'__builtins__': __builtins__, 'bpy': bpy}
-        console = InteractiveConsole(namespace)
+    def execute(self, context):
+        sc = context.space_data
 
-        import io
-        stdout = io.StringIO()
-        stderr = io.StringIO()
+        execute = getattr(bpy.ops.console, "execute_" + sc.language, None)
 
-        consoles[console_id] = console, stdout, stderr
+        if execute:
+            execute()
+        else:
+            print("Error: bpy.ops.console.execute_" + sc.language + " - not found")
 
-    return console, stdout, stderr
+        return ('FINISHED',)
 
 
-class CONSOLE_OT_exec(bpy.types.Operator):
-    '''Execute the current console line as a python expression.'''
-    bl_idname = "console.execute"
-    bl_label = "Console Execute"
+class ConsoleAutocomplete(bpy.types.Operator):
+    '''Evaluate the namespace up until the cursor and give a list of
+    options or complete the name if there is only one.'''
+    bl_idname = "console.autocomplete"
+    bl_label = "Console Autocomplete"
     bl_register = False
 
-    # Both prompts must be the same length
-    PROMPT = '>>> '
-    PROMPT_MULTI = '... '
-
-    # is this working???
-    '''
     def poll(self, context):
-        return (context.space_data.type == 'PYTHON')
-    '''
-    # its not :|
+        return context.space_data.console_type != 'REPORT'
 
     def execute(self, context):
         sc = context.space_data
 
-        try:
-            line = sc.history[-1].line
-        except:
-            return ('CANCELLED',)
+        autocomplete = getattr(bpy.ops.console, "autocomplete_" + sc.language, None)
 
-        if sc.console_type != 'PYTHON':
-            return ('CANCELLED',)
-
-        console, stdout, stderr = get_console(hash(context.region))
-
-        # redirect output
-        sys.stdout = stdout
-        sys.stderr = stderr
-
-        # run the console
-        if not line.strip():
-            line_exec = '\n'  # executes a multiline statement
+        if autocomplete:
+            autocomplete()
         else:
-            line_exec = line
+            print("Error: bpy.ops.console.autocomplete_" + sc.language + " - not found")
 
-        is_multiline = console.push(line_exec)
+        return ('FINISHED',)
 
-        stdout.seek(0)
-        stderr.seek(0)
 
-        output = stdout.read()
-        output_err = stderr.read()
+class ConsoleBanner(bpy.types.Operator):
+    bl_idname = "console.banner"
 
-        # cleanup
-        sys.stdout = sys.__stdout__
-        sys.stderr = sys.__stderr__
-        sys.last_traceback = None
+    def execute(self, context):
+        sc = context.space_data
 
-        # So we can reuse, clear all data
-        stdout.truncate(0)
-        stderr.truncate(0)
+        # default to python
+        if not sc.language:
+            sc.language = 'python'
 
-        bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT')
+        banner = getattr(bpy.ops.console, "banner_" + sc.language, None)
 
-        if is_multiline:
-            sc.prompt = self.PROMPT_MULTI
+        if banner:
+            banner()
         else:
-            sc.prompt = self.PROMPT
-
-        # insert a new blank line
-        bpy.ops.console.history_append(text="", current_character=0,
-            remove_duplicates=True)
-
-        # Insert the output into the editor
-        # not quite correct because the order might have changed,
-        # but ok 99% of the time.
-        if output:
-            add_scrollback(output, 'OUTPUT')
-        if output_err:
-            add_scrollback(output_err, 'ERROR')
+            print("Error: bpy.ops.console.banner_" + sc.language + " - not found")
 
         return ('FINISHED',)
 
 
-class CONSOLE_OT_autocomplete(bpy.types.Operator):
-    '''Evaluate the namespace up until the cursor and give a list of
-    options or complete the name if there is only one.'''
-    bl_idname = "console.autocomplete"
-    bl_label = "Console Autocomplete"
-    bl_register = False
 
-    def poll(self, context):
-        return context.space_data.console_type == 'PYTHON'
+class ConsoleLanguage(bpy.types.Operator):
+    '''Set the current language for this console'''
+    bl_idname = "console.language"
+    language = StringProperty(name="Language", maxlen= 32, default= "")
 
     def execute(self, context):
-        from console import intellisense
-
         sc = context.space_data
 
-        console = get_console(hash(context.region))[0]
-
-        current_line = sc.history[-1]
-        line = current_line.line
-
-        if not console:
-            return ('CANCELLED',)
+        # defailt to python