How to create plugins for the Nova Explorer


Overview

Nova Explorer allows the addition of new functionalities and personalized modules via the realization of plugins under Visual Studio 2008. Before describing in detail the realization process of a plugin for Nova Explorer, we need to go through this info:

  • Nova Explorer was written exclusively in C#.NET 2.0 under Visual Studio 2005 while staying based on the Nova Omega Software Development Kit (SDK). Nova Omega SDK contains all the classes useful for the handling of scenes (at the mxb format ) exported via the Nova Exporter from 3ds Max. The objects (the 3D entities) are represented in .NET by some NovaObject, the lights by some NovaLight, the scenes by some NovaScene, etc. We will thus use this library (Vertice.Nova.dll and Vertice.Nova.Interop.dll) in our development projects of plugins.

  • The libraries Vertice.Nova.dll, Vertice.Nova.Interop.dll are deployed during the installation of the Nova Explorer in the repertory selected for the installation (by default "C:\Program Files\Vertice\Nova 2009 \"). A documentation is available for the Nova Omega SDK from this same "Docs" repertory or directly via the Start menu ->Vertice\Nova Omega 2008\Documentation\. We invite you to read this documentation for all the details concerning the use of the Nova Omega SDK.

  • A library has been developed especially to interact with the Nova Explorer (Vertice.Explorer.Plugins.dll). This library contains the elements useful for the interactions with the Nova Explorer (addition of menu, controls, recovery of the current scene, of the selected object, etc), it is thus the base of all the projects of development of plugins for the Nova Explorer. Vertice.Explorer.Plugins.dll is available in the installation repertory, on the same level of Vertice.Nova.dll, Vertice.Nova.Interop.dll.

  • When starting, the Nova Explorer reads (starting from its installation repertory) the content of its "Plugins" repertory and loads the modules available (if they satisfy a certain criterion which we will talk about thereafter). All the plugins thus must be present in this repertory before being available in the Nova Explorer.

How to create a Visual Studio 2008 plugin project for the Nova Explorer



The type of project to be created is of the Class Library type. Indeed, we will not carry out an executable program but a dll that we will copy in the Plugins repertory of the Nova Explorer.

For the reasons listed above, the first action to be carried out is to specify in the Solution Explorer the references towards the libraries Vertice.Nova.dll, Vertice.Nova.Interop.dll and Vertice.Explorer.Plugins.dll:



Right click on the file « References » in the « Solution Explorer » of our project Under the « Browse » tab, we go to the installation directory of the Nova Explorer to select the 3 dll to reference.

We can begin the development of the plugin from here. Once compiled, it would be enough to copy the dll in the plugins repertory of the Nova Explorer, then launch the Nova Explorer. We will automate these tasks not to have to carry out them each time we test/compile the plugin:

Right click on the solution then « Properties »

The properties window of the solution appears. The tabs « Build » and « Debug » will be useful to us.

We have 2 things to automate:

To copy the dll directly in the Plugins repertory.


The initial Build tab of the of the Properties window. We will modify the « Output path ».
Output path » points from now on towards the Plugins repertory of the Nova Explorer.

To start automatically the Nova Explorer when we do a Start Debug/Release (F5).


The initial Debug tab of the Properties window. We will modify Start Action.
We tick "Start external program" in order to specify the path towards the executable of the Nova Explorer.

In order not to create any conflict between the versions of the dll Vertice.Nova.dll, Vertice.Nova.Interop.dll and Vertice.Nova.Plugins.dll, we must not deploy these in the Plugins folder. We will then turn the property Copy Local of all these dll to False (by clicking on the dll in the Solution Explorer and by filling the property Copy Local available in the Properties):



By carrying out a Start Debug (or F5), we note that the Nova Explorer is automatically started and that the dll is well copied in the Plugins repertory of the Nova Explorer. This being said, no change appears in the Nova Explorer for the moment.

Note:

We can have this error coming from DirectX at the time of the first execution:


DLL 'C:\WINDOWS\assembly\GAC\Microsoft.DirectX\1.0.2902.0__31bf3856ad364e35\Microsoft.DirectX.dll' is attempting managed execution inside OS Loader lock. Do not attempt to run managed code inside a DllMain or image initialization function since doing so can cause the application to hang.


It is a bug of DirectX that we can easily deactivate by carrying out the following operation:

In the Debug menu, click on the item "Exceptions"

By default, it is possible that "Exceptions" does not appear in Debug menu. We can however make Ctrl + Alt + E to reveal the Exceptions management window to add it by going in the Tools menu then by clicking on Customize to reveal the window of customization of Visual Studio 2008. In the Customize window, under the Commands tab, choose the Debug "Categories" and carry out a drag & drop of the "Exceptions" item towards the Debug menu.

In the window "Exceptions":


Reveal the sub-menu Managed Debugging Assistants, then deactivate "Thrown" at the level of the Loader Lock line:

Before continuing, ensure that the Nova Explorer is well launched when the solution is carried out and that the dll (carrying the name of the solution by default, NovaExplorerPlugin_Template.dll in our example) is well deployed in the Plugins directory of the Nova Explorer.

We will now see the mechanism allowing the Nova Explorer to recognize and to load some plugins.



The IPlugin interface

As in almost any development project of plugin, we will have an interface to implement so that the module (the dll) is recognized as a plugin.

In the case of the Nova Explorer, it is the interface IPlugin (Vertice.NovaExplorer.IPlugin):



When we launch the Nova Explorer, it consults its Plugins directory. If a module is found, Nova Explorer checks if one of the components implements the IPlugin class. If it is the case, the Start() method of this component is called.

When we leave the Nova Explorer, it calls the Stop() method of the charged modules (i.e. modules that we called the Start() method).


Let's take again the solution created previously:
Rename the class "Class1" created by default by Visual Studio "MyFirstPlugin" (for example).
Add a using Vertice.NovaExplorer.
Make inherit MyFirstPlugin from IPlugin.
Implement the IPlugin interface.


public class MyFirstPlugin: IPlugin

    {

        #region IPlugin Members

        public bool IsAvailable

        {

            get { throw new NotImplementedException(); }

        }

        public void Start()

        {

            throw new NotImplementedException();

        }

        public void Stop()

        {

            throw new NotImplementedException();

        }

        #endregion

    }

We post dialog boxes to each call of the 2 methods and of the property in order to understand the operation of the IPlugin interface well. To post a dialog box, we need the libraries Windows Forms (not included automatically at the time of the creation of a project of the Class Library type):

To compile and carry out the project (F5):
When Nova Explorer is launched, the dialog box with the text "Start method call" appears.
When we leave the Nova Explorer, the dialog box with the text "Stop method call" appears.

With the IPlugin interface, we allow our program to be recognized and carried out by the Nova Explorer. But how can we interact with this one? How to add a menu? How to have access to the current scene?

All these operations (and much more) will be carried out thanks to the PluginHelper class.



The PluginHelper utility class

The PluginHelper class allows us to have directly access to the Nova Explorer and to even react according to the users events (loading of a scene, selection of an object, etc.).


All the methods, all the properties, all the events are static members, we will thus never have to use PluginHelper (there is logically no manufacturer). We will now see all that is possible to be made with the PluginHelper class.



The PluginHelper utility class: Add/Suppress an element in the Plugin menu of the Nova Explorer

When at least one plugin is detected by the Nova Explorer, the Plugin menu is automatically created in the Explorer.

To add an entry in this menu, we will use the RegisterPluginMenuEntry method.
If we wish, at a given time, not to see appear anymore this entry in the menu, we will do an UnRegisterPluginMenuEntry.

For example, we would like to position one item "MyFirstPlugin" in the Plugin menu of the Nova Explorer and to start the posting of a dialog box when this item is turned on, then to remove the entry of the Plugin menu. The use of RegisterPluginMenuEntry and more particularly the image argument obliges us to reference System.Drawing in our project:


public class MyFirstPlugin: IPlugin

    {

        #region IPlugin Members

        public bool IsAvailable

        {

            get

            {

                MessageBox.Show("IsAvailable field request");

                return true;

            }

        }

        public void Start()

        {

            PluginHelper.RegisterPluginMenuEntry("MyFirstPlugin",

                Image.FromStream(Assembly.GetExecutingAssembly()

                .GetManifestResourceStream("NovaExplorerPlugin_Template.Resources.notepad.jpg")),

                new EventHandler(MenuClick), this);

        }

        public void MenuClick(object sender, EventArgs e)

        {

            PluginHelper.AddUIControl(typeof(NovaNotePad), "Nova Notepad");

        }

        public void Stop()

        {

            MessageBox.Show("Stop method call");

        }

        #endregion

    }


 

We now wish to add a customized control to the interface of the Nova Explorer.



The PluginHelper utility class: Add a customized control to the user interface of the Nova Explorer



We would like to create a plugin allowing to enter some text, to take notes during the navigation within a scene for example:



We call this NovaNotePad control, we add to it a RichTextBox control (from the toolbox of Visual Studio), and we "dock" this RichTextBox in NovaNotePad:



We still have to modify MyFirstPlugin.cs so that it adds this control to the interface of the Nova Explorer:



We would like now to associate an image to the plugin (in the menu):

We insert the icon in the project, and we incorporate it in the dll (in order not to have to deploy the "Resources" repertory).

We still have to modify the call to RegisterPluginMenuEntry:


public void Start()

        {

            PluginHelper.RegisterPluginMenuEntry("MyFirstPlugin",

                Image.FromStream(Assembly.GetExecutingAssembly()

                .GetManifestResourceStream(

                "NovaExplorerPlugin_Template.Resources.notepad.jpg")),

                new EventHandler(MenuClick), this);

        }

So that the plugin can compile, we will have to add the following using:

using System.Drawing;

using System.Reflection;

The icon appears in the menu:



The PluginHelper utility class: Interact with the scenes of the Nova Explorer

We have access to the current scene via the ActiveScene property (Caution! It can be null):



The interactions of use with a scene launch events to which we can subscribe:

Loading of a scene:



Selection of a scene (when several scenes are opened in the Nova Explorer):



Closure of a scene:



To subscribe to these 3 events, we will use a delegate of the type:



To save the current scene:



To subscribe to this event, we will use a delegate of the type:

We will improve our plugin to transform it into a newspaper recapitulating the interactions of the user with the scene. We thus modify the NovaNotePad component:

public partial class NovaNotePad: UserControl

    {

        public NovaNotePad()

        {

            InitializeComponent();

        }

        private void WriteLine(String strText)

        {

            this.richTextBox1.AppendText(String.Format("{0}\n",strText));

        }

        private void NovaNotePad_Load(object sender, EventArgs e)

        {

            PluginHelper.NovaSceneLoaded +=

                new PluginHelper.NovaSceneDelegate(PluginHelper_NovaSceneLoaded);

            PluginHelper.NovaSceneSaved +=

                new PluginHelper.NovaSceneFileDelegate(PluginHelper_NovaSceneSaved);

            PluginHelper.NovaSceneSelected +=

                new PluginHelper.NovaSceneDelegate(PluginHelper_NovaSceneSelected);

            PluginHelper.NovaSceneUnloaded +=

                new PluginHelper.NovaSceneDelegate(PluginHelper_NovaSceneUnloaded);

            PluginHelper.NovaSceneRendered +=

                new PluginHelper.NovaSceneDelegate(PluginHelper_NovaSceneRendered);

        }

        void PluginHelper_NovaSceneRendered(Vertice.Nova.NovaScene scene)

        {

            WriteLine(

                String.Format(

                "Events NovaSceneRendered, Scene Rendered: {0}", scene.Name));

        }

        void PluginHelper_NovaSceneUnloaded(Vertice.Nova.NovaScene scene)

        {

            WriteLine(

                String.Format(

                "Events NovaSceneUnloaded, Scene Unloaded: {0}", scene.Name));

        }

        void PluginHelper_NovaSceneSaved(Vertice.Nova.NovaScene scene, string filename)

        {

            WriteLine(

                String.Format(

                "Events NovaSceneSaved, Scene Saved: {0} in file ", scene.Name, filename));

        }

        void PluginHelper_NovaSceneSelected(Vertice.Nova.NovaScene scene)

        {

            WriteLine(

                String.Format(

                "Events NovaSceneSelected, Scene Selected: {0}", scene.Name));

        }

        void PluginHelper_NovaSceneLoaded(Vertice.Nova.NovaScene scene)

        {

            WriteLine(

                String.Format(

                "Events NovaSceneLoaded, Scene Loaded: {0}", scene.Name));

        }

    }



The PluginHelper utility class: Selection of objects in the Nova Explorer

It is possible to know the object(s) selected in the Explorer:



The event SelectionChanged is raised when:
An object is selected
An object is unselected
An object is (un)selected during a multiple selection



To subscribe to this event, we will use a delegate of the type:



It is possible to force the selection/unselection of an object directly from the plugin:




We just have to transform an object reference into a method parameter to select/unselect an object in the scene.

After having seen the addition of entries in the logs of the Nova Explorer, we will give a concrete example of the use of the selections of objects in the Nova Explorer.


The PluginHelper utility class: Add entries in the logs of the Nova Explorer


We would like to enter our own info in the log window of the Nova Explorer. We will use the following methods:

  • To enter an information, we will use::

  • To enter a warning, we will use:

  • To enter an error, we will use:

A plugin example for the Nova Explorer: de-activate the render of selected objects

We wish to create a plugin offering the following functionalities:

  • When an object is selected in the Explorer, the rendering of this object is deactivated.
  • There is no graphic control for this plugin. When the plugin is activated, we will add one item in the plugin menu to allow to deactivate the plugin.

Here is the code corresponding to this plugin:


class SelectedObjectRenderingPlugin: IPlugin

    {

        List<NovaScene> loadedScenes;

 

        public bool IsAvailable

        {

            get { return true; }

        };  }

 

        public void Start()

        {

            PluginHelper.RegisterPluginMenuEntry("Selected object rendering", null, new EventHandler(MenuClick), this);

        };  }

 

        public void Stop()

        {

 

        }     

 

        #region PluginHelper events

 

        void PluginHelper_NovaSceneUnloaded(NovaScene scene)

        {

            PluginHelper.LogInfo("Nova scene unloaded event");

        }

 

        void PluginHelper_NovaSceneSelected(NovaScene scene)

        {

            PluginHelper.LogInfo("Nova scene selected event");

        }

 

        void PluginHelper_NovaSceneLoaded(NovaScene scene)

        {

            PluginHelper.LogInfo("Nova scene loaded event");

            LoadScene(scene);

        }

 

        void PluginHelper_SelectionChanged()

        {

            PluginHelper.LogInfo("Selection changed event");

        }

 

        #endregion

 

        #region Menu Click events

 

        public void MenuClick(object sender, EventArgs e)

        {

            PluginHelper.LogInfo("Selected object rendering start");

            loadedScenes = new List<NovaScene>();

            PluginHelper.UnregisterPluginMenuEntry("Selected object rendering");

            PluginHelper.RegisterPluginMenuEntry("Stop Selected object rendering", null, new EventHandler(MenuClickStop), this);

            if (PluginHelper.ActiveScene == null)

                return;

            else

                LoadScene(PluginHelper.ActiveScene);

        }

 

        public void MenuClickStop(object sender, EventArgs e)

        {

            PluginHelper.LogInfo("Stop Selected object rendering");

            UnLoadScene();

            PluginHelper.UnregisterPluginMenuEntry("Stop Selected object rendering");

            PluginHelper.RegisterPluginMenuEntry("Selected object rendering", null, new EventHandler(MenuClick), this);

        }

 

        #endregion

 

        void LoadScene(NovaScene scene)

        {

            loadedScenes.Add(scene);

            PluginHelper.NovaSceneLoaded += new PluginHelper.NovaSceneDelegate(PluginHelper_NovaSceneLoaded);

            PluginHelper.NovaSceneSelected += new PluginHelper.NovaSceneDelegate(PluginHelper_NovaSceneSelected);

            PluginHelper.NovaSceneUnloaded += new PluginHelper.NovaSceneDelegate(PluginHelper_NovaSceneUnloaded);

            PluginHelper.SelectionChanged += new PluginHelper.SelectionDelegate(PluginHelper_SelectionChanged);

            PluginHelper.ActiveScene.BeforeRender += new Vertice.Nova.NovaScene.RenderingEvent(ActiveScene_BeforeRender);

        }

 

        void UnLoadScene()

        {

            foreach (NovaScene scene in loadedScenes)

            {

                scene.BeforeRender -= new Vertice.Nova.NovaScene.RenderingEvent(ActiveScene_BeforeRender);

                foreach (NovaObject obj in scene.Objects)

                    obj.Enabled = true;

            }

        }

 

        void ActiveScene_BeforeRender()

        {

            foreach (NovaObject obj in PluginHelper.ActiveScene.Objects)

            {

                if (PluginHelper.SelectedObjects.Contains(obj))

                    obj.Enabled = false;

                else

                    obj.Enabled = true;

            }

        }

    }


