Beispiel #1
0
        private void    ConvertMap(string _SourceFileName, string _TargetFileName)
        {
            idTech5Map.Map Map = new idTech5Map.Map(_SourceFileName);

            // Convert
            GCXFormat.Scene Scene = new GCXFormat.Scene(Map);

            // Save
            using (FileStream S = new FileInfo(_TargetFileName).Create())
                using (BinaryWriter W = new BinaryWriter(S))
                    Scene.Save(W);

            // Update log
            int MeshesCount   = 0;
            int LightsCount   = 0;
            int CamerasCount  = 0;
            int ProbesCount   = 0;
            int GenericsCount = 0;

            foreach (GCXFormat.Scene.Node Node in Scene.m_Nodes)
            {
                switch (Node.m_Type)
                {
                case GCXFormat.Scene.Node.TYPE.MESH: MeshesCount++; break;

                case GCXFormat.Scene.Node.TYPE.LIGHT: LightsCount++; break;

                case GCXFormat.Scene.Node.TYPE.CAMERA: CamerasCount++; break;

                case GCXFormat.Scene.Node.TYPE.PROBE: ProbesCount++; break;

                case GCXFormat.Scene.Node.TYPE.GENERIC: GenericsCount++; break;
                }
            }

            string TextTextures  = "";
            int    TexturesCount = 0;
//          foreach ( GCXFormat.Scene.Material Material in Scene.m_Materials ) {
//              if ( Material.m_DiffuseTextureID )
//          }

            string Text = "Nodes count: " + Scene.m_Nodes.Count + "\r\n"
                          + "	> Meshes count: "+ MeshesCount + "\r\n"
                          + "	> Lights count: "+ LightsCount + "\r\n"
                          + "	> Cameras count: "+ CamerasCount + "\r\n"
                          + "	> Probes count: "+ ProbesCount + "\r\n"
                          + "	> Generics count: "+ GenericsCount + "\r\n"
                          + "\r\n"
                          + "Total vertices: " + Scene.m_TotalVerticesCount + " - Total faces: " + Scene.m_TotalFacesCount + "\r\n"
                          + "\r\n"
                          + "Materials count: " + Scene.m_Materials.Count + "\r\n"
                          + "Textures count: " + TexturesCount + "\r\n"
                          + TextTextures;

            textBoxLog.Text = Text;
        }
Beispiel #2
0
        private void ConvertMap( string _SourceFileName, string _TargetFileName )
        {
            idTech5Map.Map	Map = new idTech5Map.Map( _SourceFileName );

            // Convert
            GCXFormat.Scene	Scene = new GCXFormat.Scene( Map );

            // Save
            using ( FileStream S = new FileInfo( _TargetFileName ).Create() )
                using ( BinaryWriter W = new BinaryWriter( S ) )
                    Scene.Save( W );

            // Update log
            int	MeshesCount = 0;
            int	LightsCount = 0;
            int	CamerasCount = 0;
            int	ProbesCount = 0;
            int	GenericsCount = 0;
            foreach ( GCXFormat.Scene.Node Node in Scene.m_Nodes )
            {
                switch ( Node.m_Type ) {
                    case GCXFormat.Scene.Node.TYPE.MESH: MeshesCount++; break;
                    case GCXFormat.Scene.Node.TYPE.LIGHT: LightsCount++; break;
                    case GCXFormat.Scene.Node.TYPE.CAMERA: CamerasCount++; break;
                    case GCXFormat.Scene.Node.TYPE.PROBE: ProbesCount++; break;
                    case GCXFormat.Scene.Node.TYPE.GENERIC: GenericsCount++; break;
                }
            }

            string		TextTextures = "";
            int			TexturesCount = 0;
            // 			foreach ( GCXFormat.Scene.Material Material in Scene.m_Materials ) {
            // 				if ( Material.m_DiffuseTextureID )
            // 			}

            string	Text = "Nodes count: " + Scene.m_Nodes.Count + "\r\n"
                        + "	> Meshes count: " + MeshesCount + "\r\n"
                        + "	> Lights count: " + LightsCount + "\r\n"
                        + "	> Cameras count: " + CamerasCount + "\r\n"
                        + "	> Probes count: " + ProbesCount + "\r\n"
                        + "	> Generics count: " + GenericsCount + "\r\n"
                        + "\r\n"
                        + "Total vertices: " + Scene.m_TotalVerticesCount + " - Total faces: " + Scene.m_TotalFacesCount + "\r\n"
                        + "\r\n"
                        + "Materials count: " + Scene.m_Materials.Count + "\r\n"
                        + "Textures count: " + TexturesCount + "\r\n"
                        + TextTextures;
            textBoxLog.Text = Text;
        }
