public ModelBoneHierarchy Load(string name, AssetLoadContext context) { // Find it in the file system. FileSystemEntry entry = null; foreach (var path in _pathResolver.GetPaths(name, context.Language)) { entry = context.FileSystem.GetFile(path); if (entry != null) { break; } } // Load hierarchy. W3dFile hierarchyFile; using (var entryStream = entry.Open()) { hierarchyFile = W3dFile.FromStream(entryStream, entry.FilePath); } var w3dHierarchy = hierarchyFile.GetHierarchy(); return(w3dHierarchy != null ? new ModelBoneHierarchy(w3dHierarchy) : ModelBoneHierarchy.CreateDefault()); }
internal static W3DAnimation FromW3dFile(W3dFile w3dFile) { var w3dAnimations = w3dFile.GetAnimations(); var w3dCompressedAnimations = w3dFile.GetCompressedAnimations(); var animations = new W3DAnimation[w3dAnimations.Count + w3dCompressedAnimations.Count]; if (animations.Length == 0) { // sometimes w3d files are referenced inside animation states that do not contain any animation chunks return(null); } if (animations.Length != 1) { throw new NotSupportedException(); } for (var i = 0; i < w3dAnimations.Count; i++) { animations[i] = new W3DAnimation(w3dAnimations[i]); } for (var i = 0; i < w3dCompressedAnimations.Count; i++) { animations[w3dAnimations.Count + i] = new W3DAnimation(w3dCompressedAnimations[i]); } return(animations[0]); }
protected override Model LoadEntry(FileSystemEntry entry, ContentManager contentManager, Game game, LoadOptions loadOptions) { W3dFile w3dFile; using (var entryStream = entry.Open()) { w3dFile = W3dFile.FromStream(entryStream, entry.FilePath); } var w3dHLod = w3dFile.GetHLod(); var w3dHierarchy = w3dFile.GetHierarchy(); if (w3dHLod != null && w3dHierarchy == null) { // Load referenced hierarchy. var hierarchyFileName = w3dHLod.Header.HierarchyName + ".W3D"; var hierarchyFilePath = Path.Combine(Path.GetDirectoryName(w3dFile.FilePath), hierarchyFileName); var hierarchyFileEntry = contentManager.FileSystem.GetFile(hierarchyFilePath); W3dFile hierarchyFile; using (var entryStream = hierarchyFileEntry.Open()) { hierarchyFile = W3dFile.FromStream(entryStream, hierarchyFileEntry.FilePath); } w3dHierarchy = hierarchyFile.GetHierarchy(); } return(CreateModel( contentManager, w3dFile, w3dHierarchy)); }
public void LoadW3dFromBigFile() { var bigFilePath = Path.Combine(InstalledFilesTestData.GetInstallationDirectory(SageGame.CncGeneralsZeroHour), "W3DZH.big"); using (var bigArchive = new BigArchive(bigFilePath)) { var entry = bigArchive.GetEntry(@"Art\W3D\ABBarracks_AC.W3D"); var w3dFile = W3dFile.FromFileSystemEntry(new FileSystemEntry(null, entry.FullName, entry.Length, entry.Open)); Assert.Equal(3, w3dFile.Meshes.Count); } }
public void LoadW3dFromBigFile() { const string bigFilePath = @"C:\Program Files (x86)\Origin Games\Command and Conquer Generals Zero Hour\Command and Conquer Generals Zero Hour\W3DZH.big"; using (var bigStream = File.OpenRead(bigFilePath)) using (var bigArchive = new BigArchive(bigStream)) { var entry = bigArchive.GetEntry(@"Art\W3D\ABBarracks_AC.W3D"); var w3dFile = W3dFile.FromFileSystemEntry(new FileSystemEntry(null, entry.FullName, entry.Length, entry.Open)); Assert.Equal(3, w3dFile.Meshes.Count); } }
public Model Load(string name, AssetLoadContext context) { // Find it in the file system. FileSystemEntry entry = null; foreach (var path in _pathResolver.GetPaths(name, context.Language)) { entry = context.FileSystem.GetFile(path); if (entry != null) { break; } } if (entry == null) { return(null); } // Load model. W3dFile w3dFile; using (var entryStream = entry.Open()) { w3dFile = W3dFile.FromStream(entryStream, entry.FilePath); } var w3dHLod = w3dFile.HLod; var w3dHierarchy = w3dFile.Hierarchy; ModelBoneHierarchy boneHierarchy; if (w3dHierarchy != null) { boneHierarchy = new ModelBoneHierarchy(w3dHierarchy); } else if (w3dHLod != null && w3dHierarchy == null) { // Load referenced hierarchy. boneHierarchy = context.AssetStore.ModelBoneHierarchies.GetByName(w3dHLod.Header.HierarchyName); } else { boneHierarchy = ModelBoneHierarchy.CreateDefault(); } return(CreateModel( context, w3dFile, boneHierarchy)); }
public W3DAnimation Load(string key, AssetLoadContext context) { var splitName = key.Split('.'); if (splitName.Length <= 1) { return(null); } // Find it in the file system. FileSystemEntry entry = null; foreach (var path in _pathResolver.GetPaths(splitName[1], context.Language)) { entry = context.FileSystem.GetFile(path); if (entry != null) { break; } } if (entry == null) { logger.Warn("Failed to load animation: " + key); return(null); } // Load animation. W3dFile w3dFile; using (var entryStream = entry.Open()) { w3dFile = W3dFile.FromStream(entryStream, entry.FilePath); } var animation = W3DAnimation.FromW3dFile(w3dFile); if (animation == null) { logger.Warn("Failed to load animation (was null): " + key); return(null); } if (!string.Equals(animation.Name, key, StringComparison.OrdinalIgnoreCase)) { logger.Warn("animation name '" + animation.Name + "' does not match '" + key + "'"); } return(animation); }
public void LoadW3dFromBigFile() { var bigFilePath = Path.Combine(InstalledFilesTestData.GetInstallationDirectory(SageGame.CncGeneralsZeroHour), "W3DZH.big"); using (var bigArchive = new BigArchive(bigFilePath)) { var entry = bigArchive.GetEntry(@"Art\W3D\ABBarracks_AC.W3D"); W3dFile w3dFile; using (var entryStream = entry.Open()) { w3dFile = W3dFile.FromStream(entryStream, entry.FullName); } Assert.Equal(3, w3dFile.GetMeshes().Count); } }
protected override Model LoadEntry(FileSystemEntry entry, ContentManager contentManager, Game game, LoadOptions loadOptions) { var w3dFile = W3dFile.FromFileSystemEntry(entry); var w3dHierarchy = w3dFile.Hierarchy; if (w3dFile.HLod != null && w3dHierarchy == null) { // Load referenced hierarchy. var hierarchyFileName = w3dFile.HLod.Header.HierarchyName + ".W3D"; var hierarchyFilePath = Path.Combine(Path.GetDirectoryName(w3dFile.FilePath), hierarchyFileName); var hierarchyFileEntry = contentManager.FileSystem.GetFile(hierarchyFilePath); var hierarchyFile = W3dFile.FromFileSystemEntry(hierarchyFileEntry); w3dHierarchy = hierarchyFile.Hierarchy; } return(CreateModel( contentManager, w3dFile, w3dHierarchy)); }
public static Animation[] LoadAnimations(W3dFile w3dFile, ContentManager contentManager) { var w3dAnimations = w3dFile.GetAnimations(); var w3dCompressedAnimations = w3dFile.GetCompressedAnimations(); var animations = new Animation[w3dAnimations.Count + w3dCompressedAnimations.Count]; for (var i = 0; i < w3dAnimations.Count; i++) { animations[i] = CreateAnimation(w3dAnimations[i]); } for (var i = 0; i < w3dCompressedAnimations.Count; i++) { animations[w3dAnimations.Count + i] = CreateAnimation(w3dCompressedAnimations[i]); } foreach (var animation in animations) { contentManager.DataContext.Animations.Add(animation.Name, animation); } return(animations); }
internal static W3DAnimation FromW3dFile(W3dFile w3dFile) { var w3dAnimations = w3dFile.GetAnimations(); var w3dCompressedAnimations = w3dFile.GetCompressedAnimations(); var animations = new W3DAnimation[w3dAnimations.Count + w3dCompressedAnimations.Count]; if (animations.Length != 1) { throw new NotSupportedException(); } for (var i = 0; i < w3dAnimations.Count; i++) { animations[i] = new W3DAnimation(w3dAnimations[i]); } for (var i = 0; i < w3dCompressedAnimations.Count; i++) { animations[w3dAnimations.Count + i] = new W3DAnimation(w3dCompressedAnimations[i]); } return(animations[0]); }
public W3dView(AssetViewContext context) : base(context) { var game = context.Game; var modelInstance = game.ContentManager .Load <Model>(context.Entry.FilePath) .CreateInstance(game.GraphicsDevice); void onUpdating(object sender, GameUpdatingEventArgs e) => modelInstance.Update(e.GameTime); game.Updating += onUpdating; AddDisposeAction(() => game.Updating -= onUpdating); void onBuildingRenderList(object sender, BuildingRenderListEventArgs e) { modelInstance.SetWorldMatrix(Matrix4x4.Identity); modelInstance.BuildRenderList(e.RenderList, e.Camera); } game.BuildingRenderList += onBuildingRenderList; AddDisposeAction(() => game.BuildingRenderList -= onBuildingRenderList); var enclosingBoundingBox = GetEnclosingBoundingBox(modelInstance); var cameraController = new ArcballCameraController( enclosingBoundingBox.GetCenter(), Vector3.Distance(enclosingBoundingBox.Min, enclosingBoundingBox.Max)); game.Scene3D = new Scene3D( game, cameraController, null, null, Array.Empty <Terrain.Road>(), null, new GameObjectCollection(game.ContentManager), new WaypointCollection(), new WaypointPathCollection(), WorldLighting.CreateDefault(), Array.Empty <Player>(), Array.Empty <Team>()); var animations = new List <AnimationInstance>(modelInstance.AnimationInstances); var w3dFile = W3dFile.FromFileSystemEntry(context.Entry); // If this is a skin file, load "external" animations. var externalAnimations = new List <AnimationInstance>(); if (w3dFile.HLod != null && w3dFile.HLod.Header.Name.EndsWith("_SKN", StringComparison.OrdinalIgnoreCase)) { var namePrefix = w3dFile.HLod.Header.Name.Substring(0, w3dFile.HLod.Header.Name.LastIndexOf('_') + 1); var parentFolder = Path.GetDirectoryName(w3dFile.FilePath); var pathPrefix = Path.Combine(parentFolder, namePrefix); foreach (var animationFileEntry in context.Entry.FileSystem.GetFiles(parentFolder)) { if (!animationFileEntry.FilePath.StartsWith(pathPrefix, StringComparison.OrdinalIgnoreCase)) { continue; } var animationModel = game.ContentManager.Load <Model>(animationFileEntry.FilePath); foreach (var animation in animationModel.Animations) { var externalAnimationInstance = new AnimationInstance(modelInstance, animation); modelInstance.AnimationInstances.Add(externalAnimationInstance); externalAnimations.Add(externalAnimationInstance); } } } _subObjects = new List <W3dItem>(); _subObjects.Add(new W3dModelItem()); foreach (var animation in animations) { _subObjects.Add(new W3dAnimationItem(animation, "Animation")); } foreach (var animation in externalAnimations) { _subObjects.Add(new W3dAnimationItem(animation, "External Animation")); } ActivateItem(_subObjects[0]); }
private static Model CreateModel( AssetLoadContext context, W3dFile w3dFile, ModelBoneHierarchy boneHierarchy) { //BoundingSphere boundingSphere = default(BoundingSphere); var w3dHLod = w3dFile.HLod; var subObjects = new List <ModelSubObject>(); if (w3dHLod != null) { foreach (var w3dSubObject in w3dHLod.Lods[0].SubObjects) { if (!w3dFile.RenderableObjectsByName.TryGetValue(w3dSubObject.Name, out var w3dRenderableObject)) { continue; } var bone = boneHierarchy.Bones[(int)w3dSubObject.BoneIndex]; //var meshBoundingSphere = mesh.BoundingSphere.Transform(bone.Transform); //boundingSphere = (i == 0) // ? meshBoundingSphere // : BoundingSphere.CreateMerged(boundingSphere, meshBoundingSphere); subObjects.Add( CreateSubObject( w3dSubObject.Name, w3dRenderableObject, bone, context)); } } else if (w3dFile.RenderableObjects.Count > 0) { // Simple models can have only one mesh with no HLod chunk. if (w3dFile.RenderableObjects.Count != 1) { throw new InvalidOperationException(); } var w3dRenderableObjectPair = w3dFile.RenderableObjectsByName.First(); subObjects.Add( CreateSubObject( w3dRenderableObjectPair.Key, w3dRenderableObjectPair.Value, boneHierarchy.Bones[0], context)); } else { } return(new Model( Path.GetFileNameWithoutExtension(w3dFile.FilePath), boneHierarchy, subObjects.ToArray())); }
public W3dFileContentViewModel(FileSystemEntry file) : base(file) { _w3dFile = W3dFile.FromFileSystemEntry(file); }
private static Model CreateModel( AssetLoadContext context, W3dFile w3dFile, ModelBoneHierarchy boneHierarchy) { //BoundingSphere boundingSphere = default(BoundingSphere); var w3dMeshes = w3dFile.GetMeshes(); var w3dHLod = w3dFile.GetHLod(); var subObjects = new List <ModelSubObject>(); if (w3dHLod != null) { foreach (var w3dSubObject in w3dHLod.Lods[0].SubObjects) { // TODO: Collision boxes var w3dMesh = w3dMeshes.FirstOrDefault(x => x.Header.ContainerName + "." + x.Header.MeshName == w3dSubObject.Name); if (w3dMesh == null) { continue; } var bone = boneHierarchy.Bones[(int)w3dSubObject.BoneIndex]; var mesh = new ModelMesh(w3dMesh, context); //var meshBoundingSphere = mesh.BoundingSphere.Transform(bone.Transform); //boundingSphere = (i == 0) // ? meshBoundingSphere // : BoundingSphere.CreateMerged(boundingSphere, meshBoundingSphere); subObjects.Add(new ModelSubObject(w3dSubObject.Name, bone, mesh)); } } else if (w3dMeshes.Count > 0) { // Simple models can have only one mesh with no HLod chunk. if (w3dMeshes.Count != 1) { throw new InvalidOperationException(); } var w3dMesh = w3dMeshes[0]; var mesh = new ModelMesh(w3dMesh, context); subObjects.Add(new ModelSubObject( w3dMesh.Header.MeshName, boneHierarchy.Bones[0], mesh)); } else { // TODO: Some .w3d files contain a single W3D_BOX. } return(new Model( Path.GetFileNameWithoutExtension(w3dFile.FilePath), boneHierarchy, subObjects.ToArray())); }
public void CanRoundtripW3dFiles() { InstalledFilesTestData.ReadFiles(".w3d", _output, entry => { switch (Path.GetFileName(entry.FilePath).ToLower()) { case "uisabotr_idel.w3d": case "uisabotr_jump.w3d": case "uisabotr_left.w3d": case "uisabotr_right.w3d": case "uisabotr_up.w3d": case "cusheep_grza.w3d": case "gbmtwalld.w3d": case "gbmtwalldramp.w3d": case "gbmtwalle.w3d": case "bbbags.w3d": case "cuwyrm_cld_skl.w3d": case "cuwyrm_cld_skn.w3d": case "gugandalfcrstl.w3d": case "guhbtshfb_cinb.w3d": case "guhbtshfb_cinc.w3d": case "kbpostgaten_al.w3d": case "kbpostgaten_am.w3d": case "lwbanhfllbst.w3d": case "lwbanhnazgul.w3d": case "lwbanhwtchkng.w3d": case "psupplies04.w3d": case "readonly-0-rev-2-lwbanhwitchk.w3d": case "wbcave_d2a.w3d": case "wbcave_d2c.w3d": case "npc14b.w3d": case "npc15b.w3d": return; // Corrupt, or unreferenced and contain chunks that don't exist elsewhere. } var w3dFile = TestUtility.DoRoundtripTest( () => entry.Open(), stream => W3dFile.FromStream(stream, entry.FilePath), (w3d, stream) => w3d.WriteTo(stream), true); foreach (var mesh in w3dFile.GetMeshes()) { Assert.Equal((int)mesh.Header.NumVertices, mesh.Vertices.Items.Length); Assert.Equal((int)mesh.Header.NumTris, mesh.Triangles.Items.Length); if (mesh.Influences != null) { Assert.Equal(mesh.Vertices.Items.Length, mesh.Influences.Items.Length); } Assert.Equal((int)mesh.MaterialInfo.PassCount, mesh.MaterialPasses.Count); Assert.Equal((int)mesh.MaterialInfo.ShaderCount, mesh.Shaders?.Items.Count ?? 0); Assert.Equal(mesh.Vertices.Items.Length, mesh.ShadeIndices.Items.Length); if (mesh.VertexMaterials != null) { Assert.True(mesh.VertexMaterials.Items.Count <= 16); foreach (var material in mesh.VertexMaterials.Items) { Assert.Equal(W3dVertexMaterialFlags.None, material.Info.Attributes); Assert.Equal(0, material.Info.Translucency); } } Assert.True(mesh.MaterialPasses.Count <= 3); Assert.True(mesh.ShaderMaterials == null || mesh.ShaderMaterials.Items.Count == 1); if (mesh.ShaderMaterials != null) { Assert.Null(mesh.VertexMaterials); Assert.Single(mesh.MaterialPasses); } foreach (var materialPass in mesh.MaterialPasses) { Assert.True(materialPass.Dcg == null || materialPass.Dcg.Items.Length == mesh.Vertices.Items.Length); Assert.Null(materialPass.Dig); Assert.Null(materialPass.Scg); Assert.True(materialPass.TextureStages.Count <= 2); foreach (var textureStage in materialPass.TextureStages) { Assert.True(textureStage.TexCoords == null || textureStage.TexCoords.Items.Length == mesh.Header.NumVertices); Assert.Null(textureStage.PerFaceTexCoordIds); var numTextureIds = textureStage.TextureIds.Items.Count; Assert.True(numTextureIds == 1 || numTextureIds == mesh.Header.NumTris); } Assert.True((materialPass.ShaderIds != null && materialPass.VertexMaterialIds != null && materialPass.TexCoords == null) || materialPass.ShaderMaterialIds != null); if (materialPass.ShaderIds != null) { var numShaderIds = materialPass.ShaderIds.Items.Length; Assert.True(numShaderIds == 1 || numShaderIds == mesh.Header.NumTris); } if (materialPass.VertexMaterialIds != null) { var numVertexMaterialIds = materialPass.VertexMaterialIds.Items.Length; Assert.True(numVertexMaterialIds == 1 || numVertexMaterialIds == mesh.Header.NumVertices); } Assert.True(materialPass.ShaderMaterialIds == null || materialPass.ShaderMaterialIds.Items[0] == 0); } if (mesh.Textures != null) { Assert.True(mesh.Textures.Items.Count <= 29); } } foreach (var animation in w3dFile.GetCompressedAnimations()) { foreach (var channel in animation.TimeCodedChannels) { switch (channel.ChannelType) { case W3dAnimationChannelType.UnknownBfme: Assert.Equal(1, channel.VectorLength); break; } } } }); }
public W3dView(FileSystemEntry entry, Func <IntPtr, Game> createGame) { _listBox = new ListBox { Width = 250, ItemTextBinding = Binding.Property((W3dItem v) => v.Name) }; _listBox.SelectedValueChanged += OnSelectedValueChanged; Panel1 = _listBox; _listBox.SelectedIndex = 0; Panel2 = new GameControl { CreateGame = h => { var game = createGame(h); var modelInstance = game.ContentManager .Load <Model>(entry.FilePath) .CreateInstance(game.GraphicsDevice); game.Updating += (sender, e) => { modelInstance.Update(e.GameTime); }; game.BuildingRenderList += (sender, e) => { modelInstance.SetWorldMatrix(Matrix4x4.Identity); modelInstance.BuildRenderList(e.RenderList, e.Camera); }; var enclosingBoundingBox = GetEnclosingBoundingBox(modelInstance); var cameraController = new ArcballCameraController( enclosingBoundingBox.GetCenter(), Vector3.Distance(enclosingBoundingBox.Min, enclosingBoundingBox.Max)); game.Scene3D = new Scene3D( game, cameraController, null, null, null, new GameObjectCollection(game.ContentManager), new WaypointCollection(), new WaypointPathCollection(), WorldLighting.CreateDefault()); var animations = new List <AnimationInstance>(modelInstance.AnimationInstances); var w3dFile = W3dFile.FromFileSystemEntry(entry); // If this is a skin file, load "external" animations. var externalAnimations = new List <AnimationInstance>(); if (w3dFile.HLod != null && w3dFile.HLod.Header.Name.EndsWith("_SKN", StringComparison.OrdinalIgnoreCase)) { var namePrefix = w3dFile.HLod.Header.Name.Substring(0, w3dFile.HLod.Header.Name.LastIndexOf('_') + 1); var parentFolder = Path.GetDirectoryName(w3dFile.FilePath); var pathPrefix = Path.Combine(parentFolder, namePrefix); foreach (var animationFileEntry in entry.FileSystem.GetFiles(parentFolder)) { if (!animationFileEntry.FilePath.StartsWith(pathPrefix, StringComparison.OrdinalIgnoreCase)) { continue; } var animationModel = game.ContentManager.Load <Model>(animationFileEntry.FilePath); foreach (var animation in animationModel.Animations) { var externalAnimationInstance = new AnimationInstance(modelInstance, animation); modelInstance.AnimationInstances.Add(externalAnimationInstance); externalAnimations.Add(externalAnimationInstance); } } } var subObjects = new List <W3dItem>(); subObjects.Add(new W3dModelItem()); foreach (var animation in animations) { subObjects.Add(new W3dAnimationItem(animation, "Animation")); } foreach (var animation in externalAnimations) { subObjects.Add(new W3dAnimationItem(animation, "External Animation")); } _listBox.DataStore = subObjects; return(game); } }; }
public void CanReadW3dFiles() { InstalledFilesTestData.ReadFiles(".w3d", _output, entry => { switch (Path.GetFileName(entry.FilePath)) { case "UISabotr_idel.w3d": case "UISabotr_Jump.w3d": case "UISabotr_Left.w3d": case "UISabotr_Right.w3d": case "UISabotr_Up.w3d": case "cusheep_grza.w3d": case "gbmtwalld.w3d": case "gbmtwalldramp.w3d": case "gbmtwalle.w3d": case "bbbags.w3d": case "cuwyrm_cld_skl.w3d": case "cuwyrm_cld_skn.w3d": case "gugandalfcrstl.w3d": case "guhbtshfb_cinb.w3d": case "guhbtshfb_cinc.w3d": case "lwbanhfllbst.w3d": case "lwbanhnazgul.w3d": case "lwbanhwtchkng.w3d": case "psupplies04.w3d": case "wbcave_d2a.w3d": case "wbcave_d2c.w3d": return; // Corrupt, or unreferenced and contain chunks that don't exist elsewhere. } var w3dFile = W3dFile.FromFileSystemEntry(entry); foreach (var mesh in w3dFile.Meshes) { Assert.Equal((int)mesh.Header.NumVertices, mesh.Vertices.Length); Assert.Equal((int)mesh.Header.NumTris, mesh.Triangles.Length); Assert.Equal(mesh.Vertices.Length, mesh.Influences.Length); Assert.Equal((int)mesh.MaterialInfo.PassCount, mesh.MaterialPasses.Length); Assert.Equal((int)mesh.MaterialInfo.ShaderCount, mesh.Shaders.Length); Assert.Equal(mesh.Vertices.Length, mesh.ShadeIndices.Length); Assert.True(mesh.Materials.Length <= 16); foreach (var material in mesh.Materials) { Assert.Equal(W3dVertexMaterialFlags.None, material.VertexMaterialInfo.Attributes); Assert.Equal(0, material.VertexMaterialInfo.Translucency); } Assert.True(mesh.MaterialPasses.Length <= 3); Assert.True(mesh.ShaderMaterials == null || mesh.ShaderMaterials.Materials.Count == 1); if (mesh.ShaderMaterials != null) { Assert.Empty(mesh.Materials); Assert.Single(mesh.MaterialPasses); } foreach (var materialPass in mesh.MaterialPasses) { Assert.True(materialPass.Dcg == null || materialPass.Dcg.Length == mesh.Vertices.Length); Assert.Null(materialPass.Dig); Assert.Null(materialPass.Scg); Assert.True(materialPass.TextureStages.Count <= 2); foreach (var textureStage in materialPass.TextureStages) { Assert.True(textureStage.TexCoords == null || textureStage.TexCoords.Length == mesh.Header.NumVertices); Assert.Null(textureStage.PerFaceTexCoordIds); var numTextureIds = textureStage.TextureIds.Length; Assert.True(numTextureIds == 1 || numTextureIds == mesh.Header.NumTris); } Assert.True((materialPass.ShaderIds != null && materialPass.VertexMaterialIds != null && materialPass.TexCoords == null) || materialPass.ShaderMaterialId != null); if (materialPass.ShaderIds != null) { var numShaderIds = materialPass.ShaderIds.Length; Assert.True(numShaderIds == 1 || numShaderIds == mesh.Header.NumTris); } if (materialPass.VertexMaterialIds != null) { var numVertexMaterialIds = materialPass.VertexMaterialIds.Length; Assert.True(numVertexMaterialIds == 1 || numVertexMaterialIds == mesh.Header.NumVertices); } Assert.True(materialPass.ShaderMaterialId == null || materialPass.ShaderMaterialId == 0); } Assert.True(mesh.Textures.Count <= 29); } foreach (var animation in w3dFile.CompressedAnimations) { foreach (var channel in animation.TimeCodedChannels) { switch (channel.ChannelType) { case W3dAnimationChannelType.UnknownBfme: Assert.Equal(1, channel.VectorLength); break; } } } }); }
private Model CreateModel( ContentManager contentManager, W3dFile w3dFile, W3dHierarchyDef w3dHierarchy) { ModelBone[] bones; if (w3dHierarchy != null) { bones = new ModelBone[w3dHierarchy.Pivots.Items.Count]; for (var i = 0; i < w3dHierarchy.Pivots.Items.Count; i++) { var pivot = w3dHierarchy.Pivots.Items[i]; var parent = pivot.ParentIdx == -1 ? null : bones[pivot.ParentIdx]; bones[i] = new ModelBone( i, pivot.Name, parent, pivot.Translation, pivot.Rotation); } } else { bones = new ModelBone[1]; bones[0] = new ModelBone(0, null, null, Vector3.Zero, Quaternion.Identity); } //BoundingSphere boundingSphere = default(BoundingSphere); var w3dMeshes = w3dFile.GetMeshes(); var w3dHLod = w3dFile.GetHLod(); var subObjects = new List <ModelSubObject>(); if (w3dHLod != null) { foreach (var w3dSubObject in w3dHLod.Lods[0].SubObjects) { // TODO: Collision boxes var w3dMesh = w3dMeshes.FirstOrDefault(x => x.Header.ContainerName + "." + x.Header.MeshName == w3dSubObject.Name); if (w3dMesh == null) { continue; } var bone = bones[(int)w3dSubObject.BoneIndex]; var mesh = CreateModelMesh( contentManager, w3dMesh); //var meshBoundingSphere = mesh.BoundingSphere.Transform(bone.Transform); //boundingSphere = (i == 0) // ? meshBoundingSphere // : BoundingSphere.CreateMerged(boundingSphere, meshBoundingSphere); subObjects.Add(new ModelSubObject(w3dSubObject.Name, bone, mesh)); } } else { // Simple models can have only one mesh with no HLod chunk. if (w3dMeshes.Count != 1) { throw new InvalidOperationException(); } var w3dMesh = w3dMeshes[0]; var mesh = CreateModelMesh( contentManager, w3dMesh); subObjects.Add(new ModelSubObject( w3dMesh.Header.MeshName, bones[0], mesh)); } LoadAnimations(w3dFile, contentManager); return(new Model( new ModelBoneHierarchy(bones), subObjects.ToArray())); }
private Model CreateModel( ContentManager contentManager, W3dFile w3dFile, W3dHierarchyDef w3dHierarchy) { ModelBone[] bones; if (w3dHierarchy != null) { if (w3dHierarchy.Pivots.Length > ModelMesh.MaxBones) { throw new NotSupportedException(); } bones = new ModelBone[w3dHierarchy.Pivots.Length]; for (var i = 0; i < w3dHierarchy.Pivots.Length; i++) { var pivot = w3dHierarchy.Pivots[i]; var parent = pivot.ParentIdx == -1 ? null : bones[pivot.ParentIdx]; bones[i] = new ModelBone( i, pivot.Name, parent, pivot.Translation, pivot.Rotation); } } else { bones = new ModelBone[1]; bones[0] = new ModelBone(0, null, null, Vector3.Zero, Quaternion.Identity); } //BoundingSphere boundingSphere = default(BoundingSphere); var meshes = new ModelMesh[w3dFile.Meshes.Count]; for (var i = 0; i < w3dFile.Meshes.Count; i++) { var w3dMesh = w3dFile.Meshes[i]; ModelBone bone; if (w3dFile.HLod != null) { var hlodSubObject = w3dFile.HLod.Lods[0].SubObjects.Single(x => x.Name == w3dMesh.Header.ContainerName + "." + w3dMesh.Header.MeshName); bone = bones[(int)hlodSubObject.BoneIndex]; } else { bone = bones[0]; } meshes[i] = CreateModelMesh( contentManager, w3dMesh, bone, bones.Length); //var meshBoundingSphere = mesh.BoundingSphere.Transform(bone.Transform); //boundingSphere = (i == 0) // ? meshBoundingSphere // : BoundingSphere.CreateMerged(boundingSphere, meshBoundingSphere); } var animations = new Animation[w3dFile.Animations.Count + w3dFile.CompressedAnimations.Count]; for (var i = 0; i < w3dFile.Animations.Count; i++) { animations[i] = CreateAnimation(w3dFile.Animations[i]); } for (var i = 0; i < w3dFile.CompressedAnimations.Count; i++) { animations[w3dFile.Animations.Count + i] = CreateAnimation(w3dFile.CompressedAnimations[i]); } return(new Model( bones, meshes, animations)); }
private W3dModelDrawConditionState CreateModelDrawConditionStateInstance(ModelConditionState conditionState) { ModelInstance modelInstance = null; if (!string.Equals(conditionState.Model, "NONE", StringComparison.OrdinalIgnoreCase)) { var w3dFilePath = Path.Combine("Art", "W3D", conditionState.Model + ".W3D"); var model = _contentManager.Load <Model>(w3dFilePath); if (model != null) { modelInstance = model.CreateInstance(_contentManager.GraphicsDevice); } } if (modelInstance != null) { // TODO: Multiple animations. Shouldn't play all of them. I think // we should randomly choose one of them? // And there is also IdleAnimation. var firstAnimation = conditionState.ConditionAnimations .Concat(conditionState.IdleAnimations) .LastOrDefault(); if (firstAnimation != null) { if (!_contentManager.DataContext.Animations.TryGetValue(firstAnimation.Animation, out var animation)) { var splitName = firstAnimation.Animation.Split('.'); var w3dFilePath = Path.Combine("Art", "W3D", splitName[1] + ".W3D"); var w3dEntry = _contentManager.FileSystem.GetFile(w3dFilePath); var w3dFile = W3dFile.FromFileSystemEntry(w3dEntry); var animations = ModelLoader.LoadAnimations(w3dFile, _contentManager); if (animations.Length != 1 || !string.Equals(animations[0].Name, firstAnimation.Animation, StringComparison.OrdinalIgnoreCase)) { throw new NotSupportedException(); } animation = animations[0]; } var animationInstance = new AnimationInstance(modelInstance, animation); modelInstance.AnimationInstances.Add(animationInstance); animationInstance.Play(); } } var particleSystems = new List <ParticleSystem>(); if (modelInstance != null) { foreach (var particleSysBone in conditionState.ParticleSysBones) { var particleSystemDefinition = _contentManager.IniDataContext.ParticleSystems.First(x => x.Name == particleSysBone.ParticleSystem); var bone = modelInstance.Model.BoneHierarchy.Bones.FirstOrDefault(x => string.Equals(x.Name, particleSysBone.BoneName, StringComparison.OrdinalIgnoreCase)); if (bone == null) { // TODO: Should this ever happen? continue; } particleSystems.Add(new ParticleSystem( _contentManager, particleSystemDefinition, () => ref modelInstance.AbsoluteBoneTransforms[bone.Index])); } } return(modelInstance != null ? new W3dModelDrawConditionState(modelInstance, particleSystems) : null); }