WorldWind 学习笔记二、WW初始化(2) .

原文转自:http://blog.csdn.net/jk276993857/article/details/5735447

 

 * 一、主函数
 * WW程序的入口在WorldWind.cs的Main函数中,其中,args可通过命令行等方式进行
 * 传递参数,例如程序目录等。详见ParseArgs(args)。在主函数中,包括以下部分:
 * 1. 获得该应用程序的版本号
 * 2. 如果已经运行了WW,将该实例参数传出,并退出
 * 3. 如果服务器上有超过50个用户同时在线则退出
 * 4. 命名主线程
 * 5. 解析由命令行输入的args参数
 * 6. 载入配置文件 (重点***)
 * 7. 添加线程异常事件处理句柄
 * 8. 创建主应用程序实例 (重点*****)
 * 9. 保存World设置
 * 10.在保存程序设置之前对用户资格证书进行加密
 * 11.保存程序设置
 *
 * 二、创建主应用程序实例
 * 在主程序Main()中主要通过以下代码创建主应用程序实例
    MainApplication app = new MainApplication();
    Application.Idle += new EventHandler(app.WorldWindow.OnApplicationIdle);
    Application.Run(app);
 * 1. 初始化MainApplication
 *    1)配置向导ConfigurationWizard
 *    如果设置文件(WorldWind.xml)不存在,我们将启用默认设置,那就是
 *    在启动时显示配置向导。我们只希望在第一次启动WW时启动该向导,因
 *    此一旦启动后就把该设置成假(如果用户需要也可设置成真)
 *    该Flag的初始定义见WorldWindSettings.cs中的Miscellaneous settings
 *   
 *    2)初始化欢迎界面splashScreen
 *    Splash类中主要有两个元素需要关注:BackgroundImage和SetText
 *    BackgroundImage已经嵌入Splash资源中,如果需要通过自定义图片,可
 *    BackgroundImage = Image.FromFile(splashImageFile.FullName);
 *    SetText()在接下来的初始化过程中,记录初始化阶段,包括:
 *      splashScreen.SetText("Initializing...");
 *      OpenStartupWorld()中
 *      splashScreen.SetText("Initializing " + startupWorldName + "..." );
 *      OpenWorld()中
 *      splashScreen.SetText("Initializing menus...");
 *      InitializePluginCompiler()中
 *      splashScreen.SetText("Initializing plugins...");
 *      compiler.LoadStartupPlugins()中
 *      worldWind.SplashScreen.SetText("Initializing plugin " + pi.Name);
 *    自定义一个欢迎界面是软件的包装,对于程序员来说其重点不在美观,而在
 *    于将初始化的内容明晰化地表现,进度条和进度文字都很直观表现,但千万要
 *    考虑到用户的感受,让用户等得久不要紧,关键是在等待的过程中,欢迎界
 *    面需要给用户一点信息,让它知道程序正在正常运行,并且运行到哪了。
 *   
 *    3)初始化窗口界面InitializeComponent()
 *    这部分主要包括了MenuItem(菜单栏)、WebBrower(浏览器)、WorldWindow(地球窗口)、
 *    ToolBar(工具栏)。对于MenuItem和Toolbar的功能和促发事件在此不做详述
 *    参见:#region MenuItem and Toolbar item Click methods
 *   
 *    在此主要说明webBrowserPanel和worldWindow
 *    this.Controls.Add(splitContainer);
 *    this.splitContainer.Panel1.Controls.Add(this.webBrowserPanel);
 *    this.splitContainer.Panel2.Controls.Add(this.worldWindow);

 *      其中WebBrowserPanel主要包含了System.Windows.Forms.WebBrowser类
 *      worldWindow窗口包含了public class WorldWindow : Control, IGlobe类
 *      关于WorldWindow的将在下面单独进行说明
 *      此处只是进行了初始化this.worldWindow = new WorldWind.WorldWindow();

	// Now perform the rendering m_Device3d initialization
	// Skip DirectX initialization in design mode
    // 对渲染设备m_Device3d进行初始化,忽略DX的初始模式下的初始化
	if(!IsInDesignMode())
		this.InitializeGraphics();

	// Post m_Device3d creation initialization
    // 在m_Device3d创建之后进行的其他参数初始化
    // 此处的drawArgs类相当重要,用于绘制参数的设置
    // Widgets用于各窗口的传递、绘制、鼠标事件等
	this.drawArgs = new DrawArgs(m_Device3d, this );
	this.m_RootWidget = new WorldWind.Widgets.RootWidget(this);
    this.m_NewRootWidget = new WorldWind.NewWidgets.RootWidget(this);

	//this.m_RootWidget.ChildWidgets.Add(layerManager);
	DrawArgs.RootWidget = this.m_RootWidget;
    DrawArgs.NewRootWidget = this.m_NewRootWidget;

    // 用于帧率控制的时间器,事件委托
	m_FpsTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_FpsTimer_Elapsed);
	m_FpsTimer.Start();

	TimeKeeper.Start();