Beispiel #3
0
        /// <summary>
        /// Loads a FBX scene and converts it (in the same folder) into its GCX equivalent
        /// </summary>
        /// <param name="_File"></param>
        public void LoadScene( FileInfo _SourceFile, FileInfo _TargetFile )
        {
            FBX.SceneLoader.SceneLoader	Loader = new FBX.SceneLoader.SceneLoader();

            FBX.SceneLoader.MaterialsDatabase	Materials = new FBX.SceneLoader.MaterialsDatabase();
            //			Materials.BuildFromM2( new DirectoryInfo( @"D:\Workspaces\Arkane\m2" ) );

            FBX.Scene.Scene	Scene = new FBX.Scene.Scene();
            Loader.Load( _SourceFile, Scene, 1.0f, Materials );

            // Start writing
            //			FileInfo	Target = new FileInfo( Path.Combine( Path.GetDirectoryName( _SourceFile.FullName ), Path.GetFileNameWithoutExtension( _SourceFile.FullName ) + ".gcx" ) );
            using ( FileStream S = _TargetFile.OpenWrite() )
                using ( BinaryWriter W = new BinaryWriter( S ) )
                {
                    GCXFormat.Scene	GCX = new GCXFormat.Scene( Scene );
                    GCX.Save( W );
                }

            // Write infos
            List<string>	Infos = new List<string>();
            Infos.Add( "Textures:" );
            foreach ( FBX.Scene.Materials.Texture2D Texture in Scene.Textures )
                Infos.Add( "ID #" + Texture.ID.ToString( "D3" ) + " URL=" + Texture.URL );
            Infos.Add( "" );

            // Here, I write an array mapping texture IDs to names, assuming textures have been converted to POM format using PNG2POM (or HDR2POM)
            // This way I can simply copy this "code friendly" list and paste it in my C++ code (e.g. const char* ppID2TextureName[] = { PasteHere }; )
            Infos.Add( "Texture Flat Names:" );
            Infos.Add( "" );
            string	DirectoryHeader = Path.GetDirectoryName( _SourceFile.ToString() );
            DirectoryHeader = DirectoryHeader.Replace( "\\", "\\\\" );	// Double antislashes
            foreach ( FBX.Scene.Materials.Texture2D Texture in Scene.Textures )
            //				Infos.Add( "ID #" + Texture.ID.ToString( "D3" ) + " URL=" + Path.GetFileNameWithoutExtension( Texture.URL ) );
                Infos.Add( "\"" + DirectoryHeader + @"\\TexturesPOM\\" + Path.GetFileNameWithoutExtension( Texture.URL ) + ".pom\"," );
            Infos.Add( "" );

            Infos.Add( "=============================" );
            Infos.Add( "Materials:" );
            foreach ( FBX.Scene.Materials.MaterialParameters Mat in Scene.MaterialParameters )
                Infos.Add( "ID #" + Mat.ID + " => " + Mat.Name + " (shader=" + Mat.ShaderURL + ")" );
            Infos.Add( "" );

            Infos.Add( "=============================" );
            Infos.Add( "Meshes:" );
            foreach ( FBX.Scene.Nodes.Mesh Mesh in Scene.Meshes )
                Infos.Add( "ID #" + Mesh.ID + " => " + Mesh.Name + " (primsCount=" + Mesh.PrimitivesCount + ")" );
            Infos.Add( "" );

            Infos.Add( "=============================" );
            Infos.Add( "Lights:" );
            foreach ( FBX.Scene.Nodes.Light Light in Scene.Lights )
                Infos.Add( "ID #" + Light.ID + " => " + Light.Name + " (type=" + Light.Type + ")" );
            Infos.Add( "" );

            Infos.Add( "=============================" );
            Infos.Add( "Cameras:" );
            foreach ( FBX.Scene.Nodes.Camera Camera in Scene.Cameras )
                Infos.Add( "ID #" + Camera.ID + " => " + Camera.Name + " (FOV=" + (Camera.FOV * 180.0f / Math.PI) + ")" );
            Infos.Add( "" );

            if ( Materials != null )
            {
                FBX.SceneLoader.MaterialsDatabase.Material[]	QueriedMaterials = Materials.QueriedMaterials;

                List<string>	QueriedTextures = new List<string>();

                // Here I'm generating the XCOPY batch commands to copy original textures from a complex directory structure
                //	into a flattened directory where they'll further be converted into POM files using PNG2POM
                Infos.Add( "=============================" );
                Infos.Add( "Queried database materials:" );
                foreach ( FBX.SceneLoader.MaterialsDatabase.Material M in QueriedMaterials )
                {
                    Infos.Add( M.Name );

                    if ( M.TextureDiffuse != null )
                        QueriedTextures.Add( "xcopy \"" + M.TextureDiffuse.Replace( '/', '\\' ) + "\" \"..\\POMTextures\\\" /Y/U/S" );
                    if ( M.TextureNormal != null )
                        QueriedTextures.Add( "xcopy \"" + M.TextureNormal.Replace( '/', '\\' ) + "\" \"..\\POMTextures\\\" /Y/U/S" );
                    if ( M.TextureSpecular != null )
                        QueriedTextures.Add( "xcopy \"" + M.TextureSpecular.Replace( '/', '\\' ) + "\" \"..\\POMTextures\\\" /Y/U/S" );
                }
                Infos.Add( "" );

                Infos.Add( "=============================" );
                Infos.Add( "Queried textures:" );
                Infos.AddRange( QueriedTextures );

            }

            textBoxReport.Lines = Infos.ToArray();
        }
