Example #1
0
        private static void write_kcl(NitroFile kcl, List <Triangle> triangles, int max_triangles, int min_width, float scale)
        {
            kcl.Clear();

            //Need to scale each vertex (1000 times scale of model)
            foreach (Triangle t in triangles)
            {
                t.u = t.u.mul(scale);
                t.v = t.v.mul(scale);
                t.w = t.w.mul(scale);
            }

            uint pos = 0;

            List <Face>  faces         = new List <Face>();
            VertexWelder vertex_welder = new VertexWelder(1 / 64f, (int)(Math.Floor((double)(triangles.Count / 256))));
            VertexWelder normal_welder = new VertexWelder(1 / 1024f, (int)(Math.Floor((double)(4 * triangles.Count / 256))));

            foreach (Triangle t in triangles)
            {
                Face f = new Face();

                Vector a = unit(cross(t.u.sub(t.w), t.n));
                Vector b = unit(cross(t.v.sub(t.u), t.n));
                Vector c = unit(cross(t.w.sub(t.v), t.n));

                f.length       = new FixedPoint(dot(t.v.sub(t.u), c), 1 / 65536f);
                f.vertex_index = (ushort)vertex_welder.add(t.u);
                f.normal_index = (ushort)normal_welder.add(t.n);
                f.a_index      = (ushort)normal_welder.add(a);
                f.b_index      = (ushort)normal_welder.add(b);
                f.c_index      = (ushort)normal_welder.add(c);
                f.group        = (ushort)t.group;

                faces.Add(f);
            }

            //Vertex Section
            pos += 56;
            kcl.Write32(0x00, pos);//Vertex section offset

            foreach (Vertex vtx in vertex_welder.vertices)
            {
                kcl.Write32(pos, (uint)vtx.x.valToWrite());
                kcl.Write32(pos + 4, (uint)vtx.y.valToWrite());
                kcl.Write32(pos + 8, (uint)vtx.z.valToWrite());

                pos += 12;
            }

            //Vector Section
            kcl.Write32(0x04, pos);//Vector section offset

            foreach (Vector vct in normal_welder.vectors)
            {
                kcl.Write16(pos, (ushort)vct.x.valToWrite());
                kcl.Write16(pos + 2, (ushort)vct.y.valToWrite());
                kcl.Write16(pos + 4, (ushort)vct.z.valToWrite());

                pos += 6;
            }

            pos = (uint)((pos + 3) & ~3);

            //Planes Section
            kcl.Write32(0x08, pos - 0x10);//Planes section offset

            foreach (Face f in faces)
            {
                kcl.Write32(pos, (uint)f.length.valToWrite());
                kcl.Write16(pos + 4, (ushort)f.vertex_index);
                kcl.Write16(pos + 6, (ushort)f.normal_index);
                kcl.Write16(pos + 8, (ushort)f.a_index);
                kcl.Write16(pos + 10, (ushort)f.b_index);
                kcl.Write16(pos + 12, (ushort)f.c_index);
                kcl.Write16(pos + 14, (ushort)f.group);

                pos += 16;
            }


            //Octree Section
            kcl.Write32(0x0C, pos);//Octree offset

            Octree octree = new Octree(triangles, max_triangles, (float)min_width);

            octree.pack(ref kcl, ref pos);

            //Header
            kcl.Write32(0x10, (uint)327680);//Unknown
            kcl.Write32(0x14, (uint)octree.bas.x.valToWrite());
            kcl.Write32(0x18, (uint)octree.bas.y.valToWrite());
            kcl.Write32(0x1C, (uint)octree.bas.z.valToWrite());
            kcl.Write32(0x20, (uint)(~((int)octree.width_x - 1) & 0xFFFFFFFF));
            kcl.Write32(0x24, (uint)(~((int)octree.width_y - 1) & 0xFFFFFFFF));
            kcl.Write32(0x28, (uint)(~((int)octree.width_z - 1) & 0xFFFFFFFF));
            kcl.Write32(0x2C, (uint)(Math.Log(octree.base_width, 2)));
            kcl.Write32(0x30, (uint)(Math.Log(octree.nx, 2)));
            kcl.Write32(0x34, (uint)(Math.Log(octree.nx, 2)) + (uint)(Math.Log(octree.ny, 2)));

            kcl.SaveChanges();
        }//End writeKCL