Example n°2: How to import an XML format file in Nova Explorer ?


We will take back the content of the dll Vertice.NovaExplorer.Plugins and it is noted that it contains the tools necessary for the installation of a personalized importation of file to the proprietary format in Nova Explorer:

  • The class OpenScenePlugin to open its own file format.

  • The interface ISavePlugin to save its own file format.

As considering previously, we create a project of the class library type that we name PluginImportXmlFile containing only one class named ImportXmlFile. We will not create personalized control but will only make available a new format of file in the "Open" menu of Nova Explorer. We will thus not implement a IPlugin interface like previously, we will make inherit our class ImportXmlFile of the OpenScenePlugin:


using System;

using System.Collections.Generic;

using System.Text;

using System.Windows.Forms;

using Vertice.NovaExplorer;

 

namespace PluginImportXmlFile

{

    public class ImportXmlFile: OpenScenePlugin

    {

 

    }

}


If we compile the project just as it is, the following errors are obtained:



This means that the OpenFilePlugin class obliges us to redefine some methods and properties:

  • The Description property which corresponds to the text posted in the fields "Files of type" of the dialog box Open of Nova Explorer.
  • The Extension property which will enable us to specify the new extension of file to be added in the dialog box Open of Nova Explorer
  • The Open method in which we will implement the process of reading of our proprietary file.
  • The Icon property which correspond to the Nova Explorer Icon
  • The Title property which correspond to the title of Nova Explorer

