Ejemplo n.º 1
0
        private COLLADAScene GetScene(Library_Visual_Scenes scenes)
        {
            var scene = new COLLADAScene();

            scene.Instance_Visual_Scene = new InstanceWithExtra()
            {
                Url = $"#{scenes.Visual_Scene.First().Id}"
            };

            return(scene);
        }
Ejemplo n.º 2
0
        public void ExportToCollada(string outputPath)
        {
            var collada     = new COLLADA();
            var asset       = new asset();
            var contributor = new assetContributor();

            if (ArtToolInfo != null)
            {
                contributor.authoring_tool = ArtToolInfo.FromArtToolName;
            }
            else
            {
                contributor.authoring_tool = "LSLib COLLADA Exporter v" + Common.LibraryVersion();
            }
            asset.contributor = new assetContributor[] { contributor };
            asset.created     = DateTime.Now;
            asset.modified    = DateTime.Now;
            asset.unit        = new assetUnit();
            asset.unit.name   = "meter";
            // TODO: Handle up vector, etc. properly?
            if (ArtToolInfo != null)
            {
                asset.unit.meter = ArtToolInfo.UnitsPerMeter;
            }
            else
            {
                asset.unit.meter = 1;
            }
            asset.up_axis = UpAxisType.Y_UP;
            collada.asset = asset;

            var geometries  = new List <geometry>();
            var controllers = new List <controller>();
            var geomNodes   = new List <node>();

            ExportModels(geometries, controllers, geomNodes);

            var animations     = new List <animation>();
            var animationClips = new List <animation_clip>();

            if (Animations != null)
            {
                foreach (var anim in Animations)
                {
                    var anims = anim.ExportAnimations();
                    animations.AddRange(anims);
                    var clip = new animation_clip();
                    clip.id           = anim.Name + "_Animation";
                    clip.name         = anim.Name;
                    clip.start        = 0.0;
                    clip.end          = anim.Duration;
                    clip.endSpecified = true;

                    var animInstances = new List <InstanceWithExtra>();
                    foreach (var animChannel in anims)
                    {
                        var instance = new InstanceWithExtra();
                        instance.url = "#" + animChannel.id;
                        animInstances.Add(instance);
                    }

                    clip.instance_animation = animInstances.ToArray();
                    animationClips.Add(clip);
                }
            }

            var rootElements = new List <object>();

            if (animations.Count > 0)
            {
                var animationLib = new library_animations();
                animationLib.animation = animations.ToArray();
                rootElements.Add(animationLib);
            }

            if (animationClips.Count > 0)
            {
                var animationClipLib = new library_animation_clips();
                animationClipLib.animation_clip = animationClips.ToArray();
                rootElements.Add(animationClipLib);
            }

            if (geometries.Count > 0)
            {
                var geometryLib = new library_geometries();
                geometryLib.geometry = geometries.ToArray();
                rootElements.Add(geometryLib);
            }

            if (controllers.Count > 0)
            {
                var controllerLib = new library_controllers();
                controllerLib.controller = controllers.ToArray();
                rootElements.Add(controllerLib);
            }

            var visualScenes = new library_visual_scenes();
            var visualScene  = new visual_scene();

            visualScene.id   = "DefaultVisualScene";
            visualScene.name = "unnamed";

            visualScene.node          = geomNodes.ToArray();
            visualScenes.visual_scene = new visual_scene[] { visualScene };

            var visualSceneInstance = new InstanceWithExtra();

            visualSceneInstance.url = "#DefaultVisualScene";
            rootElements.Add(visualScenes);

            var scene = new COLLADAScene();

            scene.instance_visual_scene = visualSceneInstance;
            collada.scene = scene;

            collada.Items = rootElements.ToArray();

            collada.Save(outputPath);
        }
