synched with trunk at revision 34793
authorNick Samarin <nicks1987@bigmir.net>
Wed, 16 Feb 2011 17:07:18 +0000 (17:07 +0000)
committerNick Samarin <nicks1987@bigmir.net>
Wed, 16 Feb 2011 17:07:18 +0000 (17:07 +0000)
102 files changed:
1  2 
source/blender/blenkernel/BKE_array_mallocn.h
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/mesh_validate.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/sca.c
source/blender/blenkernel/intern/scene.c
source/blender/blenlib/BLI_utildefines.h
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/collada/AnimationImporter.cpp
source/blender/collada/AnimationImporter.h
source/blender/collada/ArmatureExporter.cpp
source/blender/collada/ArmatureExporter.h
source/blender/collada/ArmatureImporter.cpp
source/blender/collada/ArmatureImporter.h
source/blender/collada/CameraExporter.cpp
source/blender/collada/CameraExporter.h
source/blender/collada/EffectExporter.cpp
source/blender/collada/EffectExporter.h
source/blender/collada/GeometryExporter.cpp
source/blender/collada/GeometryExporter.h
source/blender/collada/ImageExporter.cpp
source/blender/collada/ImageExporter.h
source/blender/collada/InstanceWriter.cpp
source/blender/collada/InstanceWriter.h
source/blender/collada/LightExporter.cpp
source/blender/collada/LightExporter.h
source/blender/collada/MaterialExporter.cpp
source/blender/collada/MaterialExporter.h
source/blender/collada/MeshImporter.cpp
source/blender/collada/MeshImporter.h
source/blender/collada/SkinInfo.cpp
source/blender/collada/SkinInfo.h
source/blender/collada/TransformReader.cpp
source/blender/collada/TransformReader.h
source/blender/collada/TransformWriter.cpp
source/blender/collada/TransformWriter.h
source/blender/collada/collada_internal.cpp
source/blender/collada/collada_utils.cpp
source/blender/collada/collada_utils.h
source/blender/editors/object/CMakeLists.txt
source/blender/editors/object/SConscript
source/blender/editors/object/object_intern.h
source/blender/editors/object/object_navmesh.cpp
source/blender/editors/object/object_ops.c
source/blender/editors/space_info/info_draw.c
source/blender/editors/space_info/info_report.c
source/blender/editors/space_info/textview.c
source/blender/editors/space_info/textview.h
source/blender/editors/space_logic/logic_window.c
source/blender/editors/space_view3d/view3d_fly.c
source/blender/editors/util/CMakeLists.txt
source/blender/editors/util/SConscript
source/blender/imbuf/intern/anim_movie.c
source/blender/makesdna/DNA_actuator_types.h
source/blender/makesdna/DNA_customdata_types.h
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_object_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_actuator.c
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_scene.c
source/blender/modifiers/CMakeLists.txt
source/blender/modifiers/MOD_modifiertypes.h
source/blender/modifiers/SConscript
source/blender/modifiers/intern/MOD_navmesh.cpp
source/blender/modifiers/intern/MOD_util.c
source/blender/python/generic/blf_py_api.c
source/blender/python/generic/blf_py_api.h
source/blender/python/generic/mathutils_geometry.c
source/blender/python/generic/mathutils_geometry.h
source/blender/python/intern/bpy_rna_array.c
source/blender/render/intern/include/rayintersection.h
source/blender/render/intern/raytrace/rayobject_blibvh.cpp
source/blender/render/intern/raytrace/rayobject_empty.cpp
source/blender/render/intern/raytrace/rayobject_instance.cpp
source/blender/render/intern/raytrace/rayobject_octree.cpp
source/blender/render/intern/raytrace/rayobject_raycounter.cpp
source/blender/render/intern/source/render_texture.c
source/creator/CMakeLists.txt
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Converter/CMakeLists.txt
source/gameengine/Converter/KX_ConvertActuators.cpp
source/gameengine/Converter/SConscript
source/gameengine/Ketsji/CMakeLists.txt
source/gameengine/Ketsji/KX_FontObject.cpp
source/gameengine/Ketsji/KX_FontObject.h
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Ketsji/KX_KetsjiEngine.cpp
source/gameengine/Ketsji/KX_NavMeshObject.h
source/gameengine/Ketsji/KX_PythonInit.cpp
source/gameengine/Ketsji/KX_PythonInit.h
source/gameengine/Ketsji/KX_PythonInitTypes.cpp
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_Scene.h
source/gameengine/Ketsji/SConscript
source/gameengine/Rasterizer/RAS_IRasterizer.h
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h

index 0000000,8fe32da..3bfcd48
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,82 +1,82 @@@
 - * $Id$