class ImportXmlFile: OpenScenePlugin

    {

        public override string Description

        {

            get { throw new NotImplementedException(); }

        }

        public override string Extension

        {

            get { throw new NotImplementedException(); }

        }

        public override System.Drawing.Image Icon

        {

            get { throw new NotImplementedException(); }

        }

        public override bool Open(Vertice.Nova.NovaScene scene,

                                  string filename, bool merge,

                                  bool delta)

        {

            throw new NotImplementedException();

        }

        public override string Title

        {

            get { throw new NotImplementedException(); }

        }

    }


We compile the project to deploy the dll in the Plugins repertory and Nova Explorer is launched
If we click on  
then on "Imports" the item associated to our Plugin Xml appears:


We still have to implement the Open method so that it reads our file correctly. We will need some references. One thus adds to our solution the following dll:

  • Microsoft.DirectX (in the repertory of installation of Nova)
  • Microsoft.DirectX.Direct3D (in the repertory of installation of Nova)
  • System.Drawing

For this example we have defined a descriptive file of a scene in XML format:


<?xml version="1.0" encoding="utf-8" ?>

<scene>

  <cameras>

    <camera name="camera1">

      <position x="0" y="0" z="-6"></position>

    </camera>

  </cameras>

  <lights>

    <light name="lumiere1" type="directional">

      <position x="0" y="6" z="-6"></position>

      <diffuseColor value="white"></diffuseColor>

      <direction x="-1" y="0" z="1"></direction>

    </light>

  </lights>

  <materials>

    <material name="materiel1">

      <diffuseColor value="red"></diffuseColor>

    </material>

    <material name="materiel2">

      <diffuseColor value="blue"></diffuseColor>

    </material>

  </materials>

  <objects>

    <object name="sphere1" type="sphere" radius="0.5" slices="32" stacks="32">

      <position x="0" y="-1" z="0"></position>

      <materiel name="materiel1"></materiel>

    </object>

    <object name="box1" type="box" width="1" height="1" depth="1">

      <position x="0" y="1" z="0"></position>

      <materiel name="materiel2"></materiel>

    </object>

  </objects>

