Merge from trunk -r 24247:24313, -r 24313:24390.
authorArystanbek Dyussenov <arystan.d@gmail.com>
Sat, 7 Nov 2009 14:21:07 +0000 (14:21 +0000)
committerArystanbek Dyussenov <arystan.d@gmail.com>
Sat, 7 Nov 2009 14:21:07 +0000 (14:21 +0000)
211 files changed:
CMakeLists.txt
SConstruct
config/win64-vc-config.py
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_SystemCocoa.mm
intern/ghost/intern/GHOST_SystemWin32.cpp
intern/ghost/intern/GHOST_SystemWin32.h
intern/ghost/intern/GHOST_WindowCocoa.mm
intern/moto/include/MT_assert.h
projectfiles_vc9/blender/blender.vcproj
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_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_utils.py [moved from release/scripts/modules/bpy_sys.py with 92% similarity]
release/scripts/modules/console/intellisense.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 53% similarity]
release/scripts/op/wm.py [new file with mode: 0644]
release/scripts/templates/operator.py
release/scripts/ui/properties_data_armature.py
release/scripts/ui/properties_data_bone.py
release/scripts/ui/properties_data_camera.py
release/scripts/ui/properties_data_curve.py
release/scripts/ui/properties_data_empty.py
release/scripts/ui/properties_data_lamp.py
release/scripts/ui/properties_data_lattice.py
release/scripts/ui/properties_data_mesh.py
release/scripts/ui/properties_data_metaball.py
release/scripts/ui/properties_data_modifier.py
release/scripts/ui/properties_data_text.py
release/scripts/ui/properties_game.py
release/scripts/ui/properties_material.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_cloth.py
release/scripts/ui/properties_physics_common.py
release/scripts/ui/properties_physics_field.py
release/scripts/ui/properties_physics_fluid.py
release/scripts/ui/properties_physics_smoke.py
release/scripts/ui/properties_physics_softbody.py
release/scripts/ui/properties_render.py
release/scripts/ui/properties_scene.py
release/scripts/ui/properties_texture.py
release/scripts/ui/properties_world.py
release/scripts/ui/space_buttons.py
release/scripts/ui/space_console.py
release/scripts/ui/space_filebrowser.py
release/scripts/ui/space_image.py
release/scripts/ui/space_info.py
release/scripts/ui/space_logic.py
release/scripts/ui/space_node.py
release/scripts/ui/space_outliner.py
release/scripts/ui/space_sequencer.py
release/scripts/ui/space_text.py
release/scripts/ui/space_time.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/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/particle.c
source/blender/blenkernel/intern/sequence.c
source/blender/blenkernel/intern/softbody.c
source/blender/blenkernel/intern/texture.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/animation/anim_channels_edit.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_ops.c
source/blender/editors/armature/meshlaplacian.c
source/blender/editors/armature/meshlaplacian.h
source/blender/editors/armature/poseobject.c
source/blender/editors/datafiles/B.blend.c
source/blender/editors/include/ED_armature.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/include/UI_icons.h
source/blender/editors/interface/interface_handlers.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/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_object.c
source/blender/editors/screen/area.c
source/blender/editors/screen/screen_context.c
source/blender/editors/screen/screen_edit.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/space_action/action_select.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_select.c
source/blender/editors/space_nla/nla_select.c
source/blender/editors/space_node/drawnode.c
source/blender/editors/space_node/node_select.c
source/blender/editors/space_sequencer/sequencer_select.c
source/blender/editors/space_view3d/view3d_buttons.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/space_view3d/view3d_snap.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_constraints.c
source/blender/editors/transform/transform_conversions.c
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/makesdna/DNA_constraint_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_particle_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_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_mesh.c
source/blender/makesrna/intern/rna_meta.c
source/blender/makesrna/intern/rna_modifier.c
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/makesrna/intern/rna_userdef.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_util.c
source/blender/render/intern/source/pointdensity.c
source/blender/render/intern/source/shadeoutput.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/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.cpp
source/gameengine/GamePlayer/common/windows/GPW_KeyboardDevice.h

index b020284f5483c39b23380b64546fd4c2d9ac5689..9360d930a5ab4237ebe5fab970d5000c2c65bfdc 100644 (file)
@@ -518,9 +518,9 @@ IF(APPLE)
        ENDIF (WITH_COCOA)
 
        IF(WITH_OPENMP)
-               SET(LLIBS "${LLIBS} -lgomp ")
-               SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp ")
-               SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp ")
+               SET(LLIBS "${LLIBS} -lgomp")
+               SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp")
+               SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
        ENDIF(WITH_OPENMP)
 
        IF (WITH_OPENCOLLADA)