+ /*
++ * $Id: BKE_array_mallocn.h 34235 2011-01-10 21:30:14Z gsrb3d $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+  * All rights reserved.
+  *
+  * The Original Code is: all of this file.
+  *
+  * Contributor(s): none yet.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+ */
+ #ifndef BKE_ARRAY_MALLOCN_H
+ #define BKE_ARRAY_MALLOCN_H
+ /*little array macro library.  example of usage:
+ int *arr = NULL;
+ V_DECLARE(arr);
+ int i;
+ for (i=0; i<10; i++) {
+       V_GROW(arr);
+       arr[i] = something;
+ }
+ V_FREE(arr);
+ arrays are buffered, using double-buffering (so on each reallocation,
+ the array size is doubled).  supposedly this should give good Big Oh
+ behaviour, though it may not be the best in practice.
+ */
+ #define V_DECLARE(vec) int _##vec##_count=0; void *_##vec##_tmp
+ /*in the future, I plan on having V_DECLARE allocate stack memory it'll
+   use at first, and switch over to heap when it needs more.  that'll mess
+   up cases where you'd want to use this API to build a dynamic list for
+   non-local use, so all such cases should use this macro.*/
+ #define V_DYNDECLARE(vec) V_DECLARE(vec)
+ /*this returns the entire size of the array, including any buffering.*/
+ #define V_SIZE(vec) ((signed int)((vec)==NULL ? 0 : MEM_allocN_len(vec) / sizeof(*vec)))
+ /*this returns the logical size of the array, not including buffering.*/
+ #define V_COUNT(vec) _##vec##_count
+ /*grow the array by one.  zeroes the new elements.*/
+ #define V_GROW(vec) \
+       V_SIZE(vec) > _##vec##_count ? _##vec##_count++ : \
+       ((_##vec##_tmp = MEM_callocN(sizeof(*vec)*(_##vec##_count*2+2), #vec " " __FILE__ " ")),\
+       (void)(vec && memcpy(_##vec##_tmp, vec, sizeof(*vec) * _##vec##_count)),\
+       (void)(vec && (MEM_freeN(vec),1)),\
+       (vec = _##vec##_tmp),\
+       _##vec##_count++)
+ #define V_FREE(vec) if (vec) MEM_freeN(vec);
+ /*resets the logical size of an array to zero, but doesn't
+   free the memory.*/
+ #define V_RESET(vec) _##vec##_count=0
+ /*set the count of the array*/
+ #define V_SETCOUNT(vec, count) _##vec##_count = (count)
+ #endif // BKE_ARRAY_MALLOCN_H
index 0000000,e5aacdf..b0ab00d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,379 +1,379 @@@
 - * $Id$
+ /**
++ * $Id: mesh_validate.c 34759 2011-02-10 14:13:13Z campbellbarton $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * The Original Code is Copyright (C) 2011 Blender Foundation.
+  * All rights reserved.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <limits.h>
+ #include "DNA_mesh_types.h"
+ #include "DNA_meshdata_types.h"
+ #include "BLO_sys_types.h"
+ #include "BLI_utildefines.h"
+ #include "BLI_edgehash.h"
+ #include "BKE_DerivedMesh.h"
+ #include "MEM_guardedalloc.h"
+ #include "BKE_mesh.h"
+ #define SELECT 1
+ typedef union {
+       uint32_t verts[2];
+       int64_t edval;
+ } EdgeUUID;
+ typedef struct SortFace {
+ //    unsigned int    v[4];
+       EdgeUUID                es[4];
+       unsigned int    index;
+ } SortFace;
+ static void edge_store_assign(uint32_t verts[2],  const uint32_t v1, const uint32_t v2)
+ {
+       if(v1 < v2) {
+               verts[0]= v1;
+               verts[1]= v2;
+       }
+       else {
+               verts[0]= v2;
+               verts[1]= v1;
+       }
+ }
+ static void edge_store_from_mface_quad(EdgeUUID es[4], MFace *mf)
+ {
+       edge_store_assign(es[0].verts, mf->v1, mf->v2);
+       edge_store_assign(es[1].verts, mf->v2, mf->v3);
+       edge_store_assign(es[2].verts, mf->v3, mf->v4);
+       edge_store_assign(es[3].verts, mf->v4, mf->v1);
+ }
+ static void edge_store_from_mface_tri(EdgeUUID es[3], MFace *mf)
+ {
+       edge_store_assign(es[0].verts, mf->v1, mf->v2);
+       edge_store_assign(es[1].verts, mf->v2, mf->v3);
+       edge_store_assign(es[2].verts, mf->v3, mf->v1);
+       es[3].verts[0] = es[3].verts[1] = UINT_MAX;
+ }
+ static int int64_cmp(const void *v1, const void *v2)
+ {
+       const int64_t x1= *(const int64_t *)v1;
+       const int64_t x2= *(const int64_t *)v2;
+       if( x1 > x2 ) return 1;
+       else if( x1 < x2 ) return -1;
+       return 0;
+ }
+ static int search_face_cmp(const void *v1, const void *v2)
+ {
+       const SortFace *sfa= v1, *sfb= v2;
+       if      (sfa->es[0].edval > sfb->es[0].edval) return 1;
+       else if (sfa->es[0].edval < sfb->es[0].edval) return -1;
+       else if (sfa->es[1].edval > sfb->es[1].edval) return 1;
+       else if (sfa->es[1].edval < sfb->es[1].edval) return -1;
+       else if (sfa->es[2].edval > sfb->es[2].edval) return 1;
+       else if (sfa->es[2].edval < sfb->es[2].edval) return -1;
+       else if (sfa->es[3].edval > sfb->es[3].edval) return 1;
+       else if (sfa->es[3].edval < sfb->es[3].edval) return -1;
+       else                                                                              return 0;
+ }
+ int BKE_mesh_validate_arrays(Mesh *me, MVert *UNUSED(mverts), int totvert, MEdge *medges, int totedge, MFace *mfaces, int totface, const short do_verbose, const short do_fixes)
+ {
+ #     define PRINT if(do_verbose) printf
+ #     define REMOVE_EDGE_TAG(_med) { _med->v2= _med->v1; do_edge_free= 1; }
+ #     define REMOVE_FACE_TAG(_mf) { _mf->v3=0; do_face_free= 1; }
+ //    MVert *mv;
+       MEdge *med;
+       MFace *mf;
+       MFace *mf_prev;
+       int i;
+       int do_face_free= FALSE;
+       int do_edge_free= FALSE;
+       int do_edge_recalc= FALSE;
+       EdgeHash *edge_hash = BLI_edgehash_new();
+       SortFace *sort_faces= MEM_callocN(sizeof(SortFace) * totface, "search faces");
+       SortFace *sf;
+       SortFace *sf_prev;
+       int totsortface= 0;
+       BLI_assert(!(do_fixes && me == NULL));
+       PRINT("ED_mesh_validate: verts(%d), edges(%d), faces(%d)\n", totvert, totedge, totface);
+       if(totedge == 0 && totface != 0) {
+               PRINT("    locical error, %d faces and 0 edges\n", totface);
+               do_edge_recalc= TRUE;
+       }
+       for(i=0, med= medges; i<totedge; i++, med++) {
+               int remove= FALSE;
+               if(med->v1 == med->v2) {
+                       PRINT("    edge %d: has matching verts, both %d\n", i, med->v1);
+                       remove= do_fixes;
+               }
+               if(med->v1 >= totvert) {
+                       PRINT("    edge %d: v1 index out of range, %d\n", i, med->v1);
+                       remove= do_fixes;
+               }
+               if(med->v2 >= totvert) {
+                       PRINT("    edge %d: v2 index out of range, %d\n", i, med->v2);
+                       remove= do_fixes;
+               }
+               if(BLI_edgehash_haskey(edge_hash, med->v1, med->v2)) {
+                       PRINT("    edge %d: is a duplicate of, %d\n", i, GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, med->v1, med->v2)));
+                       remove= do_fixes;
+               }
+               if(remove == FALSE){
+                       BLI_edgehash_insert(edge_hash, med->v1, med->v2, SET_INT_IN_POINTER(i));
+               }
+               else {
+                       REMOVE_EDGE_TAG(med);
+               }
+       }
+       for(i=0, mf=mfaces, sf=sort_faces; i<totface; i++, mf++) {
+               int remove= FALSE;
+               int fidx;
+               unsigned int fv[4];
+               fidx = mf->v4 ? 3:2;
+               do {
+                       fv[fidx]= *(&(mf->v1) + fidx);
+                       if(fv[fidx] >= totvert) {
+                               PRINT("    face %d: 'v%d' index out of range, %d\n", i, fidx + 1, fv[fidx]);
+                               remove= do_fixes;
+                       }
+               } while (fidx--);
+               if(remove == FALSE) {
+                       if(mf->v4) {
+                               if(mf->v1 == mf->v2) { PRINT("    face %d: verts invalid, v1/v2 both %d\n", i, mf->v1); remove= do_fixes; }
+                               if(mf->v1 == mf->v3) { PRINT("    face %d: verts invalid, v1/v3 both %d\n", i, mf->v1); remove= do_fixes;  }
+                               if(mf->v1 == mf->v4) { PRINT("    face %d: verts invalid, v1/v4 both %d\n", i, mf->v1); remove= do_fixes;  }
+                               if(mf->v2 == mf->v3) { PRINT("    face %d: verts invalid, v2/v3 both %d\n", i, mf->v2); remove= do_fixes;  }
+                               if(mf->v2 == mf->v4) { PRINT("    face %d: verts invalid, v2/v4 both %d\n", i, mf->v2); remove= do_fixes;  }
+                               if(mf->v3 == mf->v4) { PRINT("    face %d: verts invalid, v3/v4 both %d\n", i, mf->v3); remove= do_fixes;  }
+                       }
+                       else {
+                               if(mf->v1 == mf->v2) { PRINT("    faceT %d: verts invalid, v1/v2 both %d\n", i, mf->v1); remove= do_fixes; }
+                               if(mf->v1 == mf->v3) { PRINT("    faceT %d: verts invalid, v1/v3 both %d\n", i, mf->v1); remove= do_fixes; }
+                               if(mf->v2 == mf->v3) { PRINT("    faceT %d: verts invalid, v2/v3 both %d\n", i, mf->v2); remove= do_fixes; }
+                       }
+                       if(remove == FALSE) {
+                               if(totedge) {
+                                       if(mf->v4) {
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) { PRINT("    face %d: edge v1/v2 (%d,%d) is missing egde data\n", i, mf->v1, mf->v2); do_edge_recalc= TRUE; }
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) { PRINT("    face %d: edge v2/v3 (%d,%d) is missing egde data\n", i, mf->v2, mf->v3); do_edge_recalc= TRUE; }
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v4)) { PRINT("    face %d: edge v3/v4 (%d,%d) is missing egde data\n", i, mf->v3, mf->v4); do_edge_recalc= TRUE; }
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v4, mf->v1)) { PRINT("    face %d: edge v4/v1 (%d,%d) is missing egde data\n", i, mf->v4, mf->v1); do_edge_recalc= TRUE; }
+                                       }
+                                       else {
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) { PRINT("    face %d: edge v1/v2 (%d,%d) is missing egde data\n", i, mf->v1, mf->v2); do_edge_recalc= TRUE; }
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) { PRINT("    face %d: edge v2/v3 (%d,%d) is missing egde data\n", i, mf->v2, mf->v3); do_edge_recalc= TRUE; }
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v1)) { PRINT("    face %d: edge v3/v1 (%d,%d) is missing egde data\n", i, mf->v3, mf->v1); do_edge_recalc= TRUE; }
+                                       }
+                               }
+                               sf->index = i;
+                               if(mf->v4) {
+                                       edge_store_from_mface_quad(sf->es, mf);
+                                       qsort(sf->es, 4, sizeof(int64_t), int64_cmp);
+                               }
+                               else {
+                                       edge_store_from_mface_tri(sf->es, mf);
+                                       qsort(sf->es, 3, sizeof(int64_t), int64_cmp);
+                               }
+                               totsortface++;
+                               sf++;
+                       }
+               }
+               if(remove) {
+                       REMOVE_FACE_TAG(mf);
+               }
+       }
+       qsort(sort_faces, totsortface, sizeof(SortFace), search_face_cmp);
+       sf= sort_faces;
+       sf_prev= sf;
+       sf++;
+       for(i=1; i<totsortface; i++, sf++) {
+               int remove= FALSE;
+               /* on a valid mesh, code below will never run */
+               if(memcmp(sf->es, sf_prev->es, sizeof(sf_prev->es)) == 0) {
+                       mf= mfaces + sf->index;
+                       if(do_verbose) {
+                               mf_prev= mfaces + sf_prev->index;
+                               if(mf->v4) {
+                                       PRINT("    face %d & %d: are duplicates (%d,%d,%d,%d) (%d,%d,%d,%d)\n", sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4, mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4);
+                               }
+                               else {
+                                       PRINT("    face %d & %d: are duplicates (%d,%d,%d) (%d,%d,%d)\n", sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf_prev->v1, mf_prev->v2, mf_prev->v3);
+                               }
+                       }
+                       remove= do_fixes;
+               }
+               else {
+                       sf_prev= sf;
+               }
+               if(remove) {
+                       REMOVE_FACE_TAG(mf);
+               }
+       }
+       BLI_edgehash_free(edge_hash, NULL);
+       MEM_freeN(sort_faces);
+       PRINT("BKE_mesh_validate: finished\n\n");
+ #      undef PRINT
+ #      undef REMOVE_EDGE_TAG
+ #      undef REMOVE_FACE_TAG
+       if(me) {
+               if(do_face_free) {
+                       mesh_strip_loose_faces(me);
+               }
+               if (do_edge_free) {
+                       mesh_strip_loose_edges(me);
+               }
+               if(do_fixes && do_edge_recalc) {
+                       BKE_mesh_calc_edges(me, TRUE);
+               }
+       }
+       return (do_face_free || do_edge_free || do_edge_recalc);
+ }
+ int BKE_mesh_validate(Mesh *me, int do_verbose)
+ {
+       printf("MESH: %s\n", me->id.name+2);
+       return BKE_mesh_validate_arrays(me, me->mvert, me->totvert, me->medge, me->totedge, me->mface, me->totface, do_verbose, TRUE);
+ }
+ int BKE_mesh_validate_dm(DerivedMesh *dm)
+ {
+       return BKE_mesh_validate_arrays(NULL, dm->getVertArray(dm), dm->getNumVerts(dm), dm->getEdgeArray(dm), dm->getNumEdges(dm), dm->getFaceArray(dm), dm->getNumFaces(dm), TRUE, FALSE);
+ }
+ void BKE_mesh_calc_edges(Mesh *mesh, int update)
+ {
+       CustomData edata;
+       EdgeHashIterator *ehi;
+       MFace *mf = mesh->mface;
+       MEdge *med, *med_orig;
+       EdgeHash *eh = BLI_edgehash_new();
+       int i, totedge, totface = mesh->totface;
+       if(mesh->totedge==0)
+               update= 0;
+       if(update) {
+               /* assume existing edges are valid
+                * useful when adding more faces and generating edges from them */
+               med= mesh->medge;
+               for(i= 0; i<mesh->totedge; i++, med++)
+                       BLI_edgehash_insert(eh, med->v1, med->v2, med);
+       }
+       for (i = 0; i < totface; i++, mf++) {
+               if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
+                       BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
+               if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
+                       BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
+               if (mf->v4) {
+                       if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
+                               BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
+                       if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
+                               BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
+               } else {
+                       if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
+                               BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
+               }
+       }
+       totedge = BLI_edgehash_size(eh);
+       /* write new edges into a temporary CustomData */
+       memset(&edata, 0, sizeof(edata));
+       CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
+       ehi = BLI_edgehashIterator_new(eh);
+       med = CustomData_get_layer(&edata, CD_MEDGE);
+       for(i = 0; !BLI_edgehashIterator_isDone(ehi);
+               BLI_edgehashIterator_step(ehi), ++i, ++med) {
+               if(update && (med_orig=BLI_edgehashIterator_getValue(ehi))) {
+                       *med= *med_orig; /* copy from the original */
+               } else {
+                       BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);
+                       med->flag = ME_EDGEDRAW|ME_EDGERENDER|SELECT; /* select for newly created meshes which are selected [#25595] */
+               }
+       }
+       BLI_edgehashIterator_free(ehi);
+       /* free old CustomData and assign new one */
+       CustomData_free(&mesh->edata, mesh->totedge);
+       mesh->edata = edata;
+       mesh->totedge = totedge;
+       mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
+       BLI_edgehash_free(eh, NULL);
+ }
index 0000000,ccda9c1..7749aaf
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,218 +1,218 @@@
 - * $Id$
+ /*
++ * $Id: BLI_utildefines.h 34198 2011-01-09 15:12:08Z campbellbarton $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+  * All rights reserved.
+  *
+  * The Original Code is: all of this file.
+  *
+  * Contributor(s): none yet.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+ */
+ #ifndef BLI_UTILDEFINES_H
+ #define BLI_UTILDEFINES_H
+ #ifndef FALSE
+ #define FALSE 0
+ #endif
+ #ifndef TRUE
+ #define TRUE 1
+ #endif
+ #define ELEM(a, b, c)           ( (a)==(b) || (a)==(c) )
+ #define ELEM3(a, b, c, d)       ( ELEM(a, b, c) || (a)==(d) )
+ #define ELEM4(a, b, c, d, e)    ( ELEM(a, b, c) || ELEM(a, d, e) )
+ #define ELEM5(a, b, c, d, e, f) ( ELEM(a, b, c) || ELEM3(a, d, e, f) )
+ #define ELEM6(a, b, c, d, e, f, g)      ( ELEM(a, b, c) || ELEM4(a, d, e, f, g) )
+ #define ELEM7(a, b, c, d, e, f, g, h)   ( ELEM3(a, b, c, d) || ELEM4(a, e, f, g, h) )
+ #define ELEM8(a, b, c, d, e, f, g, h, i)        ( ELEM4(a, b, c, d, e) || ELEM4(a, f, g, h, i) )
+ #define ELEM9(a, b, c, d, e, f, g, h, i, j)        ( ELEM4(a, b, c, d, e) || ELEM5(a, f, g, h, i, j) )
+ #define ELEM10(a, b, c, d, e, f, g, h, i, j, k)        ( ELEM4(a, b, c, d, e) || ELEM6(a, f, g, h, i, j, k) )
+ #define ELEM11(a, b, c, d, e, f, g, h, i, j, k, l)        ( ELEM4(a, b, c, d, e) || ELEM7(a, f, g, h, i, j, k, l) )
+ /* shift around elements */
+ #define SHIFT3(type, a, b, c) { type tmp; tmp = a; a = c; c = b; b = tmp; }
+ #define SHIFT4(type, a, b, c, d) { type tmp; tmp = a; a = d; d = c; c = b; b = tmp; }
+ /* min/max */
+ #define MIN2(x,y)               ( (x)<(y) ? (x) : (y) )
+ #define MIN3(x,y,z)             MIN2( MIN2((x),(y)) , (z) )
+ #define MIN4(x,y,z,a)           MIN2( MIN2((x),(y)) , MIN2((z),(a)) )
+ #define MAX2(x,y)               ( (x)>(y) ? (x) : (y) )
+ #define MAX3(x,y,z)             MAX2( MAX2((x),(y)) , (z) )
+ #define MAX4(x,y,z,a)           MAX2( MAX2((x),(y)) , MAX2((z),(a)) )
+ #define INIT_MINMAX(min, max) { (min)[0]= (min)[1]= (min)[2]= 1.0e30f; (max)[0]= (max)[1]= (max)[2]= -1.0e30f; }
+ #define INIT_MINMAX2(min, max) { (min)[0]= (min)[1]= 1.0e30f; (max)[0]= (max)[1]= -1.0e30f; }
+ #define DO_MIN(vec, min) { if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0];      \
+                                                         if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1];   \
+                                                         if( (min)[2]>(vec)[2] ) (min)[2]= (vec)[2]; } \
+ #define DO_MAX(vec, max) { if( (max)[0]<(vec)[0] ) (max)[0]= (vec)[0];                \
+                                                         if( (max)[1]<(vec)[1] ) (max)[1]= (vec)[1];   \
+                                                         if( (max)[2]<(vec)[2] ) (max)[2]= (vec)[2]; } \
+ #define DO_MINMAX(vec, min, max) { if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0]; \
+                                                         if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1]; \
+                                                         if( (min)[2]>(vec)[2] ) (min)[2]= (vec)[2]; \
+                                                         if( (max)[0]<(vec)[0] ) (max)[0]= (vec)[0]; \
+                                                         if( (max)[1]<(vec)[1] ) (max)[1]= (vec)[1]; \
+                                                         if( (max)[2]<(vec)[2] ) (max)[2]= (vec)[2]; } \
+ #define DO_MINMAX2(vec, min, max) { if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0]; \
+                                                         if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1]; \
+                                                         if( (max)[0]<(vec)[0] ) (max)[0]= (vec)[0]; \
+                                                         if( (max)[1]<(vec)[1] ) (max)[1]= (vec)[1]; }
+ /* some math and copy defines */
+ #ifndef SWAP
+ #define SWAP(type, a, b)        { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
+ #endif
+ #define ABS(a)                                        ( (a)<0 ? (-(a)) : (a) )
+ #define AVG2(x, y)            ( 0.5 * ((x) + (y)) )
+ #define FTOCHAR(val) ((val)<=0.0f)? 0 : (((val)>(1.0f-0.5f/255.0f))? 255 : (char)((255.0f*(val))+0.5f))
+ #define FTOUSHORT(val) ((val >= 1.0f-0.5f/65535)? 65535: (val <= 0.0f)? 0: (unsigned short)(val*65535.0f + 0.5f))
+ #define VECCOPY(v1,v2)          {*(v1)= *(v2); *(v1+1)= *(v2+1); *(v1+2)= *(v2+2);}
+ #define VECCOPY2D(v1,v2)          {*(v1)= *(v2); *(v1+1)= *(v2+1);}
+ #define QUATCOPY(v1,v2)         {*(v1)= *(v2); *(v1+1)= *(v2+1); *(v1+2)= *(v2+2); *(v1+3)= *(v2+3);}
+ #define LONGCOPY(a, b, c)     {int lcpc=c, *lcpa=(int *)a, *lcpb=(int *)b; while(lcpc-->0) *(lcpa++)= *(lcpb++);}
+ #define VECADD(v1,v2,v3)      {*(v1)= *(v2) + *(v3); *(v1+1)= *(v2+1) + *(v3+1); *(v1+2)= *(v2+2) + *(v3+2);}
+ #define VECSUB(v1,v2,v3)      {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1); *(v1+2)= *(v2+2) - *(v3+2);}
+ #define VECSUB2D(v1,v2,v3)    {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1);}
+ #define VECADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac);}
+ #define VECSUBFAC(v1,v2,v3,fac) {*(v1)= *(v2) - *(v3)*(fac); *(v1+1)= *(v2+1) - *(v3+1)*(fac); *(v1+2)= *(v2+2) - *(v3+2)*(fac);}
+ #define QUATADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac); *(v1+3)= *(v2+3) + *(v3+3)*(fac);}
+ #define INPR(v1, v2)          ( (v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2] )
+ /* some misc stuff.... */
+ #define CLAMP(a, b, c)                if((a)<(b)) (a)=(b); else if((a)>(c)) (a)=(c)
+ #define CLAMPIS(a, b, c) ((a)<(b) ? (b) : (a)>(c) ? (c) : (a))
+ #define CLAMPTEST(a, b, c)    if((b)<(c)) {CLAMP(a, b, c);} else {CLAMP(a, c, b);}
+ #define IS_EQ(a,b) ((fabs((double)(a)-(b)) >= (double) FLT_EPSILON) ? 0 : 1)
+ #define IS_EQT(a, b, c) ((a > b)? (((a-b) <= c)? 1:0) : ((((b-a) <= c)? 1:0)))
+ #define IN_RANGE(a, b, c) ((b < c)? ((b<a && a<c)? 1:0) : ((c<a && a<b)? 1:0))
+ #define IN_RANGE_INCL(a, b, c) ((b < c)? ((b<=a && a<=c)? 1:0) : ((c<=a && a<=b)? 1:0))
+ /* This one rotates the bytes in an int64, int (32) and short (16) */
+ #define SWITCH_INT64(a) { \
+       char s_i, *p_i; \
+       p_i= (char *)&(a); \
+       s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \
+       s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \
+       s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \
+       s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; }
+               #define SWITCH_INT(a) { \
+       char s_i, *p_i; \
+       p_i= (char *)&(a); \
+       s_i=p_i[0]; p_i[0]=p_i[3]; p_i[3]=s_i; \
+       s_i=p_i[1]; p_i[1]=p_i[2]; p_i[2]=s_i; }
+ #define SWITCH_SHORT(a)       { \
+       char s_i, *p_i; \
+       p_i= (char *)&(a); \
+       s_i=p_i[0]; p_i[0]=p_i[1]; p_i[1]=s_i; }
+ /* Warning-free macros for storing ints in pointers. Use these _only_
+  * for storing an int in a pointer, not a pointer in an int (64bit)! */
+ #define SET_INT_IN_POINTER(i) ((void*)(intptr_t)(i))
+ #define GET_INT_FROM_POINTER(i) ((int)(intptr_t)(i))
+ /* Macro to convert a value to string in the preprocessor
+  * STRINGIFY_ARG: gives the defined name in the string
+  * STRINGIFY: gives the defined value. */
+ #define STRINGIFY_ARG(x) #x
+ #define STRINGIFY(x) STRINGIFY_ARG(x)
+ /* useful for debugging */
+ #define AT __FILE__ ":" STRINGIFY(__LINE__)
+ /* UNUSED macro, for function argument */
+ #ifdef __GNUC__
+ #  define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
+ #else
+ #  define UNUSED(x) UNUSED_ ## x
+ #endif
+ /*little macro so inline keyword works*/
+ #if defined(_MSC_VER)
+ #  define BM_INLINE static __forceinline
+ #elif defined(__GNUC__)
+ #  define BM_INLINE static inline __attribute((always_inline))
+ #else
+ /* #warning "MSC/GNUC defines not found, inline non-functional" */
+ #  define BM_INLINE static
+ #endif
+ /* BLI_assert(), default only to print
+  * for aborting need to define WITH_ASSERT_ABORT
+  */
+ #if !defined NDEBUG
+ #  ifdef WITH_ASSERT_ABORT
+ #    define _dummy_abort abort
+ #  else
+ #    define _dummy_abort() (void)0
+ #  endif
+ #  ifdef __GNUC__ /* just want to check if __func__ is available */
+ #    define BLI_assert(a) \
+ do { \
+       if (0 == (a)) { \
+               fprintf(stderr, \
+                       "BLI_assert failed: %s, %s(), %d at \'%s\'\n", \
+                       __FILE__, __func__, __LINE__, STRINGIFY(a)); \
+               _dummy_abort(); \
+       } \
+ } while (0)
+ #  else
+ #    define BLI_assert(a) \
+ do { \
+       if (0 == (a)) { \
+               fprintf(stderr, \
+                       "BLI_assert failed: %s, %d at \'%s\'\n", \
+                       __FILE__, __LINE__, STRINGIFY(a)); \
+               _dummy_abort(); \
+       } \
+ } while (0)
+ #  endif
+ #else
+ #  define BLI_assert(a) (void)0
+ #endif
+ #endif // BLI_UTILDEFINES_H
@@@ -11162,26 -11246,124 +11251,178 @@@ static void do_versions(FileData *fd, L
                for(part = main->particle.first; part; part = part->id.next) {
                        if(part->boids)
                                part->boids->pitch = 1.0f;
+                       part->flag &= ~PART_HAIR_REGROW; /* this was a deprecated flag before */
+                       part->kink_amp_clump = 1.f; /* keep old files looking similar */
+               }
+               for (sc= main->screen.first; sc; sc= sc->id.next) {
+                       ScrArea *sa;
+                       for (sa= sc->areabase.first; sa; sa= sa->next) {
+                               SpaceLink *sl;
+                               for (sl= sa->spacedata.first; sl; sl= sl->next) {
+                                       if (sl->spacetype == SPACE_INFO) {
+                                               SpaceInfo *sinfo= (SpaceInfo *)sl;
+                                               ARegion *ar;
+                                               sinfo->rpt_mask= INFO_RPT_OP;
+                                               for (ar= sa->regionbase.first; ar; ar= ar->next) {
+                                                       if (ar->regiontype == RGN_TYPE_WINDOW) {
+                                                               ar->v2d.scroll = (V2D_SCROLL_RIGHT);
+                                                               ar->v2d.align = V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_NEG_Y; /* align bottom left */
+                                                               ar->v2d.keepofs = V2D_LOCKOFS_X;
+                                                               ar->v2d.keepzoom = (V2D_LOCKZOOM_X|V2D_LOCKZOOM_Y|V2D_LIMITZOOM|V2D_KEEPASPECT);
+                                                               ar->v2d.keeptot= V2D_KEEPTOT_BOUNDS;
+                                                               ar->v2d.minzoom= ar->v2d.maxzoom= 1.0f;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+               /* fix rotation actuators for objects so they use real angles (radians)
+                * since before blender went opensource this strange scalar was used: (1 / 0.02) * 2 * math.pi/360 */
+               for(ob= main->object.first; ob; ob= ob->id.next) {
+                       bActuator *act= ob->actuators.first;
+                       while(act) {
+                               if (act->type==ACT_OBJECT) {
+                                       /* multiply velocity with 50 in old files */
+                                       bObjectActuator *oa= act->data;
+                                       mul_v3_fl(oa->drot, 0.8726646259971648f);
+                               }
+                               act= act->next;
+                       }
                }
        }
 +
 +      // init facing axis property of steering actuators
 +      {                                       
 +              Object *ob;
 +              for(ob = main->object.first; ob; ob = ob->id.next) {
 +                      bActuator *act;
 +                      for(act= ob->actuators.first; act; act= act->next) {
 +                              if(act->type==ACT_STEERING) {
 +                                      bSteeringActuator* stact = act->data;
 +                                      if (stact->facingaxis==0)
 +                                      {
 +                                              stact->facingaxis=1;
 +                                      }                                               
 +                              }
 +                      }
 +              }
 +      }
+       
+       if (main->versionfile < 256) {
+               bScreen *sc;
+               ScrArea *sa;
+               Key *key;
+               
+               /* Fix for sample line scope initializing with no height */
+               for(sc= main->screen.first; sc; sc= sc->id.next) {
+                       sa= sc->areabase.first;
+                       while(sa) {
+                               SpaceLink *sl;
+                               for (sl= sa->spacedata.first; sl; sl= sl->next) {
+                                       if(sl->spacetype==SPACE_IMAGE) {
+                                               SpaceImage *sima= (SpaceImage *)sl;
+                                               if (sima->sample_line_hist.height == 0 )
+                                                       sima->sample_line_hist.height = 100;
+                                       }
+                               }
+                               sa= sa->next;
+                       }
+               }
+               
+               /* old files could have been saved with slidermin = slidermax = 0.0, but the UI in
+                * 2.4x would never reveal this to users as a dummy value always ended up getting used
+                * instead
+                */
+               for (key = main->key.first; key; key = key->id.next) {
+                       KeyBlock *kb;
+                       
+                       for (kb = key->block.first; kb; kb = kb->next) {
+                               if (IS_EQ(kb->slidermin, kb->slidermax) && IS_EQ(kb->slidermax, 0))
+                                       kb->slidermax = kb->slidermin + 1.0f;
+                       }
+               }
+       }
+       
+       if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 1)) {
+               /* fix for bones that didn't have arm_roll before */
+               bArmature* arm;
+               Bone* bone;
+               Object *ob;
+               for (arm = main->armature.first; arm; arm = arm->id.next)
+                       for (bone = arm->bonebase.first; bone; bone = bone->next)
+                               do_version_bone_roll_256(bone);
+               /* fix for objects which have zero dquat's
+                * since this is multiplied with the quat rather then added */
+               for(ob= main->object.first; ob; ob= ob->id.next) {
+                       if(is_zero_v4(ob->dquat)) {
+                               unit_qt(ob->dquat);
+                       }
+                       if(is_zero_v3(ob->drotAxis) && ob->drotAngle == 0.0f) {
+                               unit_axis_angle(ob->drotAxis, &ob->drotAngle);
+                       }
+               }
+       }
+       /* put compatibility code here until next subversion bump */
+       
+       {
+               bScreen *sc;
+               
+               /* redraws flag in SpaceTime has been moved to Screen level */
+               for (sc = main->screen.first; sc; sc= sc->id.next) {
+                       if (sc->redraws_flag == 0) {
+                               /* just initialise to default? */
+                               // XXX: we could also have iterated through areas, and taken them from the first timeline available...
+                               sc->redraws_flag = TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN;
+                       }
+               }
+       }
++      //set defaults for obstacle avoidance, recast data
++      {
++              Scene *sce;
++              for(sce = main->scene.first; sce; sce = sce->id.next)
++              {
++                      if (sce->gm.levelHeight == 0.f)
++                              sce->gm.levelHeight = 2.f;
++
++                      if(sce->gm.recastData.cellsize == 0.0f)
++                              sce->gm.recastData.cellsize = 0.3f;
++                      if(sce->gm.recastData.cellheight == 0.0f)
++                              sce->gm.recastData.cellheight = 0.2f;
++                      if(sce->gm.recastData.agentmaxslope == 0.0f)
++                              sce->gm.recastData.agentmaxslope = M_PI/4;
++                      if(sce->gm.recastData.agentmaxclimb == 0.0f)
++                              sce->gm.recastData.agentmaxclimb = 0.9f;
++                      if(sce->gm.recastData.agentheight == 0.0f)
++                              sce->gm.recastData.agentheight = 2.0f;
++                      if(sce->gm.recastData.agentradius == 0.0f)
++                              sce->gm.recastData.agentradius = 0.6f;
++                      if(sce->gm.recastData.edgemaxlen == 0.0f)
++                              sce->gm.recastData.edgemaxlen = 12.0f;
++                      if(sce->gm.recastData.edgemaxerror == 0.0f)
++                              sce->gm.recastData.edgemaxerror = 1.3f;
++                      if(sce->gm.recastData.regionminsize == 0.0f)
++                              sce->gm.recastData.regionminsize = 50.f;
++                      if(sce->gm.recastData.regionmergesize == 0.0f)
++                              sce->gm.recastData.regionmergesize = 20.f;
++                      if(sce->gm.recastData.vertsperpoly<3)
++                              sce->gm.recastData.vertsperpoly = 6;
++                      if(sce->gm.recastData.detailsampledist == 0.0f)
++                              sce->gm.recastData.detailsampledist = 6.0f;
++                      if(sce->gm.recastData.detailsamplemaxerror == 0.0f)
++                              sce->gm.recastData.detailsamplemaxerror = 1.0f;
++              }                       
++      }
 +
        /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
        /* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */
  
index 0000000,836c1fa..865e11a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1152 +1,1152 @@@
 - * $Id$
+ /**
++ * $Id: AnimationImporter.cpp 34787 2011-02-12 06:25:04Z campbellbarton $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ /* COLLADABU_ASSERT, may be able to remove later */
+ #include "COLLADABUPlatform.h"
+ #include "DNA_armature_types.h"
+ #include "ED_keyframing.h"
+ #include "BLI_listbase.h"
+ #include "BLI_math.h"
+ #include "BLI_path_util.h"
+ #include "BLI_string.h"
+ #include "BKE_action.h"
+ #include "BKE_armature.h"
+ #include "BKE_fcurve.h"
+ #include "BKE_object.h"
+ #include "MEM_guardedalloc.h"
+ #include "collada_utils.h"
+ #include "AnimationImporter.h"
+ #include "ArmatureImporter.h"
+ #include <algorithm>
+ // use this for retrieving bone names, since these must be unique
+ template<class T>
+ static const char *bc_get_joint_name(T *node)
+ {
+       const std::string& id = node->getOriginalId();
+       return id.size() ? id.c_str() : node->getName().c_str();
+ }
+ FCurve *AnimationImporter::create_fcurve(int array_index, const char *rna_path)
+ {
+       FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
+       
+       fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
+       fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
+       fcu->array_index = array_index;
+       return fcu;
+ }
+       
+ void AnimationImporter::create_bezt(FCurve *fcu, float frame, float output)
+ {
+       BezTriple bez;
+       memset(&bez, 0, sizeof(BezTriple));
+       bez.vec[1][0] = frame;
+       bez.vec[1][1] = output;
+       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);
+ }
+ // create one or several fcurves depending on the number of parameters being animated
+ void AnimationImporter::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();
+       unsigned int i;
+       std::vector<FCurve*>& fcurves = curve_map[curve->getUniqueId()];
+       switch (dim) {
+       case 1: // X, Y, Z or angle
+       case 3: // XYZ
+       case 16: // matrix
+               {
+                       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 (unsigned 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] = bc_get_float_value(input, j) * fps; 
+                                       bez.vec[1][1] = bc_get_float_value(output, j * dim + 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);
+                       }
+               }
+               break;
+       default:
+               fprintf(stderr, "Output dimension of %d is not yet supported (animation id = %s)\n", (int)dim, curve->getOriginalId().c_str());
+       }
+       for (std::vector<FCurve*>::iterator it = fcurves.begin(); it != fcurves.end(); it++)
+               unused_curves.push_back(*it);
+ }
+ void AnimationImporter::fcurve_deg_to_rad(FCurve *cu)
+ {
+       for (unsigned int i = 0; i < cu->totvert; i++) {
+               // TODO convert handles too
+               cu->bezt[i].vec[1][1] *= M_PI / 180.0f;
+       }
+ }
+ void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated)
+ {
+       bAction *act;
+       
+       if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID*)&ob->id, 1);
+       else act = ob->adt->action;
+       
+       std::vector<FCurve*>::iterator it;
+       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(), 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;
+       
+               if (ob->type == OB_ARMATURE) {
+                       bActionGroup *grp = NULL;
+                       const char *bone_name = bc_get_joint_name(animated->node);
+                       
+                       if (bone_name) {
+                               /* try to find group */
+                               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);
+                               
+                       }
+ #if 0
+                       if (is_rotation) {
+                               fcurves_actionGroup_map[grp].push_back(fcu);
+                       }
+ #endif
+               }
+               else {
+                       BLI_addtail(&act->curves, fcu);
+               }
+               // curve is used, so remove it from unused_curves
+               unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end());
+       }
+ }
+ AnimationImporter::AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
+               TransformReader(conv), armature_importer(arm), scene(scene) { }
+ AnimationImporter::~AnimationImporter()
+ {
+       // 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 %d unused curves\n", (int)unused_curves.size());
+ }
+ bool AnimationImporter::write_animation(const COLLADAFW::Animation* anim) 
+ {
+       if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) {
+               COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve*)anim;
+               
+               // XXX Don't know if it's necessary
+               // Should we check outPhysicalDimension?
+               if (curve->getInPhysicalDimension() != COLLADAFW::PHYSICAL_DIMENSION_TIME) {
+                       fprintf(stderr, "Inputs physical dimension is not time. \n");
+                       return true;
+               }
+               // 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:
+                       case COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER:
+                               animation_to_fcurves(curve);
+                               break;
+                       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;
+                       }
+               }
+               else {
+                       // not supported yet
+                       fprintf(stderr, "MIXED anim interpolation type is not supported yet.\n");
+               }
+       }
+       else {
+               fprintf(stderr, "FORMULA animation type is not supported yet.\n");
+       }
+       
+       return true;
+ }
+       
+ // called on post-process stage after writeVisualScenes
+ bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList* animlist) 
+ {
+       const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId();
+       animlist_map[animlist_id] = animlist;
+ #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[animlist_id];
+       Object *ob = animated.ob;
+       char rna_path[100];
+       char joint_path[100];
+       bool is_joint = false;
+       // if ob is NULL, it should be a JOINT
+       if (!ob) {
+               ob = armature_importer->get_armature_for_joint(animated.node);
+               if (!ob) {
+                       fprintf(stderr, "Cannot find armature for node %s\n", get_joint_name(animated.node));
+                       return true;
+               }
+               armature_importer->get_rna_path_for_joint(animated.node, joint_path, sizeof(joint_path));
+               is_joint = true;
+       }
+       
+       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.%s", joint_path, loc ? "location" : "scale");
+                       else
+                               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 (curve_map.find(anim_uid) == curve_map.end()) {
+                                       fprintf(stderr, "Cannot find FCurve by animation UID.\n");
+                                       continue;
+                               }
+                               std::vector<FCurve*>& fcurves = curve_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 %s.\n",
+                                                       binding.animationClass, loc ? "TRANSLATE" : "SCALE");
+                               }
+                       }
+               }
+               break;
+       case COLLADAFW::Transformation::ROTATE:
+               {
+                       if (is_joint)
+                               BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_euler", joint_path);
+                       else
+                               BLI_strncpy(rna_path, "rotation_euler", sizeof(rna_path));
+                       COLLADAFW::Rotate* rot = (COLLADAFW::Rotate*)animated.tm;
+                       COLLADABU::Math::Vector3& axis = rot->getRotationAxis();
+                       
+                       for (int i = 0; i < bindings.getCount(); i++) {
+                               const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
+                               COLLADAFW::UniqueId anim_uid = binding.animation;
+                               if (curve_map.find(anim_uid) == curve_map.end()) {
+                                       fprintf(stderr, "Cannot find FCurve by animation UID.\n");
+                                       continue;
+                               }
+                               std::vector<FCurve*>& fcurves = curve_map[anim_uid];
+                               switch (binding.animationClass) {
+                               case COLLADAFW::AnimationList::ANGLE:
+                                       if (COLLADABU::Math::Vector3::UNIT_X == axis) {
+                                               add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated);
+                                       }
+                                       else if (COLLADABU::Math::Vector3::UNIT_Y == axis) {
+                                               add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated);
+                                       }
+                                       else if (COLLADABU::Math::Vector3::UNIT_Z == axis) {
+                                               add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated);
+                                       }
+                                       break;
+                               case COLLADAFW::AnimationList::AXISANGLE:
+                                       // TODO convert axis-angle to quat? or XYZ?
+                               default:
+                                       fprintf(stderr, "AnimationClass %d is not supported for ROTATE 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;
+ }
+ void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob)
+ {
+       float mat[4][4];
+       TransformReader::get_node_mat(mat, node, &uid_animated_map, ob);
+       if (ob) {
+               copy_m4_m4(ob->obmat, mat);
+               object_apply_mat4(ob, ob->obmat, 0, 0);
+       }
+ }
+ #if 0
+ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act)
+ {
+       bActionGroup *grp;
+       int i;
+       
+       for (grp = (bActionGroup*)act->groups.first; grp; grp = grp->next) {
+               FCurve *eulcu[3] = {NULL, NULL, NULL};
+               
+               if (fcurves_actionGroup_map.find(grp) == fcurves_actionGroup_map.end())
+                       continue;
+               std::vector<FCurve*> &rot_fcurves = fcurves_actionGroup_map[grp];
+               
+               if (rot_fcurves.size() > 3) continue;
+               for (i = 0; i < rot_fcurves.size(); i++)
+                       eulcu[rot_fcurves[i]->array_index] = rot_fcurves[i];
+               char joint_path[100];
+               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_quaternion", joint_path);
+               FCurve *quatcu[4] = {
+                       create_fcurve(0, rna_path),
+                       create_fcurve(1, rna_path),
+                       create_fcurve(2, 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];
+                       if (!cu) continue;
+                       for (int j = 0; j < cu->totvert; j++) {
+                               float frame = cu->bezt[j].vec[1][0];
+                               float eul[3] = {
+                                       eulcu[0] ? evaluate_fcurve(eulcu[0], frame) : 0.0f,
+                                       eulcu[1] ? evaluate_fcurve(eulcu[1], frame) : 0.0f,
+                                       eulcu[2] ? evaluate_fcurve(eulcu[2], frame) : 0.0f
+                               };
+                               // 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);
+                               mat3_to_quat(quat, rel);
+                               */
+                               eul_to_quat(quat, eul);
+                               for (int k = 0; k < 4; k++)
+                                       create_bezt(quatcu[k], frame, quat[k]);
+                       }
+               }
+               // now replace old Euler curves
+               for (i = 0; i < 3; i++) {
+                       if (!eulcu[i]) continue;
+                       action_groups_remove_channel(act, eulcu[i]);
+                       free_fcurve(eulcu[i]);
+               }
+               chan->rotmode = ROT_MODE_QUAT;
+               for (i = 0; i < 4; i++)
+                       action_groups_add_channel(act, grp, quatcu[i]);
+       }
+       bPoseChannel *pchan;
+       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)
+ Object *AnimationImporter::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)
+ {
+       bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE;
+       bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX;
+       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 ? bc_get_joint_name(node) : NULL;
+       if (!ob) {
+               fprintf(stderr, "cannot find Object for Node with id=\"%s\"\n", node->getOriginalId().c_str());
+               return NULL;
+       }
+       // 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();
+       unsigned int i;
+       // find frames at which to sample plus convert all rotation 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 (unsigned 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) || is_matrix) {
+                                                       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 (unsigned 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 %d curves, got %d\n", xyz ? 3 : 1, (int)curves.size());
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       float irest_dae[4][4];
+       float rest[4][4], irest[4][4];
+       if (is_joint) {
+               get_joint_rest_mat(irest_dae, root, node);
+               invert_m4(irest_dae);
+               Bone *bone = get_named_bone((bArmature*)ob->data, bone_name);
+               if (!bone) {
+                       fprintf(stderr, "cannot find bone \"%s\"\n", bone_name);
+                       return NULL;
+               }
+               unit_m4(rest);
+               copy_m4_m4(rest, bone->arm_mat);
+               invert_m4_m4(irest, rest);
+       }
+       Object *job = NULL;
+ #ifdef ARMATURE_TEST
+       FCurve *job_curves[10];
+       job = get_joint_object(root, node, par_job);
+ #endif
+       if (frames.size() == 0)
+               return job;
+       std::sort(frames.begin(), frames.end());
+       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;
+       case COLLADAFW::Transformation::MATRIX:
+               break;
+       default:
+               return job;
+       }
+       char rna_path[200];
+       char joint_path[200];
+       if (is_joint)
+               armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path));
+       // new curves
+       FCurve *newcu[10]; // if tm_type is matrix, then create 10 curves: 4 rot, 3 loc, 3 scale
+       unsigned int totcu = is_matrix ? 10 : (is_rotation ? 4 : 3);
+       for (i = 0; i < totcu; i++) {
+               int axis = i;
+               if (is_matrix) {
+                       if (i < 4) {
+                               tm_str = "rotation_quaternion";
+                               axis = i;
+                       }
+                       else if (i < 7) {
+                               tm_str = "location";
+                               axis = i - 4;
+                       }
+                       else {
+                               tm_str = "scale";
+                               axis = i - 7;
+                       }
+               }
+               if (is_joint)
+                       BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, tm_str);
+               else
+                       strcpy(rna_path, tm_str);
+               newcu[i] = create_fcurve(axis, rna_path);
+ #ifdef ARMATURE_TEST
+               if (is_joint)
+                       job_curves[i] = create_fcurve(axis, 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];
+               float matfra[4][4];
+               unit_m4(matfra);
+               // calc object-space mat
+               evaluate_transform_at_frame(matfra, 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, matfra, 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);
+               }
+               else {
+                       copy_m4_m4(mat, matfra);
+               }
+               float val[4], rot[4], loc[3], scale[3];
+               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;
+               case COLLADAFW::Transformation::MATRIX:
+                       mat4_to_quat(rot, mat);
+                       copy_v3_v3(loc, mat[3]);
+                       mat4_to_size(scale, mat);
+                       break;
+               default:
+                       break;
+               }
+               // add keys
+               for (i = 0; i < totcu; i++) {
+                       if (is_matrix) {
+                               if (i < 4)
+                                       add_bezt(newcu[i], fra, rot[i]);
+                               else if (i < 7)
+                                       add_bezt(newcu[i], fra, loc[i - 4]);
+                               else
+                                       add_bezt(newcu[i], fra, scale[i - 7]);
+                       }
+                       else {
+                               add_bezt(newcu[i], fra, val[i]);
+                       }
+               }
+ #ifdef ARMATURE_TEST
+               if (is_joint) {
+                       switch (tm_type) {
+                       case COLLADAFW::Transformation::ROTATE:
+                               mat4_to_quat(val, matfra);
+                               break;
+                       case COLLADAFW::Transformation::SCALE:
+                               mat4_to_size(val, matfra);
+                               break;
+                       case COLLADAFW::Transformation::TRANSLATE:
+                               copy_v3_v3(val, matfra[3]);
+                               break;
+                       case MATRIX:
+                               mat4_to_quat(rot, matfra);
+                               copy_v3_v3(loc, matfra[3]);
+                               mat4_to_size(scale, matfra);
+                               break;
+                       default:
+                               break;
+                       }
+                       for (i = 0; i < totcu; i++) {
+                               if (is_matrix) {
+                                       if (i < 4)
+                                               add_bezt(job_curves[i], fra, rot[i]);
+                                       else if (i < 7)
+                                               add_bezt(job_curves[i], fra, loc[i - 4]);
+                                       else
+                                               add_bezt(job_curves[i], fra, scale[i - 7]);
+                               }
+                               else {
+                                       add_bezt(job_curves[i], fra, val[i]);
+                               }
+                       }
+               }
+ #endif
+       }
+       verify_adt_action((ID*)&ob->id, 1);
+       ListBase *curves = &ob->adt->action->curves;
+       // 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 || is_matrix) {
+               if (is_joint) {
+                       bPoseChannel *chan = get_pose_channel(ob->pose, bone_name);
+                       chan->rotmode = ROT_MODE_QUAT;
+               }
+               else {
+                       ob->rotmode = ROT_MODE_QUAT;
+               }
+       }
+       return job;
+ }
+ // internal, better make it private
+ // warning: evaluates only rotation
+ // prerequisites: animlist_map, curve_map
+ void AnimationImporter::evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra)
+ {
+       const COLLADAFW::TransformationPointerArray& tms = node->getTransformations();
+       unit_m4(mat);
+       for (unsigned 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, node->getOriginalId().c_str())) {
+                       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);
+       }
+ }
+ // return true to indicate that mat contains a sane value
+ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra, const char *node_id)
+ {
+       const COLLADAFW::UniqueId& listid = tm->getAnimationList();
+       COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
+       if (type != COLLADAFW::Transformation::ROTATE &&
+           type != COLLADAFW::Transformation::SCALE &&
+           type != COLLADAFW::Transformation::TRANSLATE &&
+           type != COLLADAFW::Transformation::MATRIX) {
+               fprintf(stderr, "animation of transformation %d is not supported yet\n", type);
+               return false;
+       }
+       if (animlist_map.find(listid) == animlist_map.end())
+               return false;
+       const COLLADAFW::AnimationList *animlist = animlist_map[listid];
+       const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
+       if (bindings.getCount()) {
+               float vec[3];
+               bool is_scale = (type == COLLADAFW::Transformation::SCALE);
+               bool is_translate = (type == COLLADAFW::Transformation::TRANSLATE);
+               if (type == COLLADAFW::Transformation::SCALE)
+                       dae_scale_to_v3(tm, vec);
+               else if (type == COLLADAFW::Transformation::TRANSLATE)
+                       dae_translate_to_v3(tm, vec);
+               for (unsigned int j = 0; j < bindings.getCount(); j++) {
+                       const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[j];
+                       std::vector<FCurve*>& curves = curve_map[binding.animation];
+                       COLLADAFW::AnimationList::AnimationClass animclass = binding.animationClass;
+                       char path[100];
+                       switch (type) {
+                       case COLLADAFW::Transformation::ROTATE:
+                               BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, j);
+                               break;
+                       case COLLADAFW::Transformation::SCALE:
+                               BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, j);
+                               break;
+                       case COLLADAFW::Transformation::TRANSLATE:
+                               BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, j);
+                               break;
+                       case COLLADAFW::Transformation::MATRIX:
+                               BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, j);
+                               break;
+                       default:
+                               break;
+                       }
+                       if (animclass == COLLADAFW::AnimationList::UNKNOWN_CLASS) {
+                               fprintf(stderr, "%s: UNKNOWN animation class\n", path);
+                               continue;
+                       }
+                       if (type == COLLADAFW::Transformation::ROTATE) {
+                               if (curves.size() != 1) {
+                                       fprintf(stderr, "expected 1 curve, got %d\n", (int)curves.size());
+                                       return false;
+                               }
+                               // TODO support other animclasses
+                               if (animclass != COLLADAFW::AnimationList::ANGLE) {
+                                       fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass);
+                                       return false;
+                               }
+                               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 if (is_scale || is_translate) {
+                               bool is_xyz = animclass == COLLADAFW::AnimationList::POSITION_XYZ;
+                               if ((!is_xyz && curves.size() != 1) || (is_xyz && curves.size() != 3)) {
+                                       if (is_xyz)
+                                               fprintf(stderr, "%s: expected 3 curves, got %d\n", path, (int)curves.size());
+                                       else
+                                               fprintf(stderr, "%s: expected 1 curve, got %d\n", path, (int)curves.size());
+                                       return false;
+                               }
+                               
+                               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: animation class %d is not supported yet\n", path, animclass);
+                                       break;
+                               }
+                       }
+                       else if (type == COLLADAFW::Transformation::MATRIX) {
+                               // for now, of matrix animation, support only the case when all values are packed into one animation
+                               if (curves.size() != 16) {
+                                       fprintf(stderr, "%s: expected 16 curves, got %d\n", path, (int)curves.size());
+                                       return false;
+                               }
+                               COLLADABU::Math::Matrix4 matrix;
+                               int i = 0, j = 0;
+                               for (std::vector<FCurve*>::iterator it = curves.begin(); it != curves.end(); it++) {
+                                       matrix.setElement(i, j, evaluate_fcurve(*it, fra));
+                                       j++;
+                                       if (j == 4) {
+                                               i++;
+                                               j = 0;
+                                       }
+                               }
+                               COLLADAFW::Matrix tm(matrix);
+                               dae_matrix_to_mat4(&tm, mat);
+                               return true;
+                       }
+               }
+               if (is_scale)
+                       size_to_mat4(mat, vec);
+               else
+                       copy_v3_v3(mat[3], vec);
+               return is_scale || is_translate;
+       }
+       return false;
+ }
+ // gives a world-space mat of joint at rest position
+ void AnimationImporter::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 AnimationImporter::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)) {
+               if (par) {
+                       float temp[4][4];
+                       get_node_mat(temp, node, NULL, NULL);
+                       mul_m4_m4m4(m, temp, par);
+               }
+               else {
+                       get_node_mat(m, node, NULL, NULL);
+               }
+       }
+       COLLADAFW::NodePointerArray& children = node->getChildNodes();
+       for (unsigned 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 *AnimationImporter::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(CTX_data_main(C), 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 AnimationImporter::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 AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu)
+ {
+       const char *bone_name = bc_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 AnimationImporter::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);
+ }
index 0000000,01abac3..effb129
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,132 +1,132 @@@
 - * $Id$