Example #2
0
        public void pack(ref NitroFile kcl, ref uint pos)
        {
            List <Octree> branches = new List <Octree>();

            branches.Add(this);
            uint free_list_offset = 0;
            List <List <int> > list_offsets_ind  = new List <List <int> >();
            List <uint>        list_offsets_addr = new List <uint>();

            //testing
            int zero_ind_count             = 0;
            int ind_already_in_count       = 0;
            int list_offsets_added_count   = 0;
            int else_branches_append_count = 0;
            //end testing
            int i = 0;

            while (i < branches.Count)
            {
                foreach (Octree node in branches[i].children)
                {
                    if (node.is_leaf)
                    {
                        if (node.indices.Count == 0)
                        {
                            zero_ind_count += 1;
                            continue;
                        }
                        if (indicesInList(list_offsets_ind, node.indices))
                        {
                            ind_already_in_count += 1;
                            continue;
                        }
                        list_offsets_ind.Add(node.indices);
                        list_offsets_addr.Add(free_list_offset);
                        list_offsets_added_count += 1;
                        free_list_offset         += (uint)(2 * ((node.indices.Count) + 1));
                    }
                    else
                    {
                        branches.Add(node);
                        else_branches_append_count += 1;
                    }
                }
                i += 1;
            }

            uint list_base = 0;

            foreach (Octree b in branches)
            {
                list_base += (uint)(4 * b.children.Count);
            }
            list_offsets_ind.Add(new List <int>());      //Add an empty indices list
            list_offsets_addr.Add(free_list_offset - 2); //with this address
            uint branch_base        = 0;
            uint free_branch_offset = (uint)(4 * (this.children.Count));

            foreach (Octree branch in branches)
            {
                foreach (Octree node in branch.children)
                {
                    if (node.is_leaf)
                    {
                        int key = posIndicesInList(list_offsets_ind, node.indices);
                        kcl.Write32(pos, (uint)(0x80000000 | (list_base + list_offsets_addr[key] - 2 - branch_base)));
                        pos += 4;
                    }
                    else
                    {
                        kcl.Write32(pos, (free_branch_offset - branch_base));
                        pos += 4;
                        free_branch_offset += (uint)(4 * (node.children.Count));
                    }
                }
                branch_base += (uint)(4 * (branch.children.Count));
            }

            list_offsets_ind.RemoveAt(list_offsets_ind.Count - 1);
            list_offsets_addr.RemoveAt(list_offsets_addr.Count - 1);

            foreach (List <int> indices in list_offsets_ind)
            {
                foreach (int index in indices)
                {
                    kcl.Write16(pos, (ushort)(index + 1));
                    pos += 2;
                }
                kcl.Write16(pos, (ushort)0);
                pos += 2;
            }
        }//End pack function
Example #3
0
 private static void WriteBCAAnimationDescriptor(NitroFile bca, uint offset, byte interpolation, bool isConstant, int startIndex)
 {
     bca.Write8(offset + 0x00, interpolation);                            // Interpolation
     bca.Write8(offset + 0x01, (isConstant == true) ? (byte)0 : (byte)1); // Index increments with each frame
     bca.Write16(offset + 0x02, (ushort)startIndex);                      // Starting index
 }
Example #4
0
 private static void WriteBCAAnimationDescriptor(NitroFile bca, uint offset, byte interpolation, bool isConstant, int startIndex)
 {
     bca.Write8(offset + 0x00, interpolation);// Interpolation
     bca.Write8(offset + 0x01, (isConstant == true) ? (byte)0 : (byte)1);// Index increments with each frame
     bca.Write16(offset + 0x02, (ushort)startIndex);// Starting index
 }
