예제 #1
0
        public static List <WadMesh> ImportFromExternalModel(string fileName, IOGeometrySettings settings, bool mergeIntoOne)
        {
            IOModel tmpModel = null;
            var     meshList = new List <WadMesh>();

            bool calculateNormals = false;

            // Import the model
            try
            {
                var importer = BaseGeometryImporter.CreateForFile(fileName, settings, absoluteTexturePath =>
                {
                    return(new WadTexture(ImageC.FromFile(absoluteTexturePath)));
                });
                tmpModel = importer.ImportFromFile(fileName);

                calculateNormals = importer is MetasequoiaImporter;
            }
            catch (Exception ex)
            {
                logger.Error(ex, "Geometry import failed!");
                return(null);
            }

            // Create a new mesh (all meshes from model will be joined)
            WadMesh mesh           = null;
            var     lastBaseVertex = 0;

            for (int i = 0; i < tmpModel.Meshes.Count; i++)
            {
                var tmpMesh = tmpModel.Meshes[i];

                if (mesh == null || !mergeIntoOne)
                {
                    mesh      = new WadMesh();
                    mesh.Name = string.IsNullOrEmpty(tmpMesh.Name) ? "ImportedMesh" + i : tmpMesh.Name;

                    if (mergeIntoOne)
                    {
                        lastBaseVertex = 0;               // Reset if we're doing multi-mesh import
                    }
                }

                mesh.VerticesPositions.AddRange(tmpMesh.Positions);

                // Copy normals as well, if they are consistent
                if (tmpMesh.Normals.Count == tmpMesh.Positions.Count)
                {
                    mesh.VerticesNormals.AddRange(tmpMesh.Normals);
                }

                // FIXME: Why do we keep white intensity shades for wad2 meshes internally, and not vertex colors?
                if (tmpMesh.Colors.Count == tmpMesh.Positions.Count)
                {
                    mesh.VerticesShades.AddRange(tmpMesh.Colors.Select(v => (short)(8191.0f - (v.To3().GetLuma() * 8191.0f))));
                }

                foreach (var tmpSubmesh in tmpMesh.Submeshes)
                {
                    foreach (var tmpPoly in tmpSubmesh.Value.Polygons)
                    {
                        if (tmpPoly.Shape == IOPolygonShape.Quad)
                        {
                            var poly = new WadPolygon {
                                Shape = WadPolygonShape.Quad
                            };
                            poly.Index0 = tmpPoly.Indices[0] + lastBaseVertex;
                            poly.Index1 = tmpPoly.Indices[1] + lastBaseVertex;
                            poly.Index2 = tmpPoly.Indices[2] + lastBaseVertex;
                            poly.Index3 = tmpPoly.Indices[3] + lastBaseVertex;

                            var area = new TextureArea();
                            area.TexCoord0   = tmpMesh.UV[tmpPoly.Indices[0]];
                            area.TexCoord1   = tmpMesh.UV[tmpPoly.Indices[1]];
                            area.TexCoord2   = tmpMesh.UV[tmpPoly.Indices[2]];
                            area.TexCoord3   = tmpMesh.UV[tmpPoly.Indices[3]];
                            area.Texture     = tmpSubmesh.Value.Material.Texture;
                            area.DoubleSided = tmpSubmesh.Value.Material.DoubleSided;

                            poly.Texture       = area;
                            poly.ShineStrength = (byte)Math.Round(tmpSubmesh.Value.Material.Shininess / 16.0f, MidpointRounding.ToEven);

                            mesh.Polys.Add(poly);
                        }
                        else
                        {
                            var poly = new WadPolygon {
                                Shape = WadPolygonShape.Triangle
                            };
                            poly.Index0 = tmpPoly.Indices[0] + lastBaseVertex;
                            poly.Index1 = tmpPoly.Indices[1] + lastBaseVertex;
                            poly.Index2 = tmpPoly.Indices[2] + lastBaseVertex;

                            var area = new TextureArea();
                            area.TexCoord0   = tmpMesh.UV[tmpPoly.Indices[0]];
                            area.TexCoord1   = tmpMesh.UV[tmpPoly.Indices[1]];
                            area.TexCoord2   = tmpMesh.UV[tmpPoly.Indices[2]];
                            area.TexCoord3   = area.TexCoord2;
                            area.Texture     = tmpSubmesh.Value.Material.Texture;
                            area.DoubleSided = tmpSubmesh.Value.Material.DoubleSided;

                            poly.Texture       = area;
                            poly.ShineStrength = (byte)Math.Round(tmpSubmesh.Value.Material.Shininess / 16.0f, MidpointRounding.ToEven);

                            mesh.Polys.Add(poly);
                        }
                    }
                }

                if (!mergeIntoOne || i == tmpModel.Meshes.Count - 1)
                {
                    mesh.BoundingBox    = mesh.CalculateBoundingBox();
                    mesh.BoundingSphere = mesh.CalculateBoundingSphere();

                    if (mesh.VerticesNormals.Count == 0 || calculateNormals)
                    {
                        mesh.CalculateNormals(); // MQO files rarely have normals
                    }
                    if (mesh.VerticesPositions.Count != mesh.VerticesShades.Count)
                    {
                        mesh.VerticesShades.Clear(); // Reset vertex shades in case they got desynced from vertex count
                    }
                    lastBaseVertex = 0;
                    meshList.Add(mesh);
                }
                else
                {
                    lastBaseVertex = mesh.VerticesPositions.Count;
                }
            }

            return(meshList);
        }