@@ -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 cb90c2eaf663094681d006430103327c4335b6e7..e6dd85e8cff6c1702df38b0ee25b3915a18bbe09 100644 (file)
@@ -124,7 +124,10 @@ if toolset:
                #if env:
                #       btools.SetupSpawn(env)
 else:
-       env = BlenderEnvironment(ENV = os.environ)
+       if bitness==64 and platform=='win32':
+               env = BlenderEnvironment(ENV = os.environ, MSVS_ARCH='amd64')
+       else:
+               env = BlenderEnvironment(ENV = os.environ)
 
 if not env:
        print "Could not create a build environment"
index 64f023ef7be9ce012d3b1bf877a0d756e308fdfd..caad70cbe841b6042826228f1f8d879e4eef4dfb 100644 (file)
@@ -158,7 +158,7 @@ BF_COLLADA_LIB = 'bf_collada'
 
 BF_OPENCOLLADA = LIBDIR + '/opencollada'
 BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include'
-BF_OPENCOLLADA_LIB = 'opencollada'
+BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver xml2 pcre'
 BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib'
 
 WITH_BF_STATICOPENGL = False
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 5dbf79a0293797d1b26b64404ddf19cce003343a..73be363dff189756411e54f2dfcf81cbb2cb504e 100644 (file)
@@ -786,7 +786,7 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
                                case NSFlagsChanged:
                                        handleKeyEvent(event);
                                        
-                                       /* Support system-wide keyboard shortcuts, like Exposé, ...) =>included in always NSApp sendEvent */
+                                       /* Support system-wide keyboard shortcuts, like Exposâ\88\9a©, ...) =>included in always NSApp sendEvent */
                                        /*              if (([event modifierFlags] & NSCommandKeyMask) || [event type] == NSFlagsChanged) {
                                         [NSApp sendEvent:event];
                                         }*/
@@ -891,8 +891,8 @@ GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest()
        //Check open windows if some changes are not saved
        if (m_windowManager->getAnyModifiedState())
        {
-               int shouldQuit = NSRunAlertPanel(@"Exit Blender", @"Some changes have not been saved. Do you really want to quit ?",
-                                                                                @"Cancel", @"Quit anyway", nil);
+               int shouldQuit = NSRunAlertPanel(@"Exit Blender", @"Some changes have not been saved.\nDo you really want to quit ?",
+                                                                                @"Cancel", @"Quit Anyway", nil);
                if (shouldQuit == NSAlertAlternateReturn)
                {
                        pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL) );
index 2e89be40bcbc58f6cf340ebc7863af1a8c8b805e..8a17d4556958a576ee6226fddfaaa2f23677e840 100644 (file)
 
 GHOST_SystemWin32::GHOST_SystemWin32()
 : m_hasPerformanceCounter(false), m_freq(0), m_start(0),
-  m_seperateLeftRight(false),
-  m_seperateLeftRightInitialized(false)
+  m_separateLeftRight(false),
+  m_separateLeftRightInitialized(false)
 {
        m_displayManager = new GHOST_DisplayManagerWin32 ();
        GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
@@ -274,7 +274,7 @@ GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) cons
        It didn't work all that well on some newer hardware, and worked less 
        well with the passage of time, so it was fully disabled in ME.
        */