Example #5
0
        public void Optimise(NitroFile bca)
        {
            uint numBones  = bca.Read16(0x00);
            uint numFrames = bca.Read16(0x02);

            BCAOffsetData offs = new BCAOffsetData
            {
                scaleOffset = bca.Read32(0x08),
                rotOffset   = bca.Read32(0x0c),
                posOffset   = bca.Read32(0x10),
                animOffset  = bca.Read32(0x14)
            };

            //Pass 1: The constant value pass
            if (numFrames > 1)
            {
                for (uint i = 0; i < numBones; ++i)
                {
                    for (uint j = 0; j < 9; ++j)
                    {
                        if (bca.Read8(offs.animOffset + 0x24 * i + 4 * j + 1) == 0)
                        {
                            continue;
                        }

                        uint dataOffset, unitSize;
                        offs.GetDataOffsetAndSize(j / 3, out dataOffset, out unitSize);

                        bool interped   = bca.Read8(offs.animOffset + 0x24 * i + 4 * j + 0) != 0;
                        uint firstValID = bca.Read16(offs.animOffset + 0x24 * i + 4 * j + 2);
                        uint numVals    = interped ?
                                          numFrames / 2 + 1 :
                                          numFrames;

                        uint[] vals = new uint[numVals];
                        for (uint k = 0; k < numVals; ++k)
                        {
                            vals[k] = bca.ReadVar(dataOffset + (firstValID + k) * unitSize, unitSize);
                        }

                        if (!Array.Exists(vals, x => x != vals[0])) //They're all the same.
                        {
                            uint addr = dataOffset + (firstValID + numVals) * unitSize;
                            BackSpace(bca, addr, (numVals - 1) * unitSize, ref offs);
                            bca.Write16(offs.animOffset + 0x24 * i + 4 * j + 0, 0x0000);
                            continue;
                        }

                        if (interped)
                        {
                            continue;
                        }

                        //Pass 2: The interpolation pass
                        bool  shouldInterp = true;
                        int[] valInts;
                        if (unitSize == 2)
                        {
                            valInts = Array.ConvertAll(vals, x => x >= 0x8000 ? (int)(x | 0xffff0000) : (int)x);
                        }
                        else
                        {
                            valInts = Array.ConvertAll(vals, x => (int)x);
                        }

                        for (int k = 0; k < numVals - 2; k += 2)
                        {
                            if (Math.Abs(valInts[k] - 2 * valInts[k + 1] + valInts[k + 2]) > 1)
                            {
                                shouldInterp = false;
                            }
                        }

                        if (!shouldInterp)
                        {
                            continue;
                        }

                        for (uint k = 0; k < numVals; k += 2)
                        {
                            bca.WriteVar(dataOffset + (firstValID + k / 2) * unitSize, unitSize,
                                         bca.ReadVar(dataOffset + (firstValID + k) * unitSize, unitSize));
                        }
                        if (numVals % 2 == 0) //can't interpolate on last frame even if that frame is odd
                        {
                            bca.WriteVar(dataOffset + (firstValID + numVals / 2) * unitSize, unitSize,
                                         bca.ReadVar(dataOffset + (firstValID + numVals - 1) * unitSize, unitSize));
                        }

                        bca.Write8(offs.animOffset + 0x24 * i + 4 * j + 0, 1);
                        BackSpace(bca, dataOffset + (firstValID + numVals) * unitSize,
                                  (numVals - 1) / 2 * unitSize, ref offs);
                    }
                }
            }

            //Pass 3: The share equal data pass.
            for (uint trID = 0; trID < 3; ++trID)
            {
                uint dataOffset, unitSize;
                offs.GetDataOffsetAndSize(trID, out dataOffset, out unitSize);

                BCAEntryToSort[] bcaEntries = new BCAEntryToSort[3 * numBones];
                for (uint i = 0; i < numBones; ++i)
                {
                    for (uint j = 0; j < 3; ++j)
                    {
                        bool constant   = bca.Read8(offs.animOffset + 0x24 * i + 4 * (3 * trID + j) + 1) == 0;
                        bool interped   = bca.Read8(offs.animOffset + 0x24 * i + 4 * (3 * trID + j) + 0) != 0;
                        uint firstValID = bca.Read16(offs.animOffset + 0x24 * i + 4 * (3 * trID + j) + 2);
                        uint numVals    = constant ? 1 : interped ?
                                          numFrames / 2 + 1 :
                                          numFrames;

                        bcaEntries[3 * i + j].boneID = i;
                        bcaEntries[3 * i + j].axisID = j;
                        bcaEntries[3 * i + j].data   = new uint[numVals];
                        for (uint k = 0; k < numVals; ++k)
                        {
                            bcaEntries[3 * i + j].data[k] =
                                bca.ReadVar(dataOffset + (firstValID + k) * unitSize, unitSize);
                        }
                    }
                }

                BCAEntryToSort[][] sortedEnts = bcaEntries.GroupBy(x => x.data, new UintArrEqualityComparer()).
                                                Select(g => g.ToArray()).
                                                ToArray();

                foreach (BCAEntryToSort[] entArr in sortedEnts)
                {
                    uint boneID = entArr[0].boneID;
                    uint axisID = entArr[0].axisID;

                    for (int i = 1; i < entArr.Length; ++i) //Using the 1st for reference; skip it
                    {
                        bool constant = bca.Read8(offs.animOffset + 0x24 * entArr[i].boneID +
                                                  4 * (3 * trID + entArr[i].axisID) + 1) == 0;
                        bool interped = bca.Read8(offs.animOffset + 0x24 * entArr[i].boneID +
                                                  4 * (3 * trID + entArr[i].axisID) + 0) != 0;
                        uint firstValID = bca.Read16(offs.animOffset + 0x24 * entArr[i].boneID +
                                                     4 * (3 * trID + entArr[i].axisID) + 2);
                        uint numVals = constant ? 1 : interped ?
                                       numFrames / 2 + 1 :
                                       numFrames;

                        uint sameValID = bca.Read16(offs.animOffset + 0x24 * boneID +
                                                    4 * (3 * trID + axisID) + 2);
                        if (firstValID != sameValID) //Avoid deleting entries when they are already shared
                        {
                            bca.Write16(offs.animOffset + 0x24 * entArr[i].boneID +
                                        4 * (3 * trID + entArr[i].axisID) + 2, (ushort)sameValID);
                            BackSpace(bca, dataOffset + (firstValID + numVals) * unitSize,
                                      numVals * unitSize, ref offs);
                        }
                    }
                }
            }

            if ((offs.posOffset - offs.rotOffset) % 4 != 0)
            {
                BackSpace(bca, offs.posOffset, 0xfffffffe, ref offs, true);
            }
        }
