public ElementDescriptor(MDL0Polygon *polygon) { MDL0Header *model = (MDL0Header *)((byte *)polygon + polygon->_mdl0Offset); byte * pData = (byte *)polygon->DefList; byte * pCom; ElementDef *pDef; int fmtLo, fmtHi; int grp0, grp1, grp2; int format; //Create remap table for vertex weights RemapTable = new UnsafeBuffer(polygon->_numVertices * 4); RemapSize = 0; Stride = 0; //Read element descriptor from polygon display list //Use direct access instead! //May change depending on file version fmtLo = *(bint *)(pData + 12); fmtHi = *(bint *)(pData + 18); grp0 = *(bint *)(pData + 34); grp1 = *(bint *)(pData + 40); grp2 = *(bint *)(pData + 46); //grp1 = *(buint*)(pData + 40); //grp1 |= (ulong)(*(buint*)(pData + 46)) << 32; //Build extract script. //What we're doing is assigning extract commands for elements in the polygon, in true order. //This allows us to process the polygon blindly, assuming that the definition is accurate. //Theoretically, this should offer a significant speed bonus. fixed(int *pDefData = Defs) fixed(byte *pComData = Commands) { pCom = pComData; pDef = (ElementDef *)pDefData; //Pos/Norm weight if (Weighted = (fmtLo & 1) != 0) { *pCom++ = (byte)DecodeOp.PosWeight; Stride++; } //Tex matrix for (int i = 0; i < 8; i++) { if (((fmtLo >> (i + 1)) & 1) != 0) { *pCom++ = (byte)(DecodeOp.TexMtx0 + i); Stride++; } } //Positions format = ((fmtLo >> 9) & 3) - 1; if (format >= 0) { pDef->Input = (byte)format; pDef->Type = 0; if (format == 0) { throw new NotSupportedException("Direct mode is not suported for polygons!"); //pDef->Scale = (byte)((grp0 >> 4) & 0x1F); //pDef->Output = (byte)(((grp0 >> 1) & 0x7) + ((grp0 & 1) == 0 ? ElementCodec.CodecType.XY : ElementCodec.CodecType.XYZ)); //pCom[NumCommands++] = (byte)DecodeOp.ElementDirect; } else { Stride += format; pDef->Output = 12; *pCom++ = (byte)DecodeOp.ElementIndexed; } pDef++; } //Normals format = ((fmtLo >> 11) & 3) - 1; if (format >= 0) { pDef->Input = (byte)format; pDef->Type = 1; if (format == 0) { throw new NotSupportedException("Direct mode is not suported for polygons!"); //pDef->Scale = 0; //Implied? //pDef->Output = (byte)(((grp0 >> 10) & 0x7) + ((grp0 & (1 << 10)) == 0 ? ElementCodec.CodecType.XYZ : ElementCodec.CodecType.XYZ)); //pCom[NumCommands++] = (byte)DecodeOp.ElementDirect; } else { Stride += format; pDef->Output = 12; *pCom++ = (byte)DecodeOp.ElementIndexed; } pDef++; } //Colors for (int i = 0; i < 2; i++) { format = ((fmtLo >> (i * 2 + 13)) & 3) - 1; if (format >= 0) { pDef->Input = (byte)format; pDef->Type = (byte)(i + 2); if (format == 0) { throw new NotSupportedException("Direct mode is not suported for polygons!"); //pDef->Output = (byte)((grp0 >> (i * 4 + 14)) & 7); //pCom[NumCommands++] = (byte)DecodeOp.ElementDirect; } else { Stride += format; pDef->Output = 4; *pCom++ = (byte)DecodeOp.ElementIndexed; } pDef++; } } //UVs for (int i = 0; i < 8; i++) { format = ((fmtHi >> (i * 2)) & 3) - 1; if (format >= 0) { pDef->Input = (byte)format; pDef->Type = (byte)(i + 4); if (format == 0) { throw new NotSupportedException("Direct mode is not suported for polygons!"); //Needs work! //if (i == 0) //{ // pDef->Output = (byte)(((grp0 >> 22) & 7) + ((grp0 & 22) == 0 ? ElementCodec.CodecType.S : ElementCodec.CodecType.ST)); // pDef->Scale = (byte)((grp0 >> 25) & 0x1F); //} //else //{ // pDef->Output = (byte)((int)((grp1 >> (i * 9 + 1)) & 7) + ((grp1 & ((ulong)1 << (i * 9 + 1))) == 0 ? ElementCodec.CodecType.S : ElementCodec.CodecType.ST)); // pDef->Scale = (byte)((grp1 >> (i * 9 + 4)) & 0x1F); //} //pCom[NumCommands++] = (byte)DecodeOp.ElementDirect; } else { Stride += format; pDef->Output = 8; *pCom++ = (byte)DecodeOp.ElementIndexed; } pDef++; } } *pCom = 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); }
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); }
internal static unsafe void Build(ModelLinker linker, MDL0Header *header, int length, bool force) { Build(null, linker, header, length, force); }
//protected override int OnCalculateSize(bool force) //{ // int size = 0; // //Definitions // foreach (ResourceNode node in Children) // { // size += node.CalculateSize(force); // } // return size; //} protected internal override void PostProcess(VoidPtr bresAddress, VoidPtr dataAddress, int dataLength, StringTable stringTable) { base.PostProcess(bresAddress, dataAddress, dataLength, stringTable); MDL0Header * header = (MDL0Header *)dataAddress; ResourceGroup *pGroup, sGroup; ResourceEntry *pEntry, sEntry; bint * offsets = header->Offsets; int index, sIndex; //Model name header->StringOffset = (int)((byte *)stringTable[Name] + 4 - (byte *)header); //Post-process groups, using linker lists List <MDLResourceType> gList = ModelLinker.IndexBank[_version]; foreach (MDL0GroupNode node in Children) { MDLResourceType type = (MDLResourceType)Enum.Parse(typeof(MDLResourceType), node.Name); if (((index = gList.IndexOf(type)) >= 0) && (type != MDLResourceType.Shaders)) { node.PostProcess(dataAddress, dataAddress + offsets[index], stringTable); } } //Post-process definitions index = gList.IndexOf(MDLResourceType.Defs); pGroup = (ResourceGroup *)(dataAddress + offsets[index]); pGroup->_first = new ResourceEntry(0xFFFF, 0, 0, 0); pEntry = &pGroup->_first + 1; index = 1; if (_hasTree) { ResourceEntry.Build(pGroup, index++, (byte *)pGroup + (pEntry++)->_dataOffset, (BRESString *)stringTable["NodeTree"]); } if (_hasMix) { ResourceEntry.Build(pGroup, index++, (byte *)pGroup + (pEntry++)->_dataOffset, (BRESString *)stringTable["NodeMix"]); } if (_hasOpa) { ResourceEntry.Build(pGroup, index++, (byte *)pGroup + (pEntry++)->_dataOffset, (BRESString *)stringTable["DrawOpa"]); } if (_hasXlu) { ResourceEntry.Build(pGroup, index++, (byte *)pGroup + (pEntry++)->_dataOffset, (BRESString *)stringTable["DrawXlu"]); } //Link shader names using material list index = offsets[gList.IndexOf(MDLResourceType.Materials)]; sIndex = offsets[gList.IndexOf(MDLResourceType.Shaders)]; if ((index > 0) && (sIndex > 0)) { pGroup = (ResourceGroup *)(dataAddress + index); sGroup = (ResourceGroup *)(dataAddress + sIndex); pEntry = &pGroup->_first + 1; sEntry = &sGroup->_first + 1; sGroup->_first = new ResourceEntry(0xFFFF, 0, 0, 0); index = pGroup->_numEntries; for (int i = 1; i <= index; i++) { ResourceEntry.Build(sGroup, i, (byte *)sGroup + (sEntry++)->_dataOffset, (BRESString *)((byte *)pGroup + (pEntry++)->_stringOffset - 4)); } } }