+ /**
++ * $Id: AnimationImporter.h 32310 2010-10-05 00:49:39Z gsrb3d $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+  
+ #ifndef __BC_ANIMATIONIMPORTER_H__
+ #define __BC_ANIMATIONIMPORTER_H__
+ #include <map>
+ #include <vector>
+ #include "COLLADAFWAnimation.h"
+ #include "COLLADAFWAnimationCurve.h"
+ #include "COLLADAFWAnimationList.h"
+ #include "COLLADAFWNode.h"
+ #include "COLLADAFWUniqueId.h"
+ #include "DNA_anim_types.h"
+ #include "DNA_object_types.h"
+ #include "DNA_scene_types.h"
+ //#include "ArmatureImporter.h"
+ #include "TransformReader.h"
+ #include "collada_internal.h"
+ class ArmatureImporter;
+ class AnimationImporterBase
+ {
+ public:
+       // virtual void change_eul_to_quat(Object *ob, bAction *act) = 0;
+ };
+ class AnimationImporter : private TransformReader, public AnimationImporterBase
+ {
+ private:
+       ArmatureImporter *armature_importer;
+       Scene *scene;
+       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<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, const char *rna_path);
+       
+       void create_bezt(FCurve *fcu, float frame, float output);
+       // create one or several fcurves depending on the number of parameters being animated
+       void animation_to_fcurves(COLLADAFW::AnimationCurve *curve);
+       void fcurve_deg_to_rad(FCurve *cu);
+       void add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated);
+ public:
+       AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene);
+       ~AnimationImporter();
+       bool write_animation(const COLLADAFW::Animation* anim);
+       
+       // called on post-process stage after writeVisualScenes
+       bool write_animation_list(const COLLADAFW::AnimationList* animlist);
+       void read_node_transform(COLLADAFW::Node *node, Object *ob);
+ #if 0
+       virtual void change_eul_to_quat(Object *ob, bAction *act);
+ #endif
+       // prerequisites:
+       // animlist_map - map animlist id -> animlist
+       // curve_map - map anim id -> curve(s)
+       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);
+       // 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);
+       // return true to indicate that mat contains a sane value
+       bool evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra, const char *node_id);
+       // 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);
+       // 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);
+ #ifdef ARMATURE_TEST
+       Object *get_joint_object(COLLADAFW::Node *root, COLLADAFW::Node *node, Object *par_job);
+ #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);
+ #endif
+       void add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu);
+       void add_bezt(FCurve *fcu, float fra, float value);
+ };
+  
+  #endif
index 0000000,1427c33..79eadf4
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,469 +1,469 @@@
 - * $Id$
+ /**
++ * $Id: ArmatureExporter.cpp 34533 2011-01-27 19:39:06Z jesterking $
+  *
+  * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include "COLLADASWBaseInputElement.h"
+ #include "COLLADASWInstanceController.h"
+ #include "COLLADASWPrimitves.h"
+ #include "COLLADASWSource.h"
+ #include "DNA_action_types.h"
+ #include "DNA_meshdata_types.h"
+ #include "DNA_modifier_types.h"
+ #include "BKE_action.h"
+ #include "BKE_armature.h"
+ #include "BLI_listbase.h"
+ #include "GeometryExporter.h"
+ #include "ArmatureExporter.h"
+ // XXX exporter writes wrong data for shared armatures.  A separate
+ // controller should be written for each armature-mesh binding how do
+ // we make controller ids then?
+ ArmatureExporter::ArmatureExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryControllers(sw) {}
+ // write bone nodes
+ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce)
+ {
+       // write bone nodes
+       bArmature *arm = (bArmature*)ob_arm->data;
+       for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) {
+               // start from root bones
+               if (!bone->parent)
+                       add_bone_node(bone, ob_arm);
+       }
+ }
+ bool ArmatureExporter::is_skinned_mesh(Object *ob)
+ {
+       return get_assigned_armature(ob) != NULL;
+ }
+ void ArmatureExporter::add_instance_controller(Object *ob)
+ {
+       Object *ob_arm = get_assigned_armature(ob);
+       bArmature *arm = (bArmature*)ob_arm->data;
+       const std::string& controller_id = get_controller_id(ob_arm, ob);
+       COLLADASW::InstanceController ins(mSW);
+       ins.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, controller_id));
+       // write root bone URLs
+       Bone *bone;
+       for (bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) {
+               if (!bone->parent)
+                       ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm)));
+       }
+       InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob);
+               
+       ins.add();
+ }
+ void ArmatureExporter::export_controllers(Scene *sce)
+ {
+       scene = sce;
+       openLibrary();
+       GeometryFunctor gf;
+       gf.forEachMeshObjectInScene<ArmatureExporter>(sce, *this);
+       closeLibrary();
+ }
+ void ArmatureExporter::operator()(Object *ob)
+ {
+       Object *ob_arm = get_assigned_armature(ob);
+       if (ob_arm /*&& !already_written(ob_arm)*/)
+               export_controller(ob, ob_arm);
+ }
+ #if 0
+ bool ArmatureExporter::already_written(Object *ob_arm)
+ {
+       return std::find(written_armatures.begin(), written_armatures.end(), ob_arm) != written_armatures.end();
+ }
+ void ArmatureExporter::wrote(Object *ob_arm)
+ {
+       written_armatures.push_back(ob_arm);
+ }
+ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce)
+ {
+       objects.clear();
+       Base *base= (Base*) sce->base.first;
+       while(base) {
+               Object *ob = base->object;
+               
+               if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) {
+                       objects.push_back(ob);
+               }
+               base= base->next;
+       }
+ }
+ #endif
+ Object *ArmatureExporter::get_assigned_armature(Object *ob)
+ {
+       Object *ob_arm = NULL;
+       if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
+               ob_arm = ob->parent;
+       }
+       else {
+               ModifierData *mod = (ModifierData*)ob->modifiers.first;
+               while (mod) {
+                       if (mod->type == eModifierType_Armature) {
+                               ob_arm = ((ArmatureModifierData*)mod)->object;
+                       }
+                       mod = mod->next;
+               }
+       }
+       return ob_arm;
+ }
+ std::string ArmatureExporter::get_joint_sid(Bone *bone, Object *ob_arm)
+ {
+       return get_joint_id(bone, ob_arm);
+ }
+ // parent_mat is armature-space
+ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm)
+ {
+       std::string node_id = get_joint_id(bone, ob_arm);
+       std::string node_name = std::string(bone->name);
+       std::string node_sid = get_joint_sid(bone, ob_arm);
+       COLLADASW::Node node(mSW);
+       node.setType(COLLADASW::Node::JOINT);
+       node.setNodeId(node_id);
+       node.setNodeName(node_name);
+       node.setNodeSid(node_sid);
+       node.start();
+       add_bone_transform(ob_arm, bone, node);
+       for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) {
+               add_bone_node(child, ob_arm);
+       }
+       node.end();
+ }
+ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node)
+ {
+       bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
+       float mat[4][4];
+       if (bone->parent) {
+               // get bone-space matrix from armature-space
+               bPoseChannel *parchan = get_pose_channel(ob_arm->pose, bone->parent->name);
+               float invpar[4][4];
+               invert_m4_m4(invpar, parchan->pose_mat);
+               mul_m4_m4m4(mat, pchan->pose_mat, invpar);
+       }
+       else {
+               // get world-space from armature-space
+               mul_m4_m4m4(mat, pchan->pose_mat, ob_arm->obmat);
+       }
+       TransformWriter::add_node_transform(node, mat, NULL);
+ }
+ std::string ArmatureExporter::get_controller_id(Object *ob_arm, Object *ob)
+ {
+       return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) + SKIN_CONTROLLER_ID_SUFFIX;
+ }
+ // ob should be of type OB_MESH
+ // both args are required
+ void ArmatureExporter::export_controller(Object* ob, Object *ob_arm)
+ {
+       // joint names
+       // joint inverse bind matrices
+       // vertex weights
+       // input:
+       // joint names: ob -> vertex group names
+       // vertex group weights: me->dvert -> groups -> index, weight
+       /*
+       me->dvert:
+       typedef struct MDeformVert {
+               struct MDeformWeight *dw;
+               int totweight;
+               int flag;       // flag only in use for weightpaint now
+       } MDeformVert;
+       typedef struct MDeformWeight {
+               int                             def_nr;
+               float                   weight;
+       } MDeformWeight;
+       */
+       Mesh *me = (Mesh*)ob->data;
+       if (!me->dvert) return;
+       std::string controller_name = id_name(ob_arm);
+       std::string controller_id = get_controller_id(ob_arm, ob);
+       openSkin(controller_id, controller_name,
+                        COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
+       add_bind_shape_mat(ob);
+       std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id);
+       std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id);
+       std::string weights_source_id = add_weights_source(me, controller_id);
+       add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id);
+       add_vertex_weights_element(weights_source_id, joints_source_id, me, ob_arm, &ob->defbase);
+       closeSkin();
+       closeController();
+ }
+ void ArmatureExporter::add_joints_element(ListBase *defbase,
+                                               const std::string& joints_source_id, const std::string& inv_bind_mat_source_id)
+ {
+       COLLADASW::JointsElement joints(mSW);
+       COLLADASW::InputList &input = joints.getInputList();
+       input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, // constant declared in COLLADASWInputList.h
+                                                          COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id)));
+       input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::BINDMATRIX,
+                                                          COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, inv_bind_mat_source_id)));
+       joints.add();
+ }
+ void ArmatureExporter::add_bind_shape_mat(Object *ob)
+ {
+       double bind_mat[4][4];
+       converter.mat4_to_dae_double(bind_mat, ob->obmat);
+       addBindShapeTransform(bind_mat);
+ }
+ std::string ArmatureExporter::add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
+ {
+       std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX;
+       int totjoint = 0;
+       bDeformGroup *def;
+       for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
+               if (is_bone_defgroup(ob_arm, def))
+                       totjoint++;
+       }
+       COLLADASW::NameSource source(mSW);
+       source.setId(source_id);
+       source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+       source.setAccessorCount(totjoint);
+       source.setAccessorStride(1);
+       
+       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+       param.push_back("JOINT");
+       source.prepareToAppendValues();
+       for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
+               Bone *bone = get_bone_from_defgroup(ob_arm, def);
+               if (bone)
+                       source.appendValues(get_joint_sid(bone, ob_arm));
+       }
+       source.finish();
+       return source_id;
+ }
+ std::string ArmatureExporter::add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
+ {
+       std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX;
+       COLLADASW::FloatSourceF source(mSW);
+       source.setId(source_id);
+       source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+       source.setAccessorCount(BLI_countlist(defbase));
+       source.setAccessorStride(16);
+       
+       source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4);
+       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+       param.push_back("TRANSFORM");
+       source.prepareToAppendValues();
+       bPose *pose = ob_arm->pose;
+       bArmature *arm = (bArmature*)ob_arm->data;
+       int flag = arm->flag;
+       // put armature in rest position
+       if (!(arm->flag & ARM_RESTPOS)) {
+               arm->flag |= ARM_RESTPOS;
+               where_is_pose(scene, ob_arm);
+       }
+       for (bDeformGroup *def = (bDeformGroup*)defbase->first; def; def = def->next) {
+               if (is_bone_defgroup(ob_arm, def)) {
+                       bPoseChannel *pchan = get_pose_channel(pose, def->name);
+                       float mat[4][4];
+                       float world[4][4];
+                       float inv_bind_mat[4][4];
+                       // make world-space matrix, pose_mat is armature-space
+                       mul_m4_m4m4(world, pchan->pose_mat, ob_arm->obmat);
+                       
+                       invert_m4_m4(mat, world);
+                       converter.mat4_to_dae(inv_bind_mat, mat);
+                       source.appendValues(inv_bind_mat);
+               }
+       }
+       // back from rest positon
+       if (!(flag & ARM_RESTPOS)) {
+               arm->flag = flag;
+               where_is_pose(scene, ob_arm);
+       }
+       source.finish();
+       return source_id;
+ }
+ Bone *ArmatureExporter::get_bone_from_defgroup(Object *ob_arm, bDeformGroup* def)
+ {
+       bPoseChannel *pchan = get_pose_channel(ob_arm->pose, def->name);
+       return pchan ? pchan->bone : NULL;
+ }
+ bool ArmatureExporter::is_bone_defgroup(Object *ob_arm, bDeformGroup* def)
+ {
+       return get_bone_from_defgroup(ob_arm, def) != NULL;
+ }
+ std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& controller_id)
+ {
+       std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX;
+       int i;
+       int totweight = 0;
+       for (i = 0; i < me->totvert; i++) {
+               totweight += me->dvert[i].totweight;
+       }
+       COLLADASW::FloatSourceF source(mSW);
+       source.setId(source_id);
+       source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+       source.setAccessorCount(totweight);
+       source.setAccessorStride(1);
+       
+       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+       param.push_back("WEIGHT");
+       source.prepareToAppendValues();
+       // NOTE: COLLADA spec says weights should be normalized
+       for (i = 0; i < me->totvert; i++) {
+               MDeformVert *vert = &me->dvert[i];
+               for (int j = 0; j < vert->totweight; j++) {
+                       source.appendValues(vert->dw[j].weight);
+               }
+       }
+       source.finish();
+       return source_id;
+ }
+ void ArmatureExporter::add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me,
+                                                               Object *ob_arm, ListBase *defbase)
+ {
+       COLLADASW::VertexWeightsElement weights(mSW);
+       COLLADASW::InputList &input = weights.getInputList();
+       int offset = 0;
+       input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, // constant declared in COLLADASWInputList.h
+                                                                        COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id), offset++));
+       input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::WEIGHT,
+                                                                        COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id), offset++));
+       weights.setCount(me->totvert);
+       // write number of deformers per vertex
+       COLLADASW::PrimitivesBase::VCountList vcount;
+       int i;
+       for (i = 0; i < me->totvert; i++) {
+               vcount.push_back(me->dvert[i].totweight);
+       }
+       weights.prepareToAppendVCountValues();
+       weights.appendVertexCount(vcount);
+       // def group index -> joint index
+       std::map<int, int> joint_index_by_def_index;
+       bDeformGroup *def;
+       int j;
+       for (def = (bDeformGroup*)defbase->first, i = 0, j = 0; def; def = def->next, i++) {
+               if (is_bone_defgroup(ob_arm, def))
+                       joint_index_by_def_index[i] = j++;
+               else
+                       joint_index_by_def_index[i] = -1;
+       }
+       weights.CloseVCountAndOpenVElement();
+       // write deformer index - weight index pairs
+       int weight_index = 0;
+       for (i = 0; i < me->totvert; i++) {
+               MDeformVert *dvert = &me->dvert[i];
+               for (int j = 0; j < dvert->totweight; j++) {
+                       weights.appendValues(joint_index_by_def_index[dvert->dw[j].def_nr]);
+                       weights.appendValues(weight_index++);
+               }
+       }
+       weights.finish();
+ }
index 0000000,8d25082..1d8fa6d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,137 +1,137 @@@
 - * $Id$