-       if (m_seperateLeftRight && m_seperateLeftRightInitialized) {
+       if (m_separateLeftRight && m_separateLeftRightInitialized) {
                bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
                keys.set(GHOST_kModifierKeyLeftShift, down);
                down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
@@ -581,29 +581,29 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                                case VK_SHIFT:
                                                case VK_CONTROL:
                                                case VK_MENU:
-                                                       if (!system->m_seperateLeftRightInitialized) {
+                                                       if (!system->m_separateLeftRightInitialized) {
                                                                // Check whether this system supports seperate left and right keys
                                                                switch (wParam) {
                                                                        case VK_SHIFT:
-                                                                               system->m_seperateLeftRight = 
+                                                                               system->m_separateLeftRight = 
                                                                                        (HIBYTE(::GetKeyState(VK_LSHIFT)) != 0) ||
                                                                                        (HIBYTE(::GetKeyState(VK_RSHIFT)) != 0) ?
                                                                                        true : false;
                                                                                break;
                                                                        case VK_CONTROL:
-                                                                               system->m_seperateLeftRight = 
+                                                                               system->m_separateLeftRight = 
                                                                                        (HIBYTE(::GetKeyState(VK_LCONTROL)) != 0) ||
                                                                                        (HIBYTE(::GetKeyState(VK_RCONTROL)) != 0) ?
                                                                                        true : false;
                                                                                break;
                                                                        case VK_MENU:
-                                                                               system->m_seperateLeftRight = 
+                                                                               system->m_separateLeftRight = 
                                                                                        (HIBYTE(::GetKeyState(VK_LMENU)) != 0) ||
                                                                                        (HIBYTE(::GetKeyState(VK_RMENU)) != 0) ?
                                                                                        true : false;
                                                                                break;
                                                                }
-                                                               system->m_seperateLeftRightInitialized = true;
+                                                               system->m_separateLeftRightInitialized = true;
                                                        }
                                                        system->processModifierKeys(window);
                                                        // Bypass call to DefWindowProc
index 9387b6cad50db6c596ada44849cf209a34629e36..6a12975a3dd4ce8c8589e4b8046fbc29049b20bc 100644 (file)
@@ -283,9 +283,9 @@ protected:
        /** High frequency timer variable. */
        __int64 m_start;
        /** Stores the capability of this system to distinguish left and right modifier keys. */
-       bool m_seperateLeftRight;
+       bool m_separateLeftRight;
        /** Stores the initialization state of the member m_leftRightDistinguishable. */
-       bool m_seperateLeftRightInitialized;
+       bool m_separateLeftRightInitialized;
        
 };
 
index 7716175b9f631a3c3b04563c3e27ff323a187a20..f0bc8dd4d0f8de6b41ba2808520313eff7ff92b2 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
index 22f6b6a555c3e44596e6625ae18c07b81d348f0e..b8f18fc52ff290b6efc5b7d3a80e0b0261856805 100644 (file)
@@ -76,7 +76,7 @@ abort();
 #endif /* breakpoint */
 
 
-#if defined(WIN32) && !defined(__GNUC__)
+#if defined(_WIN32) && !defined(__GNUC__)
 #define MT_assert(predicate) assert(predicate)
 #else
 
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 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)
diff --git a/release/scripts/io/import_bvh.py b/release/scripts/io/import_bvh.py
new file mode 100644 (file)
index 0000000..5265007
--- /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.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("import.bvh", 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..52643af7d73b96d7702c91e45fb7b1e7b1a7a9cf 100644 (file)
@@ -46,7 +46,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 +111,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 +129,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 +253,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..961ff83
--- /dev/null
@@ -0,0 +1,72 @@
+# ##### 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 #####
+
+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(face):
+    verts = tuple(face.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_edge_keys(mesh):
+    return [edge_key for face in mesh.faces for edge_key in face.edge_keys()]
+
+def mesh_edge_face_count_dict(mesh, face_edge_keys=None):
+    
+    # Optional speedup
+    if face_edge_keys==None:
+        face_edge_keys = [face.edge_keys() for face in face_list]
+        
+    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
+
+def mesh_edge_face_count(mesh, face_edge_keys=None):
+    edge_face_count_dict = mesh.edge_face_count_dict(face_edge_keys)
+    return [edge_face_count_dict.get(ed.key(), 0) for ed in mesh.edges]
+
+import bpy
+
+# * Edge *
+class_obj = bpy.types.MeshEdge
+class_obj.key = edge_key
+
+# * Face *
+class_obj = bpy.types.MeshFace
+class_obj.edge_keys = face_edge_keys
+
+# * Mesh *
+class_obj = bpy.types.Mesh
+class_obj.edge_keys = mesh_edge_keys
+class_obj.edge_face_count = mesh_edge_face_count
+class_obj.edge_face_count_dict = mesh_edge_face_count_dict
index 203e50bdef74434a1f2ea05f329f761e67a00da3..59c2ca3ebda1ff01f7e727b21331a9b2f5931798 100644 (file)
@@ -19,4 +19,4 @@
 import bpy
 class_obj = bpy.types.Object
 
-class_obj.getChildren = lambda ob: [child for child in bpy.data.objects if child.parent == ob]
+class_obj.getChildren = lambda self: [child for child in bpy.data.objects if child.parent == self]
index 4198205e54272f7c41c1b6f03f9f5a80f43f3877..435c545dc757d6d005ad1da1546c3c2979f5e95e 100644 (file)
@@ -17,3 +17,4 @@
 # ##### END GPL LICENSE BLOCK #####
 
 import bpy_ext.Object
+import bpy_ext.Mesh
index c30869669cc20b1ebb22e4f9c5ccbbda51ba2c25..8078816f982fed373ebac7a03a50ff6bac23aafb 100644 (file)
@@ -127,6 +127,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
@@ -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)
similarity index 92%
rename from release/scripts/modules/bpy_sys.py
rename to release/scripts/modules/bpy_utils.py
index 86f9c9d63a204a8230ddb3e7c221d214a2384491..dde01152daed20e890aba9f164b73f243130239d 100644 (file)
@@ -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
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
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..4bf20e4
--- /dev/null
@@ -0,0 +1,102 @@
+# ##### 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 = '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 os
+    add_scrollback(os.popen(text).read(), 'OUTPUT')
+
+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)
+
+        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 = 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..8ea9ea0
--- /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(face_edge_keys)
+    
+    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..85df6463eb0a78823480ea253ec86802a4857238 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..454cb2f
--- /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 53%
rename from release/scripts/io/vertexpaint_dirt.py
rename to release/scripts/op/vertexpaint_dirt.py
index 9f55d3bb04231f8c7141a49074123e454675c1c2..7d32c153d0461c55e2d83408ee856d2fe95734d5 100644 (file)
@@ -1,7 +1,3 @@
-# bl_author = ["Campbell Barton aka ideasman42", "Keith Boshoff aka Wahooney"]
-# bl_url = ["www.blender.org", "blenderartists.org", "www.python.org"]
-# bl_version = "0.2"
-
 # ***** BEGIN GPL LICENSE BLOCK *****
 #
 # Script copyright (C) Campbell J Barton
@@ -25,6 +21,8 @@
 
 # History
 #
+# Originally written by Campbell Barton aka ideasman42
+#
 # 2009-11-01: * 2.5 port by Keith "Wahooney" Boshoff
 #              * Replaced old method with my own, speed is similar (about 0.001 sec on Suzanne)
 #               but results are far more accurate
@@ -38,19 +36,20 @@ import time
 from Mathutils import Vector
 from bpy.props import *
 
-def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean, dirt_only, sel_only):
+def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean, dirt_only):
 ##    Window.WaitCursor(1)
 
     #BPyMesh.meshCalcNormals(me)
 
-    vert_tone= [0.0] * len(me.verts)
-    vert_tone_count= [0] * len(me.verts)
+    vert_tone = [0.0] * len(me.verts)
+
+    min_tone =180.0
+    max_tone =0.0
 
     # create lookup table for each vertex's connected vertices (via edges)
-    con = [[] for i in range(len(me.verts))]
+    con = []
 
-    min_tone=180.0
-    max_tone=0.0
+    con = [[] for i in range(len(me.verts))]
 
     # add connected verts
     for e in me.edges:
@@ -73,64 +72,56 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
         ang = math.acos(no.dot(vec))
 
         # enforce min/max
+        ang = max(clamp_dirt, ang)
 
-        vert_tone[v.index] = max(clamp_clean, min(clamp_dirt, ang))
-
-    # average vert_tone_list into vert_tonef
-#    for i, tones in enumerate(vert_tone):
-#        if vert_tone_count[i]:
-#            vert_tone[i] = vert_tone[i] / vert_tone_count[i]
-
-    # Below we use edges to blur along so the edges need counting, not the faces
-    vert_tone_count=    [0] *    len(me.verts)
-    for ed in me.edges:
-        vert_tone_count[ed.verts[0]] += 1
-        vert_tone_count[ed.verts[1]] += 1
-
+        if not dirt_only:
+            ang = min(clamp_clean, ang)
 
-    # Blur tone
-    blur        = blur_strength
-    blur_inv    = 1.0 - blur_strength
+        vert_tone[v.index] = ang
 
+    # blur tones
     for i in range(blur_iterations):
-
         # backup the original tones
-        orig_vert_tone= list(vert_tone)
-
-        for ed in me.edges:
+        orig_vert_tone = list(vert_tone)
 
-            i1 = ed.verts[0]
-            i2 = ed.verts[1]
+        # use connected verts look up for blurring
+        for j, c in enumerate(con):
+            for v in c:
+                vert_tone[j] += blur_strength * orig_vert_tone[v]
 
-            val1 = (orig_vert_tone[i2]*blur) +  (orig_vert_tone[i1]*blur_inv)
-            val2 = (orig_vert_tone[i1]*blur) +  (orig_vert_tone[i2]*blur_inv)
+            vert_tone[j] /= len(c) * blur_strength + 1
 
-            # Apply the ton divided by the number of faces connected
-            vert_tone[i1] += val1 / max(vert_tone_count[i1], 1)
-            vert_tone[i2] += val2 / max(vert_tone_count[i2], 1)
+    min_tone = min(vert_tone)
+    max_tone = max(vert_tone)
 
+    # debug information
+    # print(min_tone * 2 * math.pi)
+    # print(max_tone * 2 * math.pi)
+    # print(clamp_clean)
+    # print(clamp_dirt)
 
-    min_tone= min(vert_tone)
-    max_tone= max(vert_tone)
+    tone_range = max_tone-min_tone
 
-    print(min_tone)
-    print(max_tone)
-    print(clamp_clean)
-    print(clamp_dirt)
-
-    tone_range= max_tone-min_tone
-    if max_tone==min_tone:
+    if not tone_range:
         return
 
-    for lay in me.vertex_colors:
-        if lay.active:
-            active_col_layer = lay.data
+    active_col_layer = None
+
+    if len(me.vertex_colors):
+        for lay in me.vertex_colors:
+            if lay.active:
+                active_col_layer = lay.data
+    else:
+        bpy.ops.mesh.vertex_color_add()
+        me.vertex_colors[0].active = True
+        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 sel_only or f.sel:
+        if not me.use_paint_mask or f.selected:
+
             f_col = active_col_layer[i]
 
             f_col = [f_col.color1, f_col.color2, f_col.color3, f_col.color4]
@@ -140,49 +131,47 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
                 tone = vert_tone[me.verts[v].index]
                 tone = (tone-min_tone)/tone_range
 
+                if dirt_only:
+                    tone = min(tone, 0.5)
+                    tone *= 2
+
                 col[0] = tone*col[0]
                 col[1] = tone*col[1]
                 col[2] = tone*col[2]
 
 ##    Window.WaitCursor(0)
 
-
 class VertexPaintDirt(bpy.types.Operator):
-    '''This script uses the concavity of vertices to shade the mesh, and optionaly blur the shading to remove artifacts from spesific edges.'''
 
     bl_idname = "mesh.vertex_paint_dirt"
     bl_label = "Dirty Vertex Colors"
     bl_register = True
     bl_undo = True
 
-    blur_strength = FloatProperty(name="Blur Strength", description="Blur strength per iteration", default=1.0, min=0.01, max=1.0)
-    blur_iterations = IntProperty(name="Blur Iterations", description="Number times to blur the colors. (higher blurs more)", default=1, min=0, max=40)
-    clean_angle = FloatProperty(name="Highlight Angle", description="Less then 90 limits the angle used in the tonal range", default=0.0, min=0.0, max=180.0)
-    dirt_angle = FloatProperty(name="Dirt Angle", description="Less then 90 limits the angle used in the tonal range", default=180.0, min=0.0, max=180.0)
-    dirt_only = BoolProperty(name="Dirt Only", description="Dont calculate cleans for convex areas", default=False)
-    sel_faces_only = BoolProperty(name="Selected Faces Only", description="Only apply to UV/Face selected faces (mix vpain/uvface select)", default=False)
+    blur_strength = FloatProperty(name = "Blur Strength", description = "Blur strength per iteration", default = 1.0, min = 0.01, max = 1.0)
+    blur_iterations = IntProperty(name = "Blur Iterations", description = "Number times to blur the colors. (higher blurs more)", default = 1, min = 0, max = 40)
+    clean_angle = FloatProperty(name = "Highlight Angle", description = "Less then 90 limits the angle used in the tonal range", default = 180.0, min = 0.0, max = 180.0)
+    dirt_angle = FloatProperty(name = "Dirt Angle", description = "Less then 90 limits the angle used in the tonal range", default = 0.0, min = 0.0, max = 180.0)
+    dirt_only = BoolProperty(name= "Dirt Only", description = "Dont calculate cleans for convex areas", default = False)
 
     def execute(self, context):
-        sce= context.scene
-        ob= context.object
+        sce = context.scene
+        ob = context.object
 
         if not ob or ob.type != 'MESH':
             print('Error, no active mesh object, aborting.')
-            print(ob)
-            print(ob.type)
             return('CANCELLED',)
 
         me = ob.data
 
         t = time.time()
 
-        applyVertexDirt(me, self.blur_iterations, self.blur_strength, math.radians(self.dirt_angle), math.radians(self.clean_angle), self.dirt_only, self.sel_faces_only)
+        applyVertexDirt(me, self.blur_iterations, self.blur_strength, math.radians(self.dirt_angle), math.radians(self.clean_angle), self.dirt_only)
 
-        print('done in %.6f' % (time.time()-t))
+        print('Dirt calculated in %.6f' % (time.time()-t))
 
         return('FINISHED',)
 
-
 bpy.ops.add(VertexPaintDirt)
 
 if __name__ == "__main__":
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.''&#