public AssetStorage(ModelLinker linker)
        {
            int index;

            //Vertices
            if (linker.Vertices != null)
            {
                Assets[0] = new UnsafeBuffer[linker.Vertices->_numEntries];
                index     = 0;
                foreach (ResourcePair p in *linker.Vertices)
                {
                    Assets[0][index++] = VertexCodec.Decode((MDL0VertexData *)p.Data);
                }
            }

            //Normals
            if (linker.Normals != null)
            {
                Assets[1] = new UnsafeBuffer[linker.Normals->_numEntries];
                index     = 0;
                foreach (ResourcePair p in *linker.Normals)
                {
                    Assets[1][index++] = VertexCodec.Decode((MDL0NormalData *)p.Data);
                }
            }

            //Colors
            if (linker.Colors != null)
            {
                Assets[2] = new UnsafeBuffer[linker.Colors->_numEntries];
                index     = 0;
                foreach (ResourcePair p in *linker.Colors)
                {
                    Assets[2][index++] = ColorCodec.Decode((MDL0ColorData *)p.Data);
                }
            }

            //UVs
            if (linker.UVs != null)
            {
                Assets[3] = new UnsafeBuffer[linker.UVs->_numEntries];
                index     = 0;
                foreach (ResourcePair p in *linker.UVs)
                {
                    Assets[3][index++] = VertexCodec.Decode((MDL0UVData *)p.Data);
                }
            }
        }
        public override void OnRebuild(VoidPtr address, int length, bool force)
        {
            if (Model._isImport || _forceRebuild)
            {
                MDL0FurPosData* header = (MDL0FurPosData*)address;

                header->_dataLen = length;
                header->_dataOffset = 0x40;
                header->_index = _entryIndex;
                header->_isXYZ = _enc._hasZ ? 1 : 0;
                header->_type = (int)_enc._type;
                header->_divisor = (byte)_enc._scale;
                header->_entryStride = (byte)_enc._dstStride;
                header->_numVertices = (short)_enc._srcCount;

                header->_numLayers = NumLayers;
                header->_offsetOfLayer = LayerOffset;

                //Write data
                _enc.Write(Vertices, (byte*)address + 0x40);
                _enc.Dispose();
                _enc = null;

                _forceRebuild = false;
            }
            else
                base.OnRebuild(address, length, force);
        }
 public override int OnCalculateSize(bool force)
 {
     if (Model._isImport || _forceRebuild)
     {
         _enc = new VertexCodec(Vertices, false, _forceFloat);
         return _enc._dataLen.Align(0x20) + 0x40;
     }
     else return base.OnCalculateSize(force);
 }
