private void InitializeFoundFilesObjects(IEnumerable <string> paths) { FilesFound = new ModelFileData[paths.Count()]; for (int i = 0; i < paths.Count(); i++) { string path = paths.ElementAt(i); FilesFound[i] = new ModelFileData(path); } ReadyToCacheCheckList = new ConcurrentQueue <ModelFileData>(FilesFound); FilesToProcess = FilesFound.Length; }
public bool LoadDirectories(IEnumerable <string> paths) { IsLoading = false; MainDispatcher = Dispatcher.CurrentDispatcher; cancellationTokenSource = new CancellationTokenSource(); cancellationToken = cancellationTokenSource.Token; cache = DefaultFactory.GetDefaultThumbnailCache(); userSettings = DefaultFactory.GetDefaultUserSettings(); renderType = (RenderAspectEnum)userSettings.GetSettingInt(UserSettingEnum.Thumbnails3DAspect); logger.Info("Loading paths: Received: [{0}]", string.Join("] [", paths)); paths = paths.Where(p1 => !paths.Any(p2 => !p1.Equals(p2) && p1.Contains(p2))).ToArray(); // Remove selected subdirectories of other selected paths. logger.Info("Loading paths: After removed subdirs: [{0}]", string.Join("] [", paths)); try { IEnumerable <string> pathsFound = new List <string>(); for (int i = 0; i < SupportedExtensionsFilter.Length; i++) { foreach (string path in paths) { pathsFound = pathsFound.Concat(UtilMethods.EnumerateFiles(path, SupportedExtensionsFilter[i], SearchOption.AllDirectories, cancellationToken)); } } pathsFound = pathsFound.ToArray(); if (cancellationToken.IsCancellationRequested) { return(false); } if (pathsFound.Count() > 0) { CalculateThumnailSizes(pathsFound.Count()); InitializeFoundFilesObjects(pathsFound); return(true); } else { FilesFound = new ModelFileData[0]; } } catch (Exception ex) { logger.Trace(ex, "Unable to load: {ex}", ex.Message); } return(false); }
public View3D(HelixViewport3D viewport) { this.Viewport = viewport; _originalCameraPosition = new Point3D(100f, -100f, 135f); _modelCameraPosition = _originalCameraPosition; _modelHeightPosition = (float)(_originalCameraPosition.Z / 2d); viewport.Camera.UpDirection = new Vector3D(0, 0, 1); viewport.Camera.Position = _originalCameraPosition; viewport.Camera.LookDirection = new Vector3D(-1, 1, -1); Viewport.ShowCameraInfo = false; Viewport.ShowViewCube = false; Viewport.ShowCameraTarget = false; Viewport.ZoomAroundMouseDownPoint = false; Viewport.RotateAroundMouseDownPoint = false; Viewport.SnapMouseDownPoint = true; Viewport.FixedRotationPointEnabled = true; Viewport.FixedRotationPoint = new Point3D(0f, 0f, 30f); Viewport.IsZoomEnabled = false; Viewport.MouseWheel += Viewport_MouseWheel; Viewport.CameraChanged += Viewport_CameraChanged; Viewport.IsMoveEnabled = false; Viewport.IsPanEnabled = true; Viewport.IsManipulationEnabled = false; Viewport.IsHeadLightEnabled = false; Viewport.RotationSensitivity = 1; Viewport.ClipToBounds = true; Viewport.LimitFPS = true; Viewport.ShowFrameRate = false; Viewport.SubTitleSize = 18d; ModelAutoRotationEnabled = true; GridLinesVisual3D FloorGridLines; FloorGridLines = new GridLinesVisual3D(); FloorGridLines.Fill = Brushes.Gray; FloorGridLines.Width = 15000; FloorGridLines.Thickness = 1; FloorGridLines.Length = FloorGridLines.Width; FloorGridLines.MajorDistance = 100; FloorGridLines.MinorDistance = 10; FloorGridLines.Center = new Point3D(0, 0, 0); UpdateLights(); Viewport.Children.Add(FloorGridLines); Viewport.IsVisibleChanged += (sender, e) => { if (ModelDataToLoadWhenVisible != null && this.Viewport.IsVisible) { SetModel(ModelDataToLoadWhenVisible); ModelDataToLoadWhenVisible = null; } }; Viewport.SizeChanged += (sender, e) => { if (e.NewSize.Width < 5 && this.Viewport.IsVisible) { Viewport.Visibility = Visibility.Hidden; } else if (e.NewSize.Width >= 5 && !this.Viewport.IsVisible) { Viewport.Visibility = Visibility.Visible; } }; }
private void SetModelTask(ModelFileData modelData) { if (CurrentModelVisual != null) { this.Viewport.Children.Remove(CurrentModelVisual); CurrentModelVisual = null; GC.Collect(0, GCCollectionMode.Forced); } if (!this.Viewport.IsVisible) { this.ModelDataToLoadWhenVisible = modelData; return; } Model3DGroup modelGroup = new Model3DGroup(); ModelVisual3D modelVisual = new ModelVisual3D(); try { if (modelData != null) { ModelFileData newModelData = new ModelFileData(modelData.FileFullPath); this.ModelData = newModelData; Viewport.SubTitle = modelData.FileName; newModelData.LoadBasicFileData(); if (userSettings.GetSettingBool(UserSettingEnum.EnableMaxSizeMBToLoadMeshInView) && modelData.FileSizeMB > userSettings.GetSettingInt(UserSettingEnum.MaxSizeMBToLoadMeshInView)) { // TODO: Load generic model. Viewport.SubTitle = Loc.GetTextFormatted("FileSizeTooBigToLoadMB", modelData.FileSizeMB, userSettings.GetSettingInt(UserSettingEnum.MaxSizeMBToLoadMeshInView)); CurrentModelVisual = null; return; } if (!newModelData.HasBytes()) { newModelData.LoadFileBytes(newModelData.FileSizeMB < 50f); } if (newModelData.Mesh == null) { newModelData.ParseFile(); } newModelData.ReleaseData(true, false); if (newModelData.Mesh == null) { newModelData.ReleaseData(true, false); SetModel(null); return; } LoadModelInfoAvailableEvent?.Invoke(newModelData.FileName, newModelData.Mesh.TriangleCount, newModelData.Mesh.Vertices.Length, (int)newModelData.FileSizeKB); float modelScale = newModelData.Mesh.Scale / 4f; float modelScaleMultiply = (newModelData.Mesh.Scale < 0.001f ? 0.1f : (newModelData.Mesh.Scale > 0.1 ? 10f : 1)); var transformTranslate = new TranslateTransform3D(-newModelData.Mesh.OffsetX, -newModelData.Mesh.OffsetY, -newModelData.Mesh.OffsetZ); AxisAngleRotation3D axisRotation = new AxisAngleRotation3D(new Vector3D(0, 0, 1), 0); transformObjectRotation = new RotateTransform3D(axisRotation, new Point3D(newModelData.Mesh.OffsetX, newModelData.Mesh.OffsetY, 0)); ScaleTransform3D transformScale = new ScaleTransform3D(modelScaleMultiply, modelScaleMultiply, modelScaleMultiply); Transform3DGroup transforms = new Transform3DGroup(); transforms.Children.Add(transformObjectRotation); transforms.Children.Add(transformTranslate); transforms.Children.Add(transformScale); Mesh3D mesh; // Mesh decimation if enabled if (userSettings.GetSettingBool(UserSettingEnum.EnableMeshDecimation) && newModelData.Mesh.TriangleCount > userSettings.GetSettingInt(UserSettingEnum.MinTrianglesForMeshDecimation)) { MeshDecimator.Math.Vector3d[] vectors3D = newModelData.Mesh.Vertices.Select(v => new MeshDecimator.Math.Vector3d(v.x, v.y, v.z)).ToArray(); Mesh decimatorMesh = new Mesh(vectors3D, newModelData.Mesh.Triangles.ToArray()); Mesh decimatedMesh = MeshDecimation.DecimateMeshLossless(decimatorMesh); mesh = new Mesh3D(decimatedMesh.Vertices.Select(v => new Point3D(v.x, v.y, v.z)), decimatedMesh.Indices); // TODO: Possibly cache the decimated models to avoid re-processing. } else { mesh = new Mesh3D(Point3DFromLinearCoordinates(newModelData.Mesh.Vertices), newModelData.Mesh.Triangles); } GeometryModel3D geometryModel = new GeometryModel3D(mesh.ToMeshGeometry3D(), GetMaterial()); geometryModel.Freeze(); modelGroup.Children.Add(geometryModel); modelGroup.Freeze(); _modelHeightPosition = newModelData.Mesh.Height * modelScaleMultiply; newModelData.ReleaseData(true, true); // Animation if (ModelAutoRotationEnabled) { DoubleAnimation animation1 = new DoubleAnimation(-90, 395d, TimeSpan.FromMilliseconds(1000)); animation1.EasingFunction = new ExponentialEase(); DoubleAnimation animation2 = new DoubleAnimation(36d, 395d, TimeSpan.FromMilliseconds(7000)); animation2.RepeatBehavior = RepeatBehavior.Forever; animation1.Completed += (o, e) => axisRotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, animation2); axisRotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, animation1); } // Camera animation var nomalizedOriginalPosition = _originalCameraPosition.ToVector3D(); nomalizedOriginalPosition.Normalize(); _modelCameraPosition = new Point3D(nomalizedOriginalPosition.X / modelScale * modelScaleMultiply, nomalizedOriginalPosition.Y / modelScale * modelScaleMultiply, nomalizedOriginalPosition.Z / modelScale * modelScaleMultiply); Point3D targetCameraPosition = _modelCameraPosition; if (_CurrentCameraPosition == CameraPositionEnum.Default) { var normalizedPosition = Viewport.Camera.Position.ToVector3D(); normalizedPosition.Normalize(); targetCameraPosition = new Point3D(normalizedPosition.X / modelScale * modelScaleMultiply, normalizedPosition.Y / modelScale * modelScaleMultiply, normalizedPosition.Z / modelScale * modelScaleMultiply); Viewport.Camera.AnimateTo(targetCameraPosition, Viewport.Camera.LookDirection, Viewport.Camera.UpDirection, 500d); } else { ResetCamera(CameraPositionEnum.Current); } minZoom = targetCameraPosition.Multiply(0.5d).DistanceTo(new Point3D()); maxZoom = minZoom * 4d; this.CurrentAxisRotation = axisRotation; modelVisual.Transform = transforms; } modelVisual.Content = modelGroup; this.Viewport.Children.Add(modelVisual); this.CurrentModelVisual = modelVisual; } catch (Exception ex) { if (CurrentModelVisual != null) { this.Viewport.Children.Add(CurrentModelVisual); this.CurrentModelVisual = null; } } if (modelData == null) { _modelCameraPosition = _originalCameraPosition; ResetCamera(CameraPositionEnum.Default, true); LoadModelInfoAvailableEvent?.Invoke("", 0, 0, 0); _modelHeightPosition = (float)(_originalCameraPosition.Z / 2d); Viewport.SubTitle = string.Empty; } GC.Collect(); }
public void SetModel(ModelFileData modelData) { // TODO: Run in a cancellable task. SetModelTask(modelData); }
public void Load(System.IO.Stream stream) { DrawableContainer.Name = FileName; Renderer = new PunchOutWii_Renderer(); DrawableContainer.Drawables.Add(Renderer); Text = FileName; HeaderFile = new DictionaryFile(); HeaderFile.Read(new FileReader(stream), FilePath); var HashList = NLG_Common.HashNames; string DataFile = $"{FilePath.Replace(".dict", ".data")}"; if (System.IO.File.Exists(DataFile)) { using (var reader = new FileReader(DataFile, true)) { reader.SetByteOrder(true); TreeNode blocks = new TreeNode("Blocks"); TreeNode chunks = new TreeNode("Chunks"); TreeNode modelFolder = new TreeNode("Models"); foreach (var blockInfo in HeaderFile.Blocks) { ChunkViewer chunkNode = new ChunkViewer("block"); if (blockInfo.Size > 0) { blocks.Nodes.Add(chunkNode); } chunkNode.FileData = new SubStream(reader.BaseStream, blockInfo.Offset, blockInfo.Size); } List <PO_Texture> currentTextures = new List <PO_Texture>(); List <ModelFileData> modelData = new List <ModelFileData>(); ModelFileData currentModel = null; STTextureFolder textureFolder = new STTextureFolder("Textures"); Nodes.Add(blocks); Nodes.Add(chunks); Nodes.Add(textureFolder); Nodes.Add(modelFolder); foreach (var chunk in HeaderFile.DataChunks) { if (chunk.BlockIndex == -1) { continue; } ChunkViewer chunkNode = new ChunkViewer(chunk.Type.ToString("") + " " + chunk.Type.ToString("X")); chunks.Nodes.Add(chunkNode); var blockInfo = HeaderFile.Blocks[chunk.BlockIndex]; if (blockInfo.Offset + chunk.Offset + chunk.Size > reader.BaseStream.Length) { continue; } chunkNode.FileData = new SubStream(reader.BaseStream, blockInfo.Offset + chunk.Offset, chunk.Size); uint chunkPos = blockInfo.Offset + chunk.Offset; reader.SeekBegin(chunkPos); switch (chunk.Type) { case SectionMagic.MaterialData: currentModel = new ModelFileData(); currentModel.MaterialOffset = chunkPos; modelData.Add(currentModel); break; case SectionMagic.TextureHeaders: uint numTextures = chunk.Size / 96; for (int i = 0; i < numTextures; i++) { var tex = new PO_Texture(); tex.ImageKey = "texture"; tex.SelectedImageKey = "texture"; tex.Read(reader); tex.Text = tex.HashID.ToString("X"); if (HashList.ContainsKey(tex.HashID)) { tex.Text = HashList[tex.HashID]; } currentTextures.Add(tex); Renderer.TextureList.Add(tex.Text, tex); textureFolder.Nodes.Add(tex); } break; case SectionMagic.TextureData: for (int i = 0; i < currentTextures.Count; i++) { reader.SeekBegin(chunkPos + currentTextures[i].DataOffset); currentTextures[i].ImageData = reader.ReadBytes((int)currentTextures[i].ImageSize); } break; case SectionMagic.IndexData: currentModel.indexBufferOffset = chunkPos; break; case SectionMagic.VertexData: currentModel.vertexBufferOffset = chunkPos; break; case SectionMagic.MeshData: uint numMeshes = chunk.Size / 52; for (int i = 0; i < numMeshes; i++) { reader.SeekBegin(chunkPos + (i * 52)); PO_Mesh mesh = new PO_Mesh(reader); currentModel.meshes.Add(mesh); } break; case SectionMagic.VertexAttributePointerData: uint numAttributes = chunk.Size / 8; for (int i = 0; i < numAttributes; i++) { PO_VertexAttribute att = new PO_VertexAttribute(); att.Offset = reader.ReadUInt32(); att.Type = reader.ReadByte(); att.Stride = reader.ReadByte(); reader.ReadUInt16(); currentModel.attributes.Add(att); } break; case SectionMagic.ModelData: uint numModels = chunk.Size / 12; Console.WriteLine($"numModels {numModels}"); for (int i = 0; i < numModels; i++) { PO_Model mdl = new PO_Model(); mdl.ParentDictionary = this; mdl.HashID = reader.ReadUInt32(); mdl.NumMeshes = reader.ReadUInt32(); reader.ReadUInt32(); //0 currentModel.models.Add(mdl); } break; case SectionMagic.BoneData: STSkeleton Skeleton = new STSkeleton(); DrawableContainer.Drawables.Add(Skeleton); uint numBones = chunk.Size / 68; for (int i = 0; i < numBones; i++) { reader.SeekBegin(chunkPos + (i * 68)); uint HashID = reader.ReadUInt32(); reader.ReadUInt32(); //unk reader.ReadUInt32(); //unk reader.ReadUInt32(); //unk reader.ReadSingle(); //0 STBone bone = new STBone(Skeleton); var Scale = new OpenTK.Vector3( reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); reader.ReadSingle(); //0 bone.EulerRotation = new OpenTK.Vector3( reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); reader.ReadSingle(); //0 bone.Position = new OpenTK.Vector3( reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); reader.ReadSingle(); //1 bone.Text = HashID.ToString("X"); if (NLG_Common.HashNames.ContainsKey(HashID)) { bone.Text = NLG_Common.HashNames[HashID]; } else { Console.WriteLine($"bone hash {HashID}"); } bone.Scale = new Vector3(0.2f, 0.2f, 0.2f); bone.RotationType = STBone.BoneRotationType.Euler; Skeleton.bones.Add(bone); } Skeleton.reset(); Skeleton.update(); break; } } foreach (var modelFile in modelData) { int pointerIndex = 0; foreach (var model in modelFile.models) { model.Text = model.HashID.ToString("X"); if (HashList.ContainsKey(model.HashID)) { model.Text = HashList[model.HashID]; } modelFolder.Nodes.Add(model); for (int i = 0; i < model.NumMeshes; i++) { var mesh = modelFile.meshes[i]; RenderableMeshWrapper genericMesh = new RenderableMeshWrapper(); model.Nodes.Add(genericMesh); model.RenderedMeshes.Add(genericMesh); Renderer.Meshes.Add(genericMesh); genericMesh.Text = mesh.HashID.ToString("X"); if (HashList.ContainsKey(mesh.HashID)) { genericMesh.Text = HashList[mesh.HashID]; } string material = mesh.MaterialHashID.ToString("X"); if (HashList.ContainsKey(mesh.MaterialHashID)) { material = HashList[mesh.MaterialHashID]; } genericMesh.Nodes.Add(material); genericMesh.Material = new STGenericMaterial(); reader.SeekBegin(modelFile.MaterialOffset + mesh.MaterialOffset); switch (mesh.MaterailPreset) { case MaterailPresets.EnvDiffuseDamage: { uint diffuseMapHashID = reader.ReadUInt32(); uint diffuseMapParam = reader.ReadUInt32(); uint envSpecMapHashID = reader.ReadUInt32(); uint envSpecMapParam = reader.ReadUInt32(); uint specMapHashID = reader.ReadUInt32(); uint specMapParam = reader.ReadUInt32(); uint megaStrikeMapHashID = reader.ReadUInt32(); uint megaStrikeMapParam = reader.ReadUInt32(); uint dirtMapHashID = reader.ReadUInt32(); uint dirtMapParam = reader.ReadUInt32(); uint iceMapHashID = reader.ReadUInt32(); uint iceMapParam = reader.ReadUInt32(); string diffuseName = diffuseMapHashID.ToString("X"); if (HashList.ContainsKey(diffuseMapHashID)) { diffuseName = HashList[diffuseMapHashID]; } var texUnit = 1; genericMesh.Material.TextureMaps.Add(new STGenericMatTexture() { textureUnit = texUnit++, Type = STGenericMatTexture.TextureType.Diffuse, Name = diffuseName, }); } break; default: { uint diffuseMapHashID = reader.ReadUInt32(); string diffuseName = diffuseMapHashID.ToString("X"); if (HashList.ContainsKey(diffuseMapHashID)) { diffuseName = HashList[diffuseMapHashID]; } Console.WriteLine($"diffuseName {diffuseName}"); var texUnit = 1; genericMesh.Material.TextureMaps.Add(new STGenericMatTexture() { textureUnit = texUnit++, Type = STGenericMatTexture.TextureType.Diffuse, Name = diffuseName, }); } break; } Console.WriteLine($"mesh {i}"); STGenericPolygonGroup polyGroup = new STGenericPolygonGroup(); genericMesh.PolygonGroups.Add(polyGroup); reader.SeekBegin(modelFile.indexBufferOffset + mesh.IndexStartOffset); List <int> faces = new List <int>(); for (int f = 0; f < mesh.IndexCount; f++) { if (mesh.IndexFormat == 0) { polyGroup.faces.Add(reader.ReadUInt16()); } else { polyGroup.faces.Add(reader.ReadByte()); } } if (mesh.FaceType == PO_Mesh.PolygonType.TriangleStrips) { polyGroup.PrimativeType = STPrimitiveType.TrangleStrips; } else { polyGroup.PrimativeType = STPrimitiveType.Triangles; } for (int a = 0; a < mesh.NumAttributePointers; a++) { Console.WriteLine($"pointer {genericMesh.Text} { modelFile.vertexBufferOffset + modelFile.attributes[pointerIndex + a].Offset}"); } for (int v = 0; v < mesh.VertexCount; v++) { Vertex vert = new Vertex(); genericMesh.vertices.Add(vert); int attributeIndex = 0; for (int a = 0; a < mesh.NumAttributePointers; a++) { var pointer = modelFile.attributes[pointerIndex + a]; reader.SeekBegin(modelFile.vertexBufferOffset + pointer.Offset + (pointer.Stride * v)); if (attributeIndex == 0) { if (pointer.Stride == 12) { vert.pos = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } } if (attributeIndex == 1) { if (pointer.Stride == 12) { vert.nrm = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } } if (attributeIndex == 2) { if (pointer.Stride == 4) { vert.uv0 = new Vector2(reader.ReadUInt16() / 1024f, reader.ReadUInt16() / 1024f); } } /* if (pointer.Type == 0xD4) * { * vert.boneIds = new List<int>() { reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte() }; * } * if (pointer.Type == 0xB0) * { * vert.boneWeights = new List<float>() { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() }; * }*/ attributeIndex++; } } genericMesh.TransformPosition(new Vector3(0), new Vector3(-90, 0, 0), new Vector3(1)); pointerIndex += mesh.NumAttributePointers; } } } } } }