+ /**
++ * $Id: ArmatureExporter.h 32355 2010-10-06 20:40:16Z gsrb3d $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #ifndef __ARMATUREEXPORTER_H__
+ #define __ARMATUREEXPORTER_H__
+ #include <string>
+ //#include <vector>
+ #include "COLLADASWStreamWriter.h"
+ #include "COLLADASWLibraryControllers.h"
+ #include "COLLADASWInputList.h"
+ #include "COLLADASWNode.h"
+ #include "DNA_armature_types.h"
+ #include "DNA_listBase.h"
+ #include "DNA_mesh_types.h"
+ #include "DNA_object_types.h"
+ #include "DNA_scene_types.h"
+ #include "TransformWriter.h"
+ #include "InstanceWriter.h"
+ // XXX exporter writes wrong data for shared armatures.  A separate
+ // controller should be written for each armature-mesh binding how do
+ // we make controller ids then?
+ class ArmatureExporter: public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter
+ {
+ private:
+       Scene *scene;
+ public:
+       ArmatureExporter(COLLADASW::StreamWriter *sw);
+       // write bone nodes
+       void add_armature_bones(Object *ob_arm, Scene *sce);
+       bool is_skinned_mesh(Object *ob);
+       void add_instance_controller(Object *ob);
+       void export_controllers(Scene *sce);
+       void operator()(Object *ob);
+ private:
+       UnitConverter converter;
+ #if 0
+       std::vector<Object*> written_armatures;
+       bool already_written(Object *ob_arm);
+       void wrote(Object *ob_arm);
+       void find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce);
+ #endif
+       Object *get_assigned_armature(Object *ob);
+       std::string get_joint_sid(Bone *bone, Object *ob_arm);
+       // parent_mat is armature-space
+       void add_bone_node(Bone *bone, Object *ob_arm);
+       void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node);
+       std::string get_controller_id(Object *ob_arm, Object *ob);
+       // ob should be of type OB_MESH
+       // both args are required
+       void export_controller(Object* ob, Object *ob_arm);
+       void add_joints_element(ListBase *defbase,
+                                                       const std::string& joints_source_id, const std::string& inv_bind_mat_source_id);
+       void add_bind_shape_mat(Object *ob);
+       std::string add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id);
+       std::string add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id);
+       Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup* def);
+       bool is_bone_defgroup(Object *ob_arm, bDeformGroup* def);
+       std::string add_weights_source(Mesh *me, const std::string& controller_id);
+       void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me,
+                                                                       Object *ob_arm, ListBase *defbase);
+ };
+ /*
+ struct GeometryFunctor {
+       // f should have
+       // void operator()(Object* ob)
+       template<class Functor>
+       void forEachMeshObjectInScene(Scene *sce, Functor &f)
+       {
+               
+               Base *base= (Base*) sce->base.first;
+               while(base) {
+                       Object *ob = base->object;
+                       
+                       if (ob->type == OB_MESH && ob->data) {
+                               f(ob);
+                       }
+                       base= base->next;
+                       
+               }
+       }
+ };*/
+ #endif
index 0000000,e78c195..072ef30
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,587 +1,587 @@@
 - * $Id$
+ /**
++ * $Id: ArmatureImporter.cpp 34787 2011-02-12 06:25:04Z campbellbarton $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ /* COLLADABU_ASSERT, may be able to remove later */
+ #include "COLLADABUPlatform.h"
+ #include <algorithm>
+ #include "COLLADAFWUniqueId.h"
+ #include "BKE_action.h"
+ #include "BKE_depsgraph.h"
+ #include "BKE_object.h"
+ #include "BLI_string.h"
+ #include "ED_armature.h"
+ #include "ArmatureImporter.h"
+ // use this for retrieving bone names, since these must be unique
+ template<class T>
+ static const char *bc_get_joint_name(T *node)
+ {
+       const std::string& id = node->getOriginalId();
+       return id.size() ? id.c_str() : node->getName().c_str();
+ }
+ ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce) :
+       TransformReader(conv), scene(sce), empty(NULL), mesh_importer(mesh), anim_importer(anim) {}
+ ArmatureImporter::~ArmatureImporter()
+ {
+       // free skin controller data if we forget to do this earlier
+       std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+       for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
+               it->second.free();
+       }
+ }
+ #if 0
+ JointData *ArmatureImporter::get_joint_data(COLLADAFW::Node *node);
+ {
+       const COLLADAFW::UniqueId& joint_id = node->getUniqueId();
+       if (joint_id_to_joint_index_map.find(joint_id) == joint_id_to_joint_index_map.end()) {
+               fprintf(stderr, "Cannot find a joint index by joint id for %s.\n",
+                               node->getOriginalId().c_str());
+               return NULL;
+       }
+       int joint_index = joint_id_to_joint_index_map[joint_id];
+       return &joint_index_to_joint_info_map[joint_index];
+ }
+ #endif
+ void ArmatureImporter::create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
+                                float parent_mat[][4], bArmature *arm)
+ {
+       float joint_inv_bind_mat[4][4];
+       // JointData* jd = get_joint_data(node);
+       float mat[4][4];
+       if (skin.get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) {
+               // get original world-space matrix
+               invert_m4_m4(mat, joint_inv_bind_mat);
+       }
+       // create a bone even if there's no joint data for it (i.e. it has no influence)
+       else {
+               float obmat[4][4];
+               // object-space
+               get_node_mat(obmat, node, NULL, NULL);
+               // get world-space
+               if (parent)
+                       mul_m4_m4m4(mat, obmat, parent_mat);
+               else
+                       copy_m4_m4(mat, obmat);
+       }
+       // TODO rename from Node "name" attrs later
+       EditBone *bone = ED_armature_edit_bone_add(arm, (char*)bc_get_joint_name(node));
+       totbone++;
+       if (parent) bone->parent = parent;
+       // set head
+       copy_v3_v3(bone->head, mat[3]);
+       // set tail, don't set it to head because 0-length bones are not allowed
+       float vec[3] = {0.0f, 0.5f, 0.0f};
+       add_v3_v3v3(bone->tail, bone->head, vec);
+       // set parent tail
+       if (parent && totchild == 1) {
+               copy_v3_v3(parent->tail, bone->head);
+               // not setting BONE_CONNECTED because this would lock child bone location with respect to parent
+               // bone->flag |= BONE_CONNECTED;
+               // XXX increase this to prevent "very" small bones?
+               const float epsilon = 0.000001f;
+               // derive leaf bone length
+               float length = len_v3v3(parent->head, parent->tail);
+               if ((length < leaf_bone_length || totbone == 0) && length > epsilon) {
+                       leaf_bone_length = length;
+               }
+               // treat zero-sized bone like a leaf bone
+               if (length <= epsilon) {
+                       add_leaf_bone(parent_mat, parent);
+               }
+               /*
+ #if 0
+               // and which row in mat is bone direction
+               float vec[3];
+               sub_v3_v3v3(vec, parent->tail, parent->head);
+ #ifdef COLLADA_DEBUG
+               print_v3("tail - head", vec);
+               print_m4("matrix", parent_mat);
+ #endif
+               for (int i = 0; i < 3; i++) {
+ #ifdef COLLADA_DEBUG
+                       char *axis_names[] = {"X", "Y", "Z"};
+                       printf("%s-axis length is %f\n", axis_names[i], len_v3(parent_mat[i]));
+ #endif
+                       float angle = angle_v2v2(vec, parent_mat[i]);
+                       if (angle < min_angle) {
+ #ifdef COLLADA_DEBUG
+                               print_v3("picking", parent_mat[i]);
+                               printf("^ %s axis of %s's matrix\n", axis_names[i], get_dae_name(node));
+ #endif
+                               bone_direction_row = i;
+                               min_angle = angle;
+                       }
+               }
+ #endif
+               */
+       }
+       COLLADAFW::NodePointerArray& children = node->getChildNodes();
+       for (unsigned int i = 0; i < children.getCount(); i++) {
+               create_bone(skin, children[i], bone, children.getCount(), mat, arm);
+       }
+       // in second case it's not a leaf bone, but we handle it the same way
+       if (!children.getCount() || children.getCount() > 1) {
+               add_leaf_bone(mat, bone);
+       }
+ }
+ void ArmatureImporter::add_leaf_bone(float mat[][4], EditBone *bone)
+ {
+       LeafBone leaf;
+       leaf.bone = bone;
+       copy_m4_m4(leaf.mat, mat);
+       BLI_strncpy(leaf.name, bone->name, sizeof(leaf.name));
+       leaf_bones.push_back(leaf);
+ }
+ void ArmatureImporter::fix_leaf_bones()
+ {
+       // just setting tail for leaf bones here
+       std::vector<LeafBone>::iterator it;
+       for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) {
+               LeafBone& leaf = *it;
+               // pointing up
+               float vec[3] = {0.0f, 0.0f, 1.0f};
+               mul_v3_fl(vec, leaf_bone_length);
+               copy_v3_v3(leaf.bone->tail, leaf.bone->head);
+               add_v3_v3v3(leaf.bone->tail, leaf.bone->head, vec);
+       }
+ }
+ #if 0
+ void ArmatureImporter::set_leaf_bone_shapes(Object *ob_arm)
+ {
+       bPose *pose = ob_arm->pose;
+       std::vector<LeafBone>::iterator it;
+       for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) {
+               LeafBone& leaf = *it;
+               bPoseChannel *pchan = get_pose_channel(pose, leaf.name);
+               if (pchan) {
+                       pchan->custom = get_empty_for_leaves();
+               }
+               else {
+                       fprintf(stderr, "Cannot find a pose channel for leaf bone %s\n", leaf.name);
+               }
+       }
+ }
+ void ArmatureImporter::set_euler_rotmode()
+ {
+       // just set rotmode = ROT_MODE_EUL on pose channel for each joint
+       std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>::iterator it;
+       for (it = joint_by_uid.begin(); it != joint_by_uid.end(); it++) {
+               COLLADAFW::Node *joint = it->second;
+               std::map<COLLADAFW::UniqueId, SkinInfo>::iterator sit;
+               
+               for (sit = skin_by_data_uid.begin(); sit != skin_by_data_uid.end(); sit++) {
+                       SkinInfo& skin = sit->second;
+                       if (skin.uses_joint_or_descendant(joint)) {
+                               bPoseChannel *pchan = skin.get_pose_channel_from_node(joint);
+                               if (pchan) {
+                                       pchan->rotmode = ROT_MODE_EUL;
+                               }
+                               else {
+                                       fprintf(stderr, "Cannot find pose channel for %s.\n", get_joint_name(joint));
+                               }
+                               break;
+                       }
+               }
+       }
+ }
+ #endif
+ Object *ArmatureImporter::get_empty_for_leaves()
+ {
+       if (empty) return empty;
+       
+       empty = add_object(scene, OB_EMPTY);
+       empty->empty_drawtype = OB_EMPTY_SPHERE;
+       return empty;
+ }
+ #if 0
+ Object *ArmatureImporter::find_armature(COLLADAFW::Node *node)
+ {
+       JointData* jd = get_joint_data(node);
+       if (jd) return jd->ob_arm;
+       COLLADAFW::NodePointerArray& children = node->getChildNodes();
+       for (int i = 0; i < children.getCount(); i++) {
+               Object *ob_arm = find_armature(children[i]);
+               if (ob_arm) return ob_arm;
+       }
+       return NULL;
+ }
+ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm)
+ {
+       // try finding it
+       std::vector<ArmatureJoints>::iterator it;
+       for (it = armature_joints.begin(); it != armature_joints.end(); it++) {
+               if ((*it).ob_arm == ob_arm) return *it;
+       }
+       // not found, create one
+       ArmatureJoints aj;
+       aj.ob_arm = ob_arm;
+       armature_joints.push_back(aj);
+       return armature_joints.back();
+ }
+ #endif
+ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
+ {
+       // just do like so:
+       // - get armature
+       // - enter editmode
+       // - add edit bones and head/tail properties using matrices and parent-child info
+       // - exit edit mode
+       // - set a sphere shape to leaf bones
+       Object *ob_arm = NULL;
+       /*
+        * find if there's another skin sharing at least one bone with this skin
+        * if so, use that skin's armature
+        */
+       /*
+         Pseudocode:
+         find_node_in_tree(node, root_joint)
+         skin::find_root_joints(root_joints):
+               std::vector root_joints;
+               for each root in root_joints:
+                       for each joint in joints:
+                               if find_node_in_tree(joint, root):
+                                       if (std::find(root_joints.begin(), root_joints.end(), root) == root_joints.end())
+                                               root_joints.push_back(root);
+         for (each skin B with armature) {
+                 find all root joints for skin B
+                 for each joint X in skin A:
+                       for each root joint R in skin B:
+                               if (find_node_in_tree(X, R)) {
+                                       shared = 1;
+                                       goto endloop;
+                               }
+         }
+         endloop:
+       */
+       SkinInfo *a = &skin;
+       Object *shared = NULL;
+       std::vector<COLLADAFW::Node*> skin_root_joints;
+       std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+       for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
+               SkinInfo *b = &it->second;
+               if (b == a || b->get_armature() == NULL)
+                       continue;
+               skin_root_joints.clear();
+               b->find_root_joints(root_joints, joint_by_uid, skin_root_joints);
+               std::vector<COLLADAFW::Node*>::iterator ri;
+               for (ri = skin_root_joints.begin(); ri != skin_root_joints.end(); ri++) {
+                       if (a->uses_joint_or_descendant(*ri)) {
+                               shared = b->get_armature();
+                               break;
+                       }
+               }
+               if (shared != NULL)
+                       break;
+       }
+       if (shared)
+               ob_arm = skin.set_armature(shared);
+       else
+               ob_arm = skin.create_armature(scene);
+       // enter armature edit mode
+       ED_armature_to_edit(ob_arm);
+       leaf_bones.clear();
+       totbone = 0;
+       // bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row
+       leaf_bone_length = FLT_MAX;
+       // min_angle = 360.0f;          // minimum angle between bone head-tail and a row of bone matrix
+       // create bones
+       /*
+          TODO:
+          check if bones have already been created for a given joint
+       */
+       std::vector<COLLADAFW::Node*>::iterator ri;
+       for (ri = root_joints.begin(); ri != root_joints.end(); ri++) {
+               // for shared armature check if bone tree is already created
+               if (shared && std::find(skin_root_joints.begin(), skin_root_joints.end(), *ri) != skin_root_joints.end())
+                       continue;
+               // since root_joints may contain joints for multiple controllers, we need to filter
+               if (skin.uses_joint_or_descendant(*ri)) {
+                       create_bone(skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, (bArmature*)ob_arm->data);
+                       if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent())
+                               skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]);
+               }
+       }
+       fix_leaf_bones();
+       // exit armature edit mode
+       ED_armature_from_edit(ob_arm);
+       ED_armature_edit_free(ob_arm);
+       DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB|OB_RECALC_DATA);
+       // set_leaf_bone_shapes(ob_arm);
+       // set_euler_rotmode();
+ }
+ // root - if this joint is the top joint in hierarchy, if a joint
+ // is a child of a node (not joint), root should be true since
+ // this is where we build armature bones from
+ void ArmatureImporter::add_joint(COLLADAFW::Node *node, bool root, Object *parent)
+ {
+       joint_by_uid[node->getUniqueId()] = node;
+       if (root) {
+               root_joints.push_back(node);
+               if (parent)
+                       joint_parent_map[node->getUniqueId()] = parent;
+       }
+ }
+ #if 0
+ void ArmatureImporter::add_root_joint(COLLADAFW::Node *node)
+ {
+       // root_joints.push_back(node);
+       Object *ob_arm = find_armature(node);
+       if (ob_arm)     {
+               get_armature_joints(ob_arm).root_joints.push_back(node);
+       }
+ #ifdef COLLADA_DEBUG
+       else {
+               fprintf(stderr, "%s cannot be added to armature.\n", get_joint_name(node));
+       }
+ #endif
+ }
+ #endif
+ // here we add bones to armatures, having armatures previously created in write_controller
+ void ArmatureImporter::make_armatures(bContext *C)
+ {
+       std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+       for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
+               SkinInfo& skin = it->second;
+               create_armature_bones(skin);
+               // link armature with a mesh object
+               Object *ob = mesh_importer->get_object_by_geom_uid(*get_geometry_uid(skin.get_controller_uid()));
+               if (ob)
+                       skin.link_armature(C, ob, joint_by_uid, this);
+               else
+                       fprintf(stderr, "Cannot find object to link armature with.\n");
+               // set armature parent if any
+               Object *par = skin.get_parent();
+               if (par)
+                       bc_set_parent(skin.get_armature(), par, C, false);
+               // free memory stolen from SkinControllerData
+               skin.free();
+       }
+ }
+ #if 0
+ // link with meshes, create vertex groups, assign weights
+ void ArmatureImporter::link_armature(Object *ob_arm, const COLLADAFW::UniqueId& geom_id, const COLLADAFW::UniqueId& controller_data_id)
+ {
+       Object *ob = mesh_importer->get_object_by_geom_uid(geom_id);
+       if (!ob) {
+               fprintf(stderr, "Cannot find object by geometry UID.\n");
+               return;
+       }
+       if (skin_by_data_uid.find(controller_data_id) == skin_by_data_uid.end()) {
+               fprintf(stderr, "Cannot find skin info by controller data UID.\n");
+               return;
+       }
+       SkinInfo& skin = skin_by_data_uid[conroller_data_id];
+       // create vertex groups
+ }
+ #endif
+ bool ArmatureImporter::write_skin_controller_data(const COLLADAFW::SkinControllerData* data)
+ {
+       // at this stage we get vertex influence info that should go into me->verts and ob->defbase
+       // there's no info to which object this should be long so we associate it with skin controller data UID
+       // don't forget to call defgroup_unique_name before we copy
+       // controller data uid -> [armature] -> joint data, 
+       // [mesh object]
+       // 
+       SkinInfo skin(unit_converter);
+       skin.borrow_skin_controller_data(data);
+       // store join inv bind matrix to use it later in armature construction
+       const COLLADAFW::Matrix4Array& inv_bind_mats = data->getInverseBindMatrices();
+       for (unsigned int i = 0; i < data->getJointsCount(); i++) {
+               skin.add_joint(inv_bind_mats[i]);
+       }
+       skin_by_data_uid[data->getUniqueId()] = skin;
+       return true;
+ }
+ bool ArmatureImporter::write_controller(const COLLADAFW::Controller* controller)
+ {
+       // - create and store armature object
+       const COLLADAFW::UniqueId& skin_id = controller->getUniqueId();
+       if (controller->getControllerType() == COLLADAFW::Controller::CONTROLLER_TYPE_SKIN) {
+               COLLADAFW::SkinController *co = (COLLADAFW::SkinController*)controller;
+               // to be able to find geom id by controller id
+               geom_uid_by_controller_uid[skin_id] = co->getSource();
+               const COLLADAFW::UniqueId& data_uid = co->getSkinControllerData();
+               if (skin_by_data_uid.find(data_uid) == skin_by_data_uid.end()) {
+                       fprintf(stderr, "Cannot find skin by controller data UID.\n");
+                       return true;
+               }
+               skin_by_data_uid[data_uid].set_controller(co);
+       }
+       // morph controller
+       else {
+               // shape keys? :)
+               fprintf(stderr, "Morph controller is not supported yet.\n");
+       }
+       return true;
+ }
+ COLLADAFW::UniqueId *ArmatureImporter::get_geometry_uid(const COLLADAFW::UniqueId& controller_uid)
+ {
+       if (geom_uid_by_controller_uid.find(controller_uid) == geom_uid_by_controller_uid.end())
+               return NULL;
+       return &geom_uid_by_controller_uid[controller_uid];
+ }
+ Object *ArmatureImporter::get_armature_for_joint(COLLADAFW::Node *node)
+ {
+       std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+       for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
+               SkinInfo& skin = it->second;
+               if (skin.uses_joint_or_descendant(node))
+                       return skin.get_armature();
+       }
+       return NULL;
+ }
+ void ArmatureImporter::get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count)
+ {
+       BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", bc_get_joint_name(node));
+ }
+ // gives a world-space mat
+ bool ArmatureImporter::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;
+ }
index 0000000,7111e2f..b682cb1
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,159 +1,159 @@@
 - * $Id$