//	WorldWind.Widgets.LayerManager layerManager = new WorldWind.Widgets.LayerManager();
//	m_RootWidget.ChildWidgets.Add(layerManager);

 *
 *      WorldWind初始化中,InitializeGraphics()创建了D3D设备m_Device3d
 *      m_Device3d = new Device(adapterOrdinal, dType, this, flags, m_presentParams);
 *
 *
 *    4) 设置缓存

        worldWindow.Cache = new Cache(
        Settings.CachePath,
        CacheLowerLimit,
        CacheUpperLimit,
        Settings.CacheCleanupInterval, 
        Settings.TotalRunTime 
*    5)读取Xml星球配置文件
 *    在星球的初始化中,主要是构建初始场景和大气层,World newWorld = new World()
 *    以及将可渲染图层添加入列表中,getRenderablesFromLayerDirectory()
public static World Load(string filename, Cache cache)
{
    try
    {
        XmlReader docReader = XmlReader.Create(filename, readerSettings);
        XPathDocument docNav = new XPathDocument(docReader);
        XPathNavigator nav = docNav.CreateNavigator();
        // 根据Xml文件进行读取星球配置,此处不采用反序列化
        // 通过节点及属性进行读取,与文件格式相关,可参见Earth.xml
        XPathNodeIterator worldIter = nav.Select("/World[@Name]");
        if (worldIter.Count > 0)
        {
            worldIter.MoveNext();
            string worldName = worldIter.Current.GetAttribute("Name", "");
            double equatorialRadius = ParseDouble(worldIter.Current.GetAttribute("EquatorialRadius", ""));
            string layerDirectory = worldIter.Current.GetAttribute("LayerDirectory", "");

            if (layerDirectory.IndexOf(":") < 0)
            {
                layerDirectory = Path.Combine(Path.GetDirectoryName(filename), layerDirectory);
            }

            TerrainAccessor[] terrainAccessor = getTerrainAccessorsFromXPathNodeIterator(worldIter.Current.Select("TerrainAccessor"),
                System.IO.Path.Combine(cache.CacheDirectory, worldName));

            // 初始化星球,此处仅对外层大气层和根瓦片层进行初始化格网
            World newWorld = new World(
                worldName,
                new Microsoft.DirectX.Vector3(0, 0, 0),
                new Microsoft.DirectX.Quaternion(0, 0, 0, 0),
                equatorialRadius,
                cache.CacheDirectory,
                (terrainAccessor != null ? terrainAccessor[0] : null)//TODO: Oops, World should be able to handle an array of terrainAccessors
                );

            // 从图层文件夹中获取可渲染物体,例如^Placenames.xml、@Images.xml等
            newWorld.RenderableObjects = getRenderablesFromLayerDirectory(layerDirectory, newWorld, cache);

            return newWorld;
        }
    }
	return null;
}
* 此处主要是World的构造函数 World newWorld = new World()其基类是RenderableObject
 * 其中构建的可渲染物体包括
        this.m_projectedVectorRenderer = new ProjectedVectorRenderer(this);
          --UpdateRootTiles();
		    --ProjectedVectorTile newTile = new ProjectedVectorTile()
              --Renderable.ImageLayer 才是最终的可渲染的物体
 * 
        m_outerSphere.Init()
          --mesh.Vertices = CreateMesh();


 注意此处的外大气层不是RenderableObject,它的渲染和更新不通过接口完成
 *
 *      6)打开启动星球
 *      OpenStartupWorld()
 *      获取startupWorldName,再OpenWorld( curWorldFile );
 *      worldWindow.CurrentWorld = WorldWind.ConfigurationLoader.Load(worldXmlFile, worldWindow.Cache);
 *      此处对于ConfigurationLoader.Load与上面所讲内容一致
 *      但存在的疑问是,这里重复操作了,可以通过一定的优化,以加快初始化速度。
 *     
 *      7)加载项,在OpenStartupWorld()->OpenWorld()中最后几行

        // 初始化加载编译器,包括VB、C#、JS编译器
	    InitializePluginCompiler();

        // 添加图层目录按钮
        // this.worldWindow.CurrentWorld.RenderableObjects.ChildObjects
        // 是从加载地球时getRenderablesFromLayerDirectory()函数加载进来的
        // 另一方面,从加载项的载入时添加的图层,例如3DStars等
        foreach (RenderableObject worldRootObject in this.worldWindow.CurrentWorld.RenderableObjects.ChildObjects)
	    {
		    this.AddLayerMenuButtons(this.worldWindow, worldRootObject);
	    }
        // 添加内部加载项目录按钮,其中InternalPlugin是从InitializePluginCompiler
        // 中的FindPlugins(Assembly.GetExecutingAssembly());函数得到的
	    this.AddInternalPluginMenuButtons();

 *          1.7.1 初始化加载项,分为三步a构造函数、b寻找可加载项,c进行加载
 *                注意此处已经将Settings中设置的启动加载项与之后的m_Plugins关联起来

 		private void InitializePluginCompiler()
		{
            Log.Write(Log.Levels.Debug, "CONF", "initializing plugin compiler...");
            this.splashScreen.SetText("Initializing plugins...");
			string pluginRoot = Path.Combine(DirectoryPath, "Plugins");
			// 构造函数
            compiler = new PluginCompiler(this, pluginRoot);

            //#if DEBUG
			// Search for plugins in worldwind.exe (plugin development/debugging aid)
			// 寻找WW内部的加载项
            compiler.FindPlugins(Assembly.GetExecutingAssembly());
            //#endif
            // 寻找Debug/Plugin/目录下的其他加载项
            // 根据文件扩展名来判定,可加载c#/vb/js等类型或.dll预编译的加载项
			compiler.FindPlugins();
            // 进行加载
			compiler.LoadStartupPlugins();
		}

 *          1.7.1.1 构造函数中,最重要的是定义了三个编译器,C#/VB/JS

		        AddCodeProvider(new Microsoft.CSharp.CSharpCodeProvider() );
		        AddCodeProvider(new Microsoft.VisualBasic.VBCodeProvider() );
		        AddCodeProvider(new Microsoft.JScript.JScriptCodeProvider() );

 *          1.7.1.2 寻找可加载项包括内部和外部,内部的通过主程序里的模块加载
 *                  外部的通过Debug/Plugin/文件中进行读取
 *                  其中FindPlugins()主要调用AddPlugin(string path)函数
 *                  此处仅根据扩展名添加加载项的路径

 				string extension = Path.GetExtension(filename).ToLower();
				if(HasCompiler(extension) || IsPreCompiled(extension))
				{
					PluginInfo plugin = new PluginInfo();
					plugin.FullPath = filename;
					m_plugins.Add(plugin);
				} 

 *          1.7.1.3 进行加载LoadStartupPlugins(),其中核心函数为Load(PluginInfo pi)

		public void Load(PluginInfo pi)
		{
			if(pi.Plugin == null)
			{
				// Try to find a suitable compiler
                // 根据扩展名查找合适的编译器
				string extension = Path.GetExtension(pi.FullPath).ToLower();
				Assembly asm = null;
				if(extension==".dll")
				{
					// Load pre-compiled assembly
                    // 对于.dll文件则直接加载预编译项
					asm = Assembly.LoadFile(pi.FullPath);
				}
				else
				{
                    // 根据扩展名加载合适的编译器,并编译
					CodeDomProvider cdp = (CodeDomProvider)codeDomProviders[extension];
					if(cdp==null)
						return;
					asm = Compile(pi, cdp);
				}
                // 获取Plugin的接口
				pi.Plugin = GetPluginInterface(asm);
			}

			string pluginPath = MainApplication.DirectoryPath;
			if( pi.FullPath != null && pi.FullPath.Length > 0)
				pluginPath = Path.GetDirectoryName(pi.FullPath);

            // 加载Plugin,其内部Load可重载
			pi.Plugin.PluginLoad(worldWind, pluginPath);

 *      1.7.2 AddLayerMenuButtons添加图层目录按钮
 *      this.worldWindow.CurrentWorld.RenderableObjects.ChildObjects
 *      是从加载地球时getRenderablesFromLayerDirectory()函数加载进来的
 *      另一方面,从加载项的载入时添加的图层,例如3DStars等,即通过上面加载
 *      Plugin内部的Load重载
 *     
 *      1.7.3 添加内部加载项目录按钮,
 *      其中InternalPlugin是从InitializePluginCompiler中的
 *      FindPlugins(Assembly.GetExecutingAssembly());函数得到的
 *      核心函数是使用worldWindow.MenuBar.AddToolsMenuButton()函数完成
 *      此处,只添加三个加载项目的目录按钮,而其他还有20个目录按钮在不同
 *      地方进行加载,可通过搜索MenuBar.AddToolsMenuButton进行查找.

 *    8) 设置垂直放大子目录
 *    9) 载入其他默认配置,以更改菜单栏状态
 *    10)强制初始绘制,以免向用户显示随机帧缓存内容
 *    Render()内容将在后续说明
 *   
 * 小结:通过对MainApplication实例的初始化,基本将主程序的窗口界面、启动
 *      星球、加载项、配置信息初始化完成,并可进行第一帧的绘制。此后的
 *      过程即为不断绘制并更新当前窗体内容。更新是通过鼠标、键盘、菜单
 *      栏、工具栏的状态改变来更新相应的参数。而绘制函数所需要的所有参
 *      数都已经在此完成,在绘制函数中,只需要不断循环即可。接下来,通过
 *      对Render函数的学习,以及对鼠标、键盘、菜单栏、工具栏的学习,即可
 *      逐步掌握WW的入门。而进阶学习还将要有更深入的了解才能有质的飞越。











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值