Example #6
0
        public void BackSpace(NitroFile bca, uint addr, uint len, ref BCAOffsetData offs, bool forAlignment = false)
        {
            bca.AddSpace(addr, (uint)-len);
            uint oldRotOffset  = offs.rotOffset;
            uint oldPosOffset  = offs.posOffset;
            uint oldAnimOffset = offs.animOffset;

            if (addr <= offs.scaleOffset)
            {
                offs.scaleOffset -= len;
            }
            if (addr <= offs.rotOffset)
            {
                offs.rotOffset -= len;
            }
            if (addr <= offs.posOffset)
            {
                offs.posOffset -= len;
            }
            if (addr <= offs.animOffset)
            {
                offs.animOffset -= len;
            }

            bca.Write32(0x08, offs.scaleOffset);
            bca.Write32(0x0c, offs.rotOffset);
            bca.Write32(0x10, offs.posOffset);
            bca.Write32(0x14, offs.animOffset);

            if (forAlignment)
            {
                return;
            }

            uint trTypeIndex;

            if (addr > offs.scaleOffset && addr <= oldRotOffset)
            {
                trTypeIndex = 0;
            }
            else if (addr > offs.rotOffset && addr <= oldPosOffset)
            {
                trTypeIndex = 1;
            }
            else if (addr > offs.posOffset && addr <= oldAnimOffset)
            {
                trTypeIndex = 2;
            }
            else
            {
                return;
            }

            uint dataOffset, unitSize;

            offs.GetDataOffsetAndSize(trTypeIndex, out dataOffset, out unitSize);

            uint startSubAt = (addr - dataOffset) / unitSize;
            uint valToSub   = len / unitSize;

            uint numBones = bca.Read16(0x00);

            for (uint i = 0; i < numBones; ++i)
            {
                for (uint j = 0; j < 3; ++j)
                {
                    uint offset = offs.animOffset + 0x24 * i + 4 * (3 * trTypeIndex + j) + 2;
                    uint temp   = bca.Read16(offset);
                    if (temp >= startSubAt)
                    {
                        bca.Write16(offset, (ushort)(temp - valToSub));
                    }
                }
            }
        }