Ejemplo n.º 3
0
        public void Export(string filePath)
        {
            PalletProperties palletProperties = _palletSolution.Analysis.PalletProperties;

            COLLADA model = new COLLADA();

            // asset
            model.asset = new asset()
            {
                created  = DateTime.Now,
                modified = DateTime.Now
            };
            model.asset.keywords = "StackBuilder Pallet Case";
            model.asset.title    = _palletSolution.Title;
            model.asset.unit     = new assetUnit()
            {
                name = "millimeters", meter = 0.001
            };
            model.asset.up_axis = UpAxisType.Z_UP;

            library_images        images     = new library_images();
            library_materials     materials  = new library_materials();
            library_effects       effects    = new library_effects();
            library_geometries    geometries = new library_geometries();
            library_nodes         nodes      = new library_nodes();
            library_cameras       cameras    = new library_cameras();
            library_animations    animations = new library_animations();
            library_visual_scenes scenes     = new library_visual_scenes();

            COLLADAScene colladaScene = new COLLADAScene();

            model.Items = new Object[] { images, materials, effects, geometries, nodes, cameras, animations, scenes };
            model.scene = colladaScene;

            // colors and materials
            List <effect>   listEffects   = new List <effect>();
            List <material> listMaterials = new List <material>();
            List <image>    listImages    = new List <image>();

            // effects
            effect   effectPallet;
            material materialPallet;

            CreateMaterial(palletProperties.Color, null, null, "Pallet", out effectPallet, out materialPallet);
            listEffects.Add(effectPallet);
            listMaterials.Add(materialPallet);

            Box box = new Box(0, _palletSolution.Analysis.BProperties);

            // build list of effects / materials / images
            uint faceIndex = 0;

            foreach (Face face in box.Faces)
            {
                // build texture image if any
                string textureName = null;
                if (face.HasBitmap)
                {
                    textureName = string.Format("textureFace_{0}", faceIndex);
                    string texturePath = System.IO.Path.Combine(
                        System.IO.Path.GetDirectoryName(filePath)
                        , textureName + ".jpg");

                    double dimX = 0.0, dimY = 0.0;

                    switch (faceIndex)
                    {
                    case 0: dimX = box.Width; dimY = box.Height; break;

                    case 1: dimX = box.Width; dimY = box.Height; break;

                    case 2: dimX = box.Length; dimY = box.Height; break;

                    case 3: dimX = box.Length; dimY = box.Height; break;

                    case 4: dimX = box.Length; dimY = box.Width; break;

                    case 5: dimX = box.Length; dimY = box.Width; break;

                    default: break;
                    }
                    face.ExtractFaceBitmap(dimX, dimY, _bmpWidth, texturePath);
                    // create image
                    listImages.Add(
                        new image()
                    {
                        id   = textureName + ".jpg",
                        name = textureName + ".jpg",
                        Item = @".\" + textureName + @".jpg"
                    }
                        );
                }
                material materialCase;
                effect   effectCase;
                CreateMaterial(face.ColorFill, textureName, "0", string.Format("Case{0}", faceIndex), out effectCase, out materialCase);
                listEffects.Add(effectCase);
                listMaterials.Add(materialCase);

                ++faceIndex;
            }

            // add to image list
            images.image = listImages.ToArray();

            // case lines material
            effect   effectCaseLines;
            material materialCaseLines;

            CreateMaterial(Color.Black, null, null, "CaseLines", out effectCaseLines, out materialCaseLines);
            listEffects.Add(effectCaseLines);
            listMaterials.Add(materialCaseLines);
            effects.effect     = listEffects.ToArray();
            materials.material = listMaterials.ToArray();

            // geometries
            geometry geomPallet = new geometry()
            {
                id = "palletGeometry", name = "palletGeometry"
            };
            geometry geomCase = new geometry()
            {
                id = "caseGeometry", name = "caseGeometry"
            };

            geometries.geometry = new geometry[] { geomPallet, geomCase };
            // pallet
            mesh meshPallet = CreatePalletMesh(palletProperties);

            geomPallet.Item = meshPallet;
            // case
            mesh meshCase = CreateCaseMesh(_palletSolution.Analysis.BProperties as BoxProperties);

            geomCase.Item = meshCase;
            // library_animations
            animation animationMain = new animation()
            {
                id = "animationMain_ID", name = "animationMain"
            };

            animations.animation = new animation[] { animationMain };

            List <object> listAnimationSource = new List <object>();

            // library_visual_scenes
            visual_scene mainScene = new visual_scene()
            {
                id = "MainScene", name = "MainScene"
            };

            scenes.visual_scene = new visual_scene[] { mainScene };

            List <node> sceneNodes = new List <node>();

            sceneNodes.Add(new node()
            {
                id   = "PalletNode",
                name = "PalletNode",
                instance_geometry = new instance_geometry[]
                {
                    new instance_geometry()
                    {
                        url           = "#palletGeometry",
                        bind_material = new bind_material()
                        {
                            technique_common = new instance_material[]
                            {
                                new instance_material()
                                {
                                    symbol = "materialPallet",
                                    target = string.Format("#{0}", materialPallet.id)
                                }
                            }
                        }
                    }
                }
            });
            uint caseIndex = 0;

            foreach (ILayer layer in _palletSolution)
            {
                BoxLayer bLayer = layer as BoxLayer;
                if (null == bLayer)
                {
                    continue;
                }

                foreach (BoxPosition bp in bLayer)
                {
                    Vector3D translation = bp.Position;
                    Vector3D rotations   = bp.Transformation.Rotations;

                    node caseNode = new node()
                    {
                        id               = string.Format("CaseNode_{0}_ID", caseIndex),
                        name             = string.Format("CaseNode_{0}", caseIndex),
                        ItemsElementName = new ItemsChoiceType2[]
                        {
                            ItemsChoiceType2.translate,
                            ItemsChoiceType2.rotate,
                            ItemsChoiceType2.rotate,
                            ItemsChoiceType2.rotate
                        },
                        Items = new object[]
                        {
                            new TargetableFloat3()
                            {
                                Values = new double[] { translation.X, translation.Y, translation.Z },
                                sid    = "t",
                            },
                            new rotate()
                            {
                                Values = new double[] { 1.0, 0.0, 0.0, rotations.X },
                                sid    = "rx"
                            },
                            new rotate()
                            {
                                Values = new double[] { 0.0, 1.0, 0.0, rotations.Y },
                                sid    = "ry"
                            },
                            new rotate()
                            {
                                Values = new double[] { 0.0, 0.0, 1.0, rotations.Z },
                                sid    = "rz"
                            }
                        },

                        instance_geometry = new instance_geometry[]
                        {
                            new instance_geometry()
                            {
                                url           = "#caseGeometry",
                                bind_material = new bind_material()
                                {
                                    technique_common = new instance_material[]
                                    {
                                        new instance_material()
                                        {
                                            symbol = "materialCase0", target = "#material_Case0_ID"
                                        },
                                        new instance_material()
                                        {
                                            symbol = "materialCase1", target = "#material_Case1_ID"
                                        },
                                        new instance_material()
                                        {
                                            symbol = "materialCase2", target = "#material_Case2_ID"
                                        },
                                        new instance_material()
                                        {
                                            symbol = "materialCase3", target = "#material_Case3_ID"
                                        },
                                        new instance_material()
                                        {
                                            symbol = "materialCase4", target = "#material_Case4_ID"
                                        },
                                        new instance_material()
                                        {
                                            symbol = "materialCase5", target = "#material_Case5_ID"
                                        },
                                        new instance_material()
                                        {
                                            symbol = "materialCaseLines", target = "#material_CaseLines_ID"
                                        }
                                    }
                                }
                            }
                        }
                    };
                    sceneNodes.Add(caseNode);

                    // animations
                    CreateAnimation(caseIndex, (uint)_palletSolution.CaseCount, listAnimationSource, bp);

                    // increment case index
                    ++caseIndex;
                }
            }

            // add nodes
            mainScene.node = sceneNodes.ToArray();

            animationMain.Items = listAnimationSource.ToArray();

            // library_cameras
            camera cameraCamera = new camera()
            {
                id = "Camera-Camera", name = "Camera-Camera"
            };
            cameraOpticsTechnique_commonPerspective cameraPerspective = new cameraOpticsTechnique_commonPerspective()
            {
                znear = new TargetableFloat()
                {
                    sid = "znear", Value = 1.0
                },
                zfar = new TargetableFloat()
                {
                    sid = "zfar", Value = 10000.0
                }
            };

            cameraCamera.optics = new cameraOptics()
            {
                technique_common = new cameraOpticsTechnique_common()
                {
                    Item = cameraPerspective
                }
            };
            cameras.camera = new camera[] { cameraCamera };

            // colladaScene
            colladaScene.instance_visual_scene = new InstanceWithExtra()
            {
                url = "#MainScene"
            };

            model.Save(filePath);
            model.Save(System.IO.Path.ChangeExtension(filePath, "xml"));
        }
