//Write assets will only be used for model imports. private static void WriteAssets(Collada form, ModelLinker linker, ref byte *pData) { int index; MDL0Node model = linker.Model; if (linker._vertices != null && linker._vertices.Count != 0) { model.LinkGroup(new MDL0GroupNode(MDLResourceType.Vertices)); model._vertGroup._parent = model; index = 0; foreach (VertexCodec c in linker._vertices) { MDL0VertexNode node = new MDL0VertexNode(); node._name = model.Name + "_" + model._objList[index]._name; if (((MDL0ObjectNode)model._objList[index])._drawCalls[0].MaterialNode != null) { node._name += "_" + ((MDL0ObjectNode)model._objList[index])._drawCalls[0].MaterialNode._name; } if (form != null) { form.Say("Writing Vertices - " + node.Name); } MDL0VertexData *header = (MDL0VertexData *)pData; header->_dataLen = c._dataLen.Align(0x20) + 0x40; header->_dataOffset = 0x40; header->_index = index++; header->_isXYZ = c._hasZ ? 1 : 0; header->_type = (int)c._type; header->_divisor = (byte)c._scale; header->_entryStride = (byte)c._dstStride; header->_numVertices = (ushort)c._dstCount; header->_eMin = c._min; header->_eMax = c._max; header->_pad1 = header->_pad2 = 0; c.Write(pData + 0x40); node._replSrc = node._replUncompSrc = new DataSource(header, header->_dataLen); model._vertGroup.AddChild(node, false); pData += header->_dataLen; } } if (linker._normals != null && linker._normals.Count != 0) { model.LinkGroup(new MDL0GroupNode(MDLResourceType.Normals)); model._normGroup._parent = model; index = 0; foreach (VertexCodec c in linker._normals) { MDL0NormalNode node = new MDL0NormalNode(); node._name = model.Name + "_" + model._objList[index]._name; if (((MDL0ObjectNode)model._objList[index])._drawCalls[0].MaterialNode != null) { node._name += "_" + ((MDL0ObjectNode)model._objList[index])._drawCalls[0].MaterialNode._name; } if (form != null) { form.Say("Writing Normals - " + node.Name); } MDL0NormalData *header = (MDL0NormalData *)pData; header->_dataLen = c._dataLen.Align(0x20) + 0x20; header->_dataOffset = 0x20; header->_index = index++; header->_isNBT = 0; header->_type = (int)c._type; header->_divisor = (byte)c._scale; header->_entryStride = (byte)c._dstStride; header->_numVertices = (ushort)c._dstCount; c.Write(pData + 0x20); node._replSrc = node._replUncompSrc = new DataSource(header, header->_dataLen); model._normGroup.AddChild(node, false); pData += header->_dataLen; } } if (linker._colors != null && linker._colors.Count != 0) { model.LinkGroup(new MDL0GroupNode(MDLResourceType.Colors)); model._colorGroup._parent = model; index = 0; foreach (ColorCodec c in linker._colors) { MDL0ColorNode node = new MDL0ColorNode(); node._name = model.Name + "_" + model._objList[index]._name; if (((MDL0ObjectNode)model._objList[index])._drawCalls[0].MaterialNode != null) { node._name += "_" + ((MDL0ObjectNode)model._objList[index])._drawCalls[0].MaterialNode._name; } if (form != null) { form.Say("Writing Colors - " + node.Name); } MDL0ColorData *header = (MDL0ColorData *)pData; header->_dataLen = c._dataLen.Align(0x20) + 0x20; header->_dataOffset = 0x20; header->_index = index++; header->_isRGBA = c._hasAlpha ? 1 : 0; header->_format = (int)c._outType; header->_entryStride = (byte)c._dstStride; header->_pad = 0; header->_numEntries = (ushort)c._dstCount; c.Write(pData + 0x20); node._replSrc = node._replUncompSrc = new DataSource(header, header->_dataLen); model._colorGroup.AddChild(node, false); pData += header->_dataLen; } } if (linker._uvs != null && linker._uvs.Count != 0) { model.LinkGroup(new MDL0GroupNode(MDLResourceType.UVs)); model._uvGroup._parent = model; index = 0; foreach (VertexCodec c in linker._uvs) { MDL0UVNode node = new MDL0UVNode() { _name = "#" + index }; if (form != null) { form.Say("Writing UVs - " + node.Name); } MDL0UVData *header = (MDL0UVData *)pData; header->_dataLen = c._dataLen.Align(0x20) + 0x40; header->_dataOffset = 0x40; header->_index = index++; header->_format = (int)c._type; header->_divisor = (byte)c._scale; header->_isST = 1; header->_entryStride = (byte)c._dstStride; header->_numEntries = (ushort)c._dstCount; header->_min = (Vector2)c._min; header->_max = (Vector2)c._max; header->_pad1 = header->_pad2 = header->_pad3 = header->_pad4 = 0; c.Write(pData + 0x40); node._replSrc = node._replUncompSrc = new DataSource(header, header->_dataLen); model._uvGroup.AddChild(node, false); pData += header->_dataLen; } } //Clean groups if (model._vertList != null && model._vertList.Count > 0) { model._children.Add(model._vertGroup); linker.Groups[(int)(MDLResourceType)Enum.Parse(typeof(MDLResourceType), model._vertGroup.Name)] = model._vertGroup; } else { model.UnlinkGroup(model._vertGroup); } if (model._normList != null && model._normList.Count > 0) { model._children.Add(model._normGroup); linker.Groups[(int)(MDLResourceType)Enum.Parse(typeof(MDLResourceType), model._normGroup.Name)] = model._normGroup; } else { model.UnlinkGroup(model._normGroup); } if (model._uvList != null && model._uvList.Count > 0) { model._children.Add(model._uvGroup); linker.Groups[(int)(MDLResourceType)Enum.Parse(typeof(MDLResourceType), model._uvGroup.Name)] = model._uvGroup; } else { model.UnlinkGroup(model._uvGroup); } if (model._colorList != null && model._colorList.Count > 0) { model._children.Add(model._colorGroup); linker.Groups[(int)(MDLResourceType)Enum.Parse(typeof(MDLResourceType), model._colorGroup.Name)] = model._colorGroup; } else { model.UnlinkGroup(model._colorGroup); } //Link sets if (model._objList != null) { foreach (MDL0ObjectNode poly in model._objList) { if (poly._elementIndices[0] != -1 && model._vertList != null && model._vertList.Count > poly._elementIndices[0]) { poly._vertexNode = (MDL0VertexNode)model._vertGroup._children[poly._elementIndices[0]]; } if (poly._elementIndices[1] != -1 && model._normList != null && model._normList.Count > poly._elementIndices[1]) { poly._normalNode = (MDL0NormalNode)model._normGroup._children[poly._elementIndices[1]]; } for (int i = 2; i < 4; i++) { if (poly._elementIndices[i] != -1 && model._colorList != null && model._colorList.Count > poly._elementIndices[i]) { poly._colorSet[i - 2] = (MDL0ColorNode)model._colorGroup._children[poly._elementIndices[i]]; } } for (int i = 4; i < 12; i++) { if (poly._elementIndices[i] != -1 && model._uvList != null && model._uvList.Count > poly._elementIndices[i]) { poly._uvSet[i - 4] = (MDL0UVNode)model._uvGroup._children[poly._elementIndices[i]]; } } } } }
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)); }
internal static unsafe void Build(Collada form, ModelLinker linker, MDL0Header *header, int length, bool force) { byte *groupAddr = (byte *)header + linker._headerLen + linker._tableLen; byte *dataAddr = groupAddr + linker._groupLen + linker._texLen; //Definitions start here byte *assetAddr = dataAddr + linker._defLen + linker._boneLen + linker._dataLen; linker.Header = header; if (form != null) { form.Say("Writing header..."); } //Create new model header *header = new MDL0Header(length, linker.Version); if (form != null) { form.Say("Writing node table..."); } //Write node table, assign node ids WriteNodeTable(linker); if (form != null) { form.Say("Writing definitions..."); } //Write def table WriteDefs(linker, ref groupAddr, ref dataAddr); //Set format list for each polygon's UVAT groups SetFormatLists(linker); //Write assets first, but only if the model is an import if (linker.Model._isImport) { WriteAssets(form, linker, ref assetAddr); } //Write groups linker.Write(form, ref groupAddr, ref dataAddr, force); //Write user entries if (linker.Model._userEntries.Count > 0 && linker.Version > 9) { header->UserDataOffset = (int)dataAddr - (int)header; linker.Model._userEntries.Write(header->UserData); } else { header->UserDataOffset = 0; } //Write textures WriteTextures(linker, ref groupAddr); //Set box min and box max if (linker.Model._isImport) { SetBox(linker); } //Store group offsets linker.Finish(); //Set new properties *header->Properties = new MDL0Props(linker.Version, linker.Model._numFacepoints, linker.Model._numTriangles, linker.Model._numNodes, linker.Model._scalingRule, linker.Model._texMtxMode, linker.Model._needsNrmMtxArray, linker.Model._needsTexMtxArray, linker.Model._enableExtents, linker.Model._envMtxMode, linker.Model._extents.Min, linker.Model._extents.Max); }
public void Write(Collada form, ref byte *pGroup, ref byte *pData, bool force) { MDL0GroupNode group; ResourceGroup *pGrp; ResourceEntry *pEntry; int len; //Write data in the order it appears foreach (MDLResourceType resType in OrderBank) { if (((group = Groups[(int)resType]) == null) || SpecialRebuildData((int)resType)) { continue; } if (resType == MDLResourceType.Bones) { if (form != null) { form.Say("Writing Bones"); } MDL0Bone *pBone = (MDL0Bone *)pData; foreach (MDL0BoneNode e in BoneCache) { len = e._calcSize; e.Rebuild(pData, len, true); pData += len; } //Loop through after all bones are written //and set header offsets to related bones foreach (MDL0BoneNode e in BoneCache) { e.CalculateOffsets(); } } else if (resType == MDLResourceType.Shaders) { MDL0GroupNode mats = Groups[(int)MDLResourceType.Materials]; MDL0Material *mHeader; if (form != null) { form.Say("Writing Shaders"); } //Write data without headers foreach (ResourceNode e in group.Children) { if (((MDL0ShaderNode)e)._materials.Count > 0) { len = e._calcSize; e.Rebuild(pData, len, force); pData += len; } } //Write one header for each material, using same order. if (mats != null) { foreach (MDL0MaterialNode mat in mats.Children) { mHeader = mat.Header; if (mat._shader != null) { len = (int)mat._shader.Header; mHeader->_shaderOffset = len - (int)mHeader; } else { mHeader->_shaderOffset = 0; } } } } else if (resType == MDLResourceType.Objects || resType == MDLResourceType.Materials) { foreach (ResourceNode r in group.Children) { if (form != null) { form.Say("Writing " + resType.ToString() + " - " + r.Name); } len = r._calcSize; r.Rebuild(pData, len, true); //Forced to fix object node ids and align materials pData += len; } } else { bool rebuild = true; if (Model._isImport) { if (group._name == "Vertices" || group._name == "Normals" || group._name == "UVs" || group._name == "Colors") { rebuild = false; //The data has already been written! } } if (rebuild) { foreach (ResourceNode e in group.Children) { //Console.WriteLine("Rebuilding the " + group.Name); if (form != null) { form.Say("Writing the " + resType.ToString() + " - " + e.Name); } len = e._calcSize; e.Rebuild(pData, len, true); //Forced just in case we need to convert to float. pData += len; } } } } //Write relocation offsets in the order of the header fixed(ResourceGroup **pOut = &Defs) foreach (MDLResourceType resType in IndexBank[Version]) { if (((group = Groups[(int)resType]) == null) || SpecialRebuildData((int)resType)) { continue; } pOut[(int)resType] = pGrp = (ResourceGroup *)pGroup; pEntry = &pGrp->_first + 1; if (resType == MDLResourceType.Bones) { *pGrp = new ResourceGroup(BoneCache.Length); foreach (ResourceNode e in BoneCache) { (pEntry++)->_dataOffset = (int)((byte *)(e.WorkingUncompressed.Address) - pGroup); } } else if (resType == MDLResourceType.Shaders) { MDL0GroupNode mats = Groups[(int)MDLResourceType.Materials]; if (mats != null) { //Create a material group with the amount of entries *pGrp = new ResourceGroup(mats.Children.Count); foreach (MDL0MaterialNode mat in mats.Children) { (pEntry++)->_dataOffset = (int)mat._shader.Header - (int)pGrp; } } } else { *pGrp = new ResourceGroup(group.Children.Count); foreach (ResourceNode e in group.Children) { (pEntry++)->_dataOffset = (int)((byte *)(e.WorkingUncompressed.Address) - pGroup); } } pGroup += pGrp->_totalSize; } }
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)); }
internal static unsafe void Build(Collada form, ModelLinker linker, MDL0Header *header, int length, bool force) { byte *groupAddr = (byte *)header + linker._headerLen + linker._tableLen; byte *dataAddr = groupAddr + linker._groupLen + linker._texLen; //Definitions start here byte *assetAddr = dataAddr + linker._defLen + linker._boneLen + linker._dataLen; linker.Header = header; if (form != null) { form.Say("Writing header..."); } //Create new model header *header = new MDL0Header(length, linker.Version); MDL0Props *props = header->Properties; if (form != null) { form.Say("Writing node table..."); } //Write node table, assign node ids WriteNodeTable(linker); if (form != null) { form.Say("Writing definitions..."); } //Write def table WriteDefs(linker, ref groupAddr, ref dataAddr); //Set format list for each polygon's UVAT groups SetFormatLists(linker); //Write assets first, but only if the model is an import if (linker.Model._isImport) { WriteAssets(form, linker, ref assetAddr); } //Write groups linker.Write(form, ref groupAddr, ref dataAddr, force); //Write Part2 Entries if (linker.Model._part2Entries.Count > 0 && linker.Version != 9) { header->_part2Offset = (int)dataAddr - (int)header; Part2Data *part2 = header->Part2; if (part2 != null) { part2->_totalLen = 0x1C + linker.Model._part2Entries.Count * 0x2C; ResourceGroup *pGroup = part2->Group; *pGroup = new ResourceGroup(linker.Model._part2Entries.Count); ResourceEntry *pEntry = &pGroup->_first + 1; byte * pData = (byte *)pGroup + pGroup->_totalSize; foreach (string s in linker.Model._part2Entries) { (pEntry++)->_dataOffset = (int)pData - (int)pGroup; Part2DataEntry *p = (Part2DataEntry *)pData; *p = new Part2DataEntry(1); pData += 0x1C; } } } else { header->_part2Offset = 0; } //Write textures WriteTextures(linker, ref groupAddr); //Set box min and box max if (linker.Model._isImport) { SetBox(linker); } //Store group offsets linker.Finish(); //Set new properties *props = new MDL0Props(linker.Version, linker.Model._numVertices, linker.Model._numFaces, linker.Model._numNodes, linker.Model._unk1, linker.Model._unk2, linker.Model._unk3, linker.Model._unk4, linker.Model._unk5, linker.Model._unk6, linker.Model.BoxMin, linker.Model.BoxMax); }