public BoundingBox CalculateBoundingBox(AnimatedModel model, AnimatedModel skin, List <int> meshesToUse = null) { Vector3 min = new Vector3(float.MaxValue); Vector3 max = new Vector3(float.MinValue); for (int i = 0; i < skin.Meshes.Count; i++) { if (meshesToUse != null && !meshesToUse.Contains(i)) { continue; } foreach (var vertex in skin.Meshes[i].Vertices) { var transformedPosition = MathC.HomogenousTransform(vertex.Position, model.AnimationTransforms[i]); min = Vector3.Min(transformedPosition, min); max = Vector3.Max(transformedPosition, max); } } BoundingBox = new BoundingBox(new Vector3((int)min.X, (int)max.Y, (int)min.Z), new Vector3((int)max.X, (int)min.Y, (int)max.Z)); return(BoundingBox); }
// This method is optional. By sorting the wad textures it may result ahead of time // we may have better texture space efficency. public void PreloadReplaceWad(IEnumerable <WadMoveable> newMoveables, IEnumerable <WadStatic> newStatics) { Dispose(); try { PreloadReplaceTextures(newMoveables, newStatics); } catch (TextureAtlasFullException) { logger.Error("Unable to preload wad because the texture atlas became too full!"); return; } // Create moveable models Parallel.ForEach(newMoveables, moveable => { var model = AnimatedModel.FromWadMoveable(GraphicsDevice, moveable, AllocateTexture); lock (Moveables) Moveables.Add(moveable, model); }); // Create static meshes Parallel.ForEach(newStatics, @static => { var model = new StaticModel(GraphicsDevice); model.Meshes.Add(ObjectMesh.FromWad2(GraphicsDevice, @static.Mesh, AllocateTexture)); model.UpdateBuffers(); lock (Statics) Statics.Add(@static, model); }); }
public static AnimatedModel FromWadMoveable(GraphicsDevice device, WadMoveable mov, Func <WadTexture, VectorInt2> allocateTexture) { AnimatedModel model = new AnimatedModel(device); List <WadBone> bones = mov.Bones; // Create meshes for (int m = 0; m < bones.Count; m++) { model.Meshes.Add(ObjectMesh.FromWad2(device, bones[m].Mesh, allocateTexture)); } // HACK: Add matrices here because if original WAD stack was corrupted, we could have broken parent - children // relations and so we could have meshes count different from matrices count for (int j = 0; j < bones.Count; j++) { model.BindPoseTransforms.Add(Matrix4x4.Identity); model.AnimationTransforms.Add(Matrix4x4.Identity); } // Build the skeleton model.Root = BuildSkeleton(model, null, bones); // Prepare animations for (int j = 0; j < mov.Animations.Count; j++) { model.Animations.Add(Animation.FromWad2(bones, mov.Animations[j])); } // Prepare data by loading the first valid animation and uploading data to the GPU model.BuildHierarchy(); if (model.Animations.Count > 0 && model.Animations.Any(a => a.KeyFrames.Count > 0)) { model.BuildAnimationPose(model.Animations.FirstOrDefault(a => a.KeyFrames.Count > 0)?.KeyFrames[0]); } model.UpdateBuffers(); return(model); }
public AnimatedModel GetMoveable(WadMoveable moveable, bool maybeRebuildAll = true) { // Check if the data is already loaded // If yes attempt to use that one AnimatedModel model; if (Moveables.TryGetValue(moveable, out model)) { if (model.Version >= moveable.Version) { return(model); } ReclaimTextureSpace(model); model.Dispose(); Moveables.Remove(moveable); } // The data is either new or has changed, unfortunately we need to reload it try { model = AnimatedModel.FromWadMoveable(GraphicsDevice, moveable, AllocateTexture); } catch (TextureAtlasFullException exc) { logger.Info(exc.Message); if (maybeRebuildAll) { logger.Info("Starting to rebuild the entire atlas."); Dispose(); return(GetMoveable(moveable, false)); } } Moveables.Add(moveable, model); return(model); }
private static Bone BuildSkeleton(AnimatedModel model, Bone parentBone, List <WadBone> bones) { model.Bones = new List <Bone>(); var stack = new Stack <Bone>(); for (int i = 0; i < bones.Count; i++) { var nb = new Bone(); nb.Name = bones[i].Name; nb.Pivot = bones[i].Translation; nb.Index = i; model.Bones.Add(nb); } var currentBone = model.Bones[0]; currentBone.Transform = Matrix4x4.Identity; currentBone.GlobalTransform = Matrix4x4.Identity; for (int j = 1; j < model.Bones.Count; j++) { int linkX = (int)bones[j].Translation.X; int linkY = (int)bones[j].Translation.Y; int linkZ = (int)bones[j].Translation.Z; switch (bones[j].OpCode) { case WadLinkOpcode.NotUseStack: model.Bones[j].Transform = Matrix4x4.CreateTranslation(linkX, linkY, linkZ); model.Bones[j].Parent = currentBone; currentBone.Children.Add(model.Bones[j]); currentBone = model.Bones[j]; break; case WadLinkOpcode.Pop: if (stack.Count <= 0) { continue; } currentBone = stack.Pop(); model.Bones[j].Transform = Matrix4x4.CreateTranslation(linkX, linkY, linkZ); model.Bones[j].Parent = currentBone; currentBone.Children.Add(model.Bones[j]); currentBone = model.Bones[j]; break; case WadLinkOpcode.Push: stack.Push(currentBone); model.Bones[j].Transform = Matrix4x4.CreateTranslation(linkX, linkY, linkZ); model.Bones[j].Parent = currentBone; currentBone.Children.Add(model.Bones[j]); currentBone = model.Bones[j]; break; case WadLinkOpcode.Read: if (stack.Count <= 0) { continue; } var bone = stack.Pop(); model.Bones[j].Transform = Matrix4x4.CreateTranslation(linkX, linkY, linkZ); model.Bones[j].Parent = bone; bone.Children.Add(model.Bones[j]); currentBone = model.Bones[j]; stack.Push(bone); break; } } return(model.Bones[0]); }