+ /**
++ * $Id: ArmatureImporter.h 33832 2010-12-21 10:43:47Z jesterking $
+  *
+  * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #ifndef __BC_ARMATUREIMPORTER_H__
+ #define __BC_ARMATUREIMPORTER_H__
+ #include "COLLADAFWNode.h"
+ #include "COLLADAFWUniqueId.h"
+ extern "C" {
+ #include "BKE_context.h"
+ #include "DNA_armature_types.h"
+ #include "DNA_object_types.h"
+ #include "DNA_scene_types.h"
+ #include "ED_armature.h"
+ }
+ #include "AnimationImporter.h"
+ #include "MeshImporter.h"
+ #include "SkinInfo.h"
+ #include "TransformReader.h"
+ #include <map>
+ #include <vector>
+ #include "collada_internal.h"
+ #include "collada_utils.h"
+ class ArmatureImporter : private TransformReader
+ {
+ private:
+       Scene *scene;
+       UnitConverter *unit_converter;
+       // std::map<int, JointData> joint_index_to_joint_info_map;
+       // std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map;
+       struct LeafBone {
+               // COLLADAFW::Node *node;
+               EditBone *bone;
+               char name[32];
+               float mat[4][4]; // bone matrix, derived from inv_bind_mat
+       };
+       std::vector<LeafBone> leaf_bones;
+       // int bone_direction_row; // XXX not used
+       float leaf_bone_length;
+       int totbone;
+       // XXX not used
+       // float min_angle; // minimum angle between bone head-tail and a row of bone matrix
+ #if 0
+       struct ArmatureJoints {
+               Object *ob_arm;
+               std::vector<COLLADAFW::Node*> root_joints;
+       };
+       std::vector<ArmatureJoints> armature_joints;
+ #endif
+       Object *empty; // empty for leaf bones
+       std::map<COLLADAFW::UniqueId, COLLADAFW::UniqueId> geom_uid_by_controller_uid;
+       std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> joint_by_uid; // contains all joints
+       std::vector<COLLADAFW::Node*> root_joints;
+       std::map<COLLADAFW::UniqueId, Object*> joint_parent_map;
+       MeshImporterBase *mesh_importer;
+       AnimationImporterBase *anim_importer;
+       // This is used to store data passed in write_controller_data.
+       // Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
+       // so that arrays don't get freed until we free them explicitly.
+       std::map<COLLADAFW::UniqueId, SkinInfo> skin_by_data_uid; // data UID = skin controller data UID
+ #if 0
+       JointData *get_joint_data(COLLADAFW::Node *node);
+ #endif
+       void create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
+                                        float parent_mat[][4], bArmature *arm);
+       void add_leaf_bone(float mat[][4], EditBone *bone);
+       void fix_leaf_bones();
+ #if 0
+       void set_leaf_bone_shapes(Object *ob_arm);
+       void set_euler_rotmode();
+ #endif
+       Object *get_empty_for_leaves();
+ #if 0
+       Object *find_armature(COLLADAFW::Node *node);
+       ArmatureJoints& get_armature_joints(Object *ob_arm);
+ #endif
+       void create_armature_bones(SkinInfo& skin);
+ public:
+       ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce);
+       ~ArmatureImporter();
+       // root - if this joint is the top joint in hierarchy, if a joint
+       // is a child of a node (not joint), root should be true since
+       // this is where we build armature bones from
+       void add_joint(COLLADAFW::Node *node, bool root, Object *parent);
+ #if 0
+       void add_root_joint(COLLADAFW::Node *node);
+ #endif
+       // here we add bones to armatures, having armatures previously created in write_controller
+       void make_armatures(bContext *C);
+ #if 0
+       // link with meshes, create vertex groups, assign weights
+       void link_armature(Object *ob_arm, const COLLADAFW::UniqueId& geom_id, const COLLADAFW::UniqueId& controller_data_id);
+ #endif
+       bool write_skin_controller_data(const COLLADAFW::SkinControllerData* data);
+       bool write_controller(const COLLADAFW::Controller* controller);
+       COLLADAFW::UniqueId *get_geometry_uid(const COLLADAFW::UniqueId& controller_uid);
+       Object *get_armature_for_joint(COLLADAFW::Node *node);
+       void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count);
+       
+       // gives a world-space mat
+       bool get_joint_bind_mat(float m[][4], COLLADAFW::Node *joint);
+ };
+ #endif
index 0000000,d5e2a7e..9c33a4f
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,86 +1,86 @@@
 - * $Id$
+ /**
++ * $Id: CameraExporter.cpp 32546 2010-10-18 00:46:41Z jesterking $
+  *
+  * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include <string>
+ #include "COLLADASWCamera.h"
+ #include "COLLADASWCameraOptic.h"
+ #include "DNA_camera_types.h"
+ #include "CameraExporter.h"
+ #include "collada_internal.h"
+ CamerasExporter::CamerasExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryCameras(sw){}
+ template<class Functor>
+ void forEachCameraObjectInScene(Scene *sce, Functor &f)
+ {
+       Base *base= (Base*) sce->base.first;
+       while(base) {
+               Object *ob = base->object;
+                       
+               if (ob->type == OB_CAMERA && ob->data) {
+                       f(ob, sce);
+               }
+               base= base->next;
+       }
+ }
+ void CamerasExporter::exportCameras(Scene *sce)
+ {
+       openLibrary();
+       
+       forEachCameraObjectInScene(sce, *this);
+       
+       closeLibrary();
+ }
+ void CamerasExporter::operator()(Object *ob, Scene *sce)
+ {
+       // TODO: shiftx, shifty, YF_dofdist
+       Camera *cam = (Camera*)ob->data;
+       std::string cam_id(get_camera_id(ob));
+       std::string cam_name(id_name(cam));
+       
+       if (cam->type == CAM_PERSP) {
+               COLLADASW::PerspectiveOptic persp(mSW);
+               persp.setXFov(lens_to_angle(cam->lens)*(180.0f/M_PI));
+               persp.setAspectRatio((float)(sce->r.xsch)/(float)(sce->r.ysch));
+               persp.setZFar(cam->clipend);
+               persp.setZNear(cam->clipsta);
+               COLLADASW::Camera ccam(mSW, &persp, cam_id, cam_name);
+               addCamera(ccam);
+       }
+       else {
+               COLLADASW::OrthographicOptic ortho(mSW);
+               ortho.setXMag(cam->ortho_scale);
+               ortho.setAspectRatio((float)(sce->r.xsch)/(float)(sce->r.ysch));
+               ortho.setZFar(cam->clipend);
+               ortho.setZNear(cam->clipsta);
+               COLLADASW::Camera ccam(mSW, &ortho, cam_id, cam_name);
+               addCamera(ccam);
+       }
+ }     
@@@ -1,5 -1,5 +1,5 @@@
  /**
-- * $Id$
++ * $Id: CameraExporter.h 32355 2010-10-06 20:40:16Z gsrb3d $
   *
   * ***** BEGIN GPL LICENSE BLOCK *****
   *
index 0000000,45b6450..be8ecc8
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,306 +1,306 @@@
 - * $Id$
+ /**
++ * $Id: EffectExporter.cpp 32360 2010-10-07 01:20:59Z gsrb3d $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include <map>
+ #include "COLLADASWEffectProfile.h"
+ #include "EffectExporter.h"
+ #include "MaterialExporter.h"
+ #include "DNA_mesh_types.h"
+ #include "DNA_texture_types.h"
+ #include "BKE_customdata.h"
+ #include "collada_internal.h"
+ #include "collada_utils.h"
+ // OB_MESH is assumed
+ static std::string getActiveUVLayerName(Object *ob)
+ {
+       Mesh *me = (Mesh*)ob->data;
+       int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+       if (num_layers)
+               return std::string(bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE));
+               
+       return "";
+ }
+ EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryEffects(sw){}
+ void EffectsExporter::exportEffects(Scene *sce)
+ {
+       openLibrary();
+       MaterialFunctor mf;
+       mf.forEachMaterialInScene<EffectsExporter>(sce, *this);
+       closeLibrary();
+ }
+ void EffectsExporter::operator()(Material *ma, Object *ob)
+ {
+       // create a list of indices to textures of type TEX_IMAGE
+       std::vector<int> tex_indices;
+       createTextureIndices(ma, tex_indices);
+       openEffect(translate_id(id_name(ma)) + "-effect");
+       
+       COLLADASW::EffectProfile ep(mSW);
+       ep.setProfileType(COLLADASW::EffectProfile::COMMON);
+       ep.openProfile();
+       // set shader type - one of three blinn, phong or lambert
+       if (ma->spec_shader == MA_SPEC_BLINN) {
+               ep.setShaderType(COLLADASW::EffectProfile::BLINN);
+               // shininess
+               ep.setShininess(ma->har);
+       }
+       else if (ma->spec_shader == MA_SPEC_PHONG) {
+               ep.setShaderType(COLLADASW::EffectProfile::PHONG);
+               // shininess
+               ep.setShininess(ma->har);
+       }
+       else {
+               // XXX write warning "Current shader type is not supported" 
+               ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
+       }
+       // index of refraction
+       if (ma->mode & MA_RAYTRANSP) {
+               ep.setIndexOfRefraction(ma->ang);
+       }
+       else {
+               ep.setIndexOfRefraction(1.0f);
+       }
+       COLLADASW::ColorOrTexture cot;
+       // transparency
+       if (ma->mode & MA_TRANSP) {
+               // Tod: because we are in A_ONE mode transparency is calculated like this:
+               ep.setTransparency(ma->alpha);
+               // cot = getcol(1.0f, 1.0f, 1.0f, 1.0f);
+               // ep.setTransparent(cot);
+       }
+       // emission
+       cot=getcol(ma->emit, ma->emit, ma->emit, 1.0f);
+       ep.setEmission(cot);
+       // diffuse multiplied by diffuse intensity
+       cot = getcol(ma->r * ma->ref, ma->g * ma->ref, ma->b * ma->ref, 1.0f);
+       ep.setDiffuse(cot);
+       // ambient
+       cot = getcol(ma->ambr, ma->ambg, ma->ambb, 1.0f);
+       ep.setAmbient(cot);
+       // reflective, reflectivity
+       if (ma->mode & MA_RAYMIRROR) {
+               cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f);
+               ep.setReflective(cot);
+               ep.setReflectivity(ma->ray_mirror);
+       }
+       // else {
+       //      cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f);
+       //      ep.setReflective(cot);
+       //      ep.setReflectivity(ma->spec);
+       // }
+       // specular
+       if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) {
+               cot = getcol(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f);
+               ep.setSpecular(cot);
+       }       
+       // XXX make this more readable if possible
+       // create <sampler> and <surface> for each image
+       COLLADASW::Sampler samplers[MAX_MTEX];
+       //COLLADASW::Surface surfaces[MAX_MTEX];
+       //void *samp_surf[MAX_MTEX][2];
+       void *samp_surf[MAX_MTEX][1];
+       
+       // image to index to samp_surf map
+       // samp_surf[index] stores 2 pointers, sampler and surface
+       std::map<std::string, int> im_samp_map;
+       unsigned int a, b;
+       for (a = 0, b = 0; a < tex_indices.size(); a++) {
+               MTex *t = ma->mtex[tex_indices[a]];
+               Image *ima = t->tex->ima;
+               
+               // Image not set for texture
+               if(!ima) continue;
+               
+               std::string key(id_name(ima));
+               key = translate_id(key);
+               // create only one <sampler>/<surface> pair for each unique image
+               if (im_samp_map.find(key) == im_samp_map.end()) {
+                       // //<newparam> <surface> <init_from>
+                       // COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D,
+                       //                                                 key + COLLADASW::Surface::SURFACE_SID_SUFFIX);
+                       // COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM);
+                       // sio.setImageReference(key);
+                       // surface.setInitOption(sio);
+                       // COLLADASW::NewParamSurface surface(mSW);
+                       // surface->setParamType(COLLADASW::CSW_SURFACE_TYPE_2D);
+                       
+                       //<newparam> <sampler> <source>
+                       COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
+                                                                          key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
+                                                                          key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
+                       sampler.setImageId(key);
+                       // copy values to arrays since they will live longer
+                       samplers[a] = sampler;
+                       //surfaces[a] = surface;
+                       
+                       // store pointers so they can be used later when we create <texture>s
+                       samp_surf[b][0] = &samplers[a];
+                       //samp_surf[b][1] = &surfaces[a];
+                       
+                       im_samp_map[key] = b;
+                       b++;
+               }
+       }
+       // used as fallback when MTex->uvname is "" (this is pretty common)
+       // it is indeed the correct value to use in that case
+       std::string active_uv(getActiveUVLayerName(ob));
+       // write textures
+       // XXX very slow
+       for (a = 0; a < tex_indices.size(); a++) {
+               MTex *t = ma->mtex[tex_indices[a]];
+               Image *ima = t->tex->ima;
+               
+               // Image not set for texture
+               if(!ima) continue;
+               // we assume map input is always TEXCO_UV
+               std::string key(id_name(ima));
+               key = translate_id(key);
+               int i = im_samp_map[key];
+               COLLADASW::Sampler *sampler = (COLLADASW::Sampler*)samp_surf[i][0];
+               //COLLADASW::Surface *surface = (COLLADASW::Surface*)samp_surf[i][1];
+               std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
+               // color
+               if (t->mapto & MAP_COL) {
+                       ep.setDiffuse(createTexture(ima, uvname, sampler));
+               }
+               // ambient
+               if (t->mapto & MAP_AMB) {
+                       ep.setAmbient(createTexture(ima, uvname, sampler));
+               }
+               // specular
+               if (t->mapto & MAP_SPEC) {
+                       ep.setSpecular(createTexture(ima, uvname, sampler));
+               }
+               // emission
+               if (t->mapto & MAP_EMIT) {
+                       ep.setEmission(createTexture(ima, uvname, sampler));
+               }
+               // reflective
+               if (t->mapto & MAP_REF) {
+                       ep.setReflective(createTexture(ima, uvname, sampler));
+               }
+               // alpha
+               if (t->mapto & MAP_ALPHA) {
+                       ep.setTransparent(createTexture(ima, uvname, sampler));
+               }
+               // extension:
+               // Normal map --> Must be stored with <extra> tag as different technique, 
+               // since COLLADA doesn't support normal maps, even in current COLLADA 1.5.
+               if (t->mapto & MAP_NORM) {
+                       COLLADASW::Texture texture(key);
+                       texture.setTexcoord(uvname);
+                       texture.setSampler(*sampler);
+                       // technique FCOLLADA, with the <bump> tag, is most likely the best understood,
+                       // most widespread de-facto standard.
+                       texture.setProfileName("FCOLLADA");
+                       texture.setChildElementName("bump");
+                       ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
+               }
+       }
+       // performs the actual writing
+       ep.addProfileElements();
+       bool twoSided = false;
+       if (ob->type == OB_MESH && ob->data) {
+               Mesh *me = (Mesh*)ob->data;
+               if (me->flag & ME_TWOSIDED)
+                       twoSided = true;
+       }
+       if (twoSided)
+               ep.addExtraTechniqueParameter("GOOGLEEARTH", "show_double_sided", 1);
+       ep.addExtraTechniques(mSW);
+       ep.closeProfile();
+       if (twoSided)
+               mSW->appendTextBlock("<extra><technique profile=\"MAX3D\"><double_sided>1</double_sided></technique></extra>");
+       closeEffect();  
+ }
+ COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima,
+                                                                               std::string& uv_layer_name,
+                                                                               COLLADASW::Sampler *sampler
+                                                                               /*COLLADASW::Surface *surface*/)
+ {
+       
+       COLLADASW::Texture texture(translate_id(id_name(ima)));
+       texture.setTexcoord(uv_layer_name);
+       //texture.setSurface(*surface);
+       texture.setSampler(*sampler);
+       
+       COLLADASW::ColorOrTexture cot(texture);
+       return cot;
+ }
+ COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, float a)
+ {
+       COLLADASW::Color color(r,g,b,a);
+       COLLADASW::ColorOrTexture cot(color);
+       return cot;
+ }
+ //returns the array of mtex indices which have image 
+ //need this for exporting textures
+ void EffectsExporter::createTextureIndices(Material *ma, std::vector<int> &indices)
+ {
+       indices.clear();
+       for (int a = 0; a < MAX_MTEX; a++) {
+               if (ma->mtex[a] &&
+                       ma->mtex[a]->tex &&
+                       ma->mtex[a]->tex->type == TEX_IMAGE &&
+                       ma->mtex[a]->texco == TEXCO_UV){
+                       indices.push_back(a);
+               }
+       }
+ }
index 0000000,e8f8754..9f7f643
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,62 +1,62 @@@
 - * $Id$
+ /**
++ * $Id: EffectExporter.h 32360 2010-10-07 01:20:59Z gsrb3d $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #ifndef __EFFECTEXPORTER_H__
+ #define __EFFECTEXPORTER_H__
+ #include <string>
+ #include <vector>
+ #include "COLLADASWColorOrTexture.h"
+ #include "COLLADASWStreamWriter.h"
+ #include "COLLADASWSampler.h"
+ #include "COLLADASWLibraryEffects.h"
+ #include "DNA_image_types.h"
+ #include "DNA_material_types.h"
+ #include "DNA_object_types.h"
+ #include "DNA_scene_types.h"
+ class EffectsExporter: COLLADASW::LibraryEffects
+ {
+ public:
+       EffectsExporter(COLLADASW::StreamWriter *sw);
+       void exportEffects(Scene *sce);
+       void operator()(Material *ma, Object *ob);
+       
+       COLLADASW::ColorOrTexture createTexture(Image *ima,
+                                                                                       std::string& uv_layer_name,
+                                                                                       COLLADASW::Sampler *sampler
+                                                                                       /*COLLADASW::Surface *surface*/);
+       
+       COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a);
+       
+       //returns the array of mtex indices which have image 
+       //need this for exporting textures
+       void createTextureIndices(Material *ma, std::vector<int> &indices);
+ };
+ #endif
index 0000000,73ad6f4..12e0ca3
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,477 +1,477 @@@
 - * $Id$