</scene>

 


We then have to see the XML file in the Open method:


using Vertice.NovaExplorer;

using System.Drawing;

using System.Reflection;

using System.Xml;

using Vertice.Nova;

using Vertice.MathServices;

using System.Globalization;

namespace NovaExplorerPlugin_Template

{

    class ImportXmlFile: OpenScenePlugin

    {

        NovaScene _scene;

        public override string Description

        {

            get

            {

                return "Test import xml file format (*.xml)";

            }

        }

        public override string Extension

        {

            get

            {

                return "*.xml";

            }

        }

        public override System.Drawing.Image Icon

        {

            get

            {

                return Image.FromStream(Assembly.GetExecutingAssembly().

                    GetManifestResourceStream(

                        "ImportXmlFileToNova.Resources.notepadSmall.jpg"));

            }

        }

        public override bool Open(Vertice.Nova.NovaScene scene,

                                  string filename, bool merge,

                                  bool delta)

        {

            // Create reference on the scene object from Nova Explorer:

            _scene = scene;

            _scene.AutoClear = true;

            XmlDocument document = new XmlDocument();

            // load fileName from the Open File Dialog box

            document.Load(filename);

            // node scene

            XmlNode root = document.DocumentElement;

            // node cameras

            foreach (XmlNode childNode in root.ChildNodes)

            {

                switch (childNode.Name)

                {

                    case "cameras":

                        ParseCamerasNode(childNode);

                        break;

                    case "lights":

                        ParseLightsNode(childNode);

                        break;

                    case "materials":

                        ParseMaterialsNode(childNode);

                        break;

                    case "objects":

                        ParseObjectsNode(childNode);

                        break;

                }

            }

            return true;

        }