Ejemplo n.º 4
0
        public static string ExportFile(FullModelData data, string path)
        {
            path = path.Replace(".model", ".dae");

            List <SectionHeader>          sections        = data.sections;
            Dictionary <UInt32, ISection> parsed_sections = data.parsed_sections;

            byte[] leftover_data = data.leftover_data;

            // Set up the XML structure
            library_geometries libgeoms = new library_geometries();

            library_visual_scenes libscenes = new library_visual_scenes();

            COLLADAScene scene = new COLLADAScene
            {
                instance_visual_scene = new InstanceWithExtra
                {
                    url = "#scene"
                }
            };

            COLLADA collada = new COLLADA
            {
                Items = new object[] { libgeoms, libscenes },
                scene = scene,
                asset = new asset
                {
                    created  = DateTime.UtcNow,
                    modified = DateTime.UtcNow,

                    // Otherwise it defaults to Y-up (see asset's constructor), while we're
                    //  using Z-up. Without the asset tag Blender defaults to Z-up, so if you
                    //  remove this then the presence of the asset tag flips the model.
                    up_axis = UpAxisType.Z_UP,
                },
            };

            // Build the mesh

            List <geometry> geometries = new List <geometry>();
            List <node>     nodes      = new List <node>();

            int model_i = 0;

            foreach (SectionHeader sectionheader in sections)
            {
                if (sectionheader.type == model_data_tag)
                {
                    Model model_data = (Model)parsed_sections[sectionheader.id];
                    if (model_data.version == 6)
                    {
                        continue;
                    }

                    model_i++;

                    string model_id = model_i + "-" + model_data.HashName.String;

                    PassthroughGP passthrough_section = model_data.PassthroughGP;
                    Geometry      geometry_section    = passthrough_section.Geometry;
                    Topology      topology_section    = passthrough_section.Topology;
                    geometry      geom = SerializeModel(geometry_section, topology_section, model_data, model_id);

                    geometries.Add(geom);

                    node root_node = new node
                    {
                        id   = "model-" + model_id,
                        name = "Model " + model_id,
                        type = NodeType.NODE,

                        instance_geometry = new instance_geometry[]
                        {
                            new instance_geometry
                            {
                                url  = "#model-geom-" + model_id,
                                name = "Model Geom" + model_id
                            }
                        }
                    };

                    nodes.Add(root_node);

                    if (model_data.SkinBones == null)
                    {
                        continue;
                    }

                    SkinBones sb = model_data.SkinBones;
                    //Console.WriteLine(sb.bones);
                    //Console.WriteLine(sb);

                    node bone_root_node = new node
                    {
                        id   = "model-" + model_id + "-boneroot",
                        name = "Model " + model_id + " Bones",
                        type = NodeType.NODE,

                        /*Items = new object[]
                         *  {
                         *      new matrix
                         *      {
                         *          sid = "transform", // Apparently Blender really wants this
                         *          Values = MathUtil.Serialize(sb.unknown_matrix)
                         *      }
                         *  },
                         * ItemsElementName = new ItemsChoiceType2[]
                         *  {
                         *      ItemsChoiceType2.matrix
                         *  }*/
                    };
                    root_node.node1 = new node[] { bone_root_node };

                    Dictionary <Object3D, node> bones = new Dictionary <Object3D, node>();

                    // In order to find locators, which aren't present in the SkinBones
                    // object, we check the child of each object we process.
                    //
                    // To then process those, we use a queue (to_parse) which lists the
                    // objects in our TODO list to search. We draw from this as we process them.
                    //
                    // We also keep the list of what we have processed in (parsed), so we don't
                    // process anything twice.
                    //
                    // TODO rewrite this code to be based around children, removing the need for a seperate
                    // loop after this that arranges the heirachy of nodes.
                    List <Object3D>  parsed   = new List <Object3D>(sb.Objects);
                    Queue <Object3D> to_parse = new Queue <Object3D>(sb.Objects);

                    int i = 0;
                    while (to_parse.Count != 0)
                    {
                        Object3D obj = to_parse.Dequeue();

                        string bonename = obj.HashName.String;

                        // Find the locators and such, and add them to the TODO list
                        foreach (Object3D child in obj.children)
                        {
                            if (!parsed.Contains(child)) // Don't process something twice
                            {
                                parsed.Add(child);
                                to_parse.Enqueue(child);
                            }
                        }

                        Vector3    translate;
                        Quaternion rotate;
                        Vector3    scale;
                        Matrix4x4.Decompose(obj.Transform, out scale, out rotate, out translate);

                        Matrix4x4 final_rot = Matrix4x4.CreateFromQuaternion(rotate);
                        final_rot.Translation = translate;

                        if (obj.Parent == null || !sb.Objects.Contains(obj.Parent))
                        {
                            Matrix4x4 fixed_obj_transform = obj.WorldTransform;
                            Matrix4x4.Decompose(fixed_obj_transform, out scale, out rotate, out translate);

                            // Fixes the head, but breaks the arms
                            // For now, leave it like this
                            //final_rot = final_rot.MultDiesel(fixed_obj_transform);
                        }

                        // If the object is not contained within the SkinBones
                        // object, it must be a locator.
                        bool locator = !sb.Objects.Contains(obj);

                        // Add the node
                        bones[obj] = new node
                        {
                            id    = "model-" + model_id + "-bone-" + bonename,
                            name  = (locator ? "locator-" : "") + bonename,
                            type  = NodeType.JOINT,
                            Items = new object[]
                            {
                                new matrix
                                {
                                    sid    = "transform", // Apparently Blender really wants this
                                    Values = MathUtil.Serialize(final_rot)
                                },
                            },
                            ItemsElementName = new ItemsChoiceType2[]
                            {
                                ItemsChoiceType2.matrix
                            }
                        };

                        i++;
                    }

                    foreach (var(obj, nod) in bones)
                    {
                        node parent = bone_root_node;

                        if (bones.ContainsKey(obj))
                        {
                            parent = bones[obj.Parent];
                        }

                        if (parent.node1 == null)
                        {
                            parent.node1 = new node[1];
                        }
                        else
                        {
                            node[] children = parent.node1;
                            Array.Resize(ref children, children.Length + 1);
                            parent.node1 = children;
                        }

                        parent.node1[parent.node1.Length - 1] = nod;
                    }
                }
            }

            libgeoms.geometry = geometries.ToArray();

            libscenes.visual_scene = new visual_scene[]
            {
                new visual_scene
                {
                    id   = "scene",
                    name = "Scene",
                    node = nodes.ToArray()
                }
            };

            using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write))
            {
                collada.Save(fs);

                // Do we need this?
                // fs.Close();
            }

            return(path);
        }