+ /**
++ * $Id: GeometryExporter.cpp 34533 2011-01-27 19:39:06Z jesterking $
+  *
+  * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include "COLLADASWPrimitves.h"
+ #include "COLLADASWSource.h"
+ #include "COLLADASWVertices.h"
+ #include "COLLADABUUtils.h"
+ #include "GeometryExporter.h"
+ #include "DNA_meshdata_types.h"
+ #include "BKE_customdata.h"
+ #include "BKE_material.h"
+ #include "collada_internal.h"
+ // TODO: optimize UV sets by making indexed list with duplicates removed
+ GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryGeometries(sw) {}
+ void GeometryExporter::exportGeom(Scene *sce)
+ {
+       openLibrary();
+       mScene = sce;
+       GeometryFunctor gf;
+       gf.forEachMeshObjectInScene<GeometryExporter>(sce, *this);
+       closeLibrary();
+ }
+ void GeometryExporter::operator()(Object *ob)
+ {
+       // XXX don't use DerivedMesh, Mesh instead?
+ #if 0         
+       DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
+ #endif
+       Mesh *me = (Mesh*)ob->data;
+       std::string geom_id = get_geometry_id(ob);
+       std::vector<Normal> nor;
+       std::vector<Face> norind;
+       // Skip if linked geometry was already exported from another reference
+       if (exportedGeometry.find(geom_id) != exportedGeometry.end())
+               return;
+       exportedGeometry.insert(geom_id);
+       bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
+       create_normals(nor, norind, me);
+       // openMesh(geoId, geoName, meshId)
+       openMesh(geom_id);
+       
+       // writes <source> for vertex coords
+       createVertsSource(geom_id, me);
+       
+       // writes <source> for normal coords
+       createNormalsSource(geom_id, me, nor);
+       bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
+       
+       // writes <source> for uv coords if mesh has uv coords
+       if (has_uvs)
+               createTexcoordsSource(geom_id, me);
+       if (has_color)
+               createVertexColorSource(geom_id, me);
+       // <vertices>
+       COLLADASW::Vertices verts(mSW);
+       verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
+       COLLADASW::InputList &input_list = verts.getInputList();
+       COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
+       input_list.push_back(input);
+       verts.add();
+       // XXX slow             
+       if (ob->totcol) {
+               for(int a = 0; a < ob->totcol; a++)     {
+                       createPolylist(a, has_uvs, has_color, ob, geom_id, norind);
+               }
+       }
+       else {
+               createPolylist(0, has_uvs, has_color, ob, geom_id, norind);
+       }
+       
+       closeMesh();
+       closeGeometry();
+       
+ #if 0
+       dm->release(dm);
+ #endif
+ }
+ // powerful because it handles both cases when there is material and when there's not
+ void GeometryExporter::createPolylist(int material_index,
+                                       bool has_uvs,
+                                       bool has_color,
+                                       Object *ob,
+                                       std::string& geom_id,
+                                       std::vector<Face>& norind)
+ {
+       Mesh *me = (Mesh*)ob->data;
+       MFace *mfaces = me->mface;
+       int totfaces = me->totface;
+       // <vcount>
+       int i;
+       int faces_in_polylist = 0;
+       std::vector<unsigned long> vcount_list;
+       // count faces with this material
+       for (i = 0; i < totfaces; i++) {
+               MFace *f = &mfaces[i];
+               
+               if (f->mat_nr == material_index) {
+                       faces_in_polylist++;
+                       if (f->v4 == 0) {
+                               vcount_list.push_back(3);
+                       }
+                       else {
+                               vcount_list.push_back(4);
+                       }
+               }
+       }
+       // no faces using this material
+       if (faces_in_polylist == 0) {
+               fprintf(stderr, "%s: no faces use material %d\n", id_name(ob).c_str(), material_index);
+               return;
+       }
+               
+       Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
+       COLLADASW::Polylist polylist(mSW);
+               
+       // sets count attribute in <polylist>
+       polylist.setCount(faces_in_polylist);
+               
+       // sets material name
+       if (ma) {
+               polylist.setMaterial(translate_id(id_name(ma)));
+       }
+                       
+       COLLADASW::InputList &til = polylist.getInputList();
+               
+       // creates <input> in <polylist> for vertices 
+       COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
+               
+       // creates <input> in <polylist> for normals
+       COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
+               
+       til.push_back(input1);
+       til.push_back(input2);
+               
+       // if mesh has uv coords writes <input> for TEXCOORD
+       int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+       for (i = 0; i < num_layers; i++) {
+               // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
+               COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
+                                                               makeUrl(makeTexcoordSourceId(geom_id, i)),
+                                                               2, // offset always 2, this is only until we have optimized UV sets
+                                                               i  // set number equals UV layer index
+                                                               );
+               til.push_back(input3);
+       }
+       if (has_color) {
+               COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::COLOR), has_uvs ? 3 : 2);
+               til.push_back(input4);
+       }
+               
+       // sets <vcount>
+       polylist.setVCountList(vcount_list);
+               
+       // performs the actual writing
+       polylist.prepareToAppendValues();
+               
+       // <p>
+       int texindex = 0;
+       for (i = 0; i < totfaces; i++) {
+               MFace *f = &mfaces[i];
+               if (f->mat_nr == material_index) {
+                       unsigned int *v = &f->v1;
+                       unsigned int *n = &norind[i].v1;
+                       for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
+                               polylist.appendValues(v[j]);
+                               polylist.appendValues(n[j]);
+                               if (has_uvs)
+                                       polylist.appendValues(texindex + j);
+                               if (has_color)
+                                       polylist.appendValues(texindex + j);
+                       }
+               }
+               texindex += 3;
+               if (f->v4 != 0)
+                       texindex++;
+       }
+               
+       polylist.finish();
+ }
+ // creates <source> for positions
+ void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
+ {
+ #if 0
+       int totverts = dm->getNumVerts(dm);
+       MVert *verts = dm->getVertArray(dm);
+ #endif
+       int totverts = me->totvert;
+       MVert *verts = me->mvert;
+       
+       COLLADASW::FloatSourceF source(mSW);
+       source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
+       source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
+                                         ARRAY_ID_SUFFIX);
+       source.setAccessorCount(totverts);
+       source.setAccessorStride(3);
+       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+       param.push_back("X");
+       param.push_back("Y");
+       param.push_back("Z");
+       /*main function, it creates <source id = "">, <float_array id = ""
+         count = ""> */
+       source.prepareToAppendValues();
+       //appends data to <float_array>
+       int i = 0;
+       for (i = 0; i < totverts; i++) {
+               source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);                    
+       }
+       
+       source.finish();
+ }
+ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
+ {
+       if (!CustomData_has_layer(&me->fdata, CD_MCOL))
+               return;
+       MFace *f;
+       int totcolor = 0, i, j;
+       for (i = 0, f = me->mface; i < me->totface; i++, f++)
+               totcolor += f->v4 ? 4 : 3;
+       COLLADASW::FloatSourceF source(mSW);
+       source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR));
+       source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + ARRAY_ID_SUFFIX);
+       source.setAccessorCount(totcolor);
+       source.setAccessorStride(3);
+       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+       param.push_back("R");
+       param.push_back("G");
+       param.push_back("B");
+       source.prepareToAppendValues();
+       int index = CustomData_get_active_layer_index(&me->fdata, CD_MCOL);
+       MCol *mcol = (MCol*)me->fdata.layers[index].data;
+       MCol *c = mcol;
+       for (i = 0, f = me->mface; i < me->totface; i++, c += 4, f++)
+               for (j = 0; j < (f->v4 ? 4 : 3); j++)
+                       source.appendValues(c[j].b / 255.0f, c[j].g / 255.0f, c[j].r / 255.0f);
+       
+       source.finish();
+ }
+ std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index)
+ {
+       char suffix[20];
+       sprintf(suffix, "-%d", layer_index);
+       return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
+ }
+ //creates <source> for texcoords
+ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
+ {
+ #if 0
+       int totfaces = dm->getNumFaces(dm);
+       MFace *mfaces = dm->getFaceArray(dm);
+ #endif
+       int totfaces = me->totface;
+       MFace *mfaces = me->mface;
+       int totuv = 0;
+       int i;
+       // count totuv
+       for (i = 0; i < totfaces; i++) {
+               MFace *f = &mfaces[i];
+               if (f->v4 == 0) {
+                       totuv+=3;
+               }
+               else {
+                       totuv+=4;
+               }
+       }
+       int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+       // write <source> for each layer
+       // each <source> will get id like meshName + "map-channel-1"
+       for (int a = 0; a < num_layers; a++) {
+               MTFace *tface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a);
+               // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a);
+               
+               COLLADASW::FloatSourceF source(mSW);
+               std::string layer_id = makeTexcoordSourceId(geom_id, a);
+               source.setId(layer_id);
+               source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
+               
+               source.setAccessorCount(totuv);
+               source.setAccessorStride(2);
+               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+               param.push_back("S");
+               param.push_back("T");
+               
+               source.prepareToAppendValues();
+               
+               for (i = 0; i < totfaces; i++) {
+                       MFace *f = &mfaces[i];
+                       
+                       for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
+                               source.appendValues(tface[i].uv[j][0],
+                                                                       tface[i].uv[j][1]);
+                       }
+               }
+               
+               source.finish();
+       }
+ }
+ //creates <source> for normals
+ void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
+ {
+ #if 0
+       int totverts = dm->getNumVerts(dm);
+       MVert *verts = dm->getVertArray(dm);
+ #endif
+       COLLADASW::FloatSourceF source(mSW);
+       source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
+       source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) +
+                                         ARRAY_ID_SUFFIX);
+       source.setAccessorCount((unsigned long)nor.size());
+       source.setAccessorStride(3);
+       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+       param.push_back("X");
+       param.push_back("Y");
+       param.push_back("Z");
+       
+       source.prepareToAppendValues();
+       std::vector<Normal>::iterator it;
+       for (it = nor.begin(); it != nor.end(); it++) {
+               Normal& n = *it;
+               source.appendValues(n.x, n.y, n.z);
+       }
+       source.finish();
+ }
+ void GeometryExporter::create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me)
+ {
+       int i, j, v;
+       MVert *vert = me->mvert;
+       std::map<unsigned int, unsigned int> nshar;
+       for (i = 0; i < me->totface; i++) {
+               MFace *fa = &me->mface[i];
+               Face f;
+               unsigned int *nn = &f.v1;
+               unsigned int *vv = &fa->v1;
+               memset(&f, 0, sizeof(f));
+               v = fa->v4 == 0 ? 3 : 4;
+               if (!(fa->flag & ME_SMOOTH)) {
+                       Normal n;
+                       if (v == 4)
+                               normal_quad_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co, vert[fa->v4].co);
+                       else
+                               normal_tri_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co);
+                       nor.push_back(n);
+               }
+               for (j = 0; j < v; j++) {
+                       if (fa->flag & ME_SMOOTH) {
+                               if (nshar.find(*vv) != nshar.end())
+                                       *nn = nshar[*vv];
+                               else {
+                                       Normal n = {
+                                               vert[*vv].no[0]/32767.0,
+                                               vert[*vv].no[1]/32767.0,
+                                               vert[*vv].no[2]/32767.0
+                                       };
+                                       nor.push_back(n);
+                                       *nn = (unsigned int)nor.size() - 1;
+                                       nshar[*vv] = *nn;
+                               }
+                               vv++;
+                       }
+                       else {
+                               *nn = (unsigned int)nor.size() - 1;
+                       }
+                       nn++;
+               }
+               ind.push_back(f);
+       }
+ }
+ std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix) {
+       return geom_id + getSuffixBySemantic(type) + other_suffix;
+ }
+ COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix) {
+       
+       std::string id(getIdBySemantics(geom_id, type, other_suffix));
+       return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
+       
+ }
+ COLLADASW::URI GeometryExporter::makeUrl(std::string id)
+ {
+       return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
+ }
+ /* int GeometryExporter::getTriCount(MFace *faces, int totface) {
+       int i;
+       int tris = 0;
+       for (i = 0; i < totface; i++) {
+               // if quad
+               if (faces[i].v4 != 0)
+                       tris += 2;
+               else
+                       tris++;
+       }
+       return tris;
+       }*/
index 0000000,b3013f7..1f08f93
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,117 +1,117 @@@
 - * $Id$
+ /**
++ * $Id: GeometryExporter.h 34533 2011-01-27 19:39:06Z jesterking $
+  *
+  * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #ifndef __GEOMETRYEXPORTER_H__
+ #define __GEOMETRYEXPORTER_H__
+ #include <string>
+ #include <vector>
+ #include <set>
+ #include "COLLADASWStreamWriter.h"
+ #include "COLLADASWLibraryGeometries.h"
+ #include "COLLADASWInputList.h"
+ #include "DNA_mesh_types.h"
+ #include "DNA_object_types.h"
+ #include "DNA_scene_types.h"
+ // TODO: optimize UV sets by making indexed list with duplicates removed
+ class GeometryExporter : COLLADASW::LibraryGeometries
+ {
+       struct Face
+       {
+               unsigned int v1, v2, v3, v4;
+       };
+       struct Normal
+       {
+               float x, y, z;
+       };
+       Scene *mScene;
+ public:
+       GeometryExporter(COLLADASW::StreamWriter *sw);
+       void exportGeom(Scene *sce);
+       void operator()(Object *ob);
+       // powerful because it handles both cases when there is material and when there's not
+       void createPolylist(int material_index,
+                                               bool has_uvs,
+                                               bool has_color,
+                                               Object *ob,
+                                               std::string& geom_id,
+                                               std::vector<Face>& norind);
+       
+       // creates <source> for positions
+       void createVertsSource(std::string geom_id, Mesh *me);
+       void createVertexColorSource(std::string geom_id, Mesh *me);
+       std::string makeTexcoordSourceId(std::string& geom_id, int layer_index);
+       //creates <source> for texcoords
+       void createTexcoordsSource(std::string geom_id, Mesh *me);
+       //creates <source> for normals
+       void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor);
+       void create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me);
+       
+       std::string getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix = "");
+       
+       COLLADASW::URI getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix = "");
+       COLLADASW::URI makeUrl(std::string id);
+       
+       /* int getTriCount(MFace *faces, int totface);*/
+ private:
+       std::set<std::string> exportedGeometry;
+ };
+ struct GeometryFunctor {
+       // f should have
+       // void operator()(Object* ob)
+       template<class Functor>
+       void forEachMeshObjectInScene(Scene *sce, Functor &f)
+       {
+               
+               Base *base= (Base*) sce->base.first;
+               while(base) {
+                       Object *ob = base->object;
+                       
+                       if (ob->type == OB_MESH && ob->data) {
+                               f(ob);
+                       }
+                       base= base->next;
+                       
+               }
+       }
+ };
+ #endif
index 0000000,240125d..f3b00f4
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,94 +1,94 @@@
 - * $Id$