Example #7
0
        public override void WriteModel(bool save = true)
        {
            ModelBase.BoneDefRoot boneTree = m_Model.m_BoneTree;
            Dictionary <string, ModelBase.AnimationDef> boneAnimationsMap = new Dictionary <string, ModelBase.AnimationDef>();

            foreach (ModelBase.AnimationDef anim in m_Model.m_Animations.Values)
            {
                boneAnimationsMap.Add(anim.m_BoneID, anim);
            }

            if (boneAnimationsMap.Count == 0)
            {
                return;
            }

            NitroFile bca = m_ModelFile;

            bca.Clear();

            uint dataoffset    = 0x00;
            uint headersize    = 0x18;
            int  numAnimations = boneTree.Count;
            int  numFrames     = boneAnimationsMap.ElementAt(0).Value.m_NumFrames;

            int numScale = 0;

            foreach (ModelBase.BoneDef boneDef in m_Model.m_BoneTree)
            {
                if (boneAnimationsMap.ContainsKey(boneDef.m_ID))
                {
                    numScale += boneAnimationsMap[boneDef.m_ID].GetScaleValuesCount();
                }
                else
                {
                    numScale += 3;// Original X, Y, Z
                }
            }
            int numRotation = 0;

            foreach (ModelBase.BoneDef boneDef in m_Model.m_BoneTree)
            {
                if (boneAnimationsMap.ContainsKey(boneDef.m_ID))
                {
                    numRotation += boneAnimationsMap[boneDef.m_ID].GetRotateValuesCount();
                }
                else
                {
                    numRotation += 3;// Original X, Y, Z
                }
            }
            int numTranslation = 0;

            foreach (ModelBase.BoneDef boneDef in m_Model.m_BoneTree)
            {
                if (boneAnimationsMap.ContainsKey(boneDef.m_ID))
                {
                    numTranslation += boneAnimationsMap[boneDef.m_ID].GetTranslateValuesCount();
                }
                else
                {
                    numTranslation += 3;// Original X, Y, Z
                }
            }
            uint scaleValuesOffset       = headersize;
            uint rotationValuesOffset    = scaleValuesOffset + (uint)(numScale * 4);
            uint translationValuesOffset = (uint)(((rotationValuesOffset + (uint)(numRotation * 2)) + 3) & ~3);
            uint animationDataOffset     = translationValuesOffset + (uint)(numTranslation * 4);

            bca.Write16(0x00, (ushort)numAnimations);   // Number of bones to be handled (should match the number of bones in the BMD)
            bca.Write16(0x02, (ushort)numFrames);       // Number of animation frames
            bca.Write32(0x04, 1);                       // Whether the animation loops, 0 - false, 1 - true
            bca.Write32(0x08, scaleValuesOffset);       // Offset to scale values section
            bca.Write32(0x0C, rotationValuesOffset);    // Offset to rotation values section
            bca.Write32(0x10, translationValuesOffset); // Offset to translation values section
            bca.Write32(0x14, animationDataOffset);     // Offset to animation section

            dataoffset = scaleValuesOffset;

            int boneScaleValuesOffset = 0;
            Dictionary <string, int> boneScaleValuesOffsets = new Dictionary <string, int>();
            int boneRotateValuesOffset = 0;
            Dictionary <string, int> boneRotateValuesOffsets = new Dictionary <string, int>();
            int boneTranslateValuesOffset = 0;
            Dictionary <string, int> boneTranslateValuesOffsets = new Dictionary <string, int>();

            foreach (ModelBase.BoneDef bone in boneTree)
            {
                boneScaleValuesOffsets.Add(bone.m_ID, boneScaleValuesOffset);

                if (boneAnimationsMap.ContainsKey(bone.m_ID))
                {
                    ModelBase.AnimationDef anim = boneAnimationsMap[bone.m_ID];

                    bca.WriteBlock(dataoffset,
                                   anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleX].GetFixedPointValues());
                    dataoffset += (uint)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleX].GetNumValues() * 4);

                    bca.WriteBlock(dataoffset,
                                   anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleY].GetFixedPointValues());
                    dataoffset += (uint)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleY].GetNumValues() * 4);

                    bca.WriteBlock(dataoffset,
                                   anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleZ].GetFixedPointValues());
                    dataoffset += (uint)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleZ].GetNumValues() * 4);

                    boneScaleValuesOffset += anim.GetScaleValuesCount();
                }
                else
                {
                    // Write bone's scale values
                    bca.Write32(dataoffset, bone.m_20_12Scale[0]);
                    dataoffset += 4;
                    bca.Write32(dataoffset, bone.m_20_12Scale[1]);
                    dataoffset += 4;
                    bca.Write32(dataoffset, bone.m_20_12Scale[2]);
                    dataoffset += 4;

                    boneScaleValuesOffset += 3;
                }
            }

            dataoffset = rotationValuesOffset;

            // Rotation is in Radians
            foreach (ModelBase.BoneDef bone in boneTree)
            {
                boneRotateValuesOffsets.Add(bone.m_ID, boneRotateValuesOffset);

                if (boneAnimationsMap.ContainsKey(bone.m_ID))
                {
                    ModelBase.AnimationDef anim = boneAnimationsMap[bone.m_ID];

                    bca.WriteBlock(dataoffset,
                                   anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateX].GetFixedPointValues());
                    dataoffset += (uint)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateX].GetNumValues() * 2);

                    bca.WriteBlock(dataoffset,
                                   anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateY].GetFixedPointValues());
                    dataoffset += (uint)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateY].GetNumValues() * 2);

                    bca.WriteBlock(dataoffset,
                                   anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateZ].GetFixedPointValues());
                    dataoffset += (uint)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateZ].GetNumValues() * 2);

                    boneRotateValuesOffset += anim.GetRotateValuesCount();
                }
                else
                {
                    // Write bone's rotation values
                    bca.Write16(dataoffset, bone.m_4_12Rotation[0]);
                    dataoffset += 2;
                    bca.Write16(dataoffset, bone.m_4_12Rotation[1]);
                    dataoffset += 2;
                    bca.Write16(dataoffset, bone.m_4_12Rotation[2]);
                    dataoffset += 2;

                    boneRotateValuesOffset += 3;
                }
            }

            dataoffset = translationValuesOffset;

            foreach (ModelBase.BoneDef bone in boneTree)
            {
                boneTranslateValuesOffsets.Add(bone.m_ID, boneTranslateValuesOffset);

                if (boneAnimationsMap.ContainsKey(bone.m_ID))
                {
                    ModelBase.AnimationDef anim = boneAnimationsMap[bone.m_ID];

                    bca.WriteBlock(dataoffset,
                                   anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateX].GetFixedPointValues());
                    dataoffset += (uint)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateX].GetNumValues() * 4);

                    bca.WriteBlock(dataoffset,
                                   anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateY].GetFixedPointValues());
                    dataoffset += (uint)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateY].GetNumValues() * 4);

                    bca.WriteBlock(dataoffset,
                                   anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateZ].GetFixedPointValues());
                    dataoffset += (uint)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateZ].GetNumValues() * 4);

                    boneTranslateValuesOffset += anim.GetTranslateValuesCount();
                }
                else
                {
                    // Write bone's translation values
                    bca.Write32(dataoffset, bone.m_20_12Translation[0]);
                    dataoffset += 4;
                    bca.Write32(dataoffset, bone.m_20_12Translation[1]);
                    dataoffset += 4;
                    bca.Write32(dataoffset, bone.m_20_12Translation[2]);
                    dataoffset += 4;

                    boneTranslateValuesOffset += 3;
                }
            }

            dataoffset = animationDataOffset;

            // For each bone, write the animation descriptor for each transformation component
            foreach (ModelBase.BoneDef bone in boneTree)
            {
                if (boneAnimationsMap.ContainsKey(bone.m_ID))
                {
                    ModelBase.AnimationDef anim = boneAnimationsMap[bone.m_ID];

                    // Scale X
                    WriteBCAAnimationDescriptor(bca, dataoffset,
                                                (byte)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleX].GetFrameStep() >> 1),
                                                anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleX].GetIsConstant(),
                                                boneScaleValuesOffsets[bone.m_ID]);
                    dataoffset += 4;

                    // Scale Y
                    WriteBCAAnimationDescriptor(bca, dataoffset,
                                                (byte)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleY].GetFrameStep() >> 1),
                                                anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleY].GetIsConstant(),
                                                (boneScaleValuesOffsets[bone.m_ID] +
                                                 anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleX].GetNumValues()));
                    dataoffset += 4;

                    // Scale Z
                    WriteBCAAnimationDescriptor(bca, dataoffset,
                                                (byte)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleZ].GetFrameStep() >> 1),
                                                anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleZ].GetIsConstant(),
                                                (boneScaleValuesOffsets[bone.m_ID] +
                                                 anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleX].GetNumValues() +
                                                 anim.m_AnimationComponents[ModelBase.AnimationComponentType.ScaleY].GetNumValues()));
                    dataoffset += 4;

                    // Rotate X
                    WriteBCAAnimationDescriptor(bca, dataoffset,
                                                (byte)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateX].GetFrameStep() >> 1),
                                                anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateX].GetIsConstant(),
                                                boneRotateValuesOffsets[bone.m_ID]);
                    dataoffset += 4;

                    // Rotate Y
                    WriteBCAAnimationDescriptor(bca, dataoffset,
                                                (byte)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateY].GetFrameStep() >> 1),
                                                anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateY].GetIsConstant(),
                                                (boneRotateValuesOffsets[bone.m_ID] +
                                                 anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateX].GetNumValues()));
                    dataoffset += 4;

                    // Rotate Z
                    WriteBCAAnimationDescriptor(bca, dataoffset,
                                                (byte)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateZ].GetFrameStep() >> 1),
                                                anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateZ].GetIsConstant(),
                                                (boneRotateValuesOffsets[bone.m_ID] +
                                                 anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateX].GetNumValues() +
                                                 anim.m_AnimationComponents[ModelBase.AnimationComponentType.RotateY].GetNumValues()));
                    dataoffset += 4;

                    // Translate X
                    WriteBCAAnimationDescriptor(bca, dataoffset,
                                                (byte)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateX].GetFrameStep() >> 1),
                                                anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateX].GetIsConstant(),
                                                boneTranslateValuesOffsets[bone.m_ID]);
                    dataoffset += 4;

                    // Translate Y
                    WriteBCAAnimationDescriptor(bca, dataoffset,
                                                (byte)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateY].GetFrameStep() >> 1),
                                                anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateY].GetIsConstant(),
                                                (boneTranslateValuesOffsets[bone.m_ID] +
                                                 anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateX].GetNumValues()));
                    dataoffset += 4;

                    // Translate Z
                    WriteBCAAnimationDescriptor(bca, dataoffset,
                                                (byte)(anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateZ].GetFrameStep() >> 1),
                                                anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateZ].GetIsConstant(),
                                                (boneTranslateValuesOffsets[bone.m_ID] +
                                                 anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateX].GetNumValues() +
                                                 anim.m_AnimationComponents[ModelBase.AnimationComponentType.TranslateY].GetNumValues()));
                    dataoffset += 4;
                }
                else
                {
                    // Set to use constant values (the bone's transformation as there's no animation)

                    // Scale X
                    WriteBCAAnimationDescriptor(bca, dataoffset, 0, true, (boneScaleValuesOffsets[bone.m_ID] + 0));
                    dataoffset += 4;

                    // Scale Y
                    WriteBCAAnimationDescriptor(bca, dataoffset, 0, true, (boneScaleValuesOffsets[bone.m_ID] + 1));
                    dataoffset += 4;

                    // Scale Z
                    WriteBCAAnimationDescriptor(bca, dataoffset, 0, true, (boneScaleValuesOffsets[bone.m_ID] + 2));
                    dataoffset += 4;

                    // Rotation X
                    WriteBCAAnimationDescriptor(bca, dataoffset, 0, true, (boneRotateValuesOffsets[bone.m_ID] + 0));
                    dataoffset += 4;

                    // Rotation Y
                    WriteBCAAnimationDescriptor(bca, dataoffset, 0, true, (boneRotateValuesOffsets[bone.m_ID] + 1));
                    dataoffset += 4;

                    // Rotation Z
                    WriteBCAAnimationDescriptor(bca, dataoffset, 0, true, (boneRotateValuesOffsets[bone.m_ID] + 2));
                    dataoffset += 4;

                    // Translation X
                    WriteBCAAnimationDescriptor(bca, dataoffset, 0, true, (boneTranslateValuesOffsets[bone.m_ID] + 0));
                    dataoffset += 4;

                    // Translation Y
                    WriteBCAAnimationDescriptor(bca, dataoffset, 0, true, (boneTranslateValuesOffsets[bone.m_ID] + 1));
                    dataoffset += 4;

                    // Translation Z
                    WriteBCAAnimationDescriptor(bca, dataoffset, 0, true, (boneTranslateValuesOffsets[bone.m_ID] + 2));
                    dataoffset += 4;
                }
            }

            if (m_BCAImportationOptions.m_Optimise)
            {
                Optimise(bca);
            }
            if (save)
            {
                bca.SaveChanges();
            }
        }
