diff options
Diffstat (limited to 'NW4RTools/ColladaWriter.cs')
-rw-r--r-- | NW4RTools/ColladaWriter.cs | 625 |
1 files changed, 316 insertions, 309 deletions
diff --git a/NW4RTools/ColladaWriter.cs b/NW4RTools/ColladaWriter.cs index 60a3a75..794226f 100644 --- a/NW4RTools/ColladaWriter.cs +++ b/NW4RTools/ColladaWriter.cs @@ -27,9 +27,9 @@ namespace NW4RTools { public void SaveModel(Stream outputStream, string modelName) { CurrentModel = CurrentFile.GetGroup<Model>("3DModels(NW4R)")[modelName]; Collada = new COLLADA(); - + Collada.asset = new asset(); - + Collada.asset.contributor = new assetContributor[1]; Collada.asset.contributor[0] = new assetContributor(); Collada.asset.contributor[0].authoring_tool = "NW4RTools Collada exporter by Treeki"; @@ -39,347 +39,354 @@ namespace NW4RTools { Collada.asset.unit = new assetUnit(); Collada.asset.unit.meter = 1.0; Collada.asset.up_axis = UpAxisType.Y_UP; - + List<object> ColladaItems = new List<object>(); - + LibGeometries = new library_geometries(); ColladaItems.Add(LibGeometries); - - LibGeometries.geometry = new geometry[CurrentModel.Shapes.Count]; - - int geoIndex = 0; + + var GeometryList = new List<geometry>(); foreach (var kv in CurrentModel.Shapes) { - var geo = LibGeometries.geometry[geoIndex] = new geometry(); - Shape shape = kv.Value; - - geo.id = kv.Key + "-lib"; - geo.name = kv.Key + "Mesh"; - - var m = new mesh(); - geo.Item = m; - - // Vertex settings - var firstDL = new InputStream(shape.DisplayList1); - firstDL.Seek(0x0C); - UInt32 vtxDesc1 = firstDL.ReadUInt32(); - firstDL.Seek(0x12); - UInt32 vtxDesc2 = firstDL.ReadUInt32(); - firstDL.Seek(0x22); - UInt32 vtxAttr1 = firstDL.ReadUInt32(); - firstDL.Seek(0x28); - UInt32 vtxAttr2 = firstDL.ReadUInt32(); - firstDL.Seek(0x2E); - UInt32 vtxAttr3 = firstDL.ReadUInt32(); + GeometryList.Add(CreateGeometryFromShape(kv.Key, kv.Value)); + } + + LibGeometries.geometry = GeometryList.ToArray(); + + // SHAPES ARE DONE. + // Next up: Visual Scenes (I will just create one atm) + + LibVisualScenes = new library_visual_scenes(); + ColladaItems.Add(LibVisualScenes); + + LibVisualScenes.visual_scene = new visual_scene[1]; + var mainScene = LibVisualScenes.visual_scene[0] = new visual_scene(); + + // TODO: Change this so it doesn't have the possibility of name collisions with shapes + mainScene.id = "RootNode"; + mainScene.name = "RootNode"; + var mainSceneNodeList = new List<node>(); + + // Right now: just make a node for each shape. + foreach (var kv in CurrentModel.Shapes) { + var thisNode = new node(); - var vs = new VertexSettings(); - vs.SetDesc(vtxDesc1, vtxDesc2); - vs.SetAttrFmt(vtxAttr1, vtxAttr2, vtxAttr3); - - // Figure out how many elements we need in the Source array - // Position data ALWAYS exists - int sourceCount = 1; - sourceCount += (shape.NrmData != null) ? 1 : 0; - for (int i = 0; i < 8; i++) - sourceCount += (shape.TexCoordData[i] != null) ? 1 : 0; - - m.source = new source[sourceCount]; - int currentSource = 0; + thisNode.id = kv.Key; + thisNode.name = kv.Key; + thisNode.instance_geometry = new instance_geometry[1]; + thisNode.instance_geometry[0] = new instance_geometry(); + thisNode.instance_geometry[0].url = String.Format("#{0}-lib", kv.Key); + + mainSceneNodeList.Add(thisNode); + } + + mainScene.node = mainSceneNodeList.ToArray(); + + + // Finally, create a scene + Collada.scene = new COLLADAScene(); + Collada.scene.instance_visual_scene = new InstanceWithExtra(); + Collada.scene.instance_visual_scene.url = "#RootNode"; + + Collada.Items = ColladaItems.ToArray(); + Collada.Save(outputStream); + } - // TODO: Refactor this messy code! - int dest; - // Write position data - var posData = shape.PosData; - var posSource = new source(); - posSource.id = kv.Key + "-lib-Position"; - m.source[currentSource++] = posSource; - var posArray = new float_array(); - posArray.id = kv.Key + "-lib-Position-array"; - posArray.count = (ulong)(posData.GetRealCount() * posData.EntryCount); - posArray.Values = new double[posArray.count]; + private geometry CreateGeometryFromShape(string name, Shape shape) { + var geo = new geometry(); + + geo.id = name + "-lib"; + geo.name = name + "Mesh"; + + var m = new mesh(); + geo.Item = m; + + // Vertex settings + var firstDL = new InputStream(shape.DisplayList1); + firstDL.Seek(0x0C); + UInt32 vtxDesc1 = firstDL.ReadUInt32(); + firstDL.Seek(0x12); + UInt32 vtxDesc2 = firstDL.ReadUInt32(); + firstDL.Seek(0x22); + UInt32 vtxAttr1 = firstDL.ReadUInt32(); + firstDL.Seek(0x28); + UInt32 vtxAttr2 = firstDL.ReadUInt32(); + firstDL.Seek(0x2E); + UInt32 vtxAttr3 = firstDL.ReadUInt32(); + + var vs = new VertexSettings(); + vs.SetDesc(vtxDesc1, vtxDesc2); + vs.SetAttrFmt(vtxAttr1, vtxAttr2, vtxAttr3); + + // Figure out how many elements we need in the Source array + // Position data ALWAYS exists + int sourceCount = 1; + sourceCount += (shape.NrmData != null) ? 1 : 0; + for (int i = 0; i < 8; i++) + sourceCount += (shape.TexCoordData[i] != null) ? 1 : 0; + + m.source = new source[sourceCount]; + int currentSource = 0; + + // TODO: Refactor this messy code! + + int dest; + + // Write position data + var posData = shape.PosData; + var posSource = new source(); + posSource.id = name + "-lib-Position"; + m.source[currentSource++] = posSource; + + var posArray = new float_array(); + posArray.id = name + "-lib-Position-array"; + posArray.count = (ulong)(posData.GetRealCount() * posData.EntryCount); + posArray.Values = new double[posArray.count]; + + dest = 0; + for (int i = 0; i < posData.EntryCount; i++) { + float[] data = posData.GetEntry(i); + for (int j = 0; j < data.Length; j++) { + posArray.Values[dest++] = data[j]; + } + } + + posSource.Item = posArray; + + // Write position technique + posSource.technique_common = new sourceTechnique_common(); + var posAcc = posSource.technique_common.accessor = new accessor(); + posAcc.source = String.Format("#{0}-lib-Position-array", name); + posAcc.count = posData.EntryCount; + posAcc.stride = (ulong)posData.GetRealCount(); + + posAcc.param = new param[posData.GetRealCount()]; + string[] posParamNames = new string[] { "X", "Y", "Z" }; + + for (int i = 0; i < posAcc.param.Length; i++) { + posAcc.param[i] = new param(); + posAcc.param[i].name = posParamNames[i]; + posAcc.param[i].type = "float"; + } + + + // Write normal data + if (shape.NrmData != null) { + var nrmData = shape.NrmData; + var nrmSource = new source(); + nrmSource.id = name + "-lib-Normal"; + m.source[currentSource++] = nrmSource; + + var nrmArray = new float_array(); + nrmArray.id = name + "-lib-Normal-array"; + nrmArray.count = (ulong)(nrmData.GetRealCount() * nrmData.EntryCount); + nrmArray.Values = new double[nrmArray.count]; + dest = 0; - for (int i = 0; i < posData.EntryCount; i++) { - float[] data = posData.GetEntry(i); + for (int i = 0; i < nrmData.EntryCount; i++) { + float[] data = nrmData.GetEntry(i); for (int j = 0; j < data.Length; j++) { - posArray.Values[dest++] = data[j]; + nrmArray.Values[dest++] = data[j]; } } - - posSource.Item = posArray; - - // Write position technique - posSource.technique_common = new sourceTechnique_common(); - var posAcc = posSource.technique_common.accessor = new accessor(); - posAcc.source = String.Format("#{0}-lib-Position-array", kv.Key); - posAcc.count = posData.EntryCount; - posAcc.stride = (ulong)posData.GetRealCount(); - - posAcc.param = new param[posData.GetRealCount()]; - string[] posParamNames = new string[] { "X", "Y", "Z" }; - - for (int i = 0; i < posAcc.param.Length; i++) { - posAcc.param[i] = new param(); - posAcc.param[i].name = posParamNames[i]; - posAcc.param[i].type = "float"; + + nrmSource.Item = nrmArray; + + // Write normal technique + nrmSource.technique_common = new sourceTechnique_common(); + var nrmAcc = nrmSource.technique_common.accessor = new accessor(); + nrmAcc.source = String.Format("#{0}-lib-Normal-array", name); + nrmAcc.count = nrmData.EntryCount; + nrmAcc.stride = (ulong)nrmData.GetRealCount(); + + nrmAcc.param = new param[nrmData.GetRealCount()]; + string[] nrmParamNames = new string[] { "X", "Y", "Z" }; + + for (int i = 0; i < nrmAcc.param.Length; i++) { + nrmAcc.param[i] = new param(); + nrmAcc.param[i].name = nrmParamNames[i]; + nrmAcc.param[i].type = "float"; } - - - // Write normal data - if (shape.NrmData != null) { - var nrmData = shape.NrmData; - var nrmSource = new source(); - nrmSource.id = kv.Key + "-lib-Normal"; - m.source[currentSource++] = nrmSource; - - var nrmArray = new float_array(); - nrmArray.id = kv.Key + "-lib-Normal-array"; - nrmArray.count = (ulong)(nrmData.GetRealCount() * nrmData.EntryCount); - nrmArray.Values = new double[nrmArray.count]; - + } + + + // Write TexCoord data + for (int tcIndex = 0; tcIndex < 8; tcIndex++) { + if (shape.TexCoordData[tcIndex] != null) { + var tcData = shape.TexCoordData[tcIndex]; + var tcSource = new source(); + tcSource.id = String.Format("{0}-lib-TexCoord{1}", name, tcIndex); + m.source[currentSource++] = tcSource; + + var tcArray = new float_array(); + tcArray.id = String.Format("{0}-lib-TexCoord{1}-array", name, tcIndex); + tcArray.count = (ulong)(tcData.GetRealCount() * tcData.EntryCount); + tcArray.Values = new double[tcArray.count]; + dest = 0; - for (int i = 0; i < nrmData.EntryCount; i++) { - float[] data = nrmData.GetEntry(i); + for (int i = 0; i < tcData.EntryCount; i++) { + float[] data = tcData.GetEntry(i); for (int j = 0; j < data.Length; j++) { - nrmArray.Values[dest++] = data[j]; + tcArray.Values[dest++] = data[j]; } } - - nrmSource.Item = nrmArray; - - // Write normal technique - nrmSource.technique_common = new sourceTechnique_common(); - var nrmAcc = nrmSource.technique_common.accessor = new accessor(); - nrmAcc.source = String.Format("#{0}-lib-Normal-array", kv.Key); - nrmAcc.count = nrmData.EntryCount; - nrmAcc.stride = (ulong)nrmData.GetRealCount(); - - nrmAcc.param = new param[nrmData.GetRealCount()]; - string[] nrmParamNames = new string[] { "X", "Y", "Z" }; - - for (int i = 0; i < nrmAcc.param.Length; i++) { - nrmAcc.param[i] = new param(); - nrmAcc.param[i].name = nrmParamNames[i]; - nrmAcc.param[i].type = "float"; + + tcSource.Item = tcArray; + + // Write texcoord technique + tcSource.technique_common = new sourceTechnique_common(); + var tcAcc = tcSource.technique_common.accessor = new accessor(); + tcAcc.source = String.Format("#{0}-lib-TexCoord{1}-array", name, tcIndex); + tcAcc.count = tcData.EntryCount; + tcAcc.stride = (ulong)tcData.GetRealCount(); + + tcAcc.param = new param[tcData.GetRealCount()]; + string[] tcParamNames = new string[] { "S", "T" }; + + for (int i = 0; i < tcAcc.param.Length; i++) { + tcAcc.param[i] = new param(); + tcAcc.param[i].name = tcParamNames[i]; + tcAcc.param[i].type = "float"; } } - - - // Write TexCoord data - for (int tcIndex = 0; tcIndex < 8; tcIndex++) { - if (shape.TexCoordData[tcIndex] != null) { - var tcData = shape.TexCoordData[tcIndex]; - var tcSource = new source(); - tcSource.id = String.Format("{0}-lib-TexCoord{1}", kv.Key, tcIndex); - m.source[currentSource++] = tcSource; - - var tcArray = new float_array(); - tcArray.id = String.Format("{0}-lib-TexCoord{1}-array", kv.Key, tcIndex); - tcArray.count = (ulong)(tcData.GetRealCount() * tcData.EntryCount); - tcArray.Values = new double[tcArray.count]; - - dest = 0; - for (int i = 0; i < tcData.EntryCount; i++) { - float[] data = tcData.GetEntry(i); - for (int j = 0; j < data.Length; j++) { - tcArray.Values[dest++] = data[j]; - } - } - - tcSource.Item = tcArray; - - // Write texcoord technique - tcSource.technique_common = new sourceTechnique_common(); - var tcAcc = tcSource.technique_common.accessor = new accessor(); - tcAcc.source = String.Format("#{0}-lib-TexCoord{1}-array", kv.Key, tcIndex); - tcAcc.count = tcData.EntryCount; - tcAcc.stride = (ulong)tcData.GetRealCount(); - - tcAcc.param = new param[tcData.GetRealCount()]; - string[] tcParamNames = new string[] { "S", "T" }; - - for (int i = 0; i < tcAcc.param.Length; i++) { - tcAcc.param[i] = new param(); - tcAcc.param[i].name = tcParamNames[i]; - tcAcc.param[i].type = "float"; - } - } - } - - - - // Ok, we've written all the raw float data, now set up vertices - // TODO: Vertex colours - m.vertices = new vertices(); - m.vertices.id = String.Format("{0}-lib-Vertex", kv.Key); - m.vertices.input = new InputLocal[1]; - m.vertices.input[0] = new InputLocal(); - m.vertices.input[0].semantic = "POSITION"; - m.vertices.input[0].source = String.Format("#{0}-lib-Position", kv.Key); - - // And before we finish, write the polygon data of course - var dl = new InputStream(shape.DisplayList2); - - List<object> meshItems = new List<object>(); - - // create the Input array -- we can reuse sourceCount! - var inputArray = new InputLocalOffset[sourceCount]; - currentSource = 0; - - var posInput = inputArray[currentSource] = new InputLocalOffset(); - posInput.semantic = "VERTEX"; - posInput.offset = (ulong)currentSource; - posInput.source = String.Format("#{0}-lib-Vertex", kv.Key); + } + + + + // Ok, we've written all the raw float data, now set up vertices + // TODO: Vertex colours + m.vertices = new vertices(); + m.vertices.id = String.Format("{0}-lib-Vertex", name); + m.vertices.input = new InputLocal[1]; + m.vertices.input[0] = new InputLocal(); + m.vertices.input[0].semantic = "POSITION"; + m.vertices.input[0].source = String.Format("#{0}-lib-Position", name); + + // And before we finish, write the polygon data of course + var dl = new InputStream(shape.DisplayList2); + + List<object> meshItems = new List<object>(); + + // create the Input array -- we can reuse sourceCount! + var inputArray = new InputLocalOffset[sourceCount]; + currentSource = 0; + + var posInput = inputArray[currentSource] = new InputLocalOffset(); + posInput.semantic = "VERTEX"; + posInput.offset = (ulong)currentSource; + posInput.source = String.Format("#{0}-lib-Vertex", name); + currentSource++; + + if (shape.NrmData != null) { + var nrmInput = inputArray[currentSource] = new InputLocalOffset(); + nrmInput.semantic = "NORMAL"; + nrmInput.offset = (ulong)currentSource; + nrmInput.source = String.Format("#{0}-lib-Normal", name); currentSource++; - - if (shape.NrmData != null) { - var nrmInput = inputArray[currentSource] = new InputLocalOffset(); - nrmInput.semantic = "NORMAL"; - nrmInput.offset = (ulong)currentSource; - nrmInput.source = String.Format("#{0}-lib-Normal", kv.Key); + } + + for (int i = 0; i < 8; i++) { + if (shape.TexCoordData[i] != null) { + var tcInput = inputArray[currentSource] = new InputLocalOffset(); + tcInput.semantic = "TEXCOORD"; + tcInput.offset = (ulong)currentSource; + tcInput.@set = (ulong)i; + tcInput.source = String.Format("#{0}-lib-TexCoord{1}", name, i); currentSource++; } - - for (int i = 0; i < 8; i++) { - if (shape.TexCoordData[i] != null) { - var tcInput = inputArray[currentSource] = new InputLocalOffset(); - tcInput.semantic = "TEXCOORD"; - tcInput.offset = (ulong)currentSource; - tcInput.set = (ulong)i; - tcInput.source = String.Format("#{0}-lib-TexCoord{1}", kv.Key, i); - currentSource++; + } + + + // Create a list for tristrips beforehand, because they're THE most common + List<string> triStrips = new List<string>(); + + + // Now go through the display list + while (true) { + if (dl.AtEnd) + break; + + byte cmd = dl.ReadByte(); + if (cmd == 0) + break; + + PrimitiveType prim = (PrimitiveType)((cmd >> 3) & 7); + int vtxCount = dl.ReadUInt16(); + + // first, parse it into a list of vertices + GXIndexedVertex[] vtxs = new GXIndexedVertex[vtxCount]; + string[] pVtxs = new string[vtxCount]; + + for (int i = 0; i < vtxCount; i++) { + vtxs[i].LoadFrom(dl, vs); + + pVtxs[i] = vtxs[i].Position.ToString(); + + if (vs.NormalDesc != VertexSettings.DescType.None) + pVtxs[i] += " " + vtxs[i].Normal.ToString(); + + for (int j = 0; j < 8; j++) { + if (vs.TexCoordDesc[j] != VertexSettings.DescType.None) { + pVtxs[i] += " " + vtxs[i].TexCoords[j].ToString(); + } } } - - - // Create a list for tristrips beforehand, because they're THE most common - List<string> triStrips = new List<string>(); - - - // Now go through the display list - while (true) { - if (dl.AtEnd) - break; - - byte cmd = dl.ReadByte(); - if (cmd == 0) - break; - - PrimitiveType prim = (PrimitiveType)((cmd >> 3) & 7); - int vtxCount = dl.ReadUInt16(); - - // first, parse it into a list of vertices - GXIndexedVertex[] vtxs = new GXIndexedVertex[vtxCount]; - string[] pVtxs = new string[vtxCount]; - + + switch (prim) { + case PrimitiveType.Triangles: + var pTri = new triangles(); + pTri.count = (ulong)(vtxCount / 3); + // should be 1? dunno + pTri.input = inputArray; + + StringBuilder pTriData = new StringBuilder(); + for (int i = 0; i < vtxCount; i++) { - vtxs[i].LoadFrom(dl, vs); - - pVtxs[i] = vtxs[i].Position.ToString(); - - if (vs.NormalDesc != VertexSettings.DescType.None) - pVtxs[i] += " " + vtxs[i].Normal.ToString(); - - for (int j = 0; j < 8; j++) { - if (vs.TexCoordDesc[j] != VertexSettings.DescType.None) { - pVtxs[i] += " " + vtxs[i].TexCoords[j].ToString(); - } - } + pTriData.AppendFormat("{0} ", pVtxs[i]); } - switch (prim) { - case PrimitiveType.Triangles: - var pTri = new triangles(); - pTri.count = (ulong)(vtxCount / 3); // should be 1? dunno - pTri.input = inputArray; - - StringBuilder pTriData = new StringBuilder(); - - for (int i = 0; i < vtxCount; i++) { - pTriData.AppendFormat("{0} ", pVtxs[i]); - } - - pTri.p = pTriData.ToString(); - - meshItems.Add(pTri); - break; - - case PrimitiveType.TriangleStrip: - StringBuilder pTriStripData = new StringBuilder(); - - for (int i = 0; i < vtxCount; i++) { - pTriStripData.AppendFormat("{0} ", pVtxs[i]); - } - - triStrips.Add(pTriStripData.ToString()); - break; - - default: - - Console.WriteLine("UNIMPLEMENTED PRIMITIVE TYPE"); - return; + + pTri.p = pTriData.ToString(); + + meshItems.Add(pTri); + break; + + case PrimitiveType.TriangleStrip: + StringBuilder pTriStripData = new StringBuilder(); + + for (int i = 0; i < vtxCount; i++) { + pTriStripData.AppendFormat("{0} ", pVtxs[i]); } - } - - // If any tristrips were found, add them! - if (triStrips.Count > 0) { - var pTriStrips = new tristrips(); - pTriStrips.input = inputArray; - pTriStrips.count = (ulong)triStrips.Count; - pTriStrips.p = triStrips.ToArray(); - meshItems.Add(pTriStrips); + + triStrips.Add(pTriStripData.ToString()); + break; + default: + + + Console.WriteLine("UNIMPLEMENTED PRIMITIVE TYPE"); + return; } - - - m.Items = meshItems.ToArray(); - - // FINALLY DONE! - - geoIndex += 1; } - - - - // SHAPES ARE DONE. - // Next up: Visual Scenes (I will just create one atm) - - LibVisualScenes = new library_visual_scenes(); - ColladaItems.Add(LibVisualScenes); - - LibVisualScenes.visual_scene = new visual_scene[1]; - var mainScene = LibVisualScenes.visual_scene[0] = new visual_scene(); - - // TODO: Change this so it doesn't have the possibility of name collisions with shapes - mainScene.id = "RootNode"; - mainScene.name = "RootNode"; - var mainSceneNodeList = new List<node>(); - - // Right now: just make a node for each shape. - foreach (var kv in CurrentModel.Shapes) { - var thisNode = new node(); - - thisNode.id = kv.Key; - thisNode.name = kv.Key; - thisNode.instance_geometry = new instance_geometry[1]; - thisNode.instance_geometry[0] = new instance_geometry(); - thisNode.instance_geometry[0].url = String.Format("#{0}-lib", kv.Key); - - mainSceneNodeList.Add(thisNode); + + + // If any tristrips were found, add them! + if (triStrips.Count > 0) { + var pTriStrips = new tristrips(); + pTriStrips.input = inputArray; + pTriStrips.count = (ulong)triStrips.Count; + pTriStrips.p = triStrips.ToArray(); + meshItems.Add(pTriStrips); } - - mainScene.node = mainSceneNodeList.ToArray(); - - - // Finally, create a scene - Collada.scene = new COLLADAScene(); - Collada.scene.instance_visual_scene = new InstanceWithExtra(); - Collada.scene.instance_visual_scene.url = "#RootNode"; - - Collada.Items = ColladaItems.ToArray(); - Collada.Save(outputStream); + + + m.Items = meshItems.ToArray(); + + // FINALLY DONE! + return geo; } } } |