+ /**
++ * $Id: ImageExporter.cpp 33274 2010-11-23 23:58:12Z jesterking $
+  *
+  * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include "COLLADABUURI.h"
+ #include "COLLADASWImage.h"
+ #include "ImageExporter.h"
+ #include "MaterialExporter.h"
+ #include "DNA_texture_types.h"
+ #include "BKE_global.h"
+ #include "BKE_main.h"
+ #include "BKE_utildefines.h"
+ #include "BLI_fileops.h"
+ #include "BLI_path_util.h"
+ #include "BLI_string.h"
+ ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const char* filename) : COLLADASW::LibraryImages(sw), mfilename(filename)
+ {}
+ void ImagesExporter::exportImages(Scene *sce)
+ {
+       openLibrary();
+       MaterialFunctor mf;
+       mf.forEachMaterialInScene<ImagesExporter>(sce, *this);
+       closeLibrary();
+ }
+ void ImagesExporter::operator()(Material *ma, Object *ob)
+ {
+       int a;
+       for (a = 0; a < MAX_MTEX; a++) {
+               MTex *mtex = ma->mtex[a];
+               if (mtex && mtex->tex && mtex->tex->ima) {
+                       Image *image = mtex->tex->ima;
+                       std::string name(id_name(image));
+                       name = translate_id(name);
+                       char rel[FILE_MAX];
+                       char abs[FILE_MAX];
+                       char src[FILE_MAX];
+                       char dir[FILE_MAX];
+                       
+                       BLI_split_dirfile(mfilename, dir, NULL);
+                       BKE_rebase_path(abs, sizeof(abs), rel, sizeof(rel), G.main->name, image->name, dir);
+                       if (abs[0] != '\0') {
+                               // make absolute source path
+                               BLI_strncpy(src, image->name, sizeof(src));
+                               BLI_path_abs(src, G.main->name);
+                               // make dest directory if it doesn't exist
+                               BLI_make_existing_file(abs);
+                       
+                               if (BLI_copy_fileops(src, abs) != 0) {
+                                       fprintf(stderr, "Cannot copy image to file's directory. \n");
+                               }
+                       } 
+                       
+                       if (find(mImages.begin(), mImages.end(), name) == mImages.end()) {
+                               COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(rel)), name, name); /* set name also to mNameNC. This helps other viewers import files exported from Blender better */
+                               img.add(mSW);
+                               mImages.push_back(name);
+                       }
+               }
+       }
+ }
@@@ -1,5 -1,5 +1,5 @@@
  /**
-- * $Id$
++ * $Id: ImageExporter.h 32355 2010-10-06 20:40:16Z gsrb3d $
   *
   * ***** BEGIN GPL LICENSE BLOCK *****
   *
index 0000000,746f41f..c3c62f4
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,64 +1,64 @@@
 - * $Id$
+ /**
++ * $Id: InstanceWriter.cpp 32355 2010-10-06 20:40:16Z gsrb3d $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include <string>
+ #include "COLLADASWInstanceMaterial.h"
+ #include "BKE_customdata.h"
+ #include "BKE_material.h"
+ #include "DNA_mesh_types.h"
+ #include "InstanceWriter.h"
+ #include "collada_internal.h"
+ #include "collada_utils.h"
+ void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob)
+ {
+       for(int a = 0; a < ob->totcol; a++)     {
+               Material *ma = give_current_material(ob, a+1);
+                       
+               COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList();
+               if (ma) {
+                       std::string matid(id_name(ma));
+                       matid = translate_id(matid);
+                       COLLADASW::InstanceMaterial im(matid, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
+                       
+                       // create <bind_vertex_input> for each uv layer
+                       Mesh *me = (Mesh*)ob->data;
+                       int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+                       
+                       for (int b = 0; b < totlayer; b++) {
+                               char *name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, b);
+                               im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", b));
+                       }
+                       
+                       iml.push_back(im);
+               }
+       }
+ }
@@@ -1,5 -1,5 +1,5 @@@
  /**
-- * $Id$
++ * $Id: InstanceWriter.h 32355 2010-10-06 20:40:16Z gsrb3d $
   *
   * ***** BEGIN GPL LICENSE BLOCK *****
   *
index 0000000,5786c68..b9a2780
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,139 +1,139 @@@
 - * $Id$
+ /**
++ * $Id: LightExporter.cpp 32468 2010-10-14 09:40:56Z jesterking $
+  *
+  * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include <string>
+ #include "COLLADASWColor.h"
+ #include "COLLADASWLight.h"
+ #include "DNA_lamp_types.h"
+ #include "BLI_math.h"
+ #include "LightExporter.h"
+ #include "collada_internal.h"
+ template<class Functor>
+ void forEachLampObjectInScene(Scene *sce, Functor &f)
+ {
+       Base *base= (Base*) sce->base.first;
+       while(base) {
+               Object *ob = base->object;
+                       
+               if (ob->type == OB_LAMP && ob->data) {
+                       f(ob);
+               }
+               base= base->next;
+       }
+ }
+ LightsExporter::LightsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryLights(sw){}
+ void LightsExporter::exportLights(Scene *sce)
+ {
+       openLibrary();
+       
+       forEachLampObjectInScene(sce, *this);
+       
+       closeLibrary();
+ }
+ void LightsExporter::operator()(Object *ob)
+ {
+       Lamp *la = (Lamp*)ob->data;
+       std::string la_id(get_light_id(ob));
+       std::string la_name(id_name(la));
+       COLLADASW::Color col(la->r, la->g, la->b);
+       float att1, att2;
+       float e, d, constatt, linatt, quadatt;
+       att1 = att2 = 0.0f;
+       
+       if(la->falloff_type==LA_FALLOFF_INVLINEAR) {
+               att1 = 1.0f;
+               att2 = 0.0f;
+       }
+       else if(la->falloff_type==LA_FALLOFF_INVSQUARE) {
+               att1 = 0.0f;
+               att2 = 1.0f;
+       }
+       else if(la->falloff_type==LA_FALLOFF_SLIDERS) {
+               att1 = la->att1;
+               att2 = la->att2;
+       }
+       
+       e = la->energy;
+       d = la->dist;
+       
+       constatt = linatt = quadatt = MAXFLOAT;
+       if(e > 0.0f) {
+               constatt = 1.0f/e;
+               linatt = att1/(d*e);
+               quadatt = att2/(d*d*(e*2));
+       }
+       
+       // sun
+       if (la->type == LA_SUN) {
+               COLLADASW::DirectionalLight cla(mSW, la_id, la_name, e);
+               cla.setColor(col);
+               cla.setConstantAttenuation(constatt);
+               addLight(cla);
+       }
+       // hemi
+       else if (la->type == LA_HEMI) {
+               COLLADASW::AmbientLight cla(mSW, la_id, la_name, e);
+               cla.setColor(col);
+               cla.setConstantAttenuation(constatt);
+               addLight(cla);
+       }
+       // spot
+       else if (la->type == LA_SPOT) {
+               COLLADASW::SpotLight cla(mSW, la_id, la_name, e);
+               cla.setColor(col);
+               cla.setFallOffAngle(la->spotsize);
+               cla.setFallOffExponent(la->spotblend);
+               cla.setConstantAttenuation(constatt);
+               cla.setLinearAttenuation(linatt);
+               cla.setQuadraticAttenuation(quadatt);
+               addLight(cla);
+       }
+       // lamp
+       else if (la->type == LA_LOCAL) {
+               COLLADASW::PointLight cla(mSW, la_id, la_name, e);
+               cla.setColor(col);
+               cla.setConstantAttenuation(constatt);
+               cla.setLinearAttenuation(linatt);
+               cla.setQuadraticAttenuation(quadatt);
+               addLight(cla);
+       }
+       // area lamp is not supported
+       // it will be exported as a local lamp
+       else {
+               COLLADASW::PointLight cla(mSW, la_id, la_name, e);
+               cla.setColor(col);
+               cla.setConstantAttenuation(constatt);
+               cla.setLinearAttenuation(linatt);
+               cla.setQuadraticAttenuation(quadatt);
+               addLight(cla);
+       }
+ }
@@@ -1,5 -1,5 +1,5 @@@
  /**
-- * $Id$
++ * $Id: LightExporter.h 32355 2010-10-06 20:40:16Z gsrb3d $
   *
   * ***** BEGIN GPL LICENSE BLOCK *****
   *
@@@ -1,5 -1,5 +1,5 @@@
  /**
-- * $Id$
++ * $Id: MaterialExporter.cpp 32679 2010-10-24 07:55:56Z damien78 $
   *
   * ***** BEGIN GPL LICENSE BLOCK *****
   *
index 0000000,2138d26..18ba7eb
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,94 +1,94 @@@
 - * $Id$
+ /**
++ * $Id: MaterialExporter.h 32355 2010-10-06 20:40:16Z gsrb3d $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
+  *                 Nathan Letwory
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #ifndef __MATERIALEXPORTER_H__
+ #define __MATERIALEXPORTER_H__
+ #include <string>
+ #include <vector>
+ #include "COLLADASWLibraryMaterials.h"
+ #include "COLLADASWStreamWriter.h"
+ #include "BKE_material.h"
+ #include "DNA_material_types.h"
+ #include "DNA_object_types.h"
+ #include "DNA_scene_types.h"
+ #include "GeometryExporter.h"
+ #include "collada_internal.h"
+ class MaterialsExporter: COLLADASW::LibraryMaterials
+ {
+ public:
+       MaterialsExporter(COLLADASW::StreamWriter *sw);
+       void exportMaterials(Scene *sce);
+       void operator()(Material *ma, Object *ob);
+ };
+ // used in forEachMaterialInScene
+ template <class Functor>
+ class ForEachMaterialFunctor
+ {
+       std::vector<std::string> mMat; // contains list of material names, to avoid duplicate calling of f
+       Functor *f;
+ public:
+       ForEachMaterialFunctor(Functor*f) : f(f) {}
+       
+       void operator ()(Object *ob)
+       {
+               int a;
+               for(a = 0; a < ob->totcol; a++) {
+                       Material *ma = give_current_material(ob, a+1);
+                       if (!ma) continue;
+                       std::string translated_id = translate_id(id_name(ma));
+                       if (find(mMat.begin(), mMat.end(), translated_id) == mMat.end()) {
+                               (*this->f)(ma, ob);
+                               mMat.push_back(translated_id);
+                       }
+               }
+       }
+ };
+ struct MaterialFunctor {
+       // calls f for each unique material linked to each object in sce
+       // f should have
+       // void operator()(Material* ma)
+       template<class Functor>
+       void forEachMaterialInScene(Scene *sce, Functor &f)
+       {
+               ForEachMaterialFunctor<Functor> matfunc(&f);
+               GeometryFunctor gf;
+               gf.forEachMeshObjectInScene<ForEachMaterialFunctor<Functor> >(sce, matfunc);
+       }
+ };
+ #endif
index 0000000,b42adc0..d29a5b6
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,915 +1,915 @@@
 - * $Id$
+ /**
++ * $Id: MeshImporter.cpp 34787 2011-02-12 06:25:04Z campbellbarton $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include <algorithm>
+ #if !defined(WIN32) || defined(FREE_WINDOWS)
+ #include <iostream>
+ #endif
+ /* COLLADABU_ASSERT, may be able to remove later */
+ #include "COLLADABUPlatform.h"
+ #include "COLLADAFWMeshPrimitive.h"
+ #include "COLLADAFWMeshVertexData.h"
+ #include "COLLADAFWPolygons.h"
+ extern "C" {
+ #include "BKE_blender.h"
+ #include "BKE_customdata.h"
+ #include "BKE_displist.h"
+ #include "BKE_global.h"
+ #include "BKE_library.h"
+ #include "BKE_main.h"
+ #include "BKE_material.h"
+ #include "BKE_mesh.h"
+ #include "BKE_object.h"
+ #include "BLI_listbase.h"
+ #include "BLI_math.h"
+ #include "BLI_string.h"
+ #include "MEM_guardedalloc.h"
+ }
+ #include "ArmatureImporter.h"
+ #include "MeshImporter.h"
+ #include "collada_utils.h"
+ // works for COLLADAFW::Node, COLLADAFW::Geometry
+ template<class T>
+ static const char *bc_get_dae_name(T *node)
+ {
+       const std::string& name = node->getName();
+       return name.size() ? name.c_str() : node->getOriginalId().c_str();
+ }
+ static const char *bc_primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type)
+ {
+       switch (type) {
+       case COLLADAFW::MeshPrimitive::LINES:
+               return "LINES";
+       case COLLADAFW::MeshPrimitive::LINE_STRIPS:
+               return "LINESTRIPS";
+       case COLLADAFW::MeshPrimitive::POLYGONS:
+               return "POLYGONS";
+       case COLLADAFW::MeshPrimitive::POLYLIST:
+               return "POLYLIST";
+       case COLLADAFW::MeshPrimitive::TRIANGLES:
+               return "TRIANGLES";
+       case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
+               return "TRIANGLE_FANS";
+       case COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS:
+               return "TRIANGLE_FANS";
+       case COLLADAFW::MeshPrimitive::POINTS:
+               return "POINTS";
+       case COLLADAFW::MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE:
+               return "UNDEFINED_PRIMITIVE_TYPE";
+       }
+       return "UNKNOWN";
+ }
+ static const char *bc_geomTypeToStr(COLLADAFW::Geometry::GeometryType type)
+ {
+       switch (type) {
+       case COLLADAFW::Geometry::GEO_TYPE_MESH:
+               return "MESH";
+       case COLLADAFW::Geometry::GEO_TYPE_SPLINE:
+               return "SPLINE";
+       case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH:
+               return "CONVEX_MESH";
+       case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN:
+       default:
+               return "UNKNOWN";
+       }
+ }
+ UVDataWrapper::UVDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata)
+ {}
+ #ifdef COLLADA_DEBUG
+ void WVDataWrapper::print()
+ {
+       fprintf(stderr, "UVs:\n");
+       switch(mVData->getType()) {
+       case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
+               {
+                       COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues();
+                       if (values->getCount()) {
+                               for (int i = 0; i < values->getCount(); i += 2) {
+                                       fprintf(stderr, "%.1f, %.1f\n", (*values)[i], (*values)[i+1]);
+                               }
+                       }
+               }
+               break;
+       case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
+               {
+                       COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues();
+                       if (values->getCount()) {
+                               for (int i = 0; i < values->getCount(); i += 2) {
+                                       fprintf(stderr, "%.1f, %.1f\n", (float)(*values)[i], (float)(*values)[i+1]);
+                               }
+                       }
+               }
+               break;
+       }
+       fprintf(stderr, "\n");
+ }
+ #endif
+ void UVDataWrapper::getUV(int uv_index[2], float *uv)
+ {
+       switch(mVData->getType()) {
+       case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
+               {
+                       COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues();
+                       if (values->empty()) return;
+                       uv[0] = (*values)[uv_index[0]];
+                       uv[1] = (*values)[uv_index[1]];
+                       
+               }
+               break;
+       case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
+               {
+                       COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues();
+                       if (values->empty()) return;
+                       uv[0] = (float)(*values)[uv_index[0]];
+                       uv[1] = (float)(*values)[uv_index[1]];
+                       
+               }
+               break;
+       case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:      
+       default:
+               fprintf(stderr, "MeshImporter.getUV(): unknown data type\n");
+       }
+ }
+ void MeshImporter::set_face_indices(MFace *mface, unsigned int *indices, bool quad)
+ {
+       mface->v1 = indices[0];
+       mface->v2 = indices[1];
+       mface->v3 = indices[2];
+       if (quad) mface->v4 = indices[3];
+       else mface->v4 = 0;
+ #ifdef COLLADA_DEBUG
+       // fprintf(stderr, "%u, %u, %u \n", indices[0], indices[1], indices[2]);
+ #endif
+ }
+ // not used anymore, test_index_face from blenkernel is better
+ #if 0
+ // change face indices order so that v4 is not 0
+ void MeshImporter::rotate_face_indices(MFace *mface) {
+       mface->v4 = mface->v1;
+       mface->v1 = mface->v2;
+       mface->v2 = mface->v3;
+       mface->v3 = 0;
+ }
+ #endif
+ void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
+                                COLLADAFW::IndexList& index_list, unsigned int *tris_indices)
+ {
+       int uv_indices[4][2];
+       // per face vertex indices, this means for quad we have 4 indices, not 8
+       COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
+       // make indices into FloatOrDoubleArray
+       for (int i = 0; i < 3; i++) {
+               int uv_index = indices[tris_indices[i]];
+               uv_indices[i][0] = uv_index * 2;
+               uv_indices[i][1] = uv_index * 2 + 1;
+       }
+       uvs.getUV(uv_indices[0], mtface->uv[0]);
+       uvs.getUV(uv_indices[1], mtface->uv[1]);
+       uvs.getUV(uv_indices[2], mtface->uv[2]);
+ }
+ void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
+                               COLLADAFW::IndexList& index_list, int index, bool quad)
+ {
+       int uv_indices[4][2];
+       // per face vertex indices, this means for quad we have 4 indices, not 8
+       COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
+       // make indices into FloatOrDoubleArray
+       for (int i = 0; i < (quad ? 4 : 3); i++) {
+               int uv_index = indices[index + i];
+               uv_indices[i][0] = uv_index * 2;
+               uv_indices[i][1] = uv_index * 2 + 1;
+       }
+       uvs.getUV(uv_indices[0], mtface->uv[0]);
+       uvs.getUV(uv_indices[1], mtface->uv[1]);
+       uvs.getUV(uv_indices[2], mtface->uv[2]);
+       if (quad) uvs.getUV(uv_indices[3], mtface->uv[3]);
+ #ifdef COLLADA_DEBUG
+       /*if (quad) {
+               fprintf(stderr, "face uv:\n"
+                               "((%d, %d), (%d, %d), (%d, %d), (%d, %d))\n"
+                               "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
+                               uv_indices[0][0], uv_indices[0][1],
+                               uv_indices[1][0], uv_indices[1][1],
+                               uv_indices[2][0], uv_indices[2][1],
+                               uv_indices[3][0], uv_indices[3][1],
+                               mtface->uv[0][0], mtface->uv[0][1],
+                               mtface->uv[1][0], mtface->uv[1][1],
+                               mtface->uv[2][0], mtface->uv[2][1],
+                               mtface->uv[3][0], mtface->uv[3][1]);
+       }
+       else {
+               fprintf(stderr, "face uv:\n"
+                               "((%d, %d), (%d, %d), (%d, %d))\n"
+                               "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
+                               uv_indices[0][0], uv_indices[0][1],
+                               uv_indices[1][0], uv_indices[1][1],
+                               uv_indices[2][0], uv_indices[2][1],
+                               mtface->uv[0][0], mtface->uv[0][1],
+                               mtface->uv[1][0], mtface->uv[1][1],
+                               mtface->uv[2][0], mtface->uv[2][1]);
+       }*/
+ #endif
+ }
+ #ifdef COLLADA_DEBUG
+ void MeshImporter::print_index_list(COLLADAFW::IndexList& index_list)
+ {
+       fprintf(stderr, "Index list for \"%s\":\n", index_list.getName().c_str());
+       for (int i = 0; i < index_list.getIndicesCount(); i += 2) {
+               fprintf(stderr, "%u, %u\n", index_list.getIndex(i), index_list.getIndex(i + 1));
+       }
+       fprintf(stderr, "\n");
+ }
+ #endif
+ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh)
+ {
+       COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
+       const char *name = bc_get_dae_name(mesh);
+       
+       for (unsigned i = 0; i < prim_arr.getCount(); i++) {
+               
+               COLLADAFW::MeshPrimitive *mp = prim_arr[i];
+               COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType();
+               const char *type_str = bc_primTypeToStr(type);
+               
+               // OpenCollada passes POLYGONS type for <polylist>
+               if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
+                       COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp;
+                       COLLADAFW::Polygons::VertexCountArray& vca = mpvc->getGroupedVerticesVertexCountArray();
+                       
+                       for(unsigned int j = 0; j < vca.getCount(); j++){
+                               int count = vca[j];
+                               if (count < 3) {
+                                       fprintf(stderr, "Primitive %s in %s has at least one face with vertex count < 3\n",
+                                                       type_str, name);
+                                       return false;
+                               }
+                       }
+                               
+               }
+               else if(type != COLLADAFW::MeshPrimitive::TRIANGLES) {
+                       fprintf(stderr, "Primitive type %s is not supported.\n", type_str);
+                       return false;
+               }
+       }
+       
+       if (mesh->getPositions().empty()) {
+               fprintf(stderr, "Mesh %s has no vertices.\n", name);
+               return false;
+       }
+       return true;
+ }
+ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
+ {
+       // vertices
+       COLLADAFW::MeshVertexData& pos = mesh->getPositions();
+       int stride = pos.getStride(0);
+       if(stride==0) stride = 3;
+       
+       me->totvert = mesh->getPositions().getFloatValues()->getCount() / stride;
+       me->mvert = (MVert*)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+       MVert *mvert;
+       int i;
+       for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
+               get_vector(mvert->co, pos, i, stride);
+       }
+ }
+ int MeshImporter::triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri)
+ {
+       ListBase dispbase;
+       DispList *dl;
+       float *vert;
+       int i = 0;
+       
+       dispbase.first = dispbase.last = NULL;
+       
+       dl = (DispList*)MEM_callocN(sizeof(DispList), "poly disp");
+       dl->nr = totvert;
+       dl->type = DL_POLY;
+       dl->parts = 1;
+       dl->verts = vert = (float*)MEM_callocN(totvert * 3 * sizeof(float), "poly verts");
+       dl->index = (int*)MEM_callocN(sizeof(int) * 3 * totvert, "dl index");
+       BLI_addtail(&dispbase, dl);
+       
+       for (i = 0; i < totvert; i++) {
+               copy_v3_v3(vert, verts[indices[i]].co);
+               vert += 3;
+       }
+       
+       filldisplist(&dispbase, &dispbase, 0);
+       int tottri = 0;
+       dl= (DispList*)dispbase.first;
+       if (dl->type == DL_INDEX3) {
+               tottri = dl->parts;
+               int *index = dl->index;
+               for (i= 0; i < tottri; i++) {
+                       int t[3]= {*index, *(index + 1), *(index + 2)};
+                       std::sort(t, t + 3);
+                       tri.push_back(t[0]);
+                       tri.push_back(t[1]);
+                       tri.push_back(t[2]);
+                       index += 3;
+               }
+       }
+       freedisplist(&dispbase);
+       return tottri;
+ }
+ int MeshImporter::count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me)
+ {
+       COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
+       unsigned int i;
+       int tottri = 0;
+       
+       for (i = 0; i < prim_arr.getCount(); i++) {
+               
+               COLLADAFW::MeshPrimitive *mp = prim_arr[i];
+               int type = mp->getPrimitiveType();
+               size_t prim_totface = mp->getFaceCount();
+               unsigned int *indices = mp->getPositionIndices().getData();
+               
+               if (type == COLLADAFW::MeshPrimitive::POLYLIST ||
+                       type == COLLADAFW::MeshPrimitive::POLYGONS) {
+                       
+                       COLLADAFW::Polygons *mpvc =     (COLLADAFW::Polygons*)mp;
+                       COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
+                       
+                       for (unsigned int j = 0; j < prim_totface; j++) {
+                               int vcount = vcounta[j];
+                               
+                               if (vcount > 4) {
+                                       std::vector<unsigned int> tri;
+                                       
+                                       // tottri += triangulate_poly(indices, vcount, me->mvert, tri) - 1; // XXX why - 1?!
+                                       tottri += triangulate_poly(indices, vcount, me->mvert, tri);
+                               }
+                               indices += vcount;
+                       }
+               }
+       }
+       return tottri;
+ }
+ // TODO: import uv set names
+ void MeshImporter::read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris)
+ {
+       unsigned int i;
+       
+       // allocate faces
+       me->totface = mesh->getFacesCount() + new_tris;
+       me->mface = (MFace*)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+       
+       // allocate UV layers
+       unsigned int totuvset = mesh->getUVCoords().getInputInfosArray().getCount();
+       for (i = 0; i < totuvset; i++) {
+               if (mesh->getUVCoords().getLength(i) == 0) {
+                       totuvset = 0;
+                       break;
+               }
+       }
+       for (i = 0; i < totuvset; i++) {
+               COLLADAFW::MeshVertexData::InputInfos *info = mesh->getUVCoords().getInputInfosArray()[i];
+               CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface, info->mName.c_str());
+               //this->set_layername_map[i] = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
+       }
+       // activate the first uv layer
+       if (totuvset) me->mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, 0);
+       UVDataWrapper uvs(mesh->getUVCoords());
+ #ifdef COLLADA_DEBUG
+       // uvs.print();
+ #endif
+       MFace *mface = me->mface;
+       MaterialIdPrimitiveArrayMap mat_prim_map;
+       int face_index = 0;
+       COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
+       bool has_normals = mesh->hasNormals();
+       COLLADAFW::MeshVertexData& nor = mesh->getNormals();
+       for (i = 0; i < prim_arr.getCount(); i++) {
+               
+               COLLADAFW::MeshPrimitive *mp = prim_arr[i];
+               // faces
+               size_t prim_totface = mp->getFaceCount();
+               unsigned int *indices = mp->getPositionIndices().getData();
+               unsigned int *nind = mp->getNormalIndices().getData();
+               unsigned int j, k;
+               int type = mp->getPrimitiveType();
+               int index = 0;
+               
+               // since we cannot set mface->mat_nr here, we store a portion of me->mface in Primitive
+               Primitive prim = {mface, 0};
+               COLLADAFW::IndexListArray& index_list_array = mp->getUVCoordIndicesArray();
+ #ifdef COLLADA_DEBUG
+               /*
+               fprintf(stderr, "Primitive %d:\n", i);
+               for (int j = 0; j < totuvset; j++) {
+                       print_index_list(*index_list_array[j]);
+               }
+               */
+ #endif
+               
+               if (type == COLLADAFW::MeshPrimitive::TRIANGLES) {
+                       for (j = 0; j < prim_totface; j++){
+                               
+                               set_face_indices(mface, indices, false);
+                               indices += 3;
+ #if 0
+                               for (k = 0; k < totuvset; k++) {
+                                       if (!index_list_array.empty() && index_list_array[k]) {
+                                               // get mtface by face index and uv set index
+                                               MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
+                                               set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, false);
+                                       }
+                               }
+ #else
+                               for (k = 0; k < index_list_array.getCount(); k++) {
+                                       // get mtface by face index and uv set index
+                                       MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
+                                       set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, false);
+                               }
+ #endif
+                               test_index_face(mface, &me->fdata, face_index, 3);
+                               if (has_normals) {
+                                       if (!flat_face(nind, nor, 3))
+                                               mface->flag |= ME_SMOOTH;
+                                       nind += 3;
+                               }
+                               
+                               index += 3;
+                               mface++;
+                               face_index++;
+                               prim.totface++;
+                       }
+               }
+               else if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
+                       COLLADAFW::Polygons *mpvc =     (COLLADAFW::Polygons*)mp;
+                       COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
+                       
+                       for (j = 0; j < prim_totface; j++) {
+                               
+                               // face
+                               int vcount = vcounta[j];
+                               if (vcount == 3 || vcount == 4) {
+                                       
+                                       set_face_indices(mface, indices, vcount == 4);
+                                       
+                                       // set mtface for each uv set
+                                       // it is assumed that all primitives have equal number of UV sets
+                                       
+ #if 0
+                                       for (k = 0; k < totuvset; k++) {
+                                               if (!index_list_array.empty() && index_list_array[k]) {
+                                                       // get mtface by face index and uv set index
+                                                       MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
+                                                       set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, mface->v4 != 0);
+                                               }
+                                       }
+ #else
+                                       for (k = 0; k < index_list_array.getCount(); k++) {
+                                               // get mtface by face index and uv set index
+                                               MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
+                                               set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, mface->v4 != 0);
+                                       }
+ #endif
+                                       test_index_face(mface, &me->fdata, face_index, vcount);
+                                       if (has_normals) {
+                                               if (!flat_face(nind, nor, vcount))
+                                                       mface->flag |= ME_SMOOTH;
+                                               nind += vcount;
+                                       }
+                                       
+                                       mface++;
+                                       face_index++;
+                                       prim.totface++;
+                                       
+                               }
+                               else {
+                                       std::vector<unsigned int> tri;
+                                       
+                                       triangulate_poly(indices, vcount, me->mvert, tri);
+                                       
+                                       for (k = 0; k < tri.size() / 3; k++) {
+                                               int v = k * 3;
+                                               unsigned int uv_indices[3] = {
+                                                       index + tri[v],
+                                                       index + tri[v + 1],
+                                                       index + tri[v + 2]
+                                               };
+                                               unsigned int tri_indices[3] = {
+                                                       indices[tri[v]],
+                                                       indices[tri[v + 1]],
+                                                       indices[tri[v + 2]]
+                                               };
+                                               set_face_indices(mface, tri_indices, false);
+                                               
+ #if 0
+                                               for (unsigned int l = 0; l < totuvset; l++) {
+                                                       if (!index_list_array.empty() && index_list_array[l]) {
+                                                               // get mtface by face index and uv set index
+                                                               MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, l);
+                                                               set_face_uv(&mtface[face_index], uvs, l, *index_list_array[l], uv_indices);
+                                                       }
+                                               }
+ #else
+                                               for (unsigned int l = 0; l < index_list_array.getCount(); l++) {
+                                                       int uvset_index = index_list_array[l]->getSetIndex();
+                                                       // get mtface by face index and uv set index
+                                                       MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
+                                                       set_face_uv(&mtface[face_index], uvs, *index_list_array[l], uv_indices);
+                                               }
+ #endif
+                                               test_index_face(mface, &me->fdata, face_index, 3);
+                                               if (has_normals) {
+                                                       unsigned int ntri[3] = {nind[tri[v]], nind[tri[v + 1]], nind[tri[v + 2]]};
+                                                       if (!flat_face(ntri, nor, 3))
+                                                               mface->flag |= ME_SMOOTH;
+                                               }
+                                               
+                                               mface++;
+                                               face_index++;
+                                               prim.totface++;
+                                       }
+                                       if (has_normals)
+                                               nind += vcount;
+                               }
+                               index += vcount;
+                               indices += vcount;
+                       }
+               }
+               
+               mat_prim_map[mp->getMaterialId()].push_back(prim);
+       }
+       geom_uid_mat_mapping_map[mesh->getUniqueId()] = mat_prim_map;
+ }
+ void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, int stride)
+ {
+       i *= stride;
+       
+       switch(arr.getType()) {
+       case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
+               {
+                       COLLADAFW::ArrayPrimitiveType<float>* values = arr.getFloatValues();
+                       if (values->empty()) return;
+                       v[0] = (*values)[i++];
+                       v[1] = (*values)[i++];
+                       v[2] = (*values)[i];
+               }
+               break;
+       case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
+               {
+                       COLLADAFW::ArrayPrimitiveType<double>* values = arr.getDoubleValues();
+                       if (values->empty()) return;
+                       v[0] = (float)(*values)[i++];
+                       v[1] = (float)(*values)[i++];
+                       v[2] = (float)(*values)[i];
+               }
+               break;
+       default:
+               break;
+       }
+ }
+ bool MeshImporter::flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count)
+ {
+       float a[3], b[3];
+       get_vector(a, nor, *nind, 3);
+       normalize_v3(a);
+       nind++;
+       for (int i = 1; i < count; i++, nind++) {
+               get_vector(b, nor, *nind, 3);
+               normalize_v3(b);
+               float dp = dot_v3v3(a, b);
+               if (dp < 0.99999f || dp > 1.00001f)
+                       return false;
+       }
+       return true;
+ }
+ MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {}
+ Object *MeshImporter::get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid)
+ {
+       if (uid_object_map.find(geom_uid) != uid_object_map.end())
+               return uid_object_map[geom_uid];
+       return NULL;
+ }
+ MTex *MeshImporter::assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture,
+                                                                Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map,
+                                                                MTex *color_texture)
+ {
+       const COLLADAFW::TextureMapId texture_index = ctexture.getTextureMapId();
+       const size_t setindex = ctexture.getSetIndex();
+       std::string uvname = ctexture.getSemantic();
+       
+       const CustomData *data = &me->fdata;
+       int layer_index = CustomData_get_layer_index(data, CD_MTFACE);
+       CustomDataLayer *cdl = &data->layers[layer_index+setindex];
+       
+       /* set uvname to bind_vertex_input semantic */
+       BLI_strncpy(cdl->name, uvname.c_str(), sizeof(cdl->name));
+       if (texindex_texarray_map.find(texture_index) == texindex_texarray_map.end()) {
+               
+               fprintf(stderr, "Cannot find texture array by texture index.\n");
+               return color_texture;
+       }
+       
+       std::vector<MTex*> textures = texindex_texarray_map[texture_index];
+       
+       std::vector<MTex*>::iterator it;
+       
+       for (it = textures.begin(); it != textures.end(); it++) {
+               
+               MTex *texture = *it;
+               
+               if (texture) {
+                       BLI_strncpy(texture->uvname, uvname.c_str(), sizeof(texture->uvname));
+                       if (texture->mapto == MAP_COL) color_texture = texture;
+               }
+       }
+       return color_texture;
+ }
+ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
+                                                               std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+                                                               Object *ob, const COLLADAFW::UniqueId *geom_uid, 
+                                                               MTex **color_texture, char *layername, MTFace *texture_face,
+                                                               std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, int mat_index)
+ {
+       Mesh *me = (Mesh*)ob->data;
+       const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial();
+       
+       // do we know this material?
+       if (uid_material_map.find(ma_uid) == uid_material_map.end()) {
+               
+               fprintf(stderr, "Cannot find material by UID.\n");
+               return NULL;
+       }
+       
+       Material *ma = uid_material_map[ma_uid];
+       assign_material(ob, ma, ob->totcol + 1);
+       
+       COLLADAFW::TextureCoordinateBindingArray& tex_array = 
+               cmaterial.getTextureCoordinateBindingArray();
+       TexIndexTextureArrayMap texindex_texarray_map = material_texture_mapping_map[ma];
+       unsigned int i;
+       // loop through <bind_vertex_inputs>
+       for (i = 0; i < tex_array.getCount(); i++) {
+               
+               *color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map,
+                                                                                                       *color_texture);
+       }
+       
+       // set texture face
+       if (*color_texture &&
+               strlen((*color_texture)->uvname) &&
+               strcmp(layername, (*color_texture)->uvname) != 0) {
+               
+               texture_face = (MTFace*)CustomData_get_layer_named(&me->fdata, CD_MTFACE,
+                                                                                                                  (*color_texture)->uvname);
+               strcpy(layername, (*color_texture)->uvname);
+       }
+       
+       MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
+       COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId();
+       
+       // assign material indices to mesh faces
+       if (mat_prim_map.find(mat_id) != mat_prim_map.end()) {
+               
+               std::vector<Primitive>& prims = mat_prim_map[mat_id];
+               
+               std::vector<Primitive>::iterator it;
+               
+               for (it = prims.begin(); it != prims.end(); it++) {
+                       Primitive& prim = *it;
+                       i = 0;
+                       while (i++ < prim.totface) {
+                               prim.mface->mat_nr = mat_index;
+                               prim.mface++;
+                               // bind texture images to faces
+                               if (texture_face && (*color_texture)) {
+                                       texture_face->mode = TF_TEX;
+                                       texture_face->tpage = (Image*)(*color_texture)->tex->ima;
+                                       texture_face++;
+                               }
+                       }
+               }
+       }
+       
+       return texture_face;
+ }
+ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
+                                                  bool isController,
+                                                  std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+                                                  std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map)
+ {
+       const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId();
+       
+       // check if node instanciates controller or geometry
+       if (isController) {
+               
+               geom_uid = armature_importer->get_geometry_uid(*geom_uid);
+               
+               if (!geom_uid) {
+                       fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n");
+                       return NULL;
+               }
+       }
+       else {
+               
+               if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) {
+                       // this could happen if a mesh was not created
+                       // (e.g. if it contains unsupported geometry)
+                       fprintf(stderr, "Couldn't find a mesh by UID.\n");
+                       return NULL;
+               }
+       }
+       if (!uid_mesh_map[*geom_uid]) return NULL;
+       
+       Object *ob = add_object(scene, OB_MESH);
+       // store object pointer for ArmatureImporter
+       uid_object_map[*geom_uid] = ob;
+       
+       // name Object
+       const std::string& id = node->getOriginalId();
+       if (id.length())
+               rename_id(&ob->id, (char*)id.c_str());
+       
+       // replace ob->data freeing the old one
+       Mesh *old_mesh = (Mesh*)ob->data;
+       set_mesh(ob, uid_mesh_map[*geom_uid]);
+       
+       if (old_mesh->id.us == 0) free_libblock(&G.main->mesh, old_mesh);
+       
+       char layername[100];
+       MTFace *texture_face = NULL;
+       MTex *color_texture = NULL;
+       
+       COLLADAFW::MaterialBindingArray& mat_array =
+               geom->getMaterialBindings();
+       
+       // loop through geom's materials
+       for (unsigned int i = 0; i < mat_array.getCount(); i++) {
+               
+               texture_face = assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid,
+                                                                                          &color_texture, layername, texture_face,
+                                                                                          material_texture_mapping_map, i);
+       }
+               
+       return ob;
+ }
+ // create a mesh storing a pointer in a map so it can be retrieved later by geometry UID
+ bool MeshImporter::write_geometry(const COLLADAFW::Geometry* geom) 
+ {
+       // TODO: import also uvs, normals
+       // XXX what to do with normal indices?
+       // XXX num_normals may be != num verts, then what to do?
+       // check geometry->getType() first
+       if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) {
+               // TODO: report warning
+               fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType()));
+               return true;
+       }
+       
+       COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh*)geom;
+       
+       if (!is_nice_mesh(mesh)) {
+               fprintf(stderr, "Ignoring mesh %s\n", bc_get_dae_name(mesh));
+               return true;
+       }
+       
+       const std::string& str_geom_id = mesh->getOriginalId();
+       Mesh *me = add_mesh((char*)str_geom_id.c_str());
+       // store the Mesh pointer to link it later with an Object
+       this->uid_mesh_map[mesh->getUniqueId()] = me;
+       
+       int new_tris = 0;
+       
+       read_vertices(mesh, me);
+       new_tris = count_new_tris(mesh, me);
+       
+       read_faces(mesh, me, new_tris);
+       make_edges(me, 0);
+       
+       mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+       return true;
+ }
index 0000000,19a6ab9..3d58ce6
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,152 +1,152 @@@
 - * $Id$