Example #4
0
        public static int CalcSize(Collada form, ModelLinker linker)
        {
            MDL0Node model = linker.Model;

            model._needsNrmMtxArray = model._needsTexMtxArray = false;
            model._numFacepoints    = model._numTriangles = 0;

            int headerLen,
                groupLen = 0,
                tableLen = 0,
                texLen   = 0,
                boneLen  = 0,
                dataLen  = 0,
                defLen   = 0,
                assetLen = 0,
                treeLen  = 0,
                mixLen   = 0,
                opaLen   = 0,
                xluLen   = 0;

            int aInd, aLen;

            //Get header length
            switch (linker.Version)
            {
            case 0x08:
            case 0x09: headerLen = 0x80; break;

            case 0x0A: headerLen = 0x88; break;

            case 0x0B: headerLen = 0x8C; break;

            default: headerLen = 0x80;
                //Unsupported version. Change to 9 as default.
                linker.Version = 9; break;
            }

            //Assign node indices
            AssignNodeIndices(linker);

            //Get table length
            tableLen = (linker._nodeCount + 1) << 2;

            //Get group/data length
            List <MDLResourceType> iList = ModelLinker.IndexBank[linker.Version];

            foreach (MDLResourceType resType in iList)
            {
                IEnumerable entryList = null;
                int         entries   = 0;

                switch (resType)
                {
                case MDLResourceType.Definitions:

                    //NodeTree
                    treeLen = linker.BoneCache.Length * 5;

                    //NodeMix
                    foreach (Influence i in model._influences._influences)
                    {
                        mixLen += 4;
                        foreach (BoneWeight w in i.Weights)
                        {
                            MDL0BoneNode bone = w.Bone as MDL0BoneNode;
                            if (bone != null && w.Weight != 0 && bone._nodeIndex < linker.NodeCache.Length && bone._nodeIndex >= 0 && linker.NodeCache[bone._nodeIndex] is MDL0BoneNode)
                            {
                                mixLen += 6;
                            }
                        }
                    }
                    foreach (MDL0BoneNode b in linker.BoneCache)
                    {
                        if (b._weightCount > 0)
                        {
                            mixLen += 5;
                        }
                    }

                    //DrawOpa and DrawXlu
                    //Get assigned materials and categorize
                    if (model._objList != null)
                    {
                        for (int i = 0; i < model._objList.Count; i++)
                        {
                            //Entries are ordered by material, not by polygon.
                            //Using the material's attached polygon list is untrustable if the definitions were corrupt on parse.
                            MDL0ObjectNode poly = model._objList[i] as MDL0ObjectNode;

                            model._numTriangles  += poly._numFaces;
                            model._numFacepoints += poly._numFacepoints;

                            foreach (DrawCall c in poly._drawCalls)
                            {
                                if (c.DrawPass == DrawCall.DrawPassType.Opaque)
                                {
                                    opaLen += 8;
                                }
                                else
                                {
                                    xluLen += 8;
                                }
                            }
                        }
                    }

                    //Add terminate byte and set model def flags
                    if (model._hasTree = (treeLen > 0))
                    {
                        treeLen++; entries++;
                    }
                    if (model._hasMix = (mixLen > 0))
                    {
                        mixLen++; entries++;
                    }
                    if (model._hasOpa = (opaLen > 0))
                    {
                        opaLen++; entries++;
                    }
                    if (model._hasXlu = (xluLen > 0))
                    {
                        xluLen++; entries++;
                    }

                    //Align data
                    defLen += (treeLen + mixLen + opaLen + xluLen).Align(4);

                    break;

                case MDLResourceType.Vertices:
                    if (model._vertList != null)
                    {
                        entryList = model._vertList;
                        break;
                    }
                    else
                    {
                        aInd = 0;     //Set the ID
                        aLen = 1;     //Offset count
                    }

EvalAssets:

                    List <ResourceNode> polyList = model._objList;
                    if (polyList == null)
                    {
                        break;
                    }

                    string str = "";

                    bool direct = linker._forceDirectAssets[aInd];

                    //Create asset lists
                    IList aList;
                    switch (aInd)     //Switch by the set ID
                    {
                    case 0: aList = linker._vertices = new List <VertexCodec>(polyList.Count); str = "Vertices "; break;

                    case 1: aList = linker._normals = new List <VertexCodec>(polyList.Count); str = "Normals "; break;

                    case 2: aList = linker._colors = new List <ColorCodec>(polyList.Count); str = "Colors "; break;

                    default: aList = linker._uvs = new List <VertexCodec>(polyList.Count); str = "UVs "; break;
                    }

                    aLen += aInd;
                    for (int i = 0; i < polyList.Count; i++)
                    {
                        MDL0ObjectNode obj = polyList[i] as MDL0ObjectNode;
                        for (int x = aInd; x < aLen; x++)
                        {
                            if (obj._manager._faceData[x] != null)
                            {
                                //Remap color nodes
                                if ((x == 2 || x == 3))
                                {
                                    if (Collada._importOptions._rmpClrs)
                                    {
                                        obj._elementIndices[x] = -1;
                                        foreach (MDL0ObjectNode thatObj in polyList.OrderBy(c => - ((MDL0ObjectNode)c)._manager.GetColors(x - 2, false).Length))
                                        {
                                            //Only compare up to the current object
                                            if (thatObj == obj)
                                            {
                                                break;
                                            }

                                            var  thatArr = thatObj._manager.GetColors(x - 2, false);
                                            var  thisArr = obj._manager.GetColors(x - 2, false);
                                            bool equals  = true;
                                            if (thisArr.Length == thatArr.Length)
                                            {
                                                for (int n = 0; n < thisArr.Length; n++)
                                                {
                                                    if (thisArr[n] != thatArr[n])
                                                    {
                                                        equals = false;
                                                        break;
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                foreach (RGBAPixel px in thisArr)
                                                {
                                                    if (Array.IndexOf(thatArr, px) < 0)
                                                    {
                                                        equals = false;
                                                        break;
                                                    }
                                                }
                                            }

                                            if (equals)
                                            {
                                                //Found a match
                                                obj._elementIndices[x]         = thatObj._elementIndices[x];
                                                obj._manager._newClrObj[x - 2] = thatObj.Index;
                                                break;
                                            }
                                        }
                                        if (obj._elementIndices[x] != -1)
                                        {
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        obj._manager._newClrObj[x - 2] = i;
                                    }
                                }

                                obj._elementIndices[x] = (short)aList.Count;

                                if (form != null)
                                {
                                    form.Say("Encoding " + str + (x - aInd) + " for Object " + i + ": " + obj.Name);
                                }

                                VertexCodec vert;
                                switch (aInd)
                                {
                                case 0:
                                    vert = new VertexCodec(obj._manager.GetVertices(false), false, Collada._importOptions._fltVerts);
                                    aList.Add(vert);
                                    if (!direct)
                                    {
                                        assetLen += vert._dataLen.Align(0x20) + 0x40;
                                    }
                                    break;

                                case 1:
                                    vert = new VertexCodec(obj._manager.GetNormals(false), false, Collada._importOptions._fltNrms);
                                    aList.Add(vert);
                                    if (!direct)
                                    {
                                        assetLen += vert._dataLen.Align(0x20) + 0x20;
                                    }
                                    break;

                                case 2:
                                    ColorCodec col = new ColorCodec(obj._manager.GetColors(x - 2, false));
                                    aList.Add(col);
                                    if (!direct)
                                    {
                                        assetLen += col._dataLen.Align(0x20) + 0x20;
                                    }
                                    break;

                                default:
                                    vert = new VertexCodec(obj._manager.GetUVs(x - 4, false), Collada._importOptions._fltUVs);
                                    aList.Add(vert);
                                    if (!direct)
                                    {
                                        assetLen += vert._dataLen.Align(0x20) + 0x40;
                                    }
                                    break;
                                }
                            }
                            else
                            {
                                obj._elementIndices[x] = -1;
                            }
                        }
                    }
                    if (!direct)
                    {
                        entries = aList.Count;
                    }
                    break;

                case MDLResourceType.Normals:
                    if (model._normList != null)
                    {
                        entryList = model._normList;
                    }
                    else
                    {
                        aInd = 1;     //Set the ID
                        aLen = 1;     //Offset count
                        goto EvalAssets;
                    }
                    break;

                case MDLResourceType.Colors:
                    if (model._colorList != null)
                    {
                        entryList = model._colorList;
                    }
                    else
                    {
                        if (Collada._importOptions._useOneNode)
                        {
                            HashSet <RGBAPixel> pixels = new HashSet <RGBAPixel>();
                            if (model._objList != null)
                            {
                                foreach (MDL0ObjectNode obj in model._objList)
                                {
                                    for (int i = 0; i < 2; i++)
                                    {
                                        var arr = obj._manager.GetColors(i, false);
                                        if (arr.Length > 0)
                                        {
                                            obj._elementIndices[i + 2] = 0;
                                            foreach (RGBAPixel p in arr)
                                            {
                                                pixels.Add(p);
                                            }
                                        }
                                        else
                                        {
                                            obj._elementIndices[i + 2] = -1;
                                        }
                                    }
                                }
                            }
                            var le = pixels.ToList();
                            le.Sort();

                            if (le.Count == 0)
                            {
                                break;
                            }

                            Collada._importOptions._singleColorNodeEntries = le.ToArray();

                            ColorCodec col = new ColorCodec(Collada._importOptions._singleColorNodeEntries);
                            linker._colors = new List <ColorCodec>()
                            {
                                col
                            };
                            assetLen += col._dataLen.Align(0x20) + 0x20;
                            entries   = 1;
                        }
                        else
                        {
                            aInd = 2;     //Set the ID
                            aLen = 2;     //Offset count
                            goto EvalAssets;
                        }
                    }
                    break;

                case MDLResourceType.UVs:
                    if (model._uvList != null)
                    {
                        entryList = model._uvList;
                    }
                    else
                    {
                        aInd = 4;     //Set the ID
                        aLen = 8;     //Offset count
                        goto EvalAssets;
                    }
                    break;

                case MDLResourceType.Bones:
                    int index = 0;
                    foreach (MDL0BoneNode b in linker.BoneCache)
                    {
                        if (form != null)
                        {
                            form.Say("Calculating the size of the Bones - " + b.Name);
                        }

                        b._entryIndex = index++;
                        boneLen      += b.CalculateSize(true);
                    }
                    entries = linker.BoneCache.Length;
                    break;

                case MDLResourceType.Materials:
                    if (model._matList != null)
                    {
                        entries = model._matList.Count;
                    }
                    break;

                case MDLResourceType.Objects:
                    if (model._objList != null)
                    {
                        entryList = model._objList;
                        foreach (MDL0ObjectNode n in model._objList)
                        {
                            if (n.NormalNode != null || n._manager._faceData[1] != null)
                            {
                                model._needsNrmMtxArray = true;
                            }
                            if (n.HasTexMtx)
                            {
                                model._needsTexMtxArray = true;
                            }
                        }
                    }
                    break;

                case MDLResourceType.Shaders:
                    if (model._matList != null && (entryList = model.GetUsedShaders()) != null)
                    {
                        entries = model._matList.Count;
                    }
                    break;

                case MDLResourceType.Textures:
                    if (model._texList != null)
                    {
                        List <MDL0TextureNode> texNodes = new List <MDL0TextureNode>();
                        foreach (MDL0TextureNode tex in model._texList)
                        {
                            texNodes.Add(tex);
                            texLen += (tex._references.Count * 8) + 4;
                        }
                        entries = (linker._texList = texNodes).Count;
                    }
                    break;

                case MDLResourceType.Palettes:
                    if (model._pltList != null)
                    {
                        List <MDL0TextureNode> pltNodes = new List <MDL0TextureNode>();
                        foreach (MDL0TextureNode plt in model._pltList)
                        {
                            pltNodes.Add(plt);
                            texLen += (plt._references.Count * 8) + 4;
                        }
                        entries = (linker._pltList = pltNodes).Count;
                    }
                    break;
                }

                if (entryList != null)
                {
                    int index = 0;
                    foreach (MDL0EntryNode e in entryList)
                    {
                        if (form != null)
                        {
                            if (resType == MDLResourceType.Objects)
                            {
                                form.Say("Encoding the " + resType.ToString() + " - " + e.Name);
                            }
                            else
                            {
                                form.Say("Calculating the size of the " + resType.ToString() + " - " + e.Name);
                            }
                        }

                        e._entryIndex = index++;
                        dataLen      += e.CalculateSize(true);
                    }
                    if (entries == 0)
                    {
                        entries = index;
                    }
                }

                if (entries > 0)
                {
                    groupLen += (entries * 0x10) + 0x18;
                }
            }

            //Align the materials perfectly using the data length
            int temp = 0;

            if (model._matList != null && iList.IndexOf(MDLResourceType.Materials) != -1)
            {
                int index             = 0;
                MDL0MaterialNode prev = null;
                foreach (MDL0MaterialNode e in model._matList)
                {
                    if (form != null)
                    {
                        form.Say("Calculating the size of the Materials - " + e.Name);
                    }

                    if (index != 0)
                    {
                        e._mdlOffset = (prev = ((MDL0MaterialNode)model._matList[index - 1]))._mdlOffset + prev._calcSize;
                    }
                    else if ((temp = (e._mdlOffset = headerLen + tableLen + groupLen + texLen + defLen + boneLen).Align(0x10)) != e._mdlOffset)
                    {
                        e._dataAlign = temp - e._mdlOffset;
                    }

                    e._entryIndex = index++;
                    dataLen      += e.CalculateSize(true);
                }
            }

            if (model._isImport && model._objList != null)
            {
                foreach (MDL0ObjectNode obj1 in model._objList)
                {
                    if (obj1 == null || obj1._drawCalls == null || obj1._drawCalls.Count == 0)
                    {
                        continue;
                    }

                    MDL0MaterialNode p = obj1._drawCalls[0].MaterialNode;
                    if (p == null)
                    {
                        continue;
                    }

                    //Set materials to use register color if option set
                    if (!Collada._importOptions._useReg &&
                        linker._colors != null &&
                        linker._colors.Count > 0)
                    {
                        p.C1AlphaMaterialSource = GXColorSrc.Vertex;
                        p.C1ColorMaterialSource = GXColorSrc.Vertex;
                    }
                    else
                    {
                        p.C1MaterialColor       = Collada._importOptions._dfltClr;
                        p.C1ColorMaterialSource = GXColorSrc.Register;
                        p.C1AlphaMaterialSource = GXColorSrc.Register;
                    }
                }
            }

            return
                ((linker._headerLen = headerLen) +
                 (linker._tableLen = tableLen) +
                 (linker._groupLen = groupLen) +
                 (linker._texLen = texLen) +
                 (linker._defLen = defLen) +
                 (linker._boneLen = boneLen) +
                 (linker._assetLen = assetLen) +
                 (linker._dataLen = dataLen) +
                 (linker.Version > 9 ? model._userEntries.GetSize() : 0));
        }
Example #5
0
        public static int CalcSize(Collada form, ModelLinker linker)
        {
            MDL0Node model = linker.Model;

            int headerLen,
                groupLen = 0,
                tableLen = 0,
                texLen   = 0,
                boneLen  = 0,
                dataLen  = 0,
                defLen   = 0,
                assetLen = 0,
                treeLen  = 0,
                mixLen   = 0,
                opaLen   = 0,
                xluLen   = 0;

            int aInd, aLen;

            //Get header length
            switch (linker.Version)
            {
            case 0x08:
            case 0x09: headerLen = 0x80; break;

            case 0x0A: headerLen = 0x88; break;

            case 0x0B: headerLen = 0x8C; break;

            default: headerLen = 0x80;
                //Unsupported version. Change to 9 as default.
                linker.Version = 9; break;
            }

            //Assign node indices
            AssignNodeIndices(linker);

            //Get table length
            tableLen = (linker._nodeCount + 1) << 2;

            //Get group/data length
            List <MDLResourceType> iList = ModelLinker.IndexBank[linker.Version];

            foreach (MDLResourceType resType in iList)
            {
                IEnumerable entryList = null;
                int         entries   = 0;

                switch (resType)
                {
                case MDLResourceType.Definitions:

                    //NodeTree
                    treeLen = linker.BoneCache.Length * 5;

                    //NodeMix
                    foreach (Influence i in model._influences._influences)
                    {
                        mixLen += 4;
                        foreach (BoneWeight w in i._weights)
                        {
                            mixLen += 6;
                        }
                    }
                    foreach (MDL0BoneNode b in linker.BoneCache)
                    {
                        if (b._weightCount > 0)
                        {
                            mixLen += 5;
                        }
                    }

                    //DrawOpa and DrawXlu
                    //Get assigned materials and categorize
                    if (model._matList != null)
                    {
                        for (int i = 0; i < model._matList.Count; i++)
                        {
                            //Entries are ordered by material, not by polygon.
                            MDL0MaterialNode mat = model._matList[i] as MDL0MaterialNode;
                            if (!mat.isMetal)
                            {
                                for (int l = 0; l < mat._polygons.Count; l++)
                                {
                                    if (!mat.XLUMaterial)
                                    {
                                        opaLen += 8;
                                    }
                                    else
                                    {
                                        xluLen += 8;
                                    }
                                }
                            }
                        }
                    }

                    //Add terminate byte and set model def flags
                    if (model._hasTree = (treeLen > 0))
                    {
                        treeLen++; entries++;
                    }
                    if (model._hasMix = (mixLen > 0))
                    {
                        mixLen++; entries++;
                    }
                    if (model._hasOpa = (opaLen > 0))
                    {
                        opaLen++; entries++;
                    }
                    if (model._hasXlu = (xluLen > 0))
                    {
                        xluLen++; entries++;
                    }

                    //Align data
                    defLen += (treeLen + mixLen + opaLen + xluLen).Align(4);

                    break;

                case MDLResourceType.Vertices:
                    if (model._vertList != null)
                    {
                        entryList = model._vertList;
                        break;
                    }
                    else
                    {
                        aInd = 0;     //Set the ID
                        aLen = 1;     //Offset count
                    }

EvalAssets:

                    List <ResourceNode> polyList = model._polyList;
                    if (polyList == null)
                    {
                        break;
                    }

                    string str = "";

                    //Create asset lists
                    IList aList;
                    switch (aInd)     //Switch by the set ID
                    {
                    case 0: aList = linker._vertices = new List <VertexCodec>(polyList.Count); str = "Vertices "; break;

                    case 1: aList = linker._normals = new List <VertexCodec>(polyList.Count); str = "Normals "; break;

                    case 2: aList = linker._colors = new List <ColorCodec>(polyList.Count); str = "Colors "; break;

                    default: aList = linker._uvs = new List <VertexCodec>(polyList.Count); str = "UVs "; break;
                    }

                    aLen += aInd;
                    for (int i = 0; i < polyList.Count; i++)
                    {
                        MDL0PolygonNode p = polyList[i] as MDL0PolygonNode;
                        for (int x = aInd; x < aLen; x++)
                        {
                            if (p._manager._faceData[x] != null)
                            {
                                if (model._importOptions._rmpClrs && model._importOptions._addClrs)
                                {
                                    if (i > 0 && x == 2 && model._noColors == true)
                                    {
                                        p._elementIndices[x] = 0; continue;
                                    }
                                    else if (i >= 0 && x == 3 && model._noColors == true)
                                    {
                                        p._elementIndices[x] = -1; break;
                                    }
                                }

                                p._elementIndices[x] = (short)aList.Count;

                                if (form != null)
                                {
                                    form.Say("Encoding " + str + (x - aInd) + " for Object " + i + ": " + p.Name);
                                }

                                switch (aInd)
                                {
                                case 0:
                                    VertexCodec vert;
                                    aList.Add(vert = new VertexCodec(p._manager.RawVertices, false, model._importOptions._fltVerts));
                                    assetLen      += vert._dataLen.Align(0x20) + 0x40;
                                    break;

                                case 1:
                                    aList.Add(vert = new VertexCodec(p._manager.RawNormals, false, model._importOptions._fltNrms));
                                    assetLen      += vert._dataLen.Align(0x20) + 0x20;
                                    break;

                                case 2:
                                    ColorCodec col;
                                    aList.Add(col = new ColorCodec(p._manager.Colors(x - 2)));
                                    assetLen     += col._dataLen.Align(0x20) + 0x20;
                                    break;

                                default:
                                    aList.Add(vert = new VertexCodec(p._manager.UVs(x - 4), model._importOptions._fltUVs));
                                    assetLen      += vert._dataLen.Align(0x20) + 0x40;
                                    break;
                                }
                            }
                            else
                            {
                                p._elementIndices[x] = -1;
                            }
                        }
                    }
                    entries = aList.Count;
                    break;

                case MDLResourceType.Normals:
                    if (model._normList != null)
                    {
                        entryList = model._normList;
                    }
                    else
                    {
                        aInd = 1;     //Set the ID
                        aLen = 1;     //Offset count
                        goto EvalAssets;
                    }
                    break;

                case MDLResourceType.Colors:
                    if (model._colorList != null)
                    {
                        entryList = model._colorList;
                    }
                    else
                    {
                        aInd = 2;     //Set the ID
                        aLen = 2;     //Offset count
                        goto EvalAssets;
                    }
                    break;

                case MDLResourceType.UVs:
                    if (model._uvList != null)
                    {
                        entryList = model._uvList;
                    }
                    else
                    {
                        aInd = 4;     //Set the ID
                        aLen = 8;     //Offset count
                        goto EvalAssets;
                    }
                    break;

                case MDLResourceType.Bones:
                    int index = 0;
                    foreach (MDL0BoneNode b in linker.BoneCache)
                    {
                        if (form != null)
                        {
                            form.Say("Calculating the size of the Bones - " + b.Name);
                        }

                        b._entryIndex = index++;
                        boneLen      += b.CalculateSize(true);
                    }
                    entries = linker.BoneCache.Length;
                    break;

                case MDLResourceType.Materials:
                    if (model._matList != null)
                    {
                        entries = model._matList.Count;
                    }
                    break;

                case MDLResourceType.Objects:
                    if (model._polyList != null)
                    {
                        entryList = model._polyList;
                    }
                    break;

                case MDLResourceType.Shaders:
                    if ((entryList = model.GetUsedShaders()) != null && model._matList != null)
                    {
                        entries = model._matList.Count;
                    }
                    break;

                case MDLResourceType.Textures:
                    if (model._texList != null)
                    {
                        foreach (MDL0TextureNode tex in model._texList)
                        {
                            texLen += (tex._references.Count * 8) + 4;
                        }

                        linker._texCount = entries = model._texList.Count;
                    }
                    break;

                case MDLResourceType.Palettes:
                    if (model._pltList != null)
                    {
                        foreach (MDL0TextureNode pal in model._pltList)
                        {
                            texLen += (pal._references.Count * 8) + 4;
                        }

                        linker._palCount = entries = model._pltList.Count;
                    }
                    break;
                }

                if (entryList != null)
                {
                    int index = 0;
                    foreach (MDL0EntryNode e in entryList)
                    {
                        if (form != null)
                        {
                            if (resType == MDLResourceType.Objects)
                            {
                                form.Say("Encoding the " + resType.ToString() + " - " + e.Name);
                            }
                            else
                            {
                                form.Say("Calculating the size of the " + resType.ToString() + " - " + e.Name);
                            }
                        }

                        e._entryIndex = index++;
                        dataLen      += e.CalculateSize(true);
                    }
                    if (entries == 0)
                    {
                        entries = index;
                    }
                }

                if (entries > 0)
                {
                    groupLen += (entries * 0x10) + 0x18;
                }
            }

            //Align the materials perfectly using the data length
            int temp = 0;

            if (model._matList != null && iList.IndexOf(MDLResourceType.Materials) != -1)
            {
                int index             = 0;
                MDL0MaterialNode prev = null;
                foreach (MDL0MaterialNode e in model._matList)
                {
                    if (form != null)
                    {
                        form.Say("Calculating the size of the Materials - " + e.Name);
                    }

                    e._entryIndex = index++;

                    if (index == 1)
                    {
                        if ((temp = (e._mdlOffset = headerLen + tableLen + groupLen + texLen + defLen + boneLen).Align(0x10)) != e._mdlOffset)
                        {
                            e._dataAlign = temp - e._mdlOffset;
                        }
                    }
                    else
                    {
                        e._mdlOffset = (prev = ((MDL0MaterialNode)model._matList[index - 1]))._mdlOffset + prev._calcSize;
                    }

                    dataLen += e.CalculateSize(true);
                }
            }

            return
                ((linker._headerLen = headerLen) +
                 (linker._tableLen = tableLen) +
                 (linker._groupLen = groupLen) +
                 (linker._texLen = texLen) +
                 (linker._defLen = defLen) +
                 (linker._boneLen = boneLen) +
                 (linker._assetLen = assetLen) +
                 (linker._dataLen = dataLen) +
                 (model._part2Entries.Count > 0 ? 0x1C + model._part2Entries.Count * 0x2C : 0));
        }
        public override void OnRebuild(VoidPtr address, int length, bool force)
        {
            if (Model._isImport || _forceRebuild)
            {
                MDL0UVData* header = (MDL0UVData*)address;

                header->_dataLen = length;
                header->_dataOffset = 0x40;
                header->_index = _entryIndex;
                header->_format = (int)_enc._type;
                header->_divisor = (byte)_enc._scale;
                header->_isST = 1;
                header->_entryStride = (byte)_enc._dstStride;
                header->_numEntries = (ushort)_enc._srcCount;
                header->_min = (Vector2)_enc._min;
                header->_min = (Vector2)_enc._max;
                header->_pad1 = header->_pad2 = header->_pad3 = header->_pad4 = 0;

                _enc.Write(Points, (byte*)address + 0x40);
                _enc.Dispose();
                _enc = null;

                _forceRebuild = false;
            }
            else
                base.OnRebuild(address, length, force);
        }
        public static int CalcSize(ModelLinker linker)
        {
            MDL0Node model = linker.Model;
            int      headerLen, groupLen = 0x18, tableLen = 0, texLen = 0, dataLen = 0;
            int      treeLen = 0, mixLen = 0, opaLen = 0, xluLen = 0;
            int      texCount = 0, decCount = 0;
            int      aInd, aLen, temp;

            //Get header length
            switch (linker.Version)
            {
            case 0x09: headerLen = 0x80; break;

            default: headerLen = 0; break;
            }

            //Assign node indices
            AssignNodeIndices(linker);

            //Get table length
            tableLen = (linker._nodeCount + 1) << 2;

            //Get group/data length
            List <MDLResourceType> iList = ModelLinker.IndexBank[linker.Version];

            foreach (MDLResourceType resType in iList)
            {
                IEnumerable entryList = null;
                int         entries   = 0;

                //entries = 0;
                switch (resType)
                {
                case MDLResourceType.Defs:
                {
                    //NodeTree
                    treeLen = linker.BoneCache.Length * 5;

                    //NodeMix
                    foreach (IMatrixNode i in linker.NodeCache)
                    {
                        if (!i.IsPrimaryNode)
                        {
                            mixLen += ((Influence)i)._weights.Length * 8 + 4;
                        }
                        else if (i.ReferenceCount > 0)
                        {
                            mixLen += 5;
                        }
                    }

                    //DrawOpa, DrawXlu
                    //Get assigned materials and categorize
                    foreach (MDL0PolygonNode poly in linker.Model.PolygonList)
                    {
                        if (poly._material == null)
                        {
                            continue;
                        }

                        //Is material transparent?
                        if (poly._material.EnableBlend)
                        {
                            opaLen += 8;
                        }
                        else
                        {
                            xluLen += 8;
                        }
                    }

                    //Add terminate byte and set model def flags
                    if (linker.Model._hasTree = (treeLen > 0))
                    {
                        treeLen++; entries++;
                    }
                    if (linker.Model._hasMix = (mixLen > 0))
                    {
                        mixLen++; entries++;
                    }
                    if (linker.Model._hasOpa = (opaLen > 0))
                    {
                        opaLen++; entries++;
                    }
                    if (linker.Model._hasXlu = (xluLen > 0))
                    {
                        xluLen++; entries++;
                    }

                    //Align data
                    dataLen += (treeLen + mixLen + opaLen + xluLen).Align(4);

                    break;
                }

                case MDLResourceType.Vertices:
                    aInd = 0;
                    aLen = 1;

EvalAssets:

                    List <ResourceNode> polyList = linker.Model._polyList;
                    if (polyList == null)
                    {
                        break;
                    }

                    //What about merging?

                    //Create asset lists
                    IList aList;
                    switch (aInd)
                    {
                    case 0: aList = linker._vertices = new List <VertexCodec>(polyList.Count); break;

                    case 1: aList = linker._normals = new List <VertexCodec>(polyList.Count); break;

                    case 2: aList = linker._colors = new List <ColorCodec>(polyList.Count); break;

                    default: aList = linker._uvs = new List <VertexCodec>(polyList.Count); break;
                    }

                    aLen += aInd;
                    temp  = polyList.Count;
                    for (int i = 0; i < temp; i++)
                    {
                        MDL0PolygonNode p = polyList[i] as MDL0PolygonNode;
                        //object c;
                        for (int x = aInd; x < aLen; x++)
                        {
                            if (p._manager._faceData[x] != null)
                            {
                                p._elementIndices[x] = (short)aList.Count;
                                switch (aInd)
                                {
                                case 0:
                                    VertexCodec vert;
                                    aList.Add(vert = new VertexCodec(p._manager.RawPoints, true));
                                    dataLen       += vert._dataLen.Align(0x20) + 0x40;
                                    break;

                                case 1:
                                    aList.Add(vert = new VertexCodec((Vector3 *)p._manager._faceData[x].Address, p._manager._pointCount, false));
                                    dataLen       += vert._dataLen.Align(0x20) + 0x20;
                                    break;

                                case 2:
                                    ColorCodec col;
                                    aList.Add(col = new ColorCodec((RGBAPixel *)p._manager._faceData[x].Address, p._manager._pointCount));
                                    dataLen      += col._dataLen.Align(0x20) + 0x20;
                                    break;

                                default:
                                    aList.Add(vert = new VertexCodec((Vector2 *)p._manager._faceData[x].Address, p._manager._pointCount));
                                    dataLen       += vert._dataLen.Align(0x20) + 0x40;
                                    break;
                                }
                            }
                            else
                            {
                                p._elementIndices[x] = -1;
                            }
                        }
                    }
                    entries = aList.Count;

                    break;

                case MDLResourceType.Normals:
                    aInd = 1;
                    aLen = 1;
                    goto EvalAssets;

                case MDLResourceType.Colors:
                    aInd = 2;
                    aLen = 2;
                    goto EvalAssets;

                case MDLResourceType.UVs:
                    aInd = 4;
                    aLen = 8;
                    goto EvalAssets;

                case MDLResourceType.Bones: entryList = linker.BoneCache; break;

                case MDLResourceType.Materials: entryList = linker.Model._matList; break;

                case MDLResourceType.Polygons: entryList = linker.Model._polyList; break;

                case MDLResourceType.Shaders:
                    if ((entryList = linker.Model._shadList) != null)
                    {
                        entries = linker.Model._shadList.Count;
                    }
                    break;

                case MDLResourceType.Textures:
                    TextureRef[] tex = linker.Model._textures.GetTextures();
                    entries = tex.Length;

                    foreach (TextureRef t in tex)
                    {
                        texCount++; texLen += t._texRefs.Count * 8 + 4;
                    }

                    break;

                case MDLResourceType.Decals:
                    TextureRef[] dec = linker.Model._textures.GetDecals();
                    entries = dec.Length;

                    foreach (TextureRef t in dec)
                    {
                        decCount++; texLen += t._decRefs.Count * 8 + 4;
                    }

                    break;
                }

                if (entryList != null)
                {
                    int index = 0;
                    foreach (MDL0EntryNode e in entryList)
                    {
                        e._entryIndex = index++;
                        dataLen      += e.CalculateSize(true);
                    }
                    if (entries == 0)
                    {
                        entries = index;
                    }
                }

                if (entries > 0)
                {
                    groupLen += entries * 0x10 + 0x18;
                }
            }

            linker._headerLen = headerLen;
            linker._tableLen  = tableLen;
            linker._groupLen  = groupLen;
            linker._texLen    = texLen;
            linker._texCount  = texCount;
            linker._decCount  = decCount;
            linker._dataLen   = dataLen;

            return(headerLen + tableLen + groupLen + texLen + dataLen);
        }
        public static int CalcSize(Collada form, ModelLinker linker)
        {
            MDL0Node model = linker.Model;
            model._needsNrmMtxArray = model._needsTexMtxArray = false;
            model._numFacepoints = model._numFaces = 0;

            int headerLen,
                groupLen = 0,
                tableLen = 0,
                texLen = 0,
                boneLen = 0,
                dataLen = 0,
                defLen = 0,
                assetLen = 0,
                treeLen = 0,
                mixLen = 0,
                opaLen = 0,
                xluLen = 0;

            int aInd, aLen;

            //Get header length
            switch (linker.Version)
            {
                case 0x08:
                case 0x09: headerLen = 0x80; break;
                case 0x0A: headerLen = 0x88; break;
                case 0x0B: headerLen = 0x8C; break;
                default: headerLen = 0x80;
                    //Unsupported version. Change to 9 as default.
                    linker.Version = 9; break;
            }

            //Assign node indices
            AssignNodeIndices(linker);

            //Get table length
            tableLen = (linker._nodeCount + 1) << 2;

            //Get group/data length
            List<MDLResourceType> iList = ModelLinker.IndexBank[linker.Version];
            foreach (MDLResourceType resType in iList)
            {
                IEnumerable entryList = null;
                int entries = 0;

                switch (resType)
                {
                    case MDLResourceType.Definitions:

                        //NodeTree
                        treeLen = linker.BoneCache.Length * 5;

                        //NodeMix
                        foreach (Influence i in model._influences._influences)
                        {
                            mixLen += 4;
                            foreach (BoneWeight w in i._weights)
                                if (w.Bone != null && w.Weight != 0 && w.Bone._nodeIndex < linker.NodeCache.Length && w.Bone._nodeIndex >= 0 && linker.NodeCache[w.Bone._nodeIndex] is MDL0BoneNode)
                                    mixLen += 6;
                        }
                        foreach (MDL0BoneNode b in linker.BoneCache)
                            if (b._weightCount > 0)
                                mixLen += 5;

                        //DrawOpa and DrawXlu
                        //Get assigned materials and categorize
                        if (model._objList != null)
                            for (int i = 0; i < model._objList.Count; i++)
                            {
                                //Entries are ordered by material, not by polygon.
                                //Using the material's attached polygon list is untrustable if the definitions were corrupt on parse.
                                MDL0ObjectNode poly = model._objList[i] as MDL0ObjectNode;

                                model._numFaces += poly._numFaces;
                                model._numFacepoints += poly._numFacepoints;

                                if (poly.OpaMaterialNode != null)
                                    opaLen += 8;
                                if (poly.XluMaterialNode != null)
                                    xluLen += 8;
                            }

                        //Add terminate byte and set model def flags
                        if (model._hasTree = (treeLen > 0)) { treeLen++; entries++; }
                        if (model._hasMix = (mixLen > 0)) { mixLen++; entries++; }
                        if (model._hasOpa = (opaLen > 0)) { opaLen++; entries++; }
                        if (model._hasXlu = (xluLen > 0)) { xluLen++; entries++; }

                        //Align data
                        defLen += (treeLen + mixLen + opaLen + xluLen).Align(4);

                        break;

                    case MDLResourceType.Vertices:
                        if (model._vertList != null)
                        {
                            entryList = model._vertList;
                            break;
                        }
                        else
                        {
                            aInd = 0; //Set the ID
                            aLen = 1; //Offset count
                        }

                    EvalAssets:

                        List<ResourceNode> polyList = model._objList;
                        if (polyList == null)
                            break;

                        string str = "";

                        bool direct = linker._forceDirectAssets[aInd];

                        //Create asset lists
                        IList aList;
                        switch (aInd) //Switch by the set ID
                        {
                            case 0: aList = linker._vertices = new List<VertexCodec>(polyList.Count); str = "Vertices "; break;
                            case 1: aList = linker._normals = new List<VertexCodec>(polyList.Count); str = "Normals "; break;
                            case 2: aList = linker._colors = new List<ColorCodec>(polyList.Count); str = "Colors "; break;
                            default: aList = linker._uvs = new List<VertexCodec>(polyList.Count); str = "UVs "; break;
                        }

                        aLen += aInd;
                        for (int i = 0; i < polyList.Count; i++)
                        {
                            MDL0ObjectNode obj = polyList[i] as MDL0ObjectNode;
                            for (int x = aInd; x < aLen; x++)
                                if (obj._manager._faceData[x] != null)
                                {
                                    //Remap color nodes
                                    if ((x == 2 || x == 3))
                                    {
                                        if (Collada._importOptions._rmpClrs)
                                        {
                                            obj._elementIndices[x] = -1;
                                            foreach (MDL0ObjectNode thatObj in polyList.OrderBy(c => -((MDL0ObjectNode)c)._manager.GetColors(x - 2, false).Length))
                                            {
                                                //Only compare up to the current object
                                                if (thatObj == obj)
                                                    break;

                                                var thatArr = thatObj._manager.GetColors(x - 2, false);
                                                var thisArr = obj._manager.GetColors(x - 2, false);
                                                bool equals = true;
                                                if (thisArr.Length == thatArr.Length)
                                                {
                                                    for (int n = 0; n < thisArr.Length; n++)
                                                        if (thisArr[n] != thatArr[n])
                                                        {
                                                            equals = false;
                                                            break;
                                                        }
                                                }
                                                else
                                                {
                                                    foreach (RGBAPixel px in thisArr)
                                                    {
                                                        if (Array.IndexOf(thatArr, px) < 0)
                                                        {
                                                            equals = false;
                                                            break;
                                                        }
                                                    }
                                                }

                                                if (equals)
                                                {
                                                    //Found a match
                                                    obj._elementIndices[x] = thatObj._elementIndices[x];
                                                    obj._manager._newClrObj[x - 2] = thatObj.Index;
                                                    break;
                                                }
                                            }
                                            if (obj._elementIndices[x] != -1)
                                                continue;
                                        }
                                        else
                                            obj._manager._newClrObj[x - 2] = i;
                                    }

                                    obj._elementIndices[x] = (short)aList.Count;

                                    if (form != null)
                                        form.Say("Encoding " + str + (x - aInd) + " for Object " + i + ": " + obj.Name);

                                    VertexCodec vert;
                                    switch (aInd)
                                    {
                                        case 0:
                                            vert = new VertexCodec(obj._manager.GetVertices(false), false, Collada._importOptions._fltVerts);
                                            aList.Add(vert);
                                            if (!direct)
                                                assetLen += vert._dataLen.Align(0x20) + 0x40;
                                            break;
                                        case 1:
                                            vert = new VertexCodec(obj._manager.GetNormals(false), false, Collada._importOptions._fltNrms);
                                            aList.Add(vert);
                                            if (!direct)
                                                assetLen += vert._dataLen.Align(0x20) + 0x20;
                                            break;
                                        case 2:
                                            ColorCodec col = new ColorCodec(obj._manager.GetColors(x - 2, false));
                                            aList.Add(col);
                                            if (!direct)
                                                assetLen += col._dataLen.Align(0x20) + 0x20;
                                            break;
                                        default:
                                            vert = new VertexCodec(obj._manager.GetUVs(x - 4, false), Collada._importOptions._fltUVs);
                                            aList.Add(vert);
                                            if (!direct)
                                                assetLen += vert._dataLen.Align(0x20) + 0x40;
                                            break;
                                    }
                                }
                                else
                                    obj._elementIndices[x] = -1;
                        }
                        if (!direct)
                            entries = aList.Count;
                        break;
                    case MDLResourceType.Normals:
                        if (model._normList != null)
                            entryList = model._normList;
                        else
                        {
                            aInd = 1; //Set the ID
                            aLen = 1; //Offset count
                            goto EvalAssets;
                        }
                        break;
                    case MDLResourceType.Colors:
                        if (model._colorList != null)
                            entryList = model._colorList;
                        else
                        {
                            if (Collada._importOptions._useOneNode)
                            {
                                HashSet<RGBAPixel> pixels = new HashSet<RGBAPixel>();
                                foreach (MDL0ObjectNode obj in model._objList)
                                {
                                    for (int i = 0; i < 2; i++)
                                    {
                                        var arr = obj._manager.GetColors(i, false);
                                        if (arr.Length > 0)
                                        {
                                            obj._elementIndices[i + 2] = 0;
                                            foreach (RGBAPixel p in arr)
                                                pixels.Add(p);
                                        }
                                        else
                                            obj._elementIndices[i + 2] = -1;
                                    }
                                }
                                var le = pixels.ToList(); le.Sort();
                                Collada._importOptions._singleColorNodeEntries = le.ToArray();

                                ColorCodec col = new ColorCodec(Collada._importOptions._singleColorNodeEntries);
                                linker._colors = new List<ColorCodec>() { col };
                                assetLen += col._dataLen.Align(0x20) + 0x20;
                                entries = 1;
                            }
                            else
                            {
                                aInd = 2; //Set the ID
                                aLen = 2; //Offset count
                                goto EvalAssets;
                            }
                        }
                        break;
                    case MDLResourceType.UVs:
                        if (model._uvList != null)
                            entryList = model._uvList;
                        else
                        {
                            aInd = 4; //Set the ID
                            aLen = 8; //Offset count
                            goto EvalAssets;
                        }
                        break;

                    case MDLResourceType.Bones:
                        int index = 0;
                        foreach (MDL0BoneNode b in linker.BoneCache)
                        {
                            if (form != null)
                                form.Say("Calculating the size of the Bones - " + b.Name);

                            b._entryIndex = index++;
                            boneLen += b.CalculateSize(true);
                        }
                        entries = linker.BoneCache.Length;
                        break;

                    case MDLResourceType.Materials:
                        if (model._matList != null)
                            entries = model._matList.Count;
                        break;

                    case MDLResourceType.Objects:
                        if (model._objList != null)
                        {
                            entryList = model._objList;
                            if (model._objList.Count > 0)
                            {
                                model._needsNrmMtxArray = true;
                                foreach (MDL0ObjectNode n in model._objList)
                                    if (n.HasTexMtx)
                                        model._needsTexMtxArray = true;
                            }
                        }
                        break;

                    case MDLResourceType.Shaders:
                        if ((entryList = model.GetUsedShaders()) != null && model._matList != null)
                            entries = model._matList.Count;
                        break;

                    case MDLResourceType.Textures:
                        if (model._texList != null)
                        {
                            foreach (MDL0TextureNode tex in model._texList)
                                texLen += (tex._references.Count * 8) + 4;

                            linker._texCount = entries = model._texList.Count;
                        }
                        break;

                    case MDLResourceType.Palettes:
                        if (model._pltList != null)
                        {
                            foreach (MDL0TextureNode pal in model._pltList)
                                texLen += (pal._references.Count * 8) + 4;

                            linker._palCount = entries = model._pltList.Count;
                        }
                        break;
                }

                if (entryList != null)
                {
                    int index = 0;
                    foreach (MDL0EntryNode e in entryList)
                    {
                        if (form != null)
                            if (resType == MDLResourceType.Objects)
                                form.Say("Encoding the " + resType.ToString() + " - " + e.Name);
                            else
                                form.Say("Calculating the size of the " + resType.ToString() + " - " + e.Name);

                        e._entryIndex = index++;
                        dataLen += e.CalculateSize(true);
                    }
                    if (entries == 0)
                        entries = index;
                }

                if (entries > 0)
                    groupLen += (entries * 0x10) + 0x18;
            }

            //Align the materials perfectly using the data length
            int temp = 0;
            if (model._matList != null && iList.IndexOf(MDLResourceType.Materials) != -1)
            {
                int index = 0;
                MDL0MaterialNode prev = null;
                foreach (MDL0MaterialNode e in model._matList)
                {
                    if (form != null)
                        form.Say("Calculating the size of the Materials - " + e.Name);

                    e._entryIndex = index++;

                    if (index == 1)
                    {
                        if ((temp = (e._mdlOffset = headerLen + tableLen + groupLen + texLen + defLen + boneLen).Align(0x10)) != e._mdlOffset)
                            e._dataAlign = temp - e._mdlOffset;
                    }
                    else
                        e._mdlOffset = (prev = ((MDL0MaterialNode)model._matList[index - 1]))._mdlOffset + prev._calcSize;

                    dataLen += e.CalculateSize(true);
                }
            }

            return
            (linker._headerLen = headerLen) +
            (linker._tableLen = tableLen) +
            (linker._groupLen = groupLen) +
            (linker._texLen = texLen) +
            (linker._defLen = defLen) +
            (linker._boneLen = boneLen) +
            (linker._assetLen = assetLen) +
            (linker._dataLen = dataLen) +
            (linker.Version > 9 ? model._userEntries.GetSize() : 0);
        }
        public override void OnRebuild(VoidPtr address, int length, bool force)
        {
            if (Model._isImport || _forceRebuild)
            {
                MDL0NormalData* header = (MDL0NormalData*)address;

                header->_dataLen = length;
                header->_dataOffset = 0x20;
                header->_index = _entryIndex;
                header->_isNBT = 0;
                header->_type = (int)_enc._type;
                header->_divisor = (byte)_enc._scale;
                header->_entryStride = (byte)_enc._dstStride;
                header->_numVertices = (ushort)_enc._srcCount;

                _enc.Write(Normals, (byte*)header + 0x20);
                _enc.Dispose();
                _enc = null;

                _forceRebuild = false;
            }
            else
                base.OnRebuild(address, length, force);
        }