Beispiel #4
0
        /// <summary>
        /// This tool builds the additional vertex stream for each primitive that will attach the best probe ID (as a U16)
        ///  to a vertex so the vertex shader has a single entry point into the probes network
        /// Most face indices have already been rendered in the probe cube map and the batch processing tool took care of
        ///  selecting the most important probe for these faces, but some faces don't have probe information.
        ///  Maybe they have been occluded by other faces (shadowing) or are too small to be rendered in the cube map.
        /// For these special faces, we need to propagate probe IDs from valid faces until the entire mesh is filled with
        ///  valid probe IDs.
        /// 
        /// We proceed primitive per primitive since they are all disconnected so no propagation would be possible cross
        ///  primitives unless we could reconnect split vertices, but I don't want to do that. Maybe it will become necessary
        ///  at some point but for the moment I don't care.
        /// Some primitives may lack probe ID completely (!!), for these I choose to assign the ID of the nearest probe, which
        ///  may be a bit dangerous, especially if we're dealing with probes that are standing right behind the primitive for example.
        /// In that case, perhaps using a scoring scheme that depends on both distance and orientation would be better? Let's see that when the problem arises...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void encodeFaceProbesToolStripMenuItem_Click( object sender, EventArgs e )
        {
            // Ask for the influence file to load from
            string	OldFileName = GetRegKey( "LastProbeInfluenceFileName", GetRegKey( "LastProbesFolderTarget", Path.GetDirectoryName( m_ApplicationPath ) ) );
            openFileDialogProbeInfluence.InitialDirectory = Path.GetDirectoryName( OldFileName );
            openFileDialogProbeInfluence.FileName = Path.GetFileName( OldFileName );
            if ( openFileDialogProbeInfluence.ShowDialog( this ) != DialogResult.OK )
                return;
            SetRegKey( "LastProbeInfluenceFileName", openFileDialogProbeInfluence.FileName );

            FileInfo	SourceInfluenceFile = new FileInfo( openFileDialogProbeInfluence.FileName );

            // Ask for the scene file to apply to
            string	OldSceneFile = GetRegKey( "LastSceneFileName", GetRegKey( "LastProbesFolderSource", Path.GetDirectoryName( m_ApplicationPath ) ) );
            openFileDialogScene.InitialDirectory = Path.GetDirectoryName( OldSceneFile );
            openFileDialogScene.FileName = Path.GetFileName( OldSceneFile );
            if ( openFileDialogScene.ShowDialog( this ) != DialogResult.OK )
                return;
            SetRegKey( "LastSceneFileName", openFileDialogScene.FileName );

            FileInfo	SceneFile = new FileInfo( openFileDialogScene.FileName );

            try
            {
                // Read the scene file
                GCXFormat.Scene	GCX = null;
                using ( FileStream S = SceneFile.OpenRead() )
                    using( BinaryReader R = new BinaryReader( S ) )
                        GCX = new GCXFormat.Scene( R );

                // Read the probe influences
                ProbeInfluence[]	FaceInfluences = new ProbeInfluence[GCX.m_TotalFacesCount];
                using ( FileStream S = SourceInfluenceFile.OpenRead() )
                    using( BinaryReader R = new BinaryReader( S ) )
                    {
                        int	SizeofProbeInfluence = System.Runtime.InteropServices.Marshal.SizeOf(typeof(UInt32)) + System.Runtime.InteropServices.Marshal.SizeOf(typeof(double));
                        int	FacesCount = (int) S.Length / SizeofProbeInfluence;
                        if ( (S.Length % SizeofProbeInfluence) != 0 )
                            throw new Exception( "Probe influence file is larger than an integer number of ProbeInfluence structures!" );

                        for ( int FaceIndex=0; FaceIndex < FacesCount; FaceIndex++ )
                        {
                            UInt32	ProbeID = R.ReadUInt32();
                            double	Importance = R.ReadDouble();
                            FaceInfluences[FaceIndex] = new ProbeInfluence() { ProbeID = ProbeID, Importance = Importance };
                        }
                        for ( int FaceIndex=FacesCount; FaceIndex < GCX.m_TotalFacesCount; FaceIndex++ )
                            FaceInfluences[FaceIndex] = new ProbeInfluence() { ProbeID = ProbeInfluence.INVALID_PROBEID, Importance = 0.0 };
                    }

                UInt32[]	VertexStreamProbeID = new UInt32[GCX.m_TotalVerticesCount];	// The final vertex stream we're building

                // Establish data for progress measurement
                int	PrimitivesCount = 0;
                foreach ( GCXFormat.Scene.Node N in GCX.m_Nodes )
                {
                    GCXFormat.Scene.Mesh	M = N as GCXFormat.Scene.Mesh;
                    if ( M != null )
                        PrimitivesCount += M.m_Primitives.Length;
                }

                //////////////////////////////////////////////////////////////////////////
                // The algorithm is quite simple:
                //	For each primitive
                //		Create a winged edge structure for each face
                //		Assign known probe influence to each face
                //		Build a list of faces without probe influence
                //
                //		While list is not empty and its size keeps decreasing
                //			For each face without influence
                //				If neighbor faces have influence information
                //					Copy best influence from neighbor
                //					Remove face from the list
                //
                //		If list is not empty			// We have a bunch of disconnected faces that can't see any probe
                //			For each face of the list
                //				Assign [NO PROBE|NEAREST PROBE|WORLD PROBE] ? (not clear yet which is best)
                //
                //		Redistribute best probe's ID to each face vertex
                //
                //	Save stream of vertex probe IDs to be merged into an additional vertex buffer stream at runtime
                //
                int	MeshIndex = 0;
                int	PrimitiveIndex = 0;
                int	FacesWithoutProbeCount = 0;
                int	PrimitivesWithoutProbeCount = 0;
                string	Errors = "";

                progressBarBatchConvert.Value = 0;
                progressBarBatchConvert.Visible = true;
                progressBarSubTask.Value = 0;
                progressBarSubTask.Visible = true;

                foreach ( GCXFormat.Scene.Node N in GCX.m_Nodes )
                {
                    GCXFormat.Scene.Mesh	M = N as GCXFormat.Scene.Mesh;
                    if ( M == null )
                        continue;

                    foreach ( GCXFormat.Scene.Mesh.Primitive P in M.m_Primitives )
                    {
                        int	FacesCount = P.m_Faces.Length;

                        try
                        {
                            P.BuildWingedEdgesMesh();
                        }
                        catch ( Exception _e )
                        {
                            Errors += "Primitive #" + PrimitiveIndex + " of mesh #" + MeshIndex + " has generated an error on Winged Mesh generation: " + _e.Message + "\r\n";

                            // Add this primitve to the list of the ones m
                            PrimitivesWithoutProbeCount++;
                            FacesWithoutProbeCount += P.m_Vertices.Length;
                            continue;
                        }

                        // Update progress
                        progressBarBatchConvert.Value = progressBarBatchConvert.Maximum * (++PrimitiveIndex) / PrimitivesCount;
                        progressBarSubTask.Value = 0;

                        // Tag winged edge faces with probe influence & list faces without valid probe ID
                        List<GCXFormat.Scene.Mesh.Primitive.WingedEdgeTriangle>	MissingProbeIDFaces = new List<GCXFormat.Scene.Mesh.Primitive.WingedEdgeTriangle>( FacesCount );
                        for ( int FaceIndex=0; FaceIndex < FacesCount; FaceIndex++ )
                        {
                            ProbeInfluence	Influence = FaceInfluences[P.m_FaceOffset+FaceIndex];
                            GCXFormat.Scene.Mesh.Primitive.WingedEdgeTriangle	Face = P.m_WingedEdgeFaces[FaceIndex];
                            Face.m_Tag = Influence;
                            if ( Influence.ProbeID == ProbeInfluence.INVALID_PROBEID )
                                MissingProbeIDFaces.Add( Face );
                        }

                        // Propagate probe influence
                        int	OriginalCount = MissingProbeIDFaces.Count;
                        int	LastListSize = MissingProbeIDFaces.Count+1;
                        while ( MissingProbeIDFaces.Count > 0 && MissingProbeIDFaces.Count < LastListSize )
                        {
                            LastListSize = MissingProbeIDFaces.Count;	// Keep track of list's size so we know if anything moved
                            for ( int FaceIndex=MissingProbeIDFaces.Count-1; FaceIndex >= 0; FaceIndex-- )	// Browse backward so we can safely remove elements from the list
                            {
                                GCXFormat.Scene.Mesh.Primitive.WingedEdgeTriangle	Face = MissingProbeIDFaces[FaceIndex];

                                // Examine neighbors' probe influence and propagate best probe
                                ProbeInfluence	BestProbe = null;
                                for ( int EdgeIndex=0; EdgeIndex < 3; EdgeIndex++ )
                                {
                                    int	NeighborFaceIndex = Face.m_Edges[EdgeIndex].GetOtherFaceIndex( Face.m_Index );
                                    if ( NeighborFaceIndex != -1 )
                                    {
                                        GCXFormat.Scene.Mesh.Primitive.WingedEdgeTriangle	NeighborFace = P.m_WingedEdgeFaces[NeighborFaceIndex];
                                        ProbeInfluence	NeighborProbe = NeighborFace.m_Tag as ProbeInfluence;
                                        if ( NeighborProbe.ProbeID != ProbeInfluence.INVALID_PROBEID && (BestProbe == null || NeighborProbe.Importance > BestProbe.Importance) )
                                            BestProbe = NeighborProbe;	// Found a better probe for that face!
                                    }
                                }

                                if ( BestProbe == null )
                                    continue;	// Still no valid probe found...

                                Face.m_Tag = BestProbe;	// Share the probe, don't care...
                                MissingProbeIDFaces.RemoveAt( FaceIndex );	// We can safely remove the face by index since we're browsing the list backward
                            }

                            // Update progress
                            progressBarSubTask.Value = progressBarSubTask.Maximum * (OriginalCount - MissingProbeIDFaces.Count) / OriginalCount;
                            progressBarSubTask.Refresh();
                        }

                        // At this point, either the list of faces missing probe IDs is empty in which case the job is done
                        //	or we need to assign an arbitrary probe ID to those faces
                        if ( MissingProbeIDFaces.Count > 0 )
                        {
                            FacesWithoutProbeCount += MissingProbeIDFaces.Count;
                            PrimitivesWithoutProbeCount++;

                            // TODO: Assign nearest probe or something!
                        }

                        // Now that we have valid probe IDs for each face, propagate best probe influence to each vertex
                        ProbeInfluence[]	BestProbePerVertex = new ProbeInfluence[P.m_Vertices.Length];
                        for ( int FaceIndex=0; FaceIndex < FacesCount; FaceIndex++ )
                        {
                            GCXFormat.Scene.Mesh.Primitive.Face	Face = P.m_Faces[FaceIndex];
                            ProbeInfluence	FaceProbe = P.m_WingedEdgeFaces[FaceIndex].m_Tag as ProbeInfluence;

                            if ( BestProbePerVertex[Face.V0] == null || BestProbePerVertex[Face.V0].Importance < FaceProbe.Importance )	BestProbePerVertex[Face.V0] = FaceProbe;	// Better probe for that vertex
                            if ( BestProbePerVertex[Face.V1] == null || BestProbePerVertex[Face.V1].Importance < FaceProbe.Importance )	BestProbePerVertex[Face.V1] = FaceProbe;	// Better probe for that vertex
                            if ( BestProbePerVertex[Face.V2] == null || BestProbePerVertex[Face.V2].Importance < FaceProbe.Importance )	BestProbePerVertex[Face.V2] = FaceProbe;	// Better probe for that vertex
                        }

                        // Finally, we can splat probe IDs into the giant vertex stream
                        for ( int VertexIndex=0; VertexIndex < P.m_Vertices.Length; VertexIndex++ )
                            VertexStreamProbeID[P.m_VertexOffset+VertexIndex] = (UInt32) (BestProbePerVertex[VertexIndex] != null ? BestProbePerVertex[VertexIndex].ProbeID : 0xFFFFFFFF);	// TODO <= warn if we still have invalid vertices!
                    }

                    MeshIndex++;
                }

                progressBarBatchConvert.Value = progressBarBatchConvert.Maximum;

                //////////////////////////////////////////////////////////////////////////
                // Save the final vertex stream to disk
                FileInfo	TargetVertexStreamFile = new FileInfo( Path.Combine( Path.GetDirectoryName( SceneFile.FullName ), Path.GetFileNameWithoutExtension( SceneFile.FullName ) + "_ProbeID.vertexStream.U16" ) );

                using ( FileStream S = TargetVertexStreamFile.Create() )
                    using( BinaryWriter W = new BinaryWriter( S ) )
                    {
                        for ( int VertexIndex=0; VertexIndex < VertexStreamProbeID.Length; VertexIndex++ )
                            W.Write( VertexStreamProbeID[VertexIndex] );
                    }

                // Notify
                MessageBoxIcon	Icon = MessageBoxIcon.Information;
                string	Info  = "Success!\r\n";
                        Info += "Processed " + PrimitivesCount + " primitives for a total of " + GCX.m_TotalFacesCount + " faces and " + GCX.m_TotalVerticesCount + " vertices.\r\n";
                if ( PrimitivesWithoutProbeCount > 0 )
                {
                    Icon = MessageBoxIcon.Warning;
                    Info += "\r\n---------------------- WARNING ----------------------\r\n";
                    Info += PrimitivesWithoutProbeCount + " primitives are missing or have incomplete probe information.\r\n";
                    Info += "A total of " + FacesWithoutProbeCount + " faces don't have probe information!\r\n";
                }
                if ( Errors != "" )
                {
                    Icon = MessageBoxIcon.Warning;
                    Info += "\r\n---------------------- ERRORS ----------------------\r\n";
                    Info += Errors;
                }
                MessageBox( Info, MessageBoxButtons.OK, Icon );
            }
            catch ( Exception _e )
            {
                MessageBox( "An error occurred while probe influences in scene file: " + _e.Message, MessageBoxButtons.OK, MessageBoxIcon.Error );
                return;
            }
            finally
            {
                progressBarBatchConvert.Visible = false;
                progressBarSubTask.Visible = false;
            }
        }
Beispiel #5
0
        /// <summary>
        /// This tool builds the additional vertex stream for each primitive that will attach the best probe ID (as a U16)
        ///  to a vertex so the vertex shader has a single entry point into the probes network
        /// Most face indices have already been rendered in the probe cube map and the batch processing tool took care of
        ///  selecting the most important probe for these faces, but some faces don't have probe information.
        ///  Maybe they have been occluded by other faces (shadowing) or are too small to be rendered in the cube map.
        /// For these special faces, we need to propagate probe IDs from valid faces until the entire mesh is filled with
        ///  valid probe IDs.
        ///
        /// We proceed primitive per primitive since they are all disconnected so no propagation would be possible cross
        ///  primitives unless we could reconnect split vertices, but I don't want to do that. Maybe it will become necessary
        ///  at some point but for the moment I don't care.
        /// Some primitives may lack probe ID completely (!!), for these I choose to assign the ID of the nearest probe, which
        ///  may be a bit dangerous, especially if we're dealing with probes that are standing right behind the primitive for example.
        /// In that case, perhaps using a scoring scheme that depends on both distance and orientation would be better? Let's see that when the problem arises...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void encodeFaceProbesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Ask for the influence file to load from
            string OldFileName = GetRegKey("LastProbeInfluenceFileName", GetRegKey("LastProbesFolderTarget", Path.GetDirectoryName(m_ApplicationPath)));

            openFileDialogProbeInfluence.InitialDirectory = Path.GetDirectoryName(OldFileName);
            openFileDialogProbeInfluence.FileName         = Path.GetFileName(OldFileName);
            if (openFileDialogProbeInfluence.ShowDialog(this) != DialogResult.OK)
            {
                return;
            }
            SetRegKey("LastProbeInfluenceFileName", openFileDialogProbeInfluence.FileName);

            FileInfo SourceInfluenceFile = new FileInfo(openFileDialogProbeInfluence.FileName);

            // Ask for the scene file to apply to
            string OldSceneFile = GetRegKey("LastSceneFileName", GetRegKey("LastProbesFolderSource", Path.GetDirectoryName(m_ApplicationPath)));

            openFileDialogScene.InitialDirectory = Path.GetDirectoryName(OldSceneFile);
            openFileDialogScene.FileName         = Path.GetFileName(OldSceneFile);
            if (openFileDialogScene.ShowDialog(this) != DialogResult.OK)
            {
                return;
            }
            SetRegKey("LastSceneFileName", openFileDialogScene.FileName);

            FileInfo SceneFile = new FileInfo(openFileDialogScene.FileName);

            try
            {
                // Read the scene file
                GCXFormat.Scene GCX = null;
                using (FileStream S = SceneFile.OpenRead())
                    using (BinaryReader R = new BinaryReader(S))
                        GCX = new GCXFormat.Scene(R);

                // Read the probe influences
                ProbeInfluence[] FaceInfluences = new ProbeInfluence[GCX.m_TotalFacesCount];
                using (FileStream S = SourceInfluenceFile.OpenRead())
                    using (BinaryReader R = new BinaryReader(S))
                    {
                        int SizeofProbeInfluence = System.Runtime.InteropServices.Marshal.SizeOf(typeof(UInt32)) + System.Runtime.InteropServices.Marshal.SizeOf(typeof(double));
                        int FacesCount           = (int)S.Length / SizeofProbeInfluence;
                        if ((S.Length % SizeofProbeInfluence) != 0)
                        {
                            throw new Exception("Probe influence file is larger than an integer number of ProbeInfluence structures!");
                        }

                        for (int FaceIndex = 0; FaceIndex < FacesCount; FaceIndex++)
                        {
                            UInt32 ProbeID    = R.ReadUInt32();
                            double Importance = R.ReadDouble();
                            FaceInfluences[FaceIndex] = new ProbeInfluence()
                            {
                                ProbeID = ProbeID, Importance = Importance
                            };
                        }
                        for (int FaceIndex = FacesCount; FaceIndex < GCX.m_TotalFacesCount; FaceIndex++)
                        {
                            FaceInfluences[FaceIndex] = new ProbeInfluence()
                            {
                                ProbeID = ProbeInfluence.INVALID_PROBEID, Importance = 0.0
                            }
                        }
                        ;
                    }

                UInt32[] VertexStreamProbeID = new UInt32[GCX.m_TotalVerticesCount];                            // The final vertex stream we're building


                // Establish data for progress measurement
                int PrimitivesCount = 0;
                foreach (GCXFormat.Scene.Node N in GCX.m_Nodes)
                {
                    GCXFormat.Scene.Mesh M = N as GCXFormat.Scene.Mesh;
                    if (M != null)
                    {
                        PrimitivesCount += M.m_Primitives.Length;
                    }
                }

                //////////////////////////////////////////////////////////////////////////
                // The algorithm is quite simple:
                //	For each primitive
                //		Create a winged edge structure for each face
                //		Assign known probe influence to each face
                //		Build a list of faces without probe influence
                //
                //		While list is not empty and its size keeps decreasing
                //			For each face without influence
                //				If neighbor faces have influence information
                //					Copy best influence from neighbor
                //					Remove face from the list
                //
                //		If list is not empty			// We have a bunch of disconnected faces that can't see any probe
                //			For each face of the list
                //				Assign [NO PROBE|NEAREST PROBE|WORLD PROBE] ? (not clear yet which is best)
                //
                //		Redistribute best probe's ID to each face vertex
                //
                //	Save stream of vertex probe IDs to be merged into an additional vertex buffer stream at runtime
                //
                int    MeshIndex                   = 0;
                int    PrimitiveIndex              = 0;
                int    FacesWithoutProbeCount      = 0;
                int    PrimitivesWithoutProbeCount = 0;
                string Errors = "";

                progressBarBatchConvert.Value   = 0;
                progressBarBatchConvert.Visible = true;
                progressBarSubTask.Value        = 0;
                progressBarSubTask.Visible      = true;

                foreach (GCXFormat.Scene.Node N in GCX.m_Nodes)
                {
                    GCXFormat.Scene.Mesh M = N as GCXFormat.Scene.Mesh;
                    if (M == null)
                    {
                        continue;
                    }

                    foreach (GCXFormat.Scene.Mesh.Primitive P in M.m_Primitives)
                    {
                        int FacesCount = P.m_Faces.Length;

                        try
                        {
                            P.BuildWingedEdgesMesh();
                        }
                        catch (Exception _e)
                        {
                            Errors += "Primitive #" + PrimitiveIndex + " of mesh #" + MeshIndex + " has generated an error on Winged Mesh generation: " + _e.Message + "\r\n";

                            // Add this primitve to the list of the ones m
                            PrimitivesWithoutProbeCount++;
                            FacesWithoutProbeCount += P.m_Vertices.Length;
                            continue;
                        }

                        // Update progress
                        progressBarBatchConvert.Value = progressBarBatchConvert.Maximum * (++PrimitiveIndex) / PrimitivesCount;
                        progressBarSubTask.Value      = 0;

                        // Tag winged edge faces with probe influence & list faces without valid probe ID
                        List <GCXFormat.Scene.Mesh.Primitive.WingedEdgeTriangle> MissingProbeIDFaces = new List <GCXFormat.Scene.Mesh.Primitive.WingedEdgeTriangle>(FacesCount);
                        for (int FaceIndex = 0; FaceIndex < FacesCount; FaceIndex++)
                        {
                            ProbeInfluence Influence = FaceInfluences[P.m_FaceOffset + FaceIndex];
                            GCXFormat.Scene.Mesh.Primitive.WingedEdgeTriangle Face = P.m_WingedEdgeFaces[FaceIndex];
                            Face.m_Tag = Influence;
                            if (Influence.ProbeID == ProbeInfluence.INVALID_PROBEID)
                            {
                                MissingProbeIDFaces.Add(Face);
                            }
                        }

                        // Propagate probe influence
                        int OriginalCount = MissingProbeIDFaces.Count;
                        int LastListSize  = MissingProbeIDFaces.Count + 1;
                        while (MissingProbeIDFaces.Count > 0 && MissingProbeIDFaces.Count < LastListSize)
                        {
                            LastListSize = MissingProbeIDFaces.Count;                                        // Keep track of list's size so we know if anything moved
                            for (int FaceIndex = MissingProbeIDFaces.Count - 1; FaceIndex >= 0; FaceIndex--) // Browse backward so we can safely remove elements from the list
                            {
                                GCXFormat.Scene.Mesh.Primitive.WingedEdgeTriangle Face = MissingProbeIDFaces[FaceIndex];

                                // Examine neighbors' probe influence and propagate best probe
                                ProbeInfluence BestProbe = null;
                                for (int EdgeIndex = 0; EdgeIndex < 3; EdgeIndex++)
                                {
                                    int NeighborFaceIndex = Face.m_Edges[EdgeIndex].GetOtherFaceIndex(Face.m_Index);
                                    if (NeighborFaceIndex != -1)
                                    {
                                        GCXFormat.Scene.Mesh.Primitive.WingedEdgeTriangle NeighborFace = P.m_WingedEdgeFaces[NeighborFaceIndex];
                                        ProbeInfluence NeighborProbe = NeighborFace.m_Tag as ProbeInfluence;
                                        if (NeighborProbe.ProbeID != ProbeInfluence.INVALID_PROBEID && (BestProbe == null || NeighborProbe.Importance > BestProbe.Importance))
                                        {
                                            BestProbe = NeighborProbe;                                                  // Found a better probe for that face!
                                        }
                                    }
                                }

                                if (BestProbe == null)
                                {
                                    continue;                                           // Still no valid probe found...
                                }
                                Face.m_Tag = BestProbe;                                 // Share the probe, don't care...
                                MissingProbeIDFaces.RemoveAt(FaceIndex);                // We can safely remove the face by index since we're browsing the list backward
                            }

                            // Update progress
                            progressBarSubTask.Value = progressBarSubTask.Maximum * (OriginalCount - MissingProbeIDFaces.Count) / OriginalCount;
                            progressBarSubTask.Refresh();
                        }

                        // At this point, either the list of faces missing probe IDs is empty in which case the job is done
                        //	or we need to assign an arbitrary probe ID to those faces
                        if (MissingProbeIDFaces.Count > 0)
                        {
                            FacesWithoutProbeCount += MissingProbeIDFaces.Count;
                            PrimitivesWithoutProbeCount++;

                            // TODO: Assign nearest probe or something!
                        }

                        // Now that we have valid probe IDs for each face, propagate best probe influence to each vertex
                        ProbeInfluence[] BestProbePerVertex = new ProbeInfluence[P.m_Vertices.Length];
                        for (int FaceIndex = 0; FaceIndex < FacesCount; FaceIndex++)
                        {
                            GCXFormat.Scene.Mesh.Primitive.Face Face = P.m_Faces[FaceIndex];
                            ProbeInfluence FaceProbe = P.m_WingedEdgeFaces[FaceIndex].m_Tag as ProbeInfluence;

                            if (BestProbePerVertex[Face.V0] == null || BestProbePerVertex[Face.V0].Importance < FaceProbe.Importance)
                            {
                                BestProbePerVertex[Face.V0] = FaceProbe;                                                                                                                                                // Better probe for that vertex
                            }
                            if (BestProbePerVertex[Face.V1] == null || BestProbePerVertex[Face.V1].Importance < FaceProbe.Importance)
                            {
                                BestProbePerVertex[Face.V1] = FaceProbe;                                                                                                                                                // Better probe for that vertex
                            }
                            if (BestProbePerVertex[Face.V2] == null || BestProbePerVertex[Face.V2].Importance < FaceProbe.Importance)
                            {
                                BestProbePerVertex[Face.V2] = FaceProbe;                                                                                                                                                // Better probe for that vertex
                            }
                        }

                        // Finally, we can splat probe IDs into the giant vertex stream
                        for (int VertexIndex = 0; VertexIndex < P.m_Vertices.Length; VertexIndex++)
                        {
                            VertexStreamProbeID[P.m_VertexOffset + VertexIndex] = (UInt32)(BestProbePerVertex[VertexIndex] != null ? BestProbePerVertex[VertexIndex].ProbeID : 0xFFFFFFFF);                             // TODO <= warn if we still have invalid vertices!
                        }
                    }

                    MeshIndex++;
                }

                progressBarBatchConvert.Value = progressBarBatchConvert.Maximum;


                //////////////////////////////////////////////////////////////////////////
                // Save the final vertex stream to disk
                FileInfo TargetVertexStreamFile = new FileInfo(Path.Combine(Path.GetDirectoryName(SceneFile.FullName), Path.GetFileNameWithoutExtension(SceneFile.FullName) + "_ProbeID.vertexStream.U16"));

                using (FileStream S = TargetVertexStreamFile.Create())
                    using (BinaryWriter W = new BinaryWriter(S))
                    {
                        for (int VertexIndex = 0; VertexIndex < VertexStreamProbeID.Length; VertexIndex++)
                        {
                            W.Write(VertexStreamProbeID[VertexIndex]);
                        }
                    }

                // Notify
                MessageBoxIcon Icon = MessageBoxIcon.Information;
                string         Info = "Success!\r\n";
                Info += "Processed " + PrimitivesCount + " primitives for a total of " + GCX.m_TotalFacesCount + " faces and " + GCX.m_TotalVerticesCount + " vertices.\r\n";
                if (PrimitivesWithoutProbeCount > 0)
                {
                    Icon  = MessageBoxIcon.Warning;
                    Info += "\r\n---------------------- WARNING ----------------------\r\n";
                    Info += PrimitivesWithoutProbeCount + " primitives are missing or have incomplete probe information.\r\n";
                    Info += "A total of " + FacesWithoutProbeCount + " faces don't have probe information!\r\n";
                }
                if (Errors != "")
                {
                    Icon  = MessageBoxIcon.Warning;
                    Info += "\r\n---------------------- ERRORS ----------------------\r\n";
                    Info += Errors;
                }
                MessageBox(Info, MessageBoxButtons.OK, Icon);
            }
            catch (Exception _e)
            {
                MessageBox("An error occurred while probe influences in scene file: " + _e.Message, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            finally
            {
                progressBarBatchConvert.Visible = false;
                progressBarSubTask.Visible      = false;
            }
        }
Beispiel #6
0
        /// <summary>
        /// Loads a FBX scene and converts it (in the same folder) into its GCX equivalent
        /// </summary>
        /// <param name="_File"></param>
        public void     LoadScene(FileInfo _SourceFile, FileInfo _TargetFile)
        {
            FBX.SceneLoader.SceneLoader Loader = new FBX.SceneLoader.SceneLoader();

            FBX.SceneLoader.MaterialsDatabase Materials = new FBX.SceneLoader.MaterialsDatabase();
//			Materials.BuildFromM2( new DirectoryInfo( @"D:\Workspaces\Arkane\m2" ) );

            FBX.Scene.Scene Scene = new FBX.Scene.Scene();
            Loader.Load(_SourceFile, Scene, 1.0f, Materials);

            // Start writing
//			FileInfo	Target = new FileInfo( Path.Combine( Path.GetDirectoryName( _SourceFile.FullName ), Path.GetFileNameWithoutExtension( _SourceFile.FullName ) + ".gcx" ) );
            using (FileStream S = _TargetFile.OpenWrite())
                using (BinaryWriter W = new BinaryWriter(S))
                {
                    GCXFormat.Scene GCX = new GCXFormat.Scene(Scene);
                    GCX.Save(W);
                }

            // Write infos
            List <string> Infos = new List <string>();

            Infos.Add("Textures:");
            foreach (FBX.Scene.Materials.Texture2D Texture in Scene.Textures)
            {
                Infos.Add("ID #" + Texture.ID.ToString("D3") + " URL=" + Texture.URL);
            }
            Infos.Add("");

            // Here, I write an array mapping texture IDs to names, assuming textures have been converted to POM format using PNG2POM (or HDR2POM)
            // This way I can simply copy this "code friendly" list and paste it in my C++ code (e.g. const char* ppID2TextureName[] = { PasteHere }; )
            Infos.Add("Texture Flat Names:");
            Infos.Add("");
            string DirectoryHeader = Path.GetDirectoryName(_SourceFile.ToString());

            DirectoryHeader = DirectoryHeader.Replace("\\", "\\\\");                    // Double antislashes
            foreach (FBX.Scene.Materials.Texture2D Texture in Scene.Textures)
            {
//				Infos.Add( "ID #" + Texture.ID.ToString( "D3" ) + " URL=" + Path.GetFileNameWithoutExtension( Texture.URL ) );
                Infos.Add("\"" + DirectoryHeader + @"\\TexturesPOM\\" + Path.GetFileNameWithoutExtension(Texture.URL) + ".pom\",");
            }
            Infos.Add("");


            Infos.Add("=============================");
            Infos.Add("Materials:");
            foreach (FBX.Scene.Materials.MaterialParameters Mat in Scene.MaterialParameters)
            {
                Infos.Add("ID #" + Mat.ID + " => " + Mat.Name + " (shader=" + Mat.ShaderURL + ")");
            }
            Infos.Add("");

            Infos.Add("=============================");
            Infos.Add("Meshes:");
            foreach (FBX.Scene.Nodes.Mesh Mesh in Scene.Meshes)
            {
                Infos.Add("ID #" + Mesh.ID + " => " + Mesh.Name + " (primsCount=" + Mesh.PrimitivesCount + ")");
            }
            Infos.Add("");

            Infos.Add("=============================");
            Infos.Add("Lights:");
            foreach (FBX.Scene.Nodes.Light Light in Scene.Lights)
            {
                Infos.Add("ID #" + Light.ID + " => " + Light.Name + " (type=" + Light.Type + ")");
            }
            Infos.Add("");

            Infos.Add("=============================");
            Infos.Add("Cameras:");
            foreach (FBX.Scene.Nodes.Camera Camera in Scene.Cameras)
            {
                Infos.Add("ID #" + Camera.ID + " => " + Camera.Name + " (FOV=" + (Camera.FOV * 180.0f / Math.PI) + ")");
            }
            Infos.Add("");

            if (Materials != null)
            {
                FBX.SceneLoader.MaterialsDatabase.Material[] QueriedMaterials = Materials.QueriedMaterials;

                List <string> QueriedTextures = new List <string>();

                // Here I'm generating the XCOPY batch commands to copy original textures from a complex directory structure
                //	into a flattened directory where they'll further be converted into POM files using PNG2POM
                Infos.Add("=============================");
                Infos.Add("Queried database materials:");
                foreach (FBX.SceneLoader.MaterialsDatabase.Material M in QueriedMaterials)
                {
                    Infos.Add(M.Name);

                    if (M.TextureDiffuse != null)
                    {
                        QueriedTextures.Add("xcopy \"" + M.TextureDiffuse.Replace('/', '\\') + "\" \"..\\POMTextures\\\" /Y/U/S");
                    }
                    if (M.TextureNormal != null)
                    {
                        QueriedTextures.Add("xcopy \"" + M.TextureNormal.Replace('/', '\\') + "\" \"..\\POMTextures\\\" /Y/U/S");
                    }
                    if (M.TextureSpecular != null)
                    {
                        QueriedTextures.Add("xcopy \"" + M.TextureSpecular.Replace('/', '\\') + "\" \"..\\POMTextures\\\" /Y/U/S");
                    }
                }
                Infos.Add("");

                Infos.Add("=============================");
                Infos.Add("Queried textures:");
                Infos.AddRange(QueriedTextures);
            }

            textBoxReport.Lines = Infos.ToArray();
        }