diff options
| author | Treeki <treeki@gmail.com> | 2011-03-03 22:01:38 +0100 | 
|---|---|---|
| committer | Treeki <treeki@gmail.com> | 2011-03-03 22:01:38 +0100 | 
| commit | a5b6dc1789f2e06a26fe6a0510aee04aeccdc70b (patch) | |
| tree | 15065b84de58b2db03527da76b32f9b4b3c23c98 | |
| parent | b28711d999c86c40a11f61846ab15685c2fc172b (diff) | |
| download | nw4rtools-a5b6dc1789f2e06a26fe6a0510aee04aeccdc70b.tar.gz nw4rtools-a5b6dc1789f2e06a26fe6a0510aee04aeccdc70b.zip  | |
tidying up a bit, also it compiles now
| -rw-r--r-- | NW4RTools/BrresReader.cs | 3 | ||||
| -rw-r--r-- | NW4RTools/ColladaExporter.cs | 732 | ||||
| -rw-r--r-- | NW4RTools/Models/Material.cs | 5 | ||||
| -rw-r--r-- | NW4RTools/Models/Model.cs | 11 | ||||
| -rw-r--r-- | NW4RTools/Models/Shape.cs | 3 | ||||
| -rw-r--r-- | NW4RTools/NW4RTools.csproj | 2 | ||||
| -rw-r--r-- | NW4RTools/Texture.cs | 2 | ||||
| -rw-r--r-- | NW4RTools/Util/NVDXT.cs | 2 | ||||
| -rwxr-xr-x | NW4RTools/bin/Debug/NW4RTools.dll | bin | 221696 -> 222208 bytes | |||
| -rw-r--r-- | NW4RTools/bin/Debug/NW4RTools.dll.mdb | bin | 109673 -> 109819 bytes | 
10 files changed, 754 insertions, 6 deletions
diff --git a/NW4RTools/BrresReader.cs b/NW4RTools/BrresReader.cs index e67581b..d5db720 100644 --- a/NW4RTools/BrresReader.cs +++ b/NW4RTools/BrresReader.cs @@ -275,7 +275,6 @@ namespace NW4RTools {  				using (var c2 = Debug.Push("Vertex Normal Data")) {  					if (vtxNrmOffset == 0) {  						Debug.Send("None"); -						mdl.VtxNrmData = new ResDict<VertexNrmData>();  					} else {  						mdl.VtxNrmData = ReadAndConvertDict<VertexNrmData>(ins.At(startPos + vtxNrmOffset), ConvertVtxNrmData);  					} @@ -284,7 +283,6 @@ namespace NW4RTools {  				using (var c2 = Debug.Push("Vertex Colour Data")) {  					if (vtxClrOffset == 0) {  						Debug.Send("None"); -						mdl.VtxClrData = new ResDict<VertexClrData>();  					} else {  						mdl.VtxClrData = ReadAndConvertDict<VertexClrData>(ins.At(startPos + vtxClrOffset), ConvertVtxClrData);  					} @@ -293,7 +291,6 @@ namespace NW4RTools {  				using (var c2 = Debug.Push("Vertex TexCoord Data")) {  					if (texCoordOffset == 0) {  						Debug.Send("None"); -						mdl.VtxTexCoordData = new ResDict<VertexTexCoordData>();  					} else {  						mdl.VtxTexCoordData = ReadAndConvertDict<VertexTexCoordData>(ins.At(startPos + texCoordOffset), ConvertVtxTexCoordData);  					} diff --git a/NW4RTools/ColladaExporter.cs b/NW4RTools/ColladaExporter.cs new file mode 100644 index 0000000..f18bfed --- /dev/null +++ b/NW4RTools/ColladaExporter.cs @@ -0,0 +1,732 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using NW4RTools.Models; +using Collada141; + +namespace NW4RTools { +	public class ColladaExporter { +		public static void WriteModel(Stream outputStream, ResFile file, string modelName) { +			new ColladaExporter(file).SaveModel(outputStream, modelName); +		} + + + +		ResFile CurrentFile; +		Models.Model CurrentModel; +		COLLADA Collada; + +		library_geometries LibGeometries; +		library_visual_scenes LibVisualScenes; +		library_images LibImages; +		library_materials LibMaterials; +		library_effects LibEffects; + +		private ColladaExporter(ResFile file) { +			CurrentFile = file; +		} + +		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"; +			Collada.asset.contributor[0].source_data = "NW4R model: " + modelName; +			//Collada.asset.created = DateTime.Now; +			//Collada.asset.modified = DateTime.Now; +			Collada.asset.unit = new assetUnit(); +			Collada.asset.unit.meter = 1.0; +			Collada.asset.up_axis = UpAxisType.Y_UP; +			 +			var ColladaItems = new List<object>(); + +			// First up, before anything else: images and materials +			// Compile a list of every texture we use in the model +			var usedTextures = new List<string>(); + +			foreach (var kv in CurrentModel.Materials) { +				foreach (var texInfo in kv.Value.TextureInfos) { +					if (!usedTextures.Contains(texInfo.TextureName)) +						usedTextures.Add(texInfo.TextureName); +				} +			} + +			// Create a Collada image for these +			LibImages = new library_images(); +			ColladaItems.Add(LibImages); + +			var ImageList = new List<image>(); +			var TexGroup = CurrentFile.GetGroup<Texture>("Textures(NW4R)"); + +			foreach (var texName in usedTextures) { +				var img = new image(); +				var tex = TexGroup[texName]; + +				img.name = "Texture-" + texName; +				img.id = img.name; +				img.Item = "./images/" + texName + ".png"; + +				ImageList.Add(img); +			} + +			LibImages.image = ImageList.ToArray(); + +			// Make a quick reference material for each one +			LibMaterials = new library_materials(); +			ColladaItems.Add(LibMaterials); + +			var MaterialList = new List<material>(); + +			foreach (var kv in CurrentModel.Materials) { +				var mat = new material(); + +				mat.name = "Material-" + kv.Key; +				mat.id = mat.name; +				mat.instance_effect = new instance_effect(); +				mat.instance_effect.url = "#Material-Effect-" + kv.Key; + +				MaterialList.Add(mat); +			} + +			LibMaterials.material = MaterialList.ToArray(); + +			// Now create an effect for each material (this is where all the real work is done!) +			LibEffects = new library_effects(); +			ColladaItems.Add(LibEffects); + +			var EffectList = new List<effect>(); +			foreach (var kv in CurrentModel.Materials) { +				EffectList.Add(CreateEffectFromMaterial(kv.Key, kv.Value)); +			} + +			LibEffects.effect = EffectList.ToArray(); + +			// Now shapes +			LibGeometries = new library_geometries(); +			ColladaItems.Add(LibGeometries); +			 +			var GeometryList = new List<geometry>(); +			foreach (var kv in CurrentModel.Shapes) { +				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>(); + +			// OK, so here's what's up: first off, we must create a definition for every node +			var NodeDefs = new Dictionary<Node, node>(); + +			foreach (var kv in CurrentModel.Nodes) { +				string nodeName = kv.Key; +				Node origNode = kv.Value; +				var cNode = new node(); + +				cNode.id = nodeName; +				cNode.name = nodeName; +				//cNode.type = NodeType.JOINT; +				cNode.node1 = new node[0]; + +				double cosX = Math.Cos(origNode.Rotation.x / 180 * Math.PI); +				double cosY = Math.Cos(origNode.Rotation.y / 180 * Math.PI); +				double cosZ = Math.Cos(origNode.Rotation.z / 180 * Math.PI); +				double sinX = Math.Sin(origNode.Rotation.x / 180 * Math.PI); +				double sinY = Math.Sin(origNode.Rotation.y / 180 * Math.PI); +				double sinZ = Math.Sin(origNode.Rotation.z / 180 * Math.PI); + +				var nodeMatrix = new matrix(); +				nodeMatrix.Values = new double[] { +					origNode.Scale.x * cosY * cosZ, +					origNode.Scale.y * (sinX * cosZ * sinY - cosX * sinZ), +					origNode.Scale.z * (sinX * sinZ + cosX * cosZ * sinY), +					origNode.Translation.x, +					origNode.Scale.x * sinZ * cosY, +					origNode.Scale.y * (sinX * sinZ * sinY + cosZ * cosX), +					origNode.Scale.z * (cosX * sinZ * sinY - sinX * cosZ), +					origNode.Translation.y, +					-origNode.Scale.x * sinY, +					origNode.Scale.y * sinX * cosY, +				origNode.Scale.z * cosX * cosY, +					origNode.Translation.z, +					0, 0, 0, 1 +				}; + +				cNode.Items = new object[] { nodeMatrix }; +				cNode.ItemsElementName = new ItemsChoiceType2[] { ItemsChoiceType2.matrix }; + +				NodeDefs[origNode] = cNode; +			} + +			// Now add them to the hierarchy +			foreach (var kv in NodeDefs) { +				Node origNode = kv.Key; +				node cNode = kv.Value; + +				if (origNode.Parent == null) { +					mainSceneNodeList.Add(cNode); +				} else { +					var parentNode = NodeDefs[origNode.Parent]; + +					// this is stupid, thanks C# +					node[] nodeArrayCopy = parentNode.node1; +					Array.Resize<node>(ref nodeArrayCopy, nodeArrayCopy.Length + 1); +					nodeArrayCopy[nodeArrayCopy.Length - 1] = cNode; +					parentNode.node1 = nodeArrayCopy; +				} +			} + +			// Apply shapes to nodes +						/*foreach (var kv in CurrentModel.Shapes) { +				Shape shape = kv.Value; +				Node origNode = CurrentModel.Nodes[CurrentModel.MatrixIDtoNodeID[shape.MatrixID]]; +				node cNode = NodeDefs[origNode]; + +				var newGeoEntry = new instance_geometry(); +				newGeoEntry.name = kv.Key; +				newGeoEntry.url = String.Format("#{0}-lib", kv.Key); + +				instance_geometry[] geoArrayCopy = cNode.instance_geometry; +				if (geoArrayCopy == null) +					geoArrayCopy = new instance_geometry[1]; +				else +					Array.Resize<instance_geometry>(ref geoArrayCopy, geoArrayCopy.Length + 1); +				geoArrayCopy[geoArrayCopy.Length - 1] = newGeoEntry; +				cNode.instance_geometry = geoArrayCopy; + +				// TODO: Add material handling, I'll probably have to parse DrawOpa/DrawXlu for this... +			}*/ + +			// WARNING: THIS NEEDS REFACTORING + +			int drawID = 0; +			 +			foreach (var insn in CurrentModel.Bytecode["DrawOpa"].Instructions) { +				if (insn is ByteCode.DrawShapeInstruction) { +					var dsInsn = insn as ByteCode.DrawShapeInstruction; +					 +					Shape shape = CurrentModel.Shapes[dsInsn.ShapeID]; +					string shapeName = CurrentModel.Shapes.GetKeyForIndex(dsInsn.ShapeID); +					 +					Node origNode = CurrentModel.Nodes[dsInsn.NodeID]; +					node cNode = NodeDefs[origNode]; +					 +					Material mat = CurrentModel.Materials[dsInsn.MaterialID]; +					string matName = CurrentModel.Materials.GetKeyForIndex(dsInsn.MaterialID); +					 +					var newGeoEntry = new instance_geometry(); +					newGeoEntry.name = String.Format("DrawOpa{0}-{1}", drawID, shapeName); +					newGeoEntry.url = String.Format("#{0}-lib", shapeName); + +					// now add the material +					var bindMaterial = newGeoEntry.bind_material = new bind_material(); +					bindMaterial.technique_common = new instance_material[1]; +					var matTechnique = bindMaterial.technique_common[0] = new instance_material(); + +					// constant marker so that I don't have to set a unique material name in each primitive +					// it doesn't matter, since each geometry instance only uses one material anyway +					matTechnique.symbol = "NW4R_MATERIAL"; +					matTechnique.target = "#Material-" + matName; + +					matTechnique.bind_vertex_input = new instance_materialBind_vertex_input[1]; +					matTechnique.bind_vertex_input[0] = new instance_materialBind_vertex_input(); +					matTechnique.bind_vertex_input[0].semantic = "CHANNEL1"; +					matTechnique.bind_vertex_input[0].input_semantic = "TEXCOORD"; +					matTechnique.bind_vertex_input[0].input_set = 0; + +					// ok, now add the instance_geometry into the node +					instance_geometry[] geoArrayCopy = cNode.instance_geometry; +					if (geoArrayCopy == null) +						geoArrayCopy = new instance_geometry[1]; +					else +						Array.Resize<instance_geometry>(ref geoArrayCopy, geoArrayCopy.Length + 1); +					geoArrayCopy[geoArrayCopy.Length - 1] = newGeoEntry; +					cNode.instance_geometry = geoArrayCopy; +					 +					drawID++; +				} +			} + +			drawID = 0; +			 +			foreach (var insn in CurrentModel.Bytecode["DrawXlu"].Instructions) { +				if (insn is ByteCode.DrawShapeInstruction) { +					var dsInsn = insn as ByteCode.DrawShapeInstruction; +					 +					Shape shape = CurrentModel.Shapes[dsInsn.ShapeID]; +					string shapeName = CurrentModel.Shapes.GetKeyForIndex(dsInsn.ShapeID); +					 +					Node origNode = CurrentModel.Nodes[dsInsn.NodeID]; +					node cNode = NodeDefs[origNode]; +					 +					Material mat = CurrentModel.Materials[dsInsn.MaterialID]; +					string matName = CurrentModel.Materials.GetKeyForIndex(dsInsn.MaterialID); +					 +					var newGeoEntry = new instance_geometry(); +					newGeoEntry.name = String.Format("DrawXlu{0}-{1}", drawID, shapeName); +					newGeoEntry.url = String.Format("#{0}-lib", shapeName); +					 +					// now add the material +					var bindMaterial = newGeoEntry.bind_material = new bind_material(); +					bindMaterial.technique_common = new instance_material[1]; +					var matTechnique = bindMaterial.technique_common[0] = new instance_material(); +					 +					// constant marker so that I don't have to set a unique material name in each primitive +					// it doesn't matter, since each geometry instance only uses one material anyway +					matTechnique.symbol = "NW4R_MATERIAL"; +					matTechnique.target = "#Material-" + matName; +					 +					matTechnique.bind_vertex_input = new instance_materialBind_vertex_input[1]; +					matTechnique.bind_vertex_input[0] = new instance_materialBind_vertex_input(); +					matTechnique.bind_vertex_input[0].semantic = "CHANNEL1"; +					matTechnique.bind_vertex_input[0].input_semantic = "TEXCOORD"; +					matTechnique.bind_vertex_input[0].input_set = 0; +					 +					// ok, now add the instance_geometry into the node +					instance_geometry[] geoArrayCopy = cNode.instance_geometry; +					if (geoArrayCopy == null) +						geoArrayCopy = new instance_geometry[1]; +					else +						Array.Resize<instance_geometry>(ref geoArrayCopy, geoArrayCopy.Length + 1); +					geoArrayCopy[geoArrayCopy.Length - 1] = newGeoEntry; +					cNode.instance_geometry = geoArrayCopy; +					 +					drawID++; +				} +			} + + +			/*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); +			}*/ +			 +			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); +		} + + + +		private effect CreateEffectFromMaterial(string name, Material mat) { +			var eff = new effect(); + +			eff.id = "Material-Effect-" + name; +			eff.name = eff.id; + +		 +			// HACK!! +			if (mat.TextureInfos.Count == 0) +				return eff; + +			// this is based off what colladamax outputs +			eff.Items = new effectFx_profile_abstractProfile_COMMON[1]; +			var profile = eff.Items[0] = new effectFx_profile_abstractProfile_COMMON(); + +			// TODO: handle this correctly for multiple textures ETC and check how bb does it + +			profile.Items = new object[2]; + +			// create a surface newparam +			var surfaceParam = new common_newparam_type(); +			var surface = new fx_surface_common(); + +			surface.type = fx_surface_type_enum.Item2D; +			surface.init_from = new fx_surface_init_from_common[1]; +			surface.init_from[0] = new fx_surface_init_from_common(); +			surface.init_from[0].Value = "Texture-" + mat.TextureInfos[0].TextureName; + +			surfaceParam.sid = "Surface-" + mat.TextureInfos[0].TextureName; +			surfaceParam.ItemElementName = ItemChoiceType.surface; +			surfaceParam.Item = surface; +			profile.Items[0] = surfaceParam; + +			// now create a sampler newparam +			var samplerParam = new common_newparam_type(); +			var sampler2d = new fx_sampler2D_common(); + +			// add wrapping +			sampler2d.source = "Surface-" + mat.TextureInfos[0].TextureName; +			sampler2d.wrap_s = mat.TextureInfos[0].WrapS.ToColladaSamplerWrap(); +			sampler2d.wrap_t = mat.TextureInfos[0].WrapT.ToColladaSamplerWrap(); + +			samplerParam.sid = "Sampler-" + mat.TextureInfos[0].TextureName; +			samplerParam.ItemElementName = ItemChoiceType.sampler2D; +			samplerParam.Item = sampler2d; +			profile.Items[1] = samplerParam; + +			// now make a technique +			// should I really use blinn...? +			profile.technique = new effectFx_profile_abstractProfile_COMMONTechnique(); +			profile.technique.sid = "common"; + +			var pShader = new effectFx_profile_abstractProfile_COMMONTechniquePhong(); +			pShader.diffuse = new common_color_or_texture_type(); + +			var diffuseTex = new common_color_or_texture_typeTexture(); +			diffuseTex.texture = "Sampler-" + mat.TextureInfos[0].TextureName; +			diffuseTex.texcoord = "CHANNEL1"; + +			pShader.diffuse.Item = diffuseTex; + +			pShader.emission = new common_color_or_texture_type(); +			var emissionClr = new common_color_or_texture_typeColor(); +			emissionClr.Values = new double[] { 0, 0, 0, 1 }; +			pShader.emission.Item = emissionClr; +			 +			pShader.ambient = new common_color_or_texture_type(); +			var ambientClr = new common_color_or_texture_typeColor(); +			ambientClr.Values = new double[] { 0, 0, 0, 1 }; +			pShader.ambient.Item = ambientClr; + +			pShader.transparent = new common_transparent_type(); +			pShader.transparent.opaque = fx_opaque_enum.A_ONE; +			var transparentClr = new common_color_or_texture_typeColor(); +			transparentClr.Values = new double[] { 1, 1, 1, 1 }; +			pShader.transparent.Item = transparentClr; +			pShader.transparency = new common_float_or_param_type(); +			var bs = new common_float_or_param_typeFloat(); +			bs.Value = 1; +			pShader.transparency.Item = bs; +			// we can reuse DiffuseTex! +			pShader.transparent.Item = diffuseTex; + +			profile.technique.Item = pShader; + +			return eff; +		} + + + +		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 < nrmData.EntryCount; i++) { +					float[] data = nrmData.GetEntry(i); +					for (int j = 0; j < data.Length; j++) { +						nrmArray.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", 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 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 < tcData.EntryCount; i++) { +						float[] data = tcData.GetEntry(i); +						for (int j = 0; j < data.Length; j++) { +							// flip T (Y axis) coordinate +							if (j == 1) +								tcArray.Values[dest++] = 1.0 - data[j]; +							else +								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", 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"; +					} +				} +			} +			 +			 +			 +			// 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++; +			} +			 +			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++; +				} +			} +			 +			 +			// 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(); +						} +					} +				} +				 +				switch (prim) { +				case PrimitiveType.Triangles: +					var pTri = new triangles(); +					pTri.material = "NW4R_MATERIAL"; +					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 geo; +				} +			} +			 +			 +			// If any tristrips were found, add them! +			if (triStrips.Count > 0) { +				var pTriStrips = new tristrips(); +				pTriStrips.material = "NW4R_MATERIAL"; +				pTriStrips.input = inputArray; +				pTriStrips.count = (ulong)triStrips.Count; +				pTriStrips.p = triStrips.ToArray(); +				meshItems.Add(pTriStrips); +			} +			 +			 +			m.Items = meshItems.ToArray(); +			 +			// FINALLY DONE! +			return geo; +		} +	} +} + diff --git a/NW4RTools/Models/Material.cs b/NW4RTools/Models/Material.cs index 9e90348..0bf0acc 100644 --- a/NW4RTools/Models/Material.cs +++ b/NW4RTools/Models/Material.cs @@ -58,6 +58,11 @@ namespace NW4RTools.Models {  		public byte[] TexCoordGenDL;  		public Material() { +			IndirectTexMtxCalcMethod1 = new byte[4]; +			IndirectTexMtxCalcMethod2 = new byte[4]; +			TexObj = new byte[8][]; +			// todo +			TextureInfos = new List<TextureInfo>();  		}  	}  } diff --git a/NW4RTools/Models/Model.cs b/NW4RTools/Models/Model.cs index 71edaf3..7c7e912 100644 --- a/NW4RTools/Models/Model.cs +++ b/NW4RTools/Models/Model.cs @@ -40,6 +40,17 @@ namespace NW4RTools.Models {  		public Model() { +			Bytecode = new ResDict<ByteCode>(); +			Nodes = new ResDict<Node>(); +			VtxPosData = new ResDict<VertexPosData>(); +			VtxNrmData = new ResDict<VertexNrmData>(); +			VtxClrData = new ResDict<VertexClrData>(); +			VtxTexCoordData = new ResDict<VertexTexCoordData>(); +			Materials = new ResDict<Material>(); +			Shaders = new ResDict<Shader>(); +			Shapes = new ResDict<Shape>(); +			PairingLookupByTexture = new ResDict<List<TexMatPairing>>(); +			PairingLookupByPalette = new ResDict<List<TexMatPairing>>();  		}  	}  } diff --git a/NW4RTools/Models/Shape.cs b/NW4RTools/Models/Shape.cs index 87bf370..93ff70b 100644 --- a/NW4RTools/Models/Shape.cs +++ b/NW4RTools/Models/Shape.cs @@ -24,6 +24,9 @@ namespace NW4RTools.Models {  		public UInt16[] ExtraData;  		public Shape() { +			Unk = new byte[12]; +			ClrData = new VertexClrData[2]; +			TexCoordData = new VertexTexCoordData[8];  		}  	}  } diff --git a/NW4RTools/NW4RTools.csproj b/NW4RTools/NW4RTools.csproj index 89af12e..80115cd 100644 --- a/NW4RTools/NW4RTools.csproj +++ b/NW4RTools/NW4RTools.csproj @@ -64,7 +64,6 @@      <Compile Include="DisplayList.cs" />      <Compile Include="VertexSettings.cs" />      <Compile Include="Util\collada_schema_1_4.cs" /> -    <Compile Include="ColladaWriter.cs" />      <Compile Include="Texture.cs" />      <Compile Include="Misc.cs" />      <Compile Include="Models\OpenGL\GLModel.cs" /> @@ -76,6 +75,7 @@      <Compile Include="Models\Animation\CharacterAnim.cs" />      <Compile Include="Models\Animation\TextureSRTAnim.cs" />      <Compile Include="Util\NVDXT.cs" /> +    <Compile Include="ColladaExporter.cs" />    </ItemGroup>    <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />    <ItemGroup> diff --git a/NW4RTools/Texture.cs b/NW4RTools/Texture.cs index 3dadce8..e45555d 100644 --- a/NW4RTools/Texture.cs +++ b/NW4RTools/Texture.cs @@ -236,7 +236,7 @@ namespace NW4RTools {  					for (int x = 0; x < width; x += 8) {  						for (int iBlockY = 0; iBlockY < 2; iBlockY++) {  							for (int iBlockX = 0; iBlockX < 2; iBlockX++) { -								var block = Util.NVDXT.compressDXT1a(bits.Scan0, +								var block = Util.NVDXT.compressDXT1a((Util.NVDXT.ARGBPixel*)bits.Scan0,  									x + (iBlockX * 4), y + (iBlockY * 4),  									bits.Stride, bits.Height); diff --git a/NW4RTools/Util/NVDXT.cs b/NW4RTools/Util/NVDXT.cs index fd7d50a..a972344 100644 --- a/NW4RTools/Util/NVDXT.cs +++ b/NW4RTools/Util/NVDXT.cs @@ -729,7 +729,7 @@ namespace NW4RTools.Util {  			CMPRBlock block = new CMPRBlock();
  			uint indices = 0xAAAAAAAA;
 -			
 +
  			block.Color0 = (ushort)((OMatch5[c.R, 0] << 11) | (OMatch6[c.G, 0] << 5) | OMatch5[c.B, 0]);
  			block.Color1 = (ushort)((OMatch5[c.R, 1] << 11) | (OMatch6[c.G, 1] << 5) | OMatch5[c.B, 1]);
 diff --git a/NW4RTools/bin/Debug/NW4RTools.dll b/NW4RTools/bin/Debug/NW4RTools.dll Binary files differindex aa6b86f..1204c1d 100755 --- a/NW4RTools/bin/Debug/NW4RTools.dll +++ b/NW4RTools/bin/Debug/NW4RTools.dll diff --git a/NW4RTools/bin/Debug/NW4RTools.dll.mdb b/NW4RTools/bin/Debug/NW4RTools.dll.mdb Binary files differindex ea4c02e..badfeb7 100644 --- a/NW4RTools/bin/Debug/NW4RTools.dll.mdb +++ b/NW4RTools/bin/Debug/NW4RTools.dll.mdb  | 