+ /**
++ * $Id: MeshImporter.h 34533 2011-01-27 19:39:06Z jesterking $
+  *
+  * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #ifndef __BC__MESHIMPORTER_H__
+ #define __BC__MESHIMPORTER_H__
+ #include <map>
+ #include <vector>
+ #include "COLLADAFWIndexList.h"
+ #include "COLLADAFWInstanceGeometry.h"
+ #include "COLLADAFWMaterialBinding.h"
+ #include "COLLADAFWMesh.h"
+ #include "COLLADAFWMeshVertexData.h"
+ #include "COLLADAFWNode.h"
+ #include "COLLADAFWTextureCoordinateBinding.h"
+ #include "COLLADAFWTypes.h"
+ #include "COLLADAFWUniqueId.h"
+ #include "DNA_material_types.h"
+ #include "DNA_mesh_types.h"
+ #include "DNA_meshdata_types.h"
+ #include "DNA_object_types.h"
+ #include "DNA_scene_types.h"
+ #include "DNA_texture_types.h"
+ #include "ArmatureImporter.h"
+ #include "collada_utils.h"
+ // only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid
+ class MeshImporterBase
+ {
+ public:
+       virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid) = 0;
+ };
+ class UVDataWrapper
+ {
+       COLLADAFW::MeshVertexData *mVData;
+ public:
+       UVDataWrapper(COLLADAFW::MeshVertexData& vdata);
+ #ifdef COLLADA_DEBUG
+       void print();
+ #endif
+       void getUV(int uv_index[2], float *uv);
+ };
+ class MeshImporter : public MeshImporterBase
+ {
+ private:
+       UnitConverter *unitconverter;
+       Scene *scene;
+       ArmatureImporter *armature_importer;
+       std::map<COLLADAFW::UniqueId, Mesh*> uid_mesh_map; // geometry unique id-to-mesh map
+       std::map<COLLADAFW::UniqueId, Object*> uid_object_map; // geom uid-to-object
+       // this structure is used to assign material indices to faces
+       // it holds a portion of Mesh faces and corresponds to a DAE primitive list (<triangles>, <polylist>, etc.)
+       struct Primitive {
+               MFace *mface;
+               unsigned int totface;
+       };
+       typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive> > MaterialIdPrimitiveArrayMap;
+       std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; // crazy name!
+       
+       void set_face_indices(MFace *mface, unsigned int *indices, bool quad);
+       // not used anymore, test_index_face from blenkernel is better
+ #if 0
+       // change face indices order so that v4 is not 0
+       void rotate_face_indices(MFace *mface);
+ #endif
+       
+       void set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
+                                        COLLADAFW::IndexList& index_list, unsigned int *tris_indices);
+       void set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
+                                       COLLADAFW::IndexList& index_list, int index, bool quad);
+ #ifdef COLLADA_DEBUG
+       void print_index_list(COLLADAFW::IndexList& index_list);
+ #endif
+       bool is_nice_mesh(COLLADAFW::Mesh *mesh);
+       void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me);
+       
+       int triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri);
+       
+       int count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me);
+       
+       // TODO: import uv set names
+       void read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris);
+       void get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, int stride);
+       bool flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count);
+       
+ public:
+       MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce);
+       virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid);
+       
+       MTex *assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture,
+                                                                        Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map,
+                                                                        MTex *color_texture);
+       
+       MTFace *assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
+                                                                       std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+                                                                       Object *ob, const COLLADAFW::UniqueId *geom_uid, 
+                                                                       MTex **color_texture, char *layername, MTFace *texture_face,
+                                                                       std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, int mat_index);
+       
+       
+       Object *create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
+                                                          bool isController,
+                                                          std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+                                                          std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map);
+       // create a mesh storing a pointer in a map so it can be retrieved later by geometry UID
+       bool write_geometry(const COLLADAFW::Geometry* geom);
+ };
+ #endif
index 0000000,4c67137..dcd4047
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,331 +1,331 @@@
 - * $Id$
+ /**
++ * $Id: SkinInfo.cpp 34787 2011-02-12 06:25:04Z campbellbarton $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include <algorithm>
+ #if !defined(WIN32) || defined(FREE_WINDOWS)
+ #include <stdint.h>
+ #endif
+ /* COLLADABU_ASSERT, may be able to remove later */
+ #include "COLLADABUPlatform.h"
+ #include "BKE_object.h"
+ #include "DNA_armature_types.h"
+ #include "DNA_modifier_types.h"
+ #include "ED_mesh.h"
+ #include "ED_object.h"
+ #include "BKE_action.h"
+ #include "BLI_listbase.h"
+ #include "BLI_math.h"
+ #include "SkinInfo.h"
+ #include "collada_utils.h"
+ // use this for retrieving bone names, since these must be unique
+ template<class T>
+ static const char *bc_get_joint_name(T *node)
+ {
+       const std::string& id = node->getOriginalId();
+       return id.size() ? id.c_str() : node->getName().c_str();
+ }
+ // This is used to store data passed in write_controller_data.
+ // Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
+ // so that arrays don't get freed until we free them explicitly.
+ SkinInfo::SkinInfo() {}
+ SkinInfo::SkinInfo(const SkinInfo& skin) : weights(skin.weights),
+                                                                joint_data(skin.joint_data),
+                                                                unit_converter(skin.unit_converter),
+                                                                ob_arm(skin.ob_arm),
+                                                                controller_uid(skin.controller_uid),
+                                                                parent(skin.parent)
+ {
+       copy_m4_m4(bind_shape_matrix, (float (*)[4])skin.bind_shape_matrix);
+       transfer_uint_array_data_const(skin.joints_per_vertex, joints_per_vertex);
+       transfer_uint_array_data_const(skin.weight_indices, weight_indices);
+       transfer_int_array_data_const(skin.joint_indices, joint_indices);
+ }
+ SkinInfo::SkinInfo(UnitConverter *conv) : unit_converter(conv), ob_arm(NULL), parent(NULL) {}
+ // nobody owns the data after this, so it should be freed manually with releaseMemory
+ template <class T>
+ void SkinInfo::transfer_array_data(T& src, T& dest)
+ {
+       dest.setData(src.getData(), src.getCount());
+       src.yieldOwnerShip();
+       dest.yieldOwnerShip();
+ }
+ // when src is const we cannot src.yieldOwnerShip, this is used by copy constructor
+ void SkinInfo::transfer_int_array_data_const(const COLLADAFW::IntValuesArray& src, COLLADAFW::IntValuesArray& dest)
+ {
+       dest.setData((int*)src.getData(), src.getCount());
+       dest.yieldOwnerShip();
+ }
+ void SkinInfo::transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest)
+ {
+       dest.setData((unsigned int*)src.getData(), src.getCount());
+       dest.yieldOwnerShip();
+ }
+ void SkinInfo::borrow_skin_controller_data(const COLLADAFW::SkinControllerData* skin)
+ {
+       transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getJointsPerVertex(), joints_per_vertex);
+       transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getWeightIndices(), weight_indices);
+       transfer_array_data((COLLADAFW::IntValuesArray&)skin->getJointIndices(), joint_indices);
+       // transfer_array_data(skin->getWeights(), weights);
+       // cannot transfer data for FloatOrDoubleArray, copy values manually
+       const COLLADAFW::FloatOrDoubleArray& weight = skin->getWeights();
+       for (unsigned int i = 0; i < weight.getValuesCount(); i++)
+               weights.push_back(bc_get_float_value(weight, i));
+       unit_converter->dae_matrix_to_mat4_(bind_shape_matrix, skin->getBindShapeMatrix());
+ }
+       
+ void SkinInfo::free()
+ {
+       joints_per_vertex.releaseMemory();
+       weight_indices.releaseMemory();
+       joint_indices.releaseMemory();
+       // weights.releaseMemory();
+ }
+ // using inverse bind matrices to construct armature
+ // it is safe to invert them to get the original matrices
+ // because if they are inverse matrices, they can be inverted
+ void SkinInfo::add_joint(const COLLADABU::Math::Matrix4& matrix)
+ {
+       JointData jd;
+       unit_converter->dae_matrix_to_mat4_(jd.inv_bind_mat, matrix);
+       joint_data.push_back(jd);
+ }
+ void SkinInfo::set_controller(const COLLADAFW::SkinController* co)
+ {
+       controller_uid = co->getUniqueId();
+       // fill in joint UIDs
+       const COLLADAFW::UniqueIdArray& joint_uids = co->getJoints();
+       for (unsigned int i = 0; i < joint_uids.getCount(); i++) {
+               joint_data[i].joint_uid = joint_uids[i];
+               // // store armature pointer
+               // JointData& jd = joint_index_to_joint_info_map[i];
+               // jd.ob_arm = ob_arm;
+               // now we'll be able to get inv bind matrix from joint id
+               // joint_id_to_joint_index_map[joint_ids[i]] = i;
+       }
+ }
+ // called from write_controller
+ Object *SkinInfo::create_armature(Scene *scene)
+ {
+       ob_arm = add_object(scene, OB_ARMATURE);
+       return ob_arm;
+ }
+ Object* SkinInfo::set_armature(Object *ob_arm)
+ {
+       if (this->ob_arm)
+               return this->ob_arm;
+       this->ob_arm = ob_arm;
+       return ob_arm;
+ }
+ bool SkinInfo::get_joint_inv_bind_matrix(float inv_bind_mat[][4], COLLADAFW::Node *node)
+ {
+       const COLLADAFW::UniqueId& uid = node->getUniqueId();
+       std::vector<JointData>::iterator it;
+       for (it = joint_data.begin(); it != joint_data.end(); it++) {
+               if ((*it).joint_uid == uid) {
+                       copy_m4_m4(inv_bind_mat, (*it).inv_bind_mat);
+                       return true;
+               }
+       }
+       return false;
+ }
+ Object *SkinInfo::get_armature()
+ {
+       return ob_arm;
+ }
+ const COLLADAFW::UniqueId& SkinInfo::get_controller_uid()
+ {
+       return controller_uid;
+ }
+ // check if this skin controller references a joint or any descendant of it
+ // 
+ // some nodes may not be referenced by SkinController,
+ // in this case to determine if the node belongs to this armature,
+ // we need to search down the tree
+ bool SkinInfo::uses_joint_or_descendant(COLLADAFW::Node *node)
+ {
+       const COLLADAFW::UniqueId& uid = node->getUniqueId();
+       std::vector<JointData>::iterator it;
+       for (it = joint_data.begin(); it != joint_data.end(); it++) {
+               if ((*it).joint_uid == uid)
+                       return true;
+       }
+       COLLADAFW::NodePointerArray& children = node->getChildNodes();
+       for (unsigned int i = 0; i < children.getCount(); i++) {
+               if (uses_joint_or_descendant(children[i]))
+                       return true;
+       }
+       return false;
+ }
+ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid,
+                                  TransformReader *tm)
+ {
+       Main *bmain = CTX_data_main(C);
+       Scene *scene = CTX_data_scene(C);
+       ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature);
+       ((ArmatureModifierData *)md)->object = ob_arm;
+       copy_m4_m4(ob->obmat, bind_shape_matrix);
+       object_apply_mat4(ob, ob->obmat, 0, 0);
+ #if 1
+       bc_set_parent(ob, ob_arm, C);
+ #else
+       Object workob;
+       ob->parent = ob_arm;
+       ob->partype = PAROBJECT;
+       what_does_parent(scene, ob, &workob);
+       invert_m4_m4(ob->parentinv, workob.obmat);
+       ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
+       DAG_scene_sort(bmain, scene);
+       DAG_ids_flush_update(bmain, 0);
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
+ #endif
+       ((bArmature*)ob_arm->data)->deformflag = ARM_DEF_VGROUP;
+       // create all vertex groups
+       std::vector<JointData>::iterator it;
+       int joint_index;
+       for (it = joint_data.begin(), joint_index = 0; it != joint_data.end(); it++, joint_index++) {
+               const char *name = "Group";
+               // skip joints that have invalid UID
+               if ((*it).joint_uid == COLLADAFW::UniqueId::INVALID) continue;
+               
+               // name group by joint node name
+               
+               if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) {
+                       name = bc_get_joint_name(joint_by_uid[(*it).joint_uid]);
+               }
+               ED_vgroup_add_name(ob, (char*)name);
+       }
+       // <vcount> - number of joints per vertex - joints_per_vertex
+       // <v> - [[bone index, weight index] * joints per vertex] * vertices - weight indices
+       // ^ bone index can be -1 meaning weight toward bind shape, how to express this in Blender?
+       // for each vertex in weight indices
+       //   for each bone index in vertex
+       //     add vertex to group at group index
+       //     treat group index -1 specially
+       // get def group by index with BLI_findlink
+       for (unsigned int vertex = 0, weight = 0; vertex < joints_per_vertex.getCount(); vertex++) {
+               unsigned int limit = weight + joints_per_vertex[vertex];
+               for ( ; weight < limit; weight++) {
+                       int joint = joint_indices[weight], joint_weight = weight_indices[weight];
+                       // -1 means "weight towards the bind shape", we just don't assign it to any group
+                       if (joint != -1) {
+                               bDeformGroup *def = (bDeformGroup*)BLI_findlink(&ob->defbase, joint);
+                               ED_vgroup_vert_add(ob, def, vertex, weights[joint_weight], WEIGHT_REPLACE);
+                       }
+               }
+       }
+ }
+ bPoseChannel *SkinInfo::get_pose_channel_from_node(COLLADAFW::Node *node)
+ {
+       return get_pose_channel(ob_arm->pose, bc_get_joint_name(node));
+ }
+ void SkinInfo::set_parent(Object *_parent)
+ {
+       parent = _parent;
+ }
+ Object* SkinInfo::get_parent()
+ {
+       return parent;
+ }
+ void SkinInfo::find_root_joints(const std::vector<COLLADAFW::Node*> &root_joints,
+                                         std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid,
+                                         std::vector<COLLADAFW::Node*>& result)
+ {
+       std::vector<COLLADAFW::Node*>::const_iterator it;
+       for (it = root_joints.begin(); it != root_joints.end(); it++) {
+               COLLADAFW::Node *root = *it;
+               std::vector<JointData>::iterator ji;
+               for (ji = joint_data.begin(); ji != joint_data.end(); ji++) {
+                       COLLADAFW::Node *joint = joint_by_uid[(*ji).joint_uid];
+                       if (find_node_in_tree(joint, root)) {
+                               if (std::find(result.begin(), result.end(), root) == result.end())
+                                       result.push_back(root);
+                       }
+               }
+       }
+ }
+ bool SkinInfo::find_node_in_tree(COLLADAFW::Node *node, COLLADAFW::Node *tree_root)
+ {
+       if (node == tree_root)
+               return true;
+       COLLADAFW::NodePointerArray& children = tree_root->getChildNodes();
+       for (unsigned int i = 0; i < children.getCount(); i++) {
+               if (find_node_in_tree(node, children[i]))
+                       return true;
+       }
+       return false;
+ }
index 0000000,1e31baf..e8fbc86
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,133 +1,133 @@@
 - * $Id$
+ /**
++ * $Id: SkinInfo.h 32310 2010-10-05 00:49:39Z gsrb3d $
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #ifndef __BC_SKININFO_H__
+ #define __BC_SKININFO_H__
+ #include <map>
+ #include <vector>
+ #include "COLLADAFWUniqueId.h"
+ #include "COLLADAFWTypes.h"
+ #include "COLLADAFWNode.h"
+ #include "COLLADAFWSkinController.h"
+ #include "COLLADAFWSkinControllerData.h"
+ #include "DNA_object_types.h"
+ #include "BKE_context.h"
+ #include "TransformReader.h"
+ #include "collada_internal.h"
+ // This is used to store data passed in write_controller_data.
+ // Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
+ // so that arrays don't get freed until we free them explicitly.
+ class SkinInfo
+ {
+ private:
+       // to build armature bones from inverse bind matrices
+       struct JointData {
+               float inv_bind_mat[4][4]; // joint inverse bind matrix
+               COLLADAFW::UniqueId joint_uid; // joint node UID
+               // Object *ob_arm;                        // armature object
+       };
+       float bind_shape_matrix[4][4];
+       // data from COLLADAFW::SkinControllerData, e