예제 #2
0
        public static WadAnimation ImportAnimationFromModel(WadToolClass tool, IWin32Window owner, int nodeCount, string fileName)
        {
            IOModel tmpModel = null;

            // Import the model
            try
            {
                var settings = new IOGeometrySettings()
                {
                    ProcessAnimations = true, ProcessGeometry = false
                };
                using (var form = new GeometryIOSettingsDialog(settings))
                {
                    form.AddPreset(IOSettingsPresets.AnimationSettingsPresets);
                    string resultingExtension = Path.GetExtension(fileName).ToLowerInvariant();

                    if (resultingExtension.Equals(".fbx"))
                    {
                        form.SelectPreset("3dsmax Filmbox (FBX)");
                    }
                    else if (resultingExtension.Equals(".dae"))
                    {
                        form.SelectPreset("3dsmax COLLADA");
                    }

                    if (form.ShowDialog(owner) != DialogResult.OK)
                    {
                        return(null);
                    }

                    var importer = BaseGeometryImporter.CreateForFile(fileName, settings, null);
                    tmpModel = importer.ImportFromFile(fileName);

                    // We don't support animation importing from custom-written mqo importer yet...
                    if (importer is MetasequoiaImporter)
                    {
                        tool.SendMessage("Metasequoia importer isn't currently supported.", PopupType.Error);
                        return(null);
                    }

                    // If no animations, return null
                    if (tmpModel.Animations.Count == 0)
                    {
                        tool.SendMessage("Selected file has no supported animations!", PopupType.Error);
                        return(null);
                    }
                }
            }
            catch (Exception ex)
            {
                tool.SendMessage("Unknown error while importing animation. \n" + ex?.Message, PopupType.Error);
                logger.Warn(ex, "'ImportAnimationFromModel' failed.");
                return(null);
            }

            IOAnimation animToImport;

            if (tmpModel.Animations.Count > 1)
            {
                using (var dialog = new AnimationImportDialog(tmpModel.Animations.Select(o => o.Name).ToList()))
                {
                    dialog.ShowDialog(owner);
                    if (dialog.DialogResult == DialogResult.Cancel)
                    {
                        return(null);
                    }
                    else
                    {
                        animToImport = tmpModel.Animations[dialog.AnimationToImport];
                    }
                }
            }
            else
            {
                animToImport = tmpModel.Animations[0];
            }


            // Integrity check, for cases when something totally went wrong with assimp
            if (animToImport == null)
            {
                tool.SendMessage("Animation importer encountered serious error. No animation imported.", PopupType.Error);
                return(null);
            }

            // Integrity check, is there any valid frames?
            if (animToImport.Frames.Count <= 0)
            {
                tool.SendMessage("Selected animation has no frames!", PopupType.Error);
                return(null);
            }

            // Integrity check, number of bones = number of nodes?
            if (animToImport.NumNodes != nodeCount)
            {
                tool.SendMessage("Selected animation has different number of bones!", PopupType.Error);
                return(null);
            }

            WadAnimation animation = new WadAnimation();

            animation.Name = animToImport.Name;

            foreach (var frame in animToImport.Frames)
            {
                var keyFrame = new WadKeyFrame();
                keyFrame.Offset = frame.Offset;
                frame.Angles.ForEach(angle => keyFrame.Angles.Add(new WadKeyFrameRotation()
                {
                    Rotations = angle
                }));

                animation.KeyFrames.Add(keyFrame);
            }

            animation.EndFrame = (ushort)(animToImport.Frames.Count - 1);

            return(animation);
        }