Example #8
0
        public void pack(ref NitroFile kcl, ref uint pos)
        {
            List<Octree> branches = new List<Octree>();
            branches.Add(this);
            uint free_list_offset = 0;
            List<List<int>> list_offsets_ind = new List<List<int>>();
            List<uint> list_offsets_addr = new List<uint>();

            //testing
            int zero_ind_count = 0;
            int ind_already_in_count = 0;
            int list_offsets_added_count = 0;
            int else_branches_append_count = 0;
            //end testing
            int i = 0;
            while (i < branches.Count)
            {
                foreach (Octree node in branches[i].children)
                {
                    if (node.is_leaf)
                    {
                        if (node.indices.Count == 0)
                        {
                            zero_ind_count += 1;
                            continue;
                        }
                        if (indicesInList(list_offsets_ind, node.indices))
                        {
                            ind_already_in_count += 1;
                            continue;
                        }
                        list_offsets_ind.Add(node.indices);
                        list_offsets_addr.Add(free_list_offset);
                        list_offsets_added_count += 1;
                        free_list_offset += (uint)(2 * ((node.indices.Count) + 1));
                    }
                    else
                    {
                        branches.Add(node);
                        else_branches_append_count += 1;
                    }
                }
                i += 1;
            }

            uint list_base = 0;
            foreach (Octree b in branches)
            {
                list_base += (uint)(4 * b.children.Count);
            }
            list_offsets_ind.Add(new List<int>());//Add an empty indices list
            list_offsets_addr.Add(free_list_offset - 2);//with this address
            uint branch_base = 0;
            uint free_branch_offset = (uint)(4 * (this.children.Count));

            foreach (Octree branch in branches)
            {
                foreach (Octree node in branch.children)
                {
                    if (node.is_leaf)
                    {
                        int key = posIndicesInList(list_offsets_ind, node.indices);
                        kcl.Write32(pos, (uint)(0x80000000 | (list_base + list_offsets_addr[key] - 2 - branch_base)));
                        pos += 4;
                    }
                    else
                    {
                        kcl.Write32(pos, (free_branch_offset - branch_base));
                        pos += 4;
                        free_branch_offset += (uint)(4 * (node.children.Count));
                    }
                }
                branch_base += (uint)(4 * (branch.children.Count));
            }

            list_offsets_ind.RemoveAt(list_offsets_ind.Count - 1);
            list_offsets_addr.RemoveAt(list_offsets_addr.Count - 1);

            foreach (List<int> indices in list_offsets_ind)
            {
                foreach (int index in indices)
                {
                    kcl.Write16(pos, (ushort)(index + 1));
                    pos += 2;
                }
                kcl.Write16(pos, (ushort)0);
                pos += 2;
            }
        }