Ejemplo n.º 5
0
        public static void ExportIOModelAsDAE(string FileName, IOModel m)
        {
            COLLADA colladaFile = new COLLADA();

            List <geometry> list_geometries = new List <geometry>(m.Meshes.Count);

            if (m.HasMeshes)
            {
                foreach (IOMesh iomesh in m.Meshes)
                {
                    geometry g = new geometry();
                    g.name = iomesh.Name;
                    g.id   = iomesh.Name + $"_{m.Meshes.IndexOf(iomesh)}";

                    List <double> list_positions = new List <double>();
                    List <double> list_normals   = new List <double>();
                    List <double> list_uvs       = new List <double>();
                    List <double> list_colors    = new List <double>();
                    foreach (IOVertex v in iomesh.Vertices)
                    {
                        list_positions.Add(v.Position.X);
                        list_positions.Add(v.Position.Y);
                        list_positions.Add(v.Position.Z);
                        list_normals.Add(v.Normal.X);
                        list_normals.Add(v.Normal.Y);
                        list_normals.Add(v.Normal.Z);
                        list_uvs.Add(v.UV0.X);
                        list_uvs.Add(v.UV0.Y);
                    }

                    // Position
                    source source_position = new source();
                    {
                        float_array floats = new float_array();
                        floats.count  = (ulong)list_positions.Count;
                        floats.id     = g.id + "_pos_arr";
                        floats.Values = list_positions.ToArray();

                        source_position = CreateSource(list_positions.Count, 3, floats.id, floats, new param[] {
                            new param()
                            {
                                name = "X", type = "float"
                            },
                            new param()
                            {
                                name = "Y", type = "float"
                            },
                            new param()
                            {
                                name = "Z", type = "float"
                            }
                        });
                    }

                    // Normal
                    source source_normal = new source();
                    {
                        float_array floats = new float_array();
                        floats.count  = (ulong)list_normals.Count;
                        floats.id     = g.id + "_nrm_arr";
                        floats.Values = list_normals.ToArray();

                        source_normal = CreateSource(list_normals.Count, 3, floats.id, floats, new param[] {
                            new param()
                            {
                                name = "X", type = "float"
                            },
                            new param()
                            {
                                name = "Y", type = "float"
                            },
                            new param()
                            {
                                name = "Z", type = "float"
                            }
                        });
                    }

                    // UV0
                    source source_uv0 = new source();
                    {
                        float_array floats = new float_array();
                        floats.count  = (ulong)list_uvs.Count;
                        floats.id     = g.id + "_uv0_arr";
                        floats.Values = list_uvs.ToArray();

                        source_uv0 = CreateSource(list_uvs.Count, 2, floats.id, floats, new param[] {
                            new param()
                            {
                                name = "S", type = "float"
                            },
                            new param()
                            {
                                name = "T", type = "float"
                            }
                        });
                    }

                    // vertices

                    vertices vertices = new vertices();
                    vertices.id    = g.id + "_verts";
                    vertices.input = new InputLocal[]
                    {
                        new InputLocal()
                        {
                            source = "#" + source_position.id, semantic = "POSITION"
                        },
                        new InputLocal()
                        {
                            source = "#" + source_normal.id, semantic = "NORMAL"
                        },
                        new InputLocal()
                        {
                            source = "#" + source_uv0.id, semantic = "TEXCOORD"
                        }
                    };

                    // triangles
                    triangles triangles = new triangles();
                    triangles.count = (ulong)iomesh.Indices.Count;
                    triangles.input = new InputLocalOffset[] {
                        new InputLocalOffset()
                        {
                            offset = 0, semantic = "VERTEX", source = "#" + vertices.id
                        }
                    };
                    triangles.p = string.Join(" ", iomesh.Indices);

                    // creating mesh
                    mesh geomesh = new mesh();
                    geomesh.source   = new source[] { source_position, source_normal, source_uv0 };
                    geomesh.Items    = new object[] { triangles };
                    geomesh.vertices = vertices;

                    g.Item = geomesh;

                    list_geometries.Add(g);
                }
            }
            library_geometries lib_geometry = new library_geometries();

            lib_geometry.geometry = list_geometries.ToArray();


            // controllers

            List <controller> list_controller = new List <controller>();

            if (m.HasMeshes && m.HasSkeleton)
            {
                // create lists
                List <source> skinSources  = new List <source>();
                List <string> boneNames    = new List <string>();
                List <double> InverseBinds = new List <double>();
                foreach (RBone b in m.Skeleton.Bones)
                {
                    boneNames.Add(b.Name);
                    InverseBinds.AddRange(new double[] { b.InvWorldTransform.M11, b.InvWorldTransform.M21, b.InvWorldTransform.M31, b.InvWorldTransform.M41,
                                                         b.InvWorldTransform.M12, b.InvWorldTransform.M22, b.InvWorldTransform.M32, b.InvWorldTransform.M42,
                                                         b.InvWorldTransform.M13, b.InvWorldTransform.M23, b.InvWorldTransform.M33, b.InvWorldTransform.M43,
                                                         b.InvWorldTransform.M14, b.InvWorldTransform.M24, b.InvWorldTransform.M34, b.InvWorldTransform.M44, });
                }



                // setup controllers
                foreach (IOMesh iomesh in m.Meshes)
                {
                    controller controller = new controller()
                    {
                        id = iomesh.Name + "_" + m.Meshes.IndexOf(iomesh) + "_controller"
                    };
                    list_controller.Add(controller);

                    // create source for weights
                    List <double> weights   = new List <double>();
                    List <int>    bones     = new List <int>();
                    List <int>    boneCount = new List <int>();
                    StringBuilder build_v   = new StringBuilder();
                    foreach (IOVertex v in iomesh.Vertices)
                    {
                        int bcount = 0;
                        if (v.BoneWeights.X > 0)
                        {
                            if (!weights.Contains(v.BoneWeights.X))
                            {
                                weights.Add(v.BoneWeights.X);
                            }
                            build_v.Append($"{(int)v.BoneIndices.X} {weights.IndexOf(v.BoneWeights.X)} ");
                            bcount++;
                        }
                        if (v.BoneWeights.Y > 0)
                        {
                            if (!weights.Contains(v.BoneWeights.Y))
                            {
                                weights.Add(v.BoneWeights.Y);
                            }
                            build_v.Append($"{(int)v.BoneIndices.Y} {weights.IndexOf(v.BoneWeights.Y)} ");
                            bcount++;
                        }
                        if (v.BoneWeights.Z > 0)
                        {
                            if (!weights.Contains(v.BoneWeights.Z))
                            {
                                weights.Add(v.BoneWeights.Z);
                            }
                            build_v.Append($"{(int)v.BoneIndices.Z} {weights.IndexOf(v.BoneWeights.Z)} ");
                            bcount++;
                        }
                        if (v.BoneWeights.W > 0)
                        {
                            if (!weights.Contains(v.BoneWeights.W))
                            {
                                weights.Add(v.BoneWeights.W);
                            }
                            build_v.Append($"{(int)v.BoneIndices.W} {weights.IndexOf(v.BoneWeights.W)} ");
                            bcount++;
                        }
                        boneCount.Add(bcount);
                    }


                    // skin

                    Name_array arr_name = new Name_array();
                    arr_name.count  = (ulong)boneNames.Count;
                    arr_name.id     = controller.id + "joints";
                    arr_name.Values = boneNames.ToArray();

                    source source_skin = CreateSource(boneNames.Count, 1, arr_name.id, arr_name, new param[] {
                        new param()
                        {
                            name = "JOINT", type = "name"
                        }
                    });

                    // bind

                    float_array arr_bind = new float_array();
                    arr_bind.count  = (ulong)InverseBinds.Count;
                    arr_bind.id     = controller.id + "binds";
                    arr_bind.Values = InverseBinds.ToArray();

                    source source_binds = CreateSource(InverseBinds.Count, 16, arr_bind.id, arr_bind, new param[] {
                        new param()
                        {
                            name = "TRANSFORM", type = "float4x4"
                        }
                    });

                    // weight

                    source source_weight = new source();
                    {
                        float_array floats = new float_array();
                        floats.count  = (ulong)weights.Count;
                        floats.id     = controller.id + "_weights";
                        floats.Values = weights.ToArray();

                        source_weight = CreateSource(weights.Count, 1, floats.id, floats, new param[] {
                            new param()
                            {
                                name = "WEIGHT", type = "float"
                            },
                        });
                    }

                    skin skin = new skin();
                    skin.source1 = "#" + iomesh.Name + $"_{m.Meshes.IndexOf(iomesh)}";
                    skin.source  = new source[] { source_skin, source_binds, source_weight };

                    skin.joints = new skinJoints()
                    {
                        input = new InputLocal[]
                        {
                            new InputLocal()
                            {
                                semantic = "JOINT",
                                source   = "#" + source_skin.id
                            },
                            new InputLocal()
                            {
                                semantic = "INV_BIND_MATRIX",
                                source   = "#" + source_binds.id
                            }
                        }
                    };


                    //skin weights
                    skin.vertex_weights       = new skinVertex_weights();
                    skin.vertex_weights.count = (ulong)iomesh.Vertices.Count;
                    skin.vertex_weights.input = new InputLocalOffset[]
                    {
                        new InputLocalOffset()
                        {
                            semantic = "JOINT",
                            source   = "#" + source_skin.id,
                            offset   = 0
                        },
                        new InputLocalOffset()
                        {
                            semantic = "WEIGHT",
                            source   = "#" + source_weight.id,
                            offset   = 1
                        }
                    };
                    skin.vertex_weights.vcount = string.Join(" ", boneCount);
                    skin.vertex_weights.v      = build_v.ToString();

                    controller.Item = skin;
                }
            }
            library_controllers lib_controllers = new library_controllers();

            lib_controllers.controller = list_controller.ToArray();


            // scene nodes

            List <node> scene_nodes  = new List <node>();
            int         visual_index = 0;

            if (m.HasSkeleton)
            {
                Dictionary <RBone, node> boneToNode = new Dictionary <RBone, node>();
                foreach (RBone b in m.Skeleton.Bones)
                {
                    // create bone node
                    node node = new node();
                    node.name = b.Name;
                    node.id   = "bone" + visual_index++;
                    node.sid  = b.Name;
                    node.type = NodeType.JOINT;

                    // add transform
                    matrix mat = new matrix()
                    {
                        Values = new double[] { b.Transform.M11, b.Transform.M21, b.Transform.M31, b.Transform.M41,
                                                b.Transform.M12, b.Transform.M22, b.Transform.M32, b.Transform.M42,
                                                b.Transform.M13, b.Transform.M23, b.Transform.M33, b.Transform.M43,
                                                b.Transform.M14, b.Transform.M24, b.Transform.M34, b.Transform.M44, }
                    };
                    node.ItemsElementName = new ItemsChoiceType2[] { ItemsChoiceType2.matrix };
                    node.Items            = new object[] { mat };

                    // deal with parenting
                    boneToNode.Add(b, node);
                    if (b.ParentID == -1)
                    {
                        scene_nodes.Add(node);
                    }
                    else
                    {
                        if (boneToNode[m.Skeleton.Bones[b.ParentID]].node1 == null)
                        {
                            boneToNode[m.Skeleton.Bones[b.ParentID]].node1 = new node[0];
                        }
                        node[] parentnode = boneToNode[m.Skeleton.Bones[b.ParentID]].node1;
                        Array.Resize <node>(ref parentnode, parentnode.Length + 1);
                        parentnode[parentnode.Length - 1] = node;
                        boneToNode[m.Skeleton.Bones[b.ParentID]].node1 = parentnode;
                    }
                }
            }
            if (m.HasMeshes)
            {
                foreach (IOMesh iomesh in m.Meshes)
                {
                    node node = new node()
                    {
                        id   = "mesh" + visual_index++,
                        name = iomesh.Name,
                        type = NodeType.NODE
                    };

                    if (m.HasSkeleton)
                    {
                        instance_controller controller = new instance_controller()
                        {
                            url = iomesh.Name + "_" + m.Meshes.IndexOf(iomesh) + "_controller"
                        };
                        controller.skeleton      = new string[] { "#bone0" };
                        node.instance_controller = new instance_controller[] { controller };
                    }
                    scene_nodes.Add(node);
                }
            }

            // visual scene root
            library_visual_scenes scenes = new library_visual_scenes();

            scenes.visual_scene = new visual_scene[] {
                new visual_scene()
                {
                    id   = "visualscene0",
                    name = "rdmscene"
                }
            };
            scenes.visual_scene[0].node = scene_nodes.ToArray();


            // scene
            COLLADAScene scene = new COLLADAScene();

            scene.instance_visual_scene = new InstanceWithExtra()
            {
                url = "#visualscene0"
            };

            // putting it all together
            colladaFile.Items = new object[] { lib_geometry, lib_controllers, scenes };
            colladaFile.scene = scene;

            colladaFile.Save(FileName);
        }