예제 #3
0
        public void Update(LevelSettings settings, Dictionary <string, Texture> absolutePathTextureLookup, ImportedGeometryInfo info)
        {
            Info          = info;
            LoadException = null;
            DirectXModel  = null;
            Textures.Clear();

            try
            {
                string importedGeometryPath      = settings.MakeAbsolute(info.Path);
                string importedGeometryDirectory = Path.GetDirectoryName(importedGeometryPath);

                // Invoke the TombLib geometry import code
                var settingsIO = new IOGeometrySettings
                {
                    Scale          = info.Scale,
                    SwapXY         = info.SwapXY,
                    SwapXZ         = info.SwapXZ,
                    SwapYZ         = info.SwapYZ,
                    FlipX          = info.FlipX,
                    FlipY          = info.FlipY,
                    FlipZ          = info.FlipZ,
                    FlipUV_V       = info.FlipUV_V,
                    InvertFaces    = info.InvertFaces,
                    UseVertexColor = true
                };

                BaseGeometryImporter importer = BaseGeometryImporter.CreateForFile(importedGeometryPath, settingsIO, absoluteTexturePath =>
                {
                    return(GetOrAddTexture(absolutePathTextureLookup, importedGeometryDirectory, absoluteTexturePath));
                });
                var tmpModel = importer.ImportFromFile(importedGeometryPath);

                SynchronizationContext.Current.Post(unused => // Synchronize DirectX, we can't 'send' because that may deadlock with the level settings reloader
                {
                    if (Device == null)
                    {
                        return;
                    }

                    // Create a new static model
                    DirectXModel             = new Model(Device, info.Scale);
                    DirectXModel.BoundingBox = tmpModel.BoundingBox;

                    // Create materials
                    foreach (var tmpMaterial in tmpModel.Materials)
                    {
                        var material              = new Material(tmpMaterial.Name);
                        material.Texture          = tmpMaterial.Texture;
                        material.AdditiveBlending = tmpMaterial.AdditiveBlending;
                        material.DoubleSided      = tmpMaterial.DoubleSided;
                        DirectXModel.Materials.Add(material);
                    }

                    // Loop for each mesh loaded in scene
                    foreach (var mesh in tmpModel.Meshes)
                    {
                        var modelMesh = new ImportedGeometryMesh(Device, mesh.Name);

                        modelMesh.HasVertexColors = (mesh.Colors.Count != 0);

                        var currentIndex = 0;
                        var currPoly     = 0;
                        foreach (var tmpSubmesh in mesh.Submeshes)
                        {
                            var material = DirectXModel.Materials[tmpModel.Materials.IndexOf(tmpSubmesh.Value.Material)];
                            var submesh  = new Submesh(material);

                            foreach (var tmpPoly in tmpSubmesh.Value.Polygons)
                            {
                                if (tmpPoly.Shape == IOPolygonShape.Quad)
                                {
                                    var vertexList = new List <ImportedGeometryVertex>();

                                    for (var i = 0; i < 4; i++)
                                    {
                                        var vertex      = new ImportedGeometryVertex();
                                        vertex.Position = mesh.Positions[tmpPoly.Indices[i]];
                                        vertex.Color    = tmpPoly.Indices[i] < mesh.Colors.Count ? mesh.Colors[tmpPoly.Indices[i]].To3() : Vector3.One;
                                        vertex.UV       = tmpPoly.Indices[i] < mesh.UV.Count ? mesh.UV[tmpPoly.Indices[i]] : Vector2.Zero;
                                        vertex.Normal   = tmpPoly.Indices[i] < mesh.Normals.Count ? mesh.Normals[tmpPoly.Indices[i]] : Vector3.Zero;
                                        vertexList.Add(vertex);
                                    }

                                    // HACK: Triangulate and disjoint quad faces for imported geometry, because otherwise another hack which joints
                                    // disjointed vertices together will fail in Rooms.cs

                                    submesh.Indices.Add(currentIndex);
                                    submesh.Indices.Add(currentIndex + 1);
                                    submesh.Indices.Add(currentIndex + 2);
                                    submesh.Indices.Add(currentIndex + 3);
                                    submesh.Indices.Add(currentIndex + 4);
                                    submesh.Indices.Add(currentIndex + 5);

                                    modelMesh.Vertices.Add(vertexList[0]);
                                    modelMesh.Vertices.Add(vertexList[1]);
                                    modelMesh.Vertices.Add(vertexList[2]);
                                    modelMesh.Vertices.Add(vertexList[0]);
                                    modelMesh.Vertices.Add(vertexList[2]);
                                    modelMesh.Vertices.Add(vertexList[3]);

                                    currentIndex += 6;
                                }
                                else
                                {
                                    for (var i = 0; i < 3; i++)
                                    {
                                        var vertex      = new ImportedGeometryVertex();
                                        vertex.Position = mesh.Positions[tmpPoly.Indices[i]];
                                        vertex.Color    = tmpPoly.Indices[i] < mesh.Colors.Count ? mesh.Colors[tmpPoly.Indices[i]].To3() : Vector3.One;
                                        vertex.UV       = tmpPoly.Indices[i] < mesh.UV.Count ? mesh.UV[tmpPoly.Indices[i]] : Vector2.Zero;
                                        vertex.Normal   = tmpPoly.Indices[i] < mesh.Normals.Count ? mesh.Normals[tmpPoly.Indices[i]] : Vector3.Zero;
                                        modelMesh.Vertices.Add(vertex);
                                        submesh.Indices.Add(currentIndex);
                                        currentIndex++;
                                    }
                                }

                                currPoly++;
                            }

                            modelMesh.Submeshes.Add(material, submesh);
                        }

                        DirectXModel.Meshes.Add(modelMesh);
                    }

                    DirectXModel.UpdateBuffers();
                }, null);
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            catch (Exception exc)
            {
                LoadException = exc;
                DirectXModel  = null;
                logger.Warn(exc, "Unable to load model \"" + info.Name + "\" from \"" + info.Path + "\" because an exception occurred during loading.");
            }
        }