        public override string Title

        {

            get

            {

                return "Test import xml file format (*.xml)";

            }

        }

        private void ParseCamerasNode(XmlNode node)

        {

            foreach (XmlNode cameraNode in node.ChildNodes)

            {

                NovaCamera camera = _scene.CreateCamera(cameraNode.

                    Attributes["name"].Value);

                camera.Position = ParseVector3(cameraNode.ChildNodes[0]);

            }

        }

        private void ParseLightsNode(XmlNode node)

        {

            foreach (XmlNode lightNode in node.ChildNodes)

            {

                NovaLight light = _scene.CreateLight(lightNode.

                    Attributes["name"].Value);

                light.Type = Vertice.Nova.Core.NovaLightType.Directional;

                light.Position = ParseVector3(lightNode.ChildNodes[0]);

                light.DiffuseColor = Color.FromName(lightNode.ChildNodes[1].

                    Attributes["value"].Value);

                light.Direction = ParseVector3(lightNode.ChildNodes[2]);

            }

        }

        private void ParseMaterialsNode(XmlNode node)

        {

            foreach (XmlNode materialNode in node.ChildNodes)

            {

                Vertice.Nova.Materials.NovaStandardMaterial material =

                    _scene.CreateStandardMaterial(materialNode.Attributes["name"].Value);

                material.Diffuse = Color.FromName(materialNode.ChildNodes[0]

                    .Attributes["value"].Value);

            }

        }