Example #9
0
        private static void write_kcl(NitroFile kcl, List<Triangle> triangles, int max_triangles, int min_width, float scale)
        {
            kcl.Clear();

            //Need to scale each vertex (1000 times scale of model)
            foreach (Triangle t in triangles)
            {
                t.u = t.u.mul(scale);
                t.v = t.v.mul(scale);
                t.w = t.w.mul(scale);
            }

            uint pos = 0;

            List<Face> faces = new List<Face>();
            VertexWelder vertex_welder = new VertexWelder(1 / 64f, (int)(Math.Floor((double)(triangles.Count / 256))));
            VertexWelder normal_welder = new VertexWelder(1 / 1024f, (int)(Math.Floor((double)(4 * triangles.Count / 256))));

            foreach (Triangle t in triangles)
            {
                Face f = new Face();

                Vector a = unit(cross(t.u.sub(t.w), t.n));
                Vector b = unit(cross(t.v.sub(t.u), t.n));
                Vector c = unit(cross(t.w.sub(t.v), t.n));

                f.length = new FixedPoint(dot(t.v.sub(t.u), c), 1 / 65536f);
                f.vertex_index = (ushort)vertex_welder.add(t.u);
                f.normal_index = (ushort)normal_welder.add(t.n);
                f.a_index = (ushort)normal_welder.add(a);
                f.b_index = (ushort)normal_welder.add(b);
                f.c_index = (ushort)normal_welder.add(c);
                f.group = (ushort)t.group;

                faces.Add(f);
            }

            //Vertex Section
            pos += 56;
            kcl.Write32(0x00, pos);//Vertex section offset

            foreach (Vertex vtx in vertex_welder.vertices)
            {
                kcl.Write32(pos, (uint)vtx.x.valToWrite());
                kcl.Write32(pos + 4, (uint)vtx.y.valToWrite());
                kcl.Write32(pos + 8, (uint)vtx.z.valToWrite());

                pos += 12;
            }

            //Vector Section
            kcl.Write32(0x04, pos);//Vector section offset

            foreach (Vector vct in normal_welder.vectors)
            {
                kcl.Write16(pos, (ushort)vct.x.valToWrite());
                kcl.Write16(pos + 2, (ushort)vct.y.valToWrite());
                kcl.Write16(pos + 4, (ushort)vct.z.valToWrite());

                pos += 6;
            }

            pos = (uint)((pos + 3) & ~3);

            //Planes Section
            kcl.Write32(0x08, pos - 0x10);//Planes section offset

            foreach (Face f in faces)
            {
                kcl.Write32(pos, (uint)f.length.valToWrite());
                kcl.Write16(pos + 4, (ushort)f.vertex_index);
                kcl.Write16(pos + 6, (ushort)f.normal_index);
                kcl.Write16(pos + 8, (ushort)f.a_index);
                kcl.Write16(pos + 10, (ushort)f.b_index);
                kcl.Write16(pos + 12, (ushort)f.c_index);
                kcl.Write16(pos + 14, (ushort)f.group);

                pos += 16;
            }

            //Octree Section
            kcl.Write32(0x0C, pos);//Octree offset

            Octree octree = new Octree(triangles, max_triangles, (float)min_width);
            octree.pack(ref kcl, ref pos);

            //Header
            kcl.Write32(0x10, (uint)327680);//Unknown
            kcl.Write32(0x14, (uint)octree.bas.x.valToWrite());
            kcl.Write32(0x18, (uint)octree.bas.y.valToWrite());
            kcl.Write32(0x1C, (uint)octree.bas.z.valToWrite());
            kcl.Write32(0x20, (uint)(~((int)octree.width_x - 1) & 0xFFFFFFFF));
            kcl.Write32(0x24, (uint)(~((int)octree.width_y - 1) & 0xFFFFFFFF));
            kcl.Write32(0x28, (uint)(~((int)octree.width_z - 1) & 0xFFFFFFFF));
            kcl.Write32(0x2C, (uint)(Math.Log(octree.base_width, 2)));
            kcl.Write32(0x30, (uint)(Math.Log(octree.nx, 2)));
            kcl.Write32(0x34, (uint)(Math.Log(octree.nx, 2)) + (uint)(Math.Log(octree.ny, 2)));

            kcl.SaveChanges();
        }