Merge from trunk -r 24758:25003.
authorArystanbek Dyussenov <arystan.d@gmail.com>
Sun, 29 Nov 2009 18:54:37 +0000 (18:54 +0000)
committerArystanbek Dyussenov <arystan.d@gmail.com>
Sun, 29 Nov 2009 18:54:37 +0000 (18:54 +0000)
1  2 
CMakeLists.txt
source/blender/collada/DocumentImporter.cpp
source/blender/windowmanager/intern/wm_operators.c

diff --combined CMakeLists.txt
index 14510cbeecdd6c8a4ad37aeba5b1c786407e318c,100d6065c770056f83c6c2573efe9dd6915a896e..184b106a84d22bbac64af836a225bfa0f21cbb38
@@@ -1,4 -1,4 +1,4 @@@
- # $Id$
 # $Id$
  # ***** BEGIN GPL LICENSE BLOCK *****
  #
  # This program is free software; you can redistribute it and/or
@@@ -79,7 -79,7 +79,7 @@@ OPTION(WITH_LZMA          "Enable best 
  OPTION(WITH_CXX_GUARDEDALLOC "Enable GuardedAlloc for C++ memory allocation" OFF)
  OPTION(WITH_BUILDINFO     "Include extra build details" ON)
  OPTION(WITH_INSTALL       "Install accompanying scripts and language files needed to run blender" ON)
 -OPTION(WITH_OPENCOLLADA               "Enable OpenCollada Support (http://www.opencollada.org/)"      OFF)
 +OPTION(WITH_OPENCOLLADA               "Enable OpenCollada Support (http://www.opencollada.org/)"      ON)
  
  # Unix defaults to OpenMP On
  IF (UNIX)
@@@ -216,8 -216,8 +216,8 @@@ IF(UNIX AND NOT APPLE
  
        IF (WITH_OPENCOLLADA)
                SET(OPENCOLLADA /usr/local/opencollada CACHE FILEPATH "OpenCollada Directory")
 -              SET(OPENCOLLADA_LIBPATH ${OPENCOLLADA})
 -              SET(OPENCOLLADA_LIB OpenCollada)
 +              SET(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib)
 +              SET(OPENCOLLADA_LIB OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver pcre ftoa Buffer)
                SET(OPENCOLLADA_INC ${OPENCOLLADA})
                SET(PCRE /usr CACHE FILEPATH "PCRE Directory")
                SET(PCRE_LIBPATH ${PCRE}/lib)
@@@ -531,19 -531,21 +531,21 @@@ IF(APPLE
        SET(LLIBS stdc++ SystemStubs)
  
        IF (WITH_COCOA)
-       SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -DGHOST_COCOA")
-       SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio")
-       IF(USE_QTKIT)
-       SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -DUSE_QTKIT")
-       SET(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QTKit")
-       ELSE(USE_QTKIT)
-       IF(WITH_QUICKTIME)
-       SET(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QuickTime")
-       ENDIF(WITH_QUICKTIME)
-       ENDIF(USE_QTKIT)
+               SET(PLATFORM_CFLAGS "-pipe -funsigned-char -DGHOST_COCOA")
+               SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio")
+               IF(USE_QTKIT)
+                       SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -DUSE_QTKIT")
+                       SET(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QTKit")
+                       IF(CMAKE_OSX_ARCHITECTURES MATCHES i386)
+                               SET(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QuickTime")
+                               #libSDL still needs 32bit carbon quicktime 
+                       ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES i386)
+               ELSEIF(WITH_QUICKTIME)
+                       SET(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QuickTime")
+               ENDIF(USE_QTKIT)
        ELSE (WITH_COCOA)
-       SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
-       SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Carbon -framework AGL -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime")
+               SET(PLATFORM_CFLAGS "-pipe -funsigned-char")
+               SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Carbon -framework AGL -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime")
        ENDIF (WITH_COCOA)
  
        IF(WITH_OPENMP)
  
        SET(EXETYPE MACOSX_BUNDLE)
  
+       SET(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
+       SET(CMAKE_CXX_FLAGS_DEBUG "-fno-strict-aliasing -g")
        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")
+               SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -mdynamic-no-pic -ftree-vectorize -msse -msse2 -fvariable-expansion-in-unroller")
+               SET(CMAKE_C_FLAGS_RELEASE "-O3 -mdynamic-no-pic -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")
+               SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -mdynamic-no-pic -ftree-vectorize -msse -msse2 -msse3 -mssse3 -fvariable-expansion-in-unroller")
+               SET(CMAKE_C_FLAGS_RELEASE "-O3 -mdynamic-no-pic -ftree-vectorize -msse -msse2 -msse3 -mssse3 -fvariable-expansion-in-unroller")
+       ELSE(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
+               SET(CMAKE_C_FLAGS_RELEASE "-mdynamic-no-pic -fno-strict-aliasing")
+               SET(CMAKE_CXX_FLAGS_RELEASE "-mdynamic-no-pic -fno-strict-aliasing")
        ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES "i386")
  
+       # Better warnings
+       SET(C_WARNINGS "-Wall -Wno-char-subscripts -Wpointer-arith -Wcast-align -Wdeclaration-after-statement")
+       SET(CXX_WARNINGS "-Wall -Wno-invalid-offsetof -Wno-sign-compare")
  ENDIF(APPLE)
  
  IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
index 381632523fa3d0e3b955d5d4022b0d3a4fc09c46,f50df355a8269e651c7fd98b77f4766071033030..9ebcc8b191f76f960cd5dac9067cb748cc1ce99f
@@@ -1,7 -1,3 +1,7 @@@
 +// TODO:
 +// * name imported objects
 +// * import object rotation as euler
 +
  #include "COLLADAFWRoot.h"
  #include "COLLADAFWIWriter.h"
  #include "COLLADAFWStableHeaders.h"
@@@ -55,7 -51,6 +55,7 @@@ extern "C
  #include "BLI_util.h"
  #include "BKE_displist.h"
  #include "BLI_math.h"
 +#include "BKE_scene.h"
  }
  #include "BKE_armature.h"
  #include "BKE_mesh.h"
  #include <float.h>
  
  // #define COLLADA_DEBUG
 +#define ARMATURE_TEST
  
  char *CustomData_get_layer_name(const struct CustomData *data, int type, int n);
  
- // armature module internal func, it's not good to use it here? (Arystan)
- struct EditBone *addEditBone(struct bArmature *arm, char *name);
  const char *primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type)
  {
        using namespace COLLADAFW;
@@@ -138,10 -129,8 +135,10 @@@ const char *geomTypeToStr(COLLADAFW::Ge
                return "SPLINE";
        case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH:
                return "CONVEX_MESH";
 +      case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN:
 +      default:
 +              return "UNKNOWN";
        }
 -      return "UNKNOWN";
  }
  
  // works for COLLADAFW::Node, COLLADAFW::Geometry
@@@ -204,16 -193,41 +201,16 @@@ public
  
                        switch(type) {
                        case COLLADAFW::Transformation::TRANSLATE:
 -                              {
 -                                      COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm;
 -                                      COLLADABU::Math::Vector3& t = tra->getTranslation();
 -
 -                                      unit_m4(cur);
 -                                      cur[3][0] = (float)t[0];
 -                                      cur[3][1] = (float)t[1];
 -                                      cur[3][2] = (float)t[2];
 -                              }
 +                              dae_translate_to_mat4(tm, cur);
                                break;
                        case COLLADAFW::Transformation::ROTATE:
 -                              {
 -                                      COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm;
 -                                      COLLADABU::Math::Vector3& raxis = ro->getRotationAxis();
 -                                      float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f);
 -                                      float axis[] = {raxis[0], raxis[1], raxis[2]};
 -                                      float quat[4];
 -                                      float rot_copy[3][3];
 -                                      float mat[3][3];
 -                                      axis_angle_to_quat(quat, axis, angle);
 -                                      
 -                                      quat_to_mat4( cur,quat);
 -                              }
 +                              dae_rotate_to_mat4(tm, cur);
                                break;
                        case COLLADAFW::Transformation::SCALE:
 -                              {
 -                                      COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale();
 -                                      float size[3] = {(float)s[0], (float)s[1], (float)s[2]};
 -                                      size_to_mat4( cur,size);
 -                              }
 +                              dae_scale_to_mat4(tm, cur);
                                break;
                        case COLLADAFW::Transformation::MATRIX:
 -                              {
 -                                      unit_converter->mat4_from_dae(cur, ((COLLADAFW::Matrix*)tm)->getMatrix());
 -                              }
 +                              dae_matrix_to_mat4(tm, cur);
                                break;
                        case COLLADAFW::Transformation::LOOKAT:
                        case COLLADAFW::Transformation::SKEW:
                        }
                }
        }
 +
 +      void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
 +      {
 +              COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm;
 +              COLLADABU::Math::Vector3& axis = ro->getRotationAxis();
 +              float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f);
 +              float ax[] = {axis[0], axis[1], axis[2]};
 +              // float quat[4];
 +              // axis_angle_to_quat(quat, axis, angle);
 +              // quat_to_mat4(m, quat);
 +              axis_angle_to_mat4(m, ax, angle);
 +      }
 +
 +      void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
 +      {
 +              COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm;
 +              COLLADABU::Math::Vector3& t = tra->getTranslation();
 +
 +              unit_m4(m);
 +
 +              m[3][0] = (float)t[0];
 +              m[3][1] = (float)t[1];
 +              m[3][2] = (float)t[2];
 +      }
 +
 +      void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
 +      {
 +              COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale();
 +              float size[3] = {(float)s[0], (float)s[1], (float)s[2]};
 +              size_to_mat4(m, size);
 +      }
 +
 +      void dae_matrix_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
 +      {
 +              unit_converter->dae_matrix_to_mat4(m, ((COLLADAFW::Matrix*)tm)->getMatrix());
 +      }
  };
  
  // only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid
@@@ -283,7 -261,7 +280,7 @@@ public
  class AnimationImporterBase
  {
  public:
 -      virtual void change_eul_to_quat(Object *ob, bAction *act) = 0;
 +      // virtual void change_eul_to_quat(Object *ob, bAction *act) = 0;
  };
  
  class ArmatureImporter : private TransformReader
@@@ -409,7 -387,7 +406,7 @@@ private
                        for (int i = 0; i < weight.getValuesCount(); i++)
                                weights.push_back(get_float_value(weight, i));
  
 -                      unit_converter->mat4_from_dae(bind_shape_matrix, skin->getBindShapeMatrix());
 +                      unit_converter->dae_matrix_to_mat4(bind_shape_matrix, skin->getBindShapeMatrix());
                }
                        
                void free()
                void add_joint(const COLLADABU::Math::Matrix4& matrix)
                {
                        JointData jd;
 -                      unit_converter->mat4_from_dae(jd.inv_bind_mat, matrix);
 +                      unit_converter->dae_matrix_to_mat4(jd.inv_bind_mat, matrix);
                        joint_data.push_back(jd);
                }
  
                void link_armature(bContext *C, Object *ob, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid,
                                                   TransformReader *tm)
                {
 -                      tm->decompose(bind_shape_matrix, ob->loc, ob->rot, ob->size);
 +                      tm->decompose(bind_shape_matrix, ob->loc, ob->rot, NULL, ob->size);
  
                        ob->parent = ob_arm;
                        ob->partype = PARSKEL;
                        }
  
                        DAG_scene_sort(CTX_data_scene(C));
-                       ED_anim_dag_flush_update(C);
+                       DAG_ids_flush_update(0);
                        WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
                }
  
                }
  
                // TODO rename from Node "name" attrs later
-               EditBone *bone = addEditBone(arm, (char*)get_joint_name(node));
+               EditBone *bone = ED_armature_edit_bone_add(arm, (char*)get_joint_name(node));
                totbone++;
  
                if (parent) bone->parent = parent;
                }
        }
  
 +#if 0
        void set_euler_rotmode()
        {
                // just set rotmode = ROT_MODE_EUL on pose channel for each joint
                        }
                }
        }
 +#endif
  
        Object *get_empty_for_leaves()
        {
  
                set_leaf_bone_shapes(ob_arm);
  
 -              set_euler_rotmode();
 +              // set_euler_rotmode();
        }
        
  
@@@ -1013,7 -989,6 +1010,7 @@@ public
                BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", get_joint_name(node));
        }
        
 +#if 0
        void fix_animation()
        {
                /* Change Euler rotation to Quaternion for bone animation */
                        anim_importer->change_eul_to_quat(ob, ob->adt->action);
                }
        }
 +#endif
 +
 +      // gives a world-space mat
 +      bool get_joint_bind_mat(float m[][4], COLLADAFW::Node *joint)
 +      {
 +              std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
 +              bool found = false;
 +              for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
 +                      SkinInfo& skin = it->second;
 +                      if ((found = skin.get_joint_inv_bind_matrix(m, joint))) {
 +                              invert_m4(m);
 +                              break;
 +                      }
 +              }
 +
 +              return found;
 +      }
  };
  
  class MeshImporter : public MeshImporterBase
@@@ -1119,9 -1077,6 +1116,9 @@@ private
                                        
                                }
                                break;
 +                      case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:      
 +                      default:
 +                              fprintf(stderr, "MeshImporter.getUV(): unknown data type\n");
                        }
                }
        };
        int count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me)
        {
                COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
 -              int i, j, k;
 +              int i, j;
                int tottri = 0;
                
                for (i = 0; i < prim_arr.getCount(); i++) {
@@@ -1772,14 -1727,11 +1769,14 @@@ private
        ArmatureImporter *armature_importer;
        Scene *scene;
  
 -      std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > uid_fcurve_map;
 +      std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > curve_map;
        std::map<COLLADAFW::UniqueId, TransformReader::Animation> uid_animated_map;
 -      std::map<bActionGroup*, std::vector<FCurve*> > fcurves_actionGroup_map;
 +      // std::map<bActionGroup*, std::vector<FCurve*> > fcurves_actionGroup_map;
 +      std::map<COLLADAFW::UniqueId, const COLLADAFW::AnimationList*> animlist_map;
 +      std::vector<FCurve*> unused_curves;
 +      std::map<COLLADAFW::UniqueId, Object*> joint_objects;
        
 -      FCurve *create_fcurve(int array_index, char *rna_path)
 +      FCurve *create_fcurve(int array_index, const char *rna_path)
        {
                FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
                
                calchandles_fcurve(fcu);
        }
  
 +      // create one or several fcurves depending on the number of parameters being animated
 +      void animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
 +      {
 +              COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues();
 +              COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues();
 +              // COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues();
 +              // COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues();
 +              float fps = (float)FPS;
 +              size_t dim = curve->getOutDimension();
 +              int i;
 +
 +              std::vector<FCurve*>& fcurves = curve_map[curve->getUniqueId()];
 +
 +              if (dim == 1) {
 +                      FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
 +
 +                      fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
 +                      // fcu->rna_path = BLI_strdupn(path, strlen(path));
 +                      fcu->array_index = 0;
 +                      //fcu->totvert = curve->getKeyCount();
 +                      
 +                      // create beztriple for each key
 +                      for (i = 0; i < curve->getKeyCount(); i++) {
 +                              BezTriple bez;
 +                              memset(&bez, 0, sizeof(BezTriple));
 +
 +                              // intangent
 +                              // bez.vec[0][0] = get_float_value(intan, i + i) * fps;
 +                              // bez.vec[0][1] = get_float_value(intan, i + i + 1);
 +
 +                              // input, output
 +                              bez.vec[1][0] = get_float_value(input, i) * fps;
 +                              bez.vec[1][1] = get_float_value(output, i);
 +
 +                              // outtangent
 +                              // bez.vec[2][0] = get_float_value(outtan, i + i) * fps;
 +                              // bez.vec[2][1] = get_float_value(outtan, i + i + 1);
 +                              
 +                              bez.ipo = U.ipo_new; /* use default interpolation mode here... */
 +                              bez.f1 = bez.f2 = bez.f3 = SELECT;
 +                              bez.h1 = bez.h2 = HD_AUTO;
 +                              insert_bezt_fcurve(fcu, &bez, 0);
 +                      }
 +
 +                      calchandles_fcurve(fcu);
 +
 +                      fcurves.push_back(fcu);
 +              }
 +              else if(dim == 3) {
 +                      for (i = 0; i < dim; i++ ) {
 +                              FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
 +                              
 +                              fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
 +                              // fcu->rna_path = BLI_strdupn(path, strlen(path));
 +                              fcu->array_index = 0;
 +                              //fcu->totvert = curve->getKeyCount();
 +                              
 +                              // create beztriple for each key
 +                              for (int j = 0; j < curve->getKeyCount(); j++) {
 +                                      BezTriple bez;
 +                                      memset(&bez, 0, sizeof(BezTriple));
 +
 +                                      // intangent
 +                                      // bez.vec[0][0] = get_float_value(intan, j * 6 + i + i) * fps;
 +                                      // bez.vec[0][1] = get_float_value(intan, j * 6 + i + i + 1);
 +
 +                                      // input, output
 +                                      bez.vec[1][0] = get_float_value(input, j) * fps; 
 +                                      bez.vec[1][1] = get_float_value(output, j * 3 + i);
 +
 +                                      // outtangent
 +                                      // bez.vec[2][0] = get_float_value(outtan, j * 6 + i + i) * fps;
 +                                      // bez.vec[2][1] = get_float_value(outtan, j * 6 + i + i + 1);
 +
 +                                      bez.ipo = U.ipo_new; /* use default interpolation mode here... */
 +                                      bez.f1 = bez.f2 = bez.f3 = SELECT;
 +                                      bez.h1 = bez.h2 = HD_AUTO;
 +                                      insert_bezt_fcurve(fcu, &bez, 0);
 +                              }
 +
 +                              calchandles_fcurve(fcu);
 +
 +                              fcurves.push_back(fcu);
 +                      }
 +              }
 +
 +              for (std::vector<FCurve*>::iterator it = fcurves.begin(); it != fcurves.end(); it++)
 +                      unused_curves.push_back(*it);
 +      }
 +
 +      void fcurve_deg_to_rad(FCurve *cu)
 +      {
 +              for (int i = 0; i < cu->totvert; i++) {
 +                      // TODO convert handles too
 +                      cu->bezt[i].vec[1][1] *= M_PI / 180.0f;
 +              }
 +      }
 +
 +#if 0
        void make_fcurves_from_animation(COLLADAFW::AnimationCurve *curve,
                                                                         COLLADAFW::FloatOrDoubleArray& input,
                                                                         COLLADAFW::FloatOrDoubleArray& output,
        {
                int i;
                // char *path = "location";
 -              std::vector<FCurve*>& fcurves = uid_fcurve_map[curve->getUniqueId()];
 +              std::vector<FCurve*>& fcurves = curve_map[curve->getUniqueId()];
  
                if (dim == 1) {
                        // create fcurve
                        }
                }
        }
 +#endif
        
        void add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated)
        {
 -              ID *id = &ob->id;
                bAction *act;
 -              bActionGroup *grp = NULL;
                
 -              if (!ob->adt || !ob->adt->action) act = verify_adt_action(id, 1);
 -              else act = verify_adt_action(id, 0);
 -
 -              if (!ob->adt || !ob->adt->action) {
 -                      fprintf(stderr, "Cannot create anim data or action for this object. \n");
 -                      return;
 -              }
 +              if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID*)&ob->id, 1);
 +              else act = ob->adt->action;
                
 -              FCurve *fcu;
                std::vector<FCurve*>::iterator it;
 -              int i = 0;
 +              int i;
  
 +#if 0
                char *p = strstr(rna_path, "rotation_euler");
                bool is_rotation = p && *(p + strlen("rotation_euler")) == '\0';
 +
 +              // convert degrees to radians for rotation
 +              if (is_rotation)
 +                      fcurve_deg_to_rad(fcu);
 +#endif
                
 -              for (it = curves.begin(); it != curves.end(); it++) {
 -                      fcu = *it;
 +              for (it = curves.begin(), i = 0; it != curves.end(); it++, i++) {
 +                      FCurve *fcu = *it;
                        fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
                        
                        if (array_index == -1) fcu->array_index = i;
                        else fcu->array_index = array_index;
 -
 -                      // convert degrees to radians for rotation
 -                      if (is_rotation) {
 -                              for(int j = 0; j < fcu->totvert; j++) {
 -                                      float rot_intan = fcu->bezt[j].vec[0][1];
 -                                      float rot_output = fcu->bezt[j].vec[1][1];
 -                                      float rot_outtan = fcu->bezt[j].vec[2][1];
 -                                  fcu->bezt[j].vec[0][1] = rot_intan * M_PI / 180.0f;
 -                                      fcu->bezt[j].vec[1][1] = rot_output * M_PI / 180.0f;
 -                                      fcu->bezt[j].vec[2][1] = rot_outtan * M_PI / 180.0f;
 -                              }
 -                      }
 -                      
 +              
                        if (ob->type == OB_ARMATURE) {
 -                              bAction *act = ob->adt->action;
 +                              bActionGroup *grp = NULL;
                                const char *bone_name = get_joint_name(animated->node);
                                
                                if (bone_name) {
                                                grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
                                                
                                                grp->flag = AGRP_SELECTED;
 -                                              BLI_snprintf(grp->name, sizeof(grp->name), bone_name);
 +                                              BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
                                                
                                                BLI_addtail(&act->groups, grp);
                                                BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64);
                                        action_groups_add_channel(act, grp, fcu);
                                        
                                }
 +#if 0
                                if (is_rotation) {
                                        fcurves_actionGroup_map[grp].push_back(fcu);
                                }
 +#endif
                        }
                        else {
                                BLI_addtail(&act->curves, fcu);
                        }
  
 -                      i++;
 +                      // curve is used, so remove it from unused_curves
 +                      unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end());
                }
        }
  public:
        AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
                TransformReader(conv), armature_importer(arm), scene(scene) { }
  
 -      bool write_animation( const COLLADAFW::Animation* anim ) 
 +      ~AnimationImporter()
        {
 -              float fps = (float)FPS;
 +              // free unused FCurves
 +              for (std::vector<FCurve*>::iterator it = unused_curves.begin(); it != unused_curves.end(); it++)
 +                      free_fcurve(*it);
 +
 +              if (unused_curves.size())
 +                      fprintf(stderr, "removed %u unused curves\n", unused_curves.size());
 +      }
  
 +      bool write_animation(const COLLADAFW::Animation* anim) 
 +      {
                if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) {
                        COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve*)anim;
 -                      size_t dim = curve->getOutDimension();
                        
                        // XXX Don't know if it's necessary
                        // Should we check outPhysicalDimension?
                                return true;
                        }
  
 -                      COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues();
 -                      COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues();
 -                      COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues();
 -                      COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues();
 -
                        // a curve can have mixed interpolation type,
                        // in this case curve->getInterpolationTypes returns a list of interpolation types per key
                        COLLADAFW::AnimationCurve::InterpolationType interp = curve->getInterpolationType();
                        if (interp != COLLADAFW::AnimationCurve::INTERPOLATION_MIXED) {
                                switch (interp) {
                                case COLLADAFW::AnimationCurve::INTERPOLATION_LINEAR:
 -                                      // support this
 -                                      make_fcurves_from_animation(curve, input, output, intan, outtan, dim, fps);
 -                                      break;
                                case COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER:
 -                                      // and this
 -                                      make_fcurves_from_animation(curve, input, output, intan, outtan, dim, fps);
 +                                      animation_to_fcurves(curve);
                                        break;
 -                              case COLLADAFW::AnimationCurve::INTERPOLATION_CARDINAL:
 -                              case COLLADAFW::AnimationCurve::INTERPOLATION_HERMITE:
 -                              case COLLADAFW::AnimationCurve::INTERPOLATION_BSPLINE:
 -                              case COLLADAFW::AnimationCurve::INTERPOLATION_STEP:
 +                              default:
 +                                      // TODO there're also CARDINAL, HERMITE, BSPLINE and STEP types
                                        fprintf(stderr, "CARDINAL, HERMITE, BSPLINE and STEP anim interpolation types not supported yet.\n");
                                        break;
                                }
        }
        
        // called on post-process stage after writeVisualScenes
 -      bool write_animation_list( const COLLADAFW::AnimationList* animationList 
 +      bool write_animation_list(const COLLADAFW::AnimationList* animlist
        {
 -              const COLLADAFW::UniqueId& anim_list_id = animationList->getUniqueId();
 +              const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId();
 +
 +              animlist_map[animlist_id] = animlist;
  
 -              // possible in case we cannot interpret some transform
 -              if (uid_animated_map.find(anim_list_id) == uid_animated_map.end()) {
 +#if 0
 +              // should not happen
 +              if (uid_animated_map.find(animlist_id) == uid_animated_map.end()) {
                        return true;
                }
  
                // for bones rna_path is like: pose.bones["bone-name"].rotation
                
                // what does this AnimationList animate?
 -              Animation& animated = uid_animated_map[anim_list_id];
 +              Animation& animated = uid_animated_map[animlist_id];
                Object *ob = animated.ob;
  
                char rna_path[100];
                        is_joint = true;
                }
                
 -              const COLLADAFW::AnimationList::AnimationBindings& bindings = animationList->getAnimationBindings();
 +              const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
  
                switch (animated.tm->getTransformationType()) {
                case COLLADAFW::Transformation::TRANSLATE:
 +              case COLLADAFW::Transformation::SCALE:
                        {
 +                              bool loc = animated.tm->getTransformationType() == COLLADAFW::Transformation::TRANSLATE;
                                if (is_joint)
 -                                      BLI_snprintf(rna_path, sizeof(rna_path), "%s.location", joint_path);
 +                                      BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, loc ? "location" : "scale");
                                else
 -                                      BLI_strncpy(rna_path, "location", sizeof(rna_path));
 +                                      BLI_strncpy(rna_path, loc ? "location" : "scale", sizeof(rna_path));
  
                                for (int i = 0; i < bindings.getCount(); i++) {
                                        const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
                                        COLLADAFW::UniqueId anim_uid = binding.animation;
  
 -                                      if (uid_fcurve_map.find(anim_uid) == uid_fcurve_map.end()) {
 +                                      if (curve_map.find(anim_uid) == curve_map.end()) {
                                                fprintf(stderr, "Cannot find FCurve by animation UID.\n");
                                                continue;
                                        }
  
 -                                      std::vector<FCurve*>& fcurves = uid_fcurve_map[anim_uid];
 +                                      std::vector<FCurve*>& fcurves = curve_map[anim_uid];
                                        
                                        switch (binding.animationClass) {
                                        case COLLADAFW::AnimationList::POSITION_X:
                                                add_fcurves_to_object(ob, fcurves, rna_path, -1, &animated);
                                                break;
                                        default:
 -                                              fprintf(stderr, "AnimationClass %d is not supported for TRANSLATE transformation.\n",
 -                                                              binding.animationClass);
 +                                              fprintf(stderr, "AnimationClass %d is not supported for %s.\n",
 +                                                              binding.animationClass, loc ? "TRANSLATE" : "SCALE");
                                        }
                                }
                        }
                                        const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
                                        COLLADAFW::UniqueId anim_uid = binding.animation;
  
 -                                      if (uid_fcurve_map.find(anim_uid) == uid_fcurve_map.end()) {
 +                                      if (curve_map.find(anim_uid) == curve_map.end()) {
                                                fprintf(stderr, "Cannot find FCurve by animation UID.\n");
                                                continue;
                                        }
  
 -                                      std::vector<FCurve*>& fcurves = uid_fcurve_map[anim_uid];
 +                                      std::vector<FCurve*>& fcurves = curve_map[anim_uid];
  
                                        switch (binding.animationClass) {
                                        case COLLADAFW::AnimationList::ANGLE:
                                }
                        }
                        break;
 -              case COLLADAFW::Transformation::SCALE:
 -                      {
 -                              if (is_joint)
 -                                      BLI_snprintf(rna_path, sizeof(rna_path), "%s.scale", joint_path);
 -                              else
 -                                      BLI_strncpy(rna_path, "scale", sizeof(rna_path));
 -
 -                              // same as for TRANSLATE
 -                              for (int i = 0; i < bindings.getCount(); i++) {
 -                                      const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
 -                                      COLLADAFW::UniqueId anim_uid = binding.animation;
 -
 -                                      if (uid_fcurve_map.find(anim_uid) == uid_fcurve_map.end()) {
 -                                              fprintf(stderr, "Cannot find FCurve by animation UID.\n");
 -                                              continue;
 -                                      }
 -                                      
 -                                      std::vector<FCurve*>& fcurves = uid_fcurve_map[anim_uid];
 -                                      
 -                                      switch (binding.animationClass) {
 -                                      case COLLADAFW::AnimationList::POSITION_X:
 -                                              add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated);
 -                                              break;
 -                                      case COLLADAFW::AnimationList::POSITION_Y:
 -                                              add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated);
 -                                              break;
 -                                      case COLLADAFW::AnimationList::POSITION_Z:
 -                                              add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated);
 -                                              break;
 -                                      case COLLADAFW::AnimationList::POSITION_XYZ:
 -                                              add_fcurves_to_object(ob, fcurves, rna_path, -1, &animated);
 -                                              break;
 -                                      default:
 -                                              fprintf(stderr, "AnimationClass %d is not supported for SCALE transformation.\n",
 -                                                              binding.animationClass);
 -                                      }
 -                              }
 -                      }
 -                      break;
                case COLLADAFW::Transformation::MATRIX:
                case COLLADAFW::Transformation::SKEW:
                case COLLADAFW::Transformation::LOOKAT:
                        fprintf(stderr, "Animation of MATRIX, SKEW and LOOKAT transformations is not supported yet.\n");
                        break;
                }
 +#endif
                
                return true;
        }
                float mat[4][4];
                TransformReader::get_node_mat(mat, node, &uid_animated_map, ob);
                if (ob)
 -                      TransformReader::decompose(mat, ob->loc, ob->rot, ob->size);
 +                      TransformReader::decompose(mat, ob->loc, ob->rot, NULL, ob->size);
        }
        
 +#if 0
        virtual void change_eul_to_quat(Object *ob, bAction *act)
        {
                bActionGroup *grp;
                        char rna_path[100];
  
                        BLI_snprintf(joint_path, sizeof(joint_path), "pose.bones[\"%s\"]", grp->name);
 -                      BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_euler", joint_path);
 +                      BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_quaternion", joint_path);
  
                        FCurve *quatcu[4] = {
                                create_fcurve(0, rna_path),
                                create_fcurve(3, rna_path)
                        };
  
 +                      bPoseChannel *chan = get_pose_channel(ob->pose, grp->name);
 +
 +                      float m4[4][4], irest[3][3];
 +                      invert_m4_m4(m4, chan->bone->arm_mat);
 +                      copy_m3_m4(irest, m4);
 +
                        for (i = 0; i < 3; i++) {
  
                                FCurve *cu = eulcu[i];
                                                eulcu[2] ? evaluate_fcurve(eulcu[2], frame) : 0.0f
                                        };
  
 -                                      float quat[4];
 +                                      // make eul relative to bone rest pose
 +                                      float rot[3][3], rel[3][3], quat[4];
 +
 +                                      /*eul_to_mat3(rot, eul);
 +
 +                                      mul_m3_m3m3(rel, irest, rot);
  
 -                                      eul_to_quat( quat,eul);
 +                                      mat3_to_quat(quat, rel);
 +                                      */
 +
 +                                      eul_to_quat(quat, eul);
  
                                        for (int k = 0; k < 4; k++)
                                                create_bezt(quatcu[k], frame, quat[k]);
                                free_fcurve(eulcu[i]);
                        }
  
 -                      get_pose_channel(ob->pose, grp->name)->rotmode = ROT_MODE_QUAT;
 +                      chan->rotmode = ROT_MODE_QUAT;
  
                        for (i = 0; i < 4; i++)
                                action_groups_add_channel(act, grp, quatcu[i]);
                for (pchan = (bPoseChannel*)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
                        pchan->rotmode = ROT_MODE_QUAT;
                }
 -      }       
 +      }
 +#endif
 +
 +      // prerequisites:
 +      // animlist_map - map animlist id -> animlist
 +      // curve_map - map anim id -> curve(s)
 +#ifdef ARMATURE_TEST
 +      Object *translate_animation(COLLADAFW::Node *node,
 +                                                              std::map<COLLADAFW::UniqueId, Object*>& object_map,
 +                                                              std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
 +                                                              COLLADAFW::Transformation::TransformationType tm_type,
 +                                                              Object *par_job = NULL)
 +#else
 +      void translate_animation(COLLADAFW::Node *node,
 +                                                       std::map<COLLADAFW::UniqueId, Object*>& object_map,
 +                                                       std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
 +                                                       COLLADAFW::Transformation::TransformationType tm_type)
 +#endif
 +      {
 +              bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE;
 +              bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
 +              COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()];
 +              Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()];
 +              const char *bone_name = is_joint ? get_joint_name(node) : NULL;
 +
 +              if (!ob) {
 +                      fprintf(stderr, "cannot find Object for Node with id=\"%s\"\n", node->getOriginalId().c_str());
 +#ifdef ARMATURE_TEST
 +                      return NULL;
 +#else
 +                      return;
 +#endif
 +              }
 +
 +              // frames at which to sample
 +              std::vector<float> frames;
 +
 +              // for each <rotate>, <translate>, etc. there is a separate Transformation
 +              const COLLADAFW::TransformationPointerArray& tms = node->getTransformations();
 +
 +              std::vector<FCurve*> old_curves;
 +
 +              int i;
 +
 +              // find frames at which to sample plus convert all keys to radians
 +              for (i = 0; i < tms.getCount(); i++) {
 +                      COLLADAFW::Transformation *tm = tms[i];
 +                      COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
 +
 +                      if (type == tm_type) {
 +                              const COLLADAFW::UniqueId& listid = tm->getAnimationList();
 +
 +                              if (animlist_map.find(listid) != animlist_map.end()) {
 +                                      const COLLADAFW::AnimationList *animlist = animlist_map[listid];
 +                                      const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
 +
 +                                      if (bindings.getCount()) {
 +                                              for (int j = 0; j < bindings.getCount(); j++) {
 +                                                      std::vector<FCurve*>& curves = curve_map[bindings[j].animation];
 +                                                      bool xyz = ((type == COLLADAFW::Transformation::TRANSLATE || type == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ);
 +
 +                                                      if ((!xyz && curves.size() == 1) || (xyz && curves.size() == 3)) {
 +                                                              std::vector<FCurve*>::iterator iter;
 +
 +                                                              for (iter = curves.begin(); iter != curves.end(); iter++) {
 +                                                                      FCurve *fcu = *iter;
 +
 +                                                                      if (is_rotation)
 +                                                                              fcurve_deg_to_rad(fcu);
 +
 +                                                                      for (int k = 0; k < fcu->totvert; k++) {
 +                                                                              float fra = fcu->bezt[k].vec[1][0];
 +                                                                              if (std::find(frames.begin(), frames.end(), fra) == frames.end())
 +                                                                                      frames.push_back(fra);
 +                                                                      }
 +                                                              }
 +                                                      }
 +                                                      else {
 +                                                              fprintf(stderr, "expected 1 or 3 curves, got %u\n", curves.size());
 +                                                      }
 +
 +                                                      for (std::vector<FCurve*>::iterator it = curves.begin(); it != curves.end(); it++)
 +                                                              old_curves.push_back(*it);
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              sort(frames.begin(), frames.end());
 +
 +              float irest_dae[4][4];
 +              float rest[4][4], irest[4][4];
 +
 +              if (is_joint) {
 +                      if (is_joint)
 +                              get_joint_rest_mat(irest_dae, root, node);
 +                      else
 +                              evaluate_transform_at_frame(irest_dae, node, 0.0f);
 +                      invert_m4(irest_dae);
 +
 +                      Bone *bone = get_named_bone((bArmature*)ob->data, bone_name);
 +                      if (!bone) {
 +                              fprintf(stderr, "cannot find bone \"%s\"", bone_name);
 +#ifdef ARMATURE_TEST
 +                              return NULL;
 +#else
 +                              return;
 +#endif
 +                      }
 +
 +                      unit_m4(rest);
 +                      copy_m4_m4(rest, bone->arm_mat);
 +                      invert_m4_m4(irest, rest);
 +              }
 +
 +              char rna_path[200];
 +
 +#ifdef ARMATURE_TEST
 +              Object *job = get_joint_object(root, node, par_job);
 +              FCurve *job_curves[4];
 +#endif
 +
 +              if (frames.size() == 0) {
 +#ifdef ARMATURE_TEST
 +                      return job;
 +#else
 +                      return;
 +#endif
 +              }
 +
 +              const char *tm_str = NULL;
 +              switch (tm_type) {
 +              case COLLADAFW::Transformation::ROTATE:
 +                      tm_str = "rotation_quaternion";
 +                      break;
 +              case COLLADAFW::Transformation::SCALE:
 +                      tm_str = "scale";
 +                      break;
 +              case COLLADAFW::Transformation::TRANSLATE:
 +                      tm_str = "location";
 +                      break;
 +              default:
 +#ifdef ARMATURE_TEST
 +                      return job;
 +#else
 +                      return;
 +#endif
 +              }
 +
 +              if (is_joint) {
 +                      char joint_path[200];
 +                      armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path));
 +                      BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, tm_str);
 +              }
 +              else {
 +                      strcpy(rna_path, tm_str);
 +              }
 +
 +              // new curves
 +              FCurve *newcu[4];
 +              int totcu = is_rotation ? 4 : 3;
 +
 +              for (i = 0; i < totcu; i++) {
 +                      newcu[i] = create_fcurve(i, rna_path);
 +#ifdef ARMATURE_TEST
 +                      job_curves[i] = create_fcurve(i, tm_str);
 +#endif
 +              }
 +
 +              std::vector<float>::iterator it;
 +
 +              // sample values at each frame
 +              for (it = frames.begin(); it != frames.end(); it++) {
 +                      float fra = *it;
 +
 +                      float mat[4][4];
 +
 +                      unit_m4(mat);
 +
 +                      // calc object-space mat
 +                      evaluate_transform_at_frame(mat, node, fra);
 +
 +                      // for joints, we need a special matrix
 +                      if (is_joint) {
 +                              // special matrix: iR * M * iR_dae * R
 +                              // where R, iR are bone rest and inverse rest mats in world space (Blender bones),
 +                              // iR_dae is joint inverse rest matrix (DAE) and M is an evaluated joint world-space matrix (DAE)
 +                              float temp[4][4], par[4][4];
 +
 +                              // calc M
 +                              calc_joint_parent_mat_rest(par, NULL, root, node);
 +                              mul_m4_m4m4(temp, mat, par);
 +
 +                              // evaluate_joint_world_transform_at_frame(temp, NULL, , node, fra);
 +
 +                              // calc special matrix
 +                              mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL);
 +                      }
 +
 +                      float val[4];
 +
 +                      switch (tm_type) {
 +                      case COLLADAFW::Transformation::ROTATE:
 +                              mat4_to_quat(val, mat);
 +                              break;
 +                      case COLLADAFW::Transformation::SCALE:
 +                              mat4_to_size(val, mat);
 +                              break;
 +                      case COLLADAFW::Transformation::TRANSLATE:
 +                              copy_v3_v3(val, mat[3]);
 +                              break;
 +                      default:
 +                              break;
 +                      }
 +
 +                      // add 4 or 3 keys
 +                      for (i = 0; i < totcu; i++) {
 +                              add_bezt(newcu[i], fra, val[i]);
 +                      }
 +
 +#ifdef ARMATURE_TEST
 +                      if (is_joint) {
 +                              evaluate_transform_at_frame(mat, node, fra);
 +
 +                              switch (tm_type) {
 +                              case COLLADAFW::Transformation::ROTATE:
 +                                      mat4_to_quat(val, mat);
 +                                      break;
 +                              case COLLADAFW::Transformation::SCALE:
 +                                      mat4_to_size(val, mat);
 +                                      break;
 +                              case COLLADAFW::Transformation::TRANSLATE:
 +                                      copy_v3_v3(val, mat[3]);
 +                                      break;
 +                              default:
 +                                      break;
 +                              }
 +
 +                              for (i = 0; i < totcu; i++)
 +                                      add_bezt(job_curves[i], fra, val[i]);
 +                      }
 +#endif
 +              }
 +
 +              verify_adt_action((ID*)&ob->id, 1);
 +
 +              ListBase *curves = &ob->adt->action->curves;
 +              // no longer needed
 +#if 0
 +              // remove old curves
 +              for (std::vector<FCurve*>::iterator it = old_curves.begin(); it != old_curves.end(); it++) {
 +                      if (is_joint)
 +                              action_groups_remove_channel(ob->adt->action, *it);
 +                      else
 +                              BLI_remlink(curves, *it);
 +
 +                      // std::remove(unused_curves.begin(), unused_curves.end(), *it);
 +                      // free_fcurve(*it);
 +              }
 +#endif
 +
 +              // add curves
 +              for (i = 0; i < totcu; i++) {
 +                      if (is_joint)
 +                              add_bone_fcurve(ob, node, newcu[i]);
 +                      else
 +                              BLI_addtail(curves, newcu[i]);
 +
 +#ifdef ARMATURE_TEST
 +                      if (is_joint)
 +                              BLI_addtail(&job->adt->action->curves, job_curves[i]);
 +#endif
 +              }
 +
 +              if (is_rotation) {
 +                      if (is_joint) {
 +                              bPoseChannel *chan = get_pose_channel(ob->pose, bone_name);
 +                              chan->rotmode = ROT_MODE_QUAT;
 +                      }
 +                      else {
 +                              ob->rotmode = ROT_MODE_QUAT;
 +                      }
 +              }
 +
 +#ifdef ARMATURE_TEST
 +              return job;
 +#endif
 +      }
 +
 +      // internal, better make it private
 +      // warning: evaluates only rotation
 +      // prerequisites: animlist_map, curve_map
 +      void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra)
 +      {
 +              const COLLADAFW::TransformationPointerArray& tms = node->getTransformations();
 +
 +              unit_m4(mat);
 +
 +              for (int i = 0; i < tms.getCount(); i++) {
 +                      COLLADAFW::Transformation *tm = tms[i];
 +                      COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
 +                      float m[4][4];
 +
 +                      unit_m4(m);
 +
 +                      if (!evaluate_animation(tm, m, fra)) {
 +                              switch (type) {
 +                              case COLLADAFW::Transformation::ROTATE:
 +                                      dae_rotate_to_mat4(tm, m);
 +                                      break;
 +                              case COLLADAFW::Transformation::TRANSLATE:
 +                                      dae_translate_to_mat4(tm, m);
 +                                      break;
 +                              case COLLADAFW::Transformation::SCALE:
 +                                      dae_scale_to_mat4(tm, m);
 +                                      break;
 +                              case COLLADAFW::Transformation::MATRIX:
 +                                      dae_matrix_to_mat4(tm, m);
 +                                      break;
 +                              default:
 +                                      fprintf(stderr, "unsupported transformation type %d\n", type);
 +                              }
 +                      }
 +
 +                      float temp[4][4];
 +                      copy_m4_m4(temp, mat);
 +
 +                      mul_m4_m4m4(mat, m, temp);
 +              }
 +      }
 +
 +      bool evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra)
 +      {
 +              const COLLADAFW::UniqueId& listid = tm->getAnimationList();
 +
 +              if (animlist_map.find(listid) != animlist_map.end()) {
 +                      const COLLADAFW::AnimationList *animlist = animlist_map[listid];
 +                      const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
 +
 +                      if (bindings.getCount()) {
 +                              for (int j = 0; j < bindings.getCount(); j++) {
 +                                      std::vector<FCurve*>& curves = curve_map[bindings[j].animation];
 +                                      COLLADAFW::AnimationList::AnimationClass animclass = bindings[j].animationClass;
 +                                      COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
 +                                      bool xyz = ((type == COLLADAFW::Transformation::TRANSLATE || type == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ);
 +
 +                                      if (type == COLLADAFW::Transformation::ROTATE) {
 +                                              if (curves.size() != 1) {
 +                                                      fprintf(stderr, "expected 1 curve, got %u\n", curves.size());
 +                                              }
 +                                              else {
 +                                                      if (animclass == COLLADAFW::AnimationList::ANGLE) {
 +                                                              COLLADABU::Math::Vector3& axis = ((COLLADAFW::Rotate*)tm)->getRotationAxis();
 +                                                              float ax[3] = {axis[0], axis[1], axis[2]};
 +                                                              float angle = evaluate_fcurve(curves[0], fra);
 +                                                              axis_angle_to_mat4(mat, ax, angle);
 +
 +                                                              return true;
 +                                                      }
 +                                                      else {
 +                                                              // TODO support other animclasses
 +                                                              fprintf(stderr, "<rotate> animclass %d is not supported yet\n", bindings[j].animationClass);
 +                                                      }
 +                                              }
 +                                      }
 +                                      else if (type == COLLADAFW::Transformation::SCALE || type == COLLADAFW::Transformation::TRANSLATE) {
 +                                              if ((!xyz && curves.size() == 1) || (xyz && curves.size() == 3)) {
 +                                                      bool animated = true;
 +                                                      bool scale = (type == COLLADAFW::Transformation::SCALE);
 +
 +                                                      float vec[3] = {0.0f, 0.0f, 0.0f};
 +                                                      if (scale)
 +                                                              vec[0] = vec[1] = vec[2] = 1.0f;
 +
 +                                                      switch (animclass) {
 +                                                      case COLLADAFW::AnimationList::POSITION_X:
 +                                                              vec[0] = evaluate_fcurve(curves[0], fra);
 +                                                              break;
 +                                                      case COLLADAFW::AnimationList::POSITION_Y:
 +                                                              vec[1] = evaluate_fcurve(curves[0], fra);
 +                                                              break;
 +                                                      case COLLADAFW::AnimationList::POSITION_Z:
 +                                                              vec[2] = evaluate_fcurve(curves[0], fra);
 +                                                              break;
 +                                                      case COLLADAFW::AnimationList::POSITION_XYZ:
 +                                                              vec[0] = evaluate_fcurve(curves[0], fra);
 +                                                              vec[1] = evaluate_fcurve(curves[1], fra);
 +                                                              vec[2] = evaluate_fcurve(curves[2], fra);
 +                                                              break;
 +                                                      default:
 +                                                              fprintf(stderr, "<%s> animclass %d is not supported yet\n", scale ? "scale" : "translate", animclass);
 +                                                              animated = false;
 +                                                              break;
 +                                                      }
 +
 +                                                      if (animated) {
 +                                                              if (scale)
 +                                                                      size_to_mat4(mat, vec);
 +                                                              else
 +                                                                      copy_v3_v3(mat[3], vec);
 +                                                      }
 +
 +                                                      return animated;
 +                                              }
 +                                              else {
 +                                                      fprintf(stderr, "expected 1 or 3 curves, got %u, animclass is %d\n", curves.size(), animclass);
 +                                              }
 +                                      }
 +                                      else {
 +                                              // not very useful for user
 +                                              fprintf(stderr, "animation of transformation %d is not supported yet\n", type);
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              return false;
 +      }
 +
 +      // gives a world-space mat of joint at rest position
 +      void get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node)
 +      {
 +              // if bind mat is not available,
 +              // use "current" node transform, i.e. all those tms listed inside <node>
 +              if (!armature_importer->get_joint_bind_mat(mat, node)) {
 +                      float par[4][4], m[4][4];
 +
 +                      calc_joint_parent_mat_rest(par, NULL, root, node);
 +                      get_node_mat(m, node, NULL, NULL);
 +                      mul_m4_m4m4(mat, m, par);
 +              }
 +      }
 +
 +      // gives a world-space mat, end's mat not included
 +      bool calc_joint_parent_mat_rest(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end)
 +      {
 +              float m[4][4];
 +
 +              if (node == end) {
 +                      par ? copy_m4_m4(mat, par) : unit_m4(mat);
 +                      return true;
 +              }
 +
 +              // use bind matrix if available or calc "current" world mat
 +              if (!armature_importer->get_joint_bind_mat(m, node)) {
 +                      float temp[4][4];
 +                      get_node_mat(temp, node, NULL, NULL);
 +                      mul_m4_m4m4(m, temp, par);
 +              }
 +
 +              COLLADAFW::NodePointerArray& children = node->getChildNodes();
 +              for (int i = 0; i < children.getCount(); i++) {
 +                      if (calc_joint_parent_mat_rest(mat, m, children[i], end))
 +                              return true;
 +              }
 +
 +              return false;
 +      }
 +
 +#ifdef ARMATURE_TEST
 +      Object *get_joint_object(COLLADAFW::Node *root, COLLADAFW::Node *node, Object *par_job)
 +      {
 +              if (joint_objects.find(node->getUniqueId()) == joint_objects.end()) {
 +                      Object *job = add_object(scene, OB_EMPTY);
 +
 +                      rename_id((ID*)&job->id, (char*)get_joint_name(node));
 +
 +                      job->lay = object_in_scene(job, scene)->lay = 2;
 +
 +                      mul_v3_fl(job->size, 0.5f);
 +                      job->recalc |= OB_RECALC_OB;
 +
 +                      verify_adt_action((ID*)&job->id, 1);
 +
 +                      job->rotmode = ROT_MODE_QUAT;
 +
 +                      float mat[4][4];
 +                      get_joint_rest_mat(mat, root, node);
 +
 +                      if (par_job) {
 +                              float temp[4][4], ipar[4][4];
 +                              invert_m4_m4(ipar, par_job->obmat);
 +                              copy_m4_m4(temp, mat);
 +                              mul_m4_m4m4(mat, temp, ipar);
 +                      }
 +
 +                      TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size);
 +
 +                      if (par_job) {
 +                              job->parent = par_job;
 +
 +                              par_job->recalc |= OB_RECALC_OB;
 +                              job->parsubstr[0] = 0;
 +                      }
 +
 +                      where_is_object(scene, job);
 +
 +                      // after parenting and layer change
 +                      DAG_scene_sort(scene);
 +
 +                      joint_objects[node->getUniqueId()] = job;
 +              }
 +
 +              return joint_objects[node->getUniqueId()];
 +      }
 +#endif
 +
 +#if 0
 +      // recursively evaluates joint tree until end is found, mat then is world-space matrix of end
 +      // mat must be identity on enter, node must be root
 +      bool evaluate_joint_world_transform_at_frame(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra)
 +      {
 +              float m[4][4];
 +              if (par) {
 +                      float temp[4][4];
 +                      evaluate_transform_at_frame(temp, node, node == end ? fra : 0.0f);
 +                      mul_m4_m4m4(m, temp, par);
 +              }
 +              else {
 +                      evaluate_transform_at_frame(m, node, node == end ? fra : 0.0f);
 +              }
 +
 +              if (node == end) {
 +                      copy_m4_m4(mat, m);
 +                      return true;
 +              }
 +              else {
 +                      COLLADAFW::NodePointerArray& children = node->getChildNodes();
 +                      for (int i = 0; i < children.getCount(); i++) {
 +                              if (evaluate_joint_world_transform_at_frame(mat, m, children[i], end, fra))
 +                                      return true;
 +                      }
 +              }
 +
 +              return false;
 +      }
 +#endif
 +
 +      void add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu)
 +      {
 +              const char *bone_name = get_joint_name(node);
 +              bAction *act = ob->adt->action;
 +                              
 +              /* try to find group */
 +              bActionGroup *grp = action_groups_find_named(act, bone_name);
 +
 +              /* no matching groups, so add one */
 +              if (grp == NULL) {
 +                      /* Add a new group, and make it active */
 +                      grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
 +                                              
 +                      grp->flag = AGRP_SELECTED;
 +                      BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
 +                                              
 +                      BLI_addtail(&act->groups, grp);
 +                      BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64);
 +              }
 +                                      
 +              /* add F-Curve to group */
 +              action_groups_add_channel(act, grp, fcu);
 +      }
 +
 +      void add_bezt(FCurve *fcu, float fra, float value)
 +      {
 +              BezTriple bez;
 +              memset(&bez, 0, sizeof(BezTriple));
 +              bez.vec[1][0] = fra;
 +              bez.vec[1][1] = value;
 +              bez.ipo = U.ipo_new; /* use default interpolation mode here... */
 +              bez.f1 = bez.f2 = bez.f3 = SELECT;
 +              bez.h1 = bez.h2 = HD_AUTO;
 +              insert_bezt_fcurve(fcu, &bez, 0);
 +              calchandles_fcurve(fcu);
 +      }
  };
  
  /*
@@@ -2934,11 -2245,6 +2931,11 @@@ private
        std::map<COLLADAFW::UniqueId, Camera*> uid_camera_map;
        std::map<COLLADAFW::UniqueId, Lamp*> uid_lamp_map;
        std::map<Material*, TexIndexTextureArrayMap> material_texture_mapping_map;
 +      std::map<COLLADAFW::UniqueId, Object*> object_map;
 +      std::vector<const COLLADAFW::VisualScene*> vscenes;
 +
 +      std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> root_map; // find root joint by child joint uid, for bone tree evaluation during resampling
 +
        // animation
        // std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > uid_fcurve_map;
        // Nodes don't share AnimationLists (Arystan)
  public:
  
        /** Constructor. */
 -      Writer(bContext *C, const char *filename) : mContext(C), mFilename(filename),
 +      Writer(bContext *C, const char *filename) : mFilename(filename), mContext(C),
                                                                                                armature_importer(&unit_converter, &mesh_importer, &anim_importer, CTX_data_scene(C)),
                                                                                                mesh_importer(&armature_importer, CTX_data_scene(C)),
                                                                                                anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C)) {}
        /** This method is called after the last write* method. No other methods will be called after this.*/
        virtual void finish()
        {
 +#if 0
                armature_importer.fix_animation();
 +#endif
 +
 +              for (std::vector<const COLLADAFW::VisualScene*>::iterator it = vscenes.begin(); it != vscenes.end(); it++) {
 +                      const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes();
 +
 +                      for (int i = 0; i < roots.getCount(); i++)
 +                              translate_anim_recursive(roots[i]);
 +              }
 +
 +      }
 +
 +
 +#ifdef ARMATURE_TEST
 +      void translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW::Node *par = NULL, Object *parob = NULL)
 +      {
 +              if (par && par->getType() == COLLADAFW::Node::JOINT) {
 +                      // par is root if there's no corresp. key in root_map
 +                      if (root_map.find(par->getUniqueId()) == root_map.end())
 +                              root_map[node->getUniqueId()] = par;
 +                      else
 +                              root_map[node->getUniqueId()] = root_map[par->getUniqueId()];
 +              }
 +
 +              COLLADAFW::Transformation::TransformationType types[] = {
 +                      COLLADAFW::Transformation::ROTATE,
 +                      COLLADAFW::Transformation::SCALE,
 +                      COLLADAFW::Transformation::TRANSLATE
 +              };
 +
 +              int i;
 +              Object *ob;
 +
 +              for (i = 0; i < 3; i++)
 +                      ob = anim_importer.translate_animation(node, object_map, root_map, types[i]);
 +
 +              COLLADAFW::NodePointerArray &children = node->getChildNodes();
 +              for (int i = 0; i < children.getCount(); i++) {
 +                      translate_anim_recursive(children[i], node, ob);
 +              }
        }
 +#else
 +
 +#endif
  
        /** When this method is called, the writer must write the global document asset.
                @return The writer should return true, if writing succeeded, false otherwise.*/
                        
                        // check if object is not NULL
                        if (!ob) return;
 +
 +                      object_map[node->getUniqueId()] = ob;
                        
                        // if par was given make this object child of the previous 
                        if (par && ob) {
 -                              Object workob;
 -
                                ob->parent = par;
  
                                // doing what 'set parent' operator does
                @return The writer should return true, if writing succeeded, false otherwise.*/
        virtual bool writeVisualScene ( const COLLADAFW::VisualScene* visualScene ) 
        {
 -              // This method is guaranteed to be called _after_ writeGeometry, writeMaterial, etc.
 +              // this method called on post process after writeGeometry, writeMaterial, etc.
  
                // for each <node> in <visual_scene>:
                // create an Object
                // writeGeometry because <geometry> does not reference <node>,
                // we link Objects with Meshes here
  
 +              vscenes.push_back(visualScene);
 +
                // TODO: create a new scene except the selected <visual_scene> - use current blender
                // scene for it
                Scene *sce = CTX_data_scene(mContext);
 +              const COLLADAFW::NodePointerArray& roots = visualScene->getRootNodes();
  
 -              for (int i = 0; i < visualScene->getRootNodes().getCount(); i++) {
 -                      COLLADAFW::Node *node = visualScene->getRootNodes()[i];
 -                      const COLLADAFW::Node::NodeType& type = node->getType();
 -
 -                      write_node(node, NULL, sce, NULL);
 +              for (int i = 0; i < roots.getCount(); i++) {
 +                      write_node(roots[i], NULL, sce, NULL);
                }
  
                armature_importer.make_armatures(mContext);
                
                ma->mtex[i] = add_mtex();
                ma->mtex[i]->texco = TEXCO_UV;
 -              ma->mtex[i]->tex = add_texture("texture");
 +              ma->mtex[i]->tex = add_texture("Texture");
                ma->mtex[i]->tex->type = TEX_IMAGE;
                ma->mtex[i]->tex->imaflag &= ~TEX_USEALPHA;
                ma->mtex[i]->tex->ima = uid_image_map[ima_uid];
        // this function is called only for animations that pass COLLADAFW::validate
        virtual bool writeAnimation( const COLLADAFW::Animation* anim ) 
        {
 +              // return true;
                return anim_importer.write_animation(anim);
        }
        
        // called on post-process stage after writeVisualScenes
        virtual bool writeAnimationList( const COLLADAFW::AnimationList* animationList ) 
        {
 +              // return true;
                return anim_importer.write_animation_list(animationList);
        }
        
index a68a4b8414e68aad82c8627b7c7f8affc2666665,15e27f45d5e8ad0d1976373147c181c045769b48..9e24b6a9b178b2c013b72ea2c33e84009044ae63
@@@ -465,8 -465,11 +465,11 @@@ char *WM_operator_pystring(bContext *C
        PointerRNA opptr_default;
        PropertyRNA *prop_default;
        char *buf_default;
-       if(!all_args) {
-               WM_operator_properties_create(&opptr_default, ot->idname);
+       if(all_args==0 || opptr==NULL) {
+               WM_operator_properties_create_ptr(&opptr_default, ot);
+               if(opptr==NULL)
+                       opptr = &opptr_default;
        }
  
  
        }
        RNA_PROP_END;
  
-       if(all_args==0)
+       if(all_args==0 || opptr==&opptr_default )
                WM_operator_properties_free(&opptr_default);
  
        BLI_dynstr_append(dynstr, ")");
        return cstring;
  }
  
+ void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
+ {
+       RNA_pointer_create(NULL, ot->srna, NULL, ptr);
+ }
  void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
  {
        wmOperatorType *ot= WM_operatortype_find(opstring, 0);
  
        if(ot)
-               RNA_pointer_create(NULL, ot->srna, NULL, ptr);
+               WM_operator_properties_create_ptr(ptr, ot);
        else
                RNA_pointer_create(NULL, &RNA_OperatorProperties, NULL, ptr);
  }
@@@ -699,10 -707,12 +707,12 @@@ static uiBlock *wm_block_create_redo(bC
        uiBlock *block;
        uiLayout *layout;
        uiStyle *style= U.uistyles.first;
+       int columns= 2, width= 300;
        
        block= uiBeginBlock(C, ar, "redo_popup", UI_EMBOSS);
        uiBlockClearFlag(block, UI_BLOCK_LOOP);
-       uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1);
+       uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
        uiBlockSetHandleFunc(block, redo_cb, arg_op);
  
        if(!op->properties) {
                op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
        }
  
+       // XXX - hack, only for editing docs
+       if(strcmp(op->type->idname, "WM_OT_doc_edit")==0) {
+               columns= 1;
+               width= 500;
+       }
        RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-       layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 300, 20, style);
+       layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, width, 20, style);
        uiItemL(layout, op->type->name, 0);
  
        if(op->type->ui)
-               op->type->ui((bContext*)C, &ptr, layout);
+               op->type->ui((bContext*)C, op, layout);
        else
-               uiDefAutoButsRNA(C, layout, &ptr, 2);
+               uiDefAutoButsRNA(C, layout, &ptr, columns);
  
        uiPopupBoundsBlock(block, 4.0f, 0, 0);
        uiEndBlock(C, block);
@@@ -745,7 -761,6 +761,7 @@@ int WM_operator_redo_popup(bContext *C
        return OPERATOR_CANCELLED;
  }
  
 +
  /* ***************** Debug menu ************************* */
  
  static uiBlock *wm_block_create_menu(bContext *C, ARegion *ar, void *arg_op)
        
        block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
        uiBlockClearFlag(block, UI_BLOCK_LOOP);
-       uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1);
+       uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
        
        layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 300, 20, style);
        uiItemL(layout, op->type->name, 0);
  
        if(op->type->ui)
-               op->type->ui(C, op->ptr, layout);
+               op->type->ui(C, op, layout);
        else
                uiDefAutoButsRNA(C, layout, op->ptr, 2);
        
@@@ -806,6 -821,72 +822,72 @@@ static void WM_OT_debug_menu(wmOperator
        RNA_def_int(ot->srna, "debugval", 0, -10000, 10000, "Debug Value", "", INT_MIN, INT_MAX);
  }
  
+ /* ***************** Splash Screen ************************* */
+ static void wm_block_splash_close(bContext *C, void *arg_block, void *arg_unused)
+ {
+       uiPupBlockClose(C, arg_block);
+ }
+ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused)
+ {
+       uiBlock *block;
+       uiBut *but;
+       uiLayout *layout, *split, *col;
+       uiStyle *style= U.uistyles.first;
+       
+       block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
+       uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1);
+       
+       but= uiDefBut(block, BUT_IMAGE, 0, "", 0, 10, 501, 282, NULL, 0.0, 0.0, 0, 0, "");
+       uiButSetFunc(but, wm_block_splash_close, block, NULL);
+       
+       uiBlockSetEmboss(block, UI_EMBOSSP);
+       
+       layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 10, 10, 480, 110, style);
+       uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
+       
+       split = uiLayoutSplit(layout, 0);
+       col = uiLayoutColumn(split, 0);
+       uiItemL(col, "Links", 0);
+       uiItemO(col, NULL, ICON_URL, "HELP_OT_release_logs");
+       uiItemO(col, NULL, ICON_URL, "HELP_OT_manual");
+       uiItemO(col, NULL, ICON_URL, "HELP_OT_blender_website");
+       uiItemO(col, NULL, ICON_URL, "HELP_OT_user_community");
+       uiItemO(col, NULL, ICON_URL, "HELP_OT_python_api");
+       uiItemS(col);
+       
+       col = uiLayoutColumn(split, 0);
+       uiItemL(col, "Recent", 0);
+       uiItemsEnumO(col, "WM_OT_open_recentfile_splash", "file");
+       uiItemS(col);
+       uiCenteredBoundsBlock(block, 0.0f);
+       uiEndBlock(C, block);
+       
+       return block;
+ }
+ static int wm_splash_invoke(bContext *C, wmOperator *op, wmEvent *event)
+ {
+       uiPupBlock(C, wm_block_create_splash, NULL);
+       
+       return OPERATOR_FINISHED;
+ }
+ static void WM_OT_splash(wmOperatorType *ot)
+ {
+       ot->name= "Splash Screen";
+       ot->idname= "WM_OT_splash";
+       ot->description= "Opens a blocking popup region with release info";
+       
+       ot->invoke= wm_splash_invoke;
+       ot->poll= WM_operator_winactive;
+ }
  /* ***************** Search menu ************************* */
  static void operator_call_cb(struct bContext *C, void *arg1, void *arg2)
  {
@@@ -851,7 -932,7 +933,7 @@@ static uiBlock *wm_block_search_menu(bC
        uiBut *but;
        
        block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
-       uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_RET_1);
+       uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
        
        but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 10, 180, 19, "");
        uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
@@@ -1011,6 -1092,7 +1093,7 @@@ static EnumPropertyItem *open_recentfil
        /* dynamically construct enum */
        for(recent = G.recent_files.first, i=0; (i<U.recent_files) && (recent); recent = recent->next, i++) {
                tmp.value= i+1;
+               tmp.icon= ICON_FILE_BLEND;
                tmp.identifier= recent->filename;
                tmp.name= BLI_short_filename(recent->filename);
                RNA_enum_item_add(&item, &totitem, &tmp);
@@@ -1040,6 -1122,47 +1123,47 @@@ static void WM_OT_open_recentfile(wmOpe
        RNA_def_enum_funcs(prop, open_recentfile_itemf);
  }
  
+ static EnumPropertyItem *open_recentfile_splash_itemf(bContext *C, PointerRNA *ptr, int *free)
+ {
+       EnumPropertyItem tmp = {0, "", 0, "", ""};
+       EnumPropertyItem *item= NULL;
+       struct RecentFile *recent;
+       int totitem= 0, i;
+       
+       /* dynamically construct enum */
+       for(recent = G.recent_files.first, i=0; (i<6) && (recent); recent = recent->next, i++) {
+               tmp.value= i+1;
+               tmp.icon= ICON_FILE_BLEND;
+               tmp.identifier= recent->filename;
+               tmp.name= BLI_last_slash(recent->filename);
+               if(tmp.name) tmp.name += 1;
+               else tmp.name = recent->filename;
+               RNA_enum_item_add(&item, &totitem, &tmp);
+       }
+       
+       RNA_enum_item_end(&item, &totitem);
+       *free= 1;
+       
+       return item;
+ }
+ static void WM_OT_open_recentfile_splash(wmOperatorType *ot)
+ {
+       PropertyRNA *prop;
+       static EnumPropertyItem file_items[]= {
+               {0, NULL, 0, NULL, NULL}};
+       
+       ot->name= "Open Recent File";
+       ot->idname= "WM_OT_open_recentfile_splash";
+       ot->description="Open recent files list.";
+       
+       ot->exec= recentfile_exec;
+       ot->poll= WM_operator_winactive;
+       
+       prop= RNA_def_enum(ot->srna, "file", file_items, 1, "File", "");
+       RNA_def_enum_funcs(prop, open_recentfile_splash_itemf);
+ }
  /* *************** open file **************** */
  
  static void open_set_load_ui(wmOperator *op)
@@@ -1922,7 -2045,7 +2046,7 @@@ void wm_tweakevent_test(bContext *C, wm
                }
        }
        else {
-               if(action==WM_HANDLER_BREAK) {
+               if(action & WM_HANDLER_BREAK) {
                        WM_gesture_end(C, win->tweak);
                        win->tweak= NULL;
                }
@@@ -2304,7 -2427,6 +2428,7 @@@ void WM_OT_radial_control_partial(wmOpe
        RNA_def_int_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX);
  }
  
 +
  /* ************************** timer for testing ***************** */
  
  /* uses no type defines, fully local testing function anyway... ;) */
@@@ -2458,6 -2580,7 +2582,7 @@@ void wm_operatortype_init(void
        WM_operatortype_append(WM_OT_window_fullscreen_toggle);
        WM_operatortype_append(WM_OT_exit_blender);
        WM_operatortype_append(WM_OT_open_recentfile);
+       WM_operatortype_append(WM_OT_open_recentfile_splash);
        WM_operatortype_append(WM_OT_open_mainfile);
        WM_operatortype_append(WM_OT_link_append);
        WM_operatortype_append(WM_OT_recover_last_session);
        WM_operatortype_append(WM_OT_redraw_timer);
        WM_operatortype_append(WM_OT_memory_statistics);
        WM_operatortype_append(WM_OT_debug_menu);
+       WM_operatortype_append(WM_OT_splash);
        WM_operatortype_append(WM_OT_search_menu);
 -      WM_operatortype_append(WM_OT_call_menu);
  
  #ifdef WITH_COLLADA
        /* XXX: move these */
        WM_operatortype_append(WM_OT_collada_import);
  #endif
  
 +      WM_operatortype_append(WM_OT_call_menu);
  }
  
  /* called in transform_ops.c, on each regeneration of keymaps  */
@@@ -2541,12 -2665,12 +2667,12 @@@ static void gesture_border_modal_keymap
        {GESTURE_MODAL_BORDER_BEGIN,    "BEGIN", 0, "Begin", ""},
        {0, NULL, 0, NULL, NULL}};
  
-       wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Gesture Border");
+       wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Gesture Border");
  
        /* this function is called for each spacetype, only needs to add map once */
        if(keymap) return;
  
-       keymap= WM_modalkeymap_add(keyconf, "View3D Gesture Border", modal_items);
+       keymap= WM_modalkeymap_add(keyconf, "Gesture Border", modal_items);
  
        /* items for modal map */
        WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
  #endif
  
        /* assign map to operators */
-       WM_modalkeymap_assign(keymap, "ACT_OT_select_border");
+       WM_modalkeymap_assign(keymap, "ACTION_OT_select_border");
        WM_modalkeymap_assign(keymap, "ANIM_OT_channels_select_border");
        WM_modalkeymap_assign(keymap, "ANIM_OT_previewrange_set");
        WM_modalkeymap_assign(keymap, "CONSOLE_OT_select_border");
  //    WM_modalkeymap_assign(keymap, "SCREEN_OT_border_select"); // template
        WM_modalkeymap_assign(keymap, "SEQUENCER_OT_select_border");
        WM_modalkeymap_assign(keymap, "UV_OT_select_border");
+       WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border");
        WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border");
        WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");
        WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_border");
-       WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border");
+       WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); // XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel
  }
  
  /* default keymap for windows and screens, only call once per WM */