        private void ParseObjectsNode(XmlNode node)

        {

            foreach (XmlNode objectNode in node.ChildNodes)

            {

                NovaObject obj = _scene.CreateObject(objectNode.Attributes["name"].Value);

                switch (objectNode.Attributes["type"].Value)

                {

                    case "sphere":

                        float radius = float.Parse(

                            objectNode.Attributes["radius"].Value,

                            CultureInfo.InvariantCulture);

                        int slices = int.Parse(

                            objectNode.Attributes["slices"].Value);

                        int stacks = int.Parse(

                            objectNode.Attributes["stacks"].Value);

                        obj.CreateAsSphere(radius, slices, stacks);

                        break;

                    case "box":

                        float width = float.Parse(objectNode.Attributes["width"].Value,

                            CultureInfo.InvariantCulture);

                        float height = float.Parse(objectNode.Attributes["height"].Value,

                            CultureInfo.InvariantCulture);

                        float depth = float.Parse(objectNode.Attributes["depth"].Value,

                            CultureInfo.InvariantCulture);

                        obj.CreateAsBox(width, height, depth);

                        break;

                    case "cylinder":

                        break;

                }

                obj.Position = ParseVector3(objectNode.ChildNodes[0]);

                obj.Material = _scene.GetMaterial(objectNode.ChildNodes[1].

                    Attributes["name"].Value);

            }

        }

        private Vector3 ParseVector3(XmlNode node)

        {

            Vector3 res = new Vector3();

            res.X = float.Parse(node.Attributes["x"].Value,

                CultureInfo.InvariantCulture);

            res.Y = float.Parse(node.Attributes["y"].Value,

                CultureInfo.InvariantCulture);

            res.Z = float.Parse(node.Attributes["z"].Value,

                CultureInfo.InvariantCulture);

            return res;

        }

    }

}


Now we want to save a scene in our XML format. We will us the ISavePlugin interface. For example, if we want to save the cameras of a scene in our proprietary format:


using System;

using System.Collections.Generic;

using System.Text;

using Vertice.NovaExplorer;

using System.Xml;

using Vertice.Nova;

namespace ImportXmlFileToNova

{

    class SaveXmlFile: ISaveScenePlugin

    {

       #region ISaveScenePlugin Members

        public string Extension

        {

            get

            {

                return "*.xml";

            }

        }

        public string Description

        {

            get

            {

                return "Save sTo Xml file format (*.xml)";

            }

        }

        public void Save(Vertice.Nova.NovaScene scene,

                         string filename,

                         Vertice.Nova.NovaScene.SaveOptions options)

        {

            XmlTextWriter writer =

                new XmlTextWriter(filename, Encoding.Default);

            writer.Formatting = Formatting.Indented;

            writer.WriteStartDocument();

            writer.WriteStartElement("scene");

            WriteCameras(writer, scene);

            WriteLights(writer, scene);

            // todo

            //WriteMaterials(writer, scene);

            //WriteObjects(writer, scene);

            writer.WriteEndElement();

            writer.Close();

        }

        private void WriteCameras(XmlTextWriter writer,

                                  NovaScene scene)

        {

            writer.WriteStartElement("cameras");

            foreach (NovaCamera camera in scene.Cameras)

            {

                writer.WriteStartElement("camera");

                writer.WriteAttributeString("name", camera.Name);

                WriteVector3(writer, camera.Position, "position");

                writer.WriteEndElement();

            }

            writer.WriteEndElement();

        }

        private void WriteLights(XmlTextWriter writer,

                                 NovaScene scene)

        {

            writer.WriteStartElement("lights");

            foreach (NovaLight tmpLight in scene.Lights)

            {

                writer.WriteStartElement("light");

                writer.WriteAttributeString("name", tmpLight.Name);

                writer.WriteAttributeString("type",

                                            tmpLight.Type.ToString());

                WriteVector3(writer, tmpLight.Position, "position");

                WriteElementWithValue(writer, "diffuseColor", "value",

                                      tmpLight.DiffuseColor.Name);

                WriteVector3(writer, tmpLight.Direction, "direction");

                writer.WriteEndElement();

            }

            writer.WriteEndElement();

        }

        private void WriteVector3(XmlTextWriter writer,

            Vertice.MathServices.Vector3 vector3, string p)

        {

            writer.WriteStartElement(p);

            writer.WriteAttributeString("x", vector3.X.ToString());

            writer.WriteAttributeString("y", vector3.Y.ToString());

            writer.WriteAttributeString("z", vector3.Z.ToString());

            writer.WriteEndElement();

        }

        private void WriteElementWithValue(XmlTextWriter writer,

            String elementName, String key, String value)

        {

            writer.WriteStartElement(elementName);

            writer.WriteAttributeString(key, value);

            writer.WriteEndElement();

        }

        #endregion ISaveScenePlugin Members

    }

}

More questions? Please visit our forum