home *** CD-ROM | disk | FTP | other *** search
/ Mundo do CD-ROM 119 / cdrom119.iso / internet / wwind / World_Wind_1.3.5_Full.exe / Plugins / GlobalClouds / GlobalClouds.cs next >
Encoding:
Text File  |  2006-05-08  |  27.2 KB  |  846 lines

  1. //----------------------------------------------------------------------------
  2. // NAME: GlobalClouds
  3. // VERSION: 0.6
  4. // DESCRIPTION: Download and renders the latest global cloud cover around the world. Updates every three hours and keeps ten days history. Adds itself as a layer in Layer Manager (key: L). Right click on layer for settings.
  5. // DEVELOPER: Patrick Murris
  6. // WEBSITE: http://www.alpix.com/3d/worldwin
  7. //----------------------------------------------------------------------------
  8. // Based on the Stars plugin, itself based on Bjorn Reppen 'Atmosphere' plugin
  9. // Latest cloud map comes from a random server listed at http://xplanet.sourceforge.net/clouds.php 
  10. // and is mirrored at http://www.twobeds.com/nasa/clouds/clouds_2048.jpg for this plugin.
  11. //
  12. // 0.6 Feb  10, 2006    Fixed 'Error loading texture' bug after 10 days plugin not used (History cleanup at starup removed)
  13. // 0.5 Dec  22, 2005    Promoted to RenderPriority.AtmosphericImages
  14. // 0.4 Dec   6, 2005    Added 'Earth only' test and fixed ZBuffer bug
  15. // 0.3 Nov  29, 2005    Added next and previous buttons in settings 
  16. // 0.2 Nov  26, 2005    Added download and processing of latest cloud cover 
  17. // 0.1 Nov  22, 2005    Testing global cloud layer... 
  18. //----------------------------------------------------------------------------
  19. // Known issues : Doesnt handle http errors as expected (try/catch/retrycount++...)
  20. //        : May leave garbage if plugin unloaded while downloading
  21. //----------------------------------------------------------------------------
  22.  
  23.  
  24. using Microsoft.DirectX;
  25. using Microsoft.DirectX.Direct3D;
  26. using System.Windows.Forms;
  27. using WorldWind.Renderable;
  28. using WorldWind.Camera;
  29. using WorldWind.Net;
  30. using WorldWind.VisualControl;
  31. using WorldWind;
  32. using System.IO;
  33. using System.Drawing;
  34. using System.Net;
  35. using System.Collections;
  36. using System;
  37.  
  38. namespace Murris.Plugins
  39. {
  40.     /// <summary>
  41.     /// The plugin (main class)
  42.     /// </summary>
  43.     public class GlobalClouds : WorldWind.PluginEngine.Plugin 
  44.     {
  45.         private WorldWind.WindowsControlMenuButton m_ToolbarItem;
  46.         private Control control = new Control();
  47.         private EventHandler evhand;
  48.         private GlobalCloudsLayer layer;
  49.         /// <summary>
  50.         /// Name displayed in layer manager
  51.         /// </summary>
  52.         public static string LayerName = "GlobalClouds";
  53.  
  54.         /// <summary>
  55.         /// Plugin entry point - All plugins must implement this function
  56.         /// </summary>
  57.         public override void Load()
  58.         {
  59.             if (ParentApplication.WorldWindow.CurrentWorld != null && ParentApplication.WorldWindow.CurrentWorld.Name.IndexOf("Earth") >= 0)
  60.             {
  61.                 // Add layer visibility controller (and save it to make sure you can kill it later!)
  62.                 control.Visible = true;
  63.                 evhand = new EventHandler(control_VisibleChanged);
  64.                 control.VisibleChanged += evhand;
  65.                 // Add toolbar item
  66.                 m_ToolbarItem = new WorldWind.WindowsControlMenuButton("Global Clouds", Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), @"Data\Icons\Interface\earth-eastern.png"), control);
  67.                 m_Application.WorldWindow.MenuBar.AddToolsMenuButton(m_ToolbarItem);
  68.  
  69.                 layer = new GlobalCloudsLayer(LayerName, PluginDirectory, ParentApplication.WorldWindow);
  70.                 layer.IsOn = World.Settings.ShowClouds;
  71.                 //ParentApplication.WorldWindow.CurrentWorld.RenderableObjects.ChildObjects.Insert(0,layer);
  72.                 ParentApplication.WorldWindow.CurrentWorld.RenderableObjects.Add(layer);
  73.  
  74.                 m_ToolbarItem.SetPushed(World.Settings.ShowClouds);
  75.                
  76.             }
  77.         }
  78.  
  79.         /// <summary>
  80.         /// Unloads our plugin
  81.         /// </summary>
  82.         public override void Unload() 
  83.         {
  84.             // Remove layer controller
  85.             control.VisibleChanged -= evhand;
  86.             control.Dispose();
  87.  
  88.             // Remove toolbar item
  89.             if (m_ToolbarItem != null)
  90.                 m_Application.WorldWindow.MenuBar.RemoveToolsMenuButton(m_ToolbarItem);
  91.  
  92.             ParentApplication.WorldWindow.CurrentWorld.RenderableObjects.Remove(LayerName);
  93.         }
  94.         /// <summary>
  95.         /// Toggles visibility on the CompassLayer
  96.         /// </summary>
  97.         /// <param name="sender"></param>
  98.         /// <param name="e"></param>
  99.         private void control_VisibleChanged(object sender, EventArgs e)
  100.         {
  101.             if (control.Visible)
  102.                 layer.IsOn = true;
  103.             else
  104.                 layer.IsOn = false;
  105.         }
  106.     }
  107.  
  108.     /// <summary>
  109.     /// GlobalCloudsLayer
  110.     /// </summary>
  111.     public class GlobalCloudsLayer : RenderableObject
  112.     {
  113.         static string version = "0.6";
  114.         string settingsFileName = "GlobalClouds.ini";
  115.         string serverListFileName = "GlobalCloudsServers.txt";
  116.         string pluginPath;
  117.         public World world;
  118.         public DrawArgs drawArgs;
  119.         Mesh layerMesh;
  120.         Texture texture = null;
  121.         Form pDialog;
  122.  
  123.         // current GlobalClouds bitmap
  124.         public string textureFileName = "";
  125.  
  126.         public string latestFileName = "";
  127.         public DateTime latestTime = DateTime.MinValue;
  128.         public int historyDays = 10;                    // How many days to keep cloud maps
  129.         public int refreshHours = 3;                    // How often to refresh cloud map
  130.  
  131.         /// <summary>
  132.         /// Constructor
  133.         /// </summary>
  134.         public GlobalCloudsLayer(string LayerName, string pluginPath, WorldWindow worldWindow) : base(LayerName)
  135.         {
  136.             this.pluginPath = pluginPath;
  137.             this.world = worldWindow.CurrentWorld;
  138.             this.drawArgs = worldWindow.DrawArgs;
  139.             this.RenderPriority = RenderPriority.AtmosphericImages;
  140.             //CleanupHistory();
  141.             CleanupJpg();
  142.             FindLatest();
  143.             ReadSettings();
  144.             if(textureFileName == "" && latestFileName != "") textureFileName = latestFileName;
  145.  
  146.             //MessageBox.Show("Server url : " + GetServerUrl(),"Info.", MessageBoxButtons.OK, MessageBoxIcon.Error );
  147.         }
  148.         
  149.         /// <summary>
  150.         /// Find which cloud map is the latest and at what date/time
  151.         /// </summary>
  152.         public void FindLatest()
  153.         {
  154.             DirectoryInfo di = new DirectoryInfo(pluginPath);
  155.             FileInfo[] imgFiles = di.GetFiles("clouds*.png");
  156.             for(int i = 0; i < imgFiles.Length; i++)
  157.             {
  158.                 if(imgFiles[i].LastWriteTime > latestTime)
  159.                 {
  160.                     latestFileName = imgFiles[i].Name;
  161.                     latestTime = imgFiles[i].LastWriteTime;
  162.                 }
  163.             }
  164.         }
  165.  
  166.         public override bool IsOn
  167.         {
  168.             get
  169.             {
  170.                 return base.IsOn;
  171.             }
  172.             set
  173.             {
  174.                 World.Settings.ShowClouds = value;
  175.                 base.IsOn = value;
  176.             }
  177.         }
  178.  
  179.  
  180.         /// <summary>
  181.         /// Delete cloud maps older than historyDays
  182.         /// </summary>
  183.         public void CleanupHistory()
  184.         {
  185.             DateTime oldest = DateTime.Now.AddDays(-historyDays);
  186.             DirectoryInfo di = new DirectoryInfo(pluginPath);
  187.             FileInfo[] imgFiles = di.GetFiles("clouds*.png");
  188.             for(int i = 0; i < imgFiles.Length; i++)
  189.             {
  190.                 if(imgFiles[i].LastWriteTime < oldest)
  191.                 {
  192.                     File.Delete(Path.Combine(pluginPath, imgFiles[i].Name));
  193.                 }
  194.             }
  195.         }
  196.         /// <summary>
  197.         /// Delete .jpg cloud maps
  198.         /// </summary>
  199.         public void CleanupJpg()
  200.         {
  201.             DirectoryInfo di = new DirectoryInfo(pluginPath);
  202.             FileInfo[] imgFiles = di.GetFiles("clouds*.jpg");
  203.             for(int i = 0; i < imgFiles.Length; i++)
  204.             {
  205.                 File.Delete(Path.Combine(pluginPath, imgFiles[i].Name));
  206.             }
  207.         }
  208.  
  209.         /// <summary>
  210.         /// Read saved settings from ini file
  211.         /// </summary>
  212.         public void ReadSettings()
  213.         {
  214.             string line = "";
  215.             try 
  216.             {
  217.                 TextReader tr = File.OpenText(Path.Combine(pluginPath, settingsFileName));
  218.                 line = tr.ReadLine();
  219.                 tr.Close();
  220.             }
  221.             catch(Exception caught) {}
  222.             if(line != "")
  223.             {
  224.                 string[] settingsList = line.Split(';');
  225.                 string saveVersion = settingsList[0];    // version when settings where saved
  226.                 if(settingsList[1] != null) textureFileName = settingsList[1];
  227.             }
  228.         }
  229.  
  230.         /// <summary>
  231.         /// Save settings in ini file
  232.         /// </summary>
  233.         public void SaveSettings()
  234.         {
  235.             string line = version + ";" + textureFileName;
  236.             try
  237.             {
  238.                 StreamWriter sw = new StreamWriter(Path.Combine(pluginPath, settingsFileName));
  239.                 sw.Write(line);
  240.                 sw.Close();
  241.             }
  242.             catch(Exception caught) {}
  243.         }
  244.  
  245.         #region RenderableObject
  246.  
  247.         /// <summary>
  248.         /// This is where we do our rendering 
  249.         /// Called from UI thread = UI code safe in this function
  250.         /// </summary>
  251.         public override void Render(DrawArgs drawArgs)
  252.         {
  253.             if(!isInitialized) return;
  254.             if(world.Name != "Earth") return;    // Earth only
  255.  
  256.             // Check for update
  257.             if(!isDownloading && DateTime.Now > latestTime.AddHours(refreshHours)) 
  258.             {
  259.                 if(retryCount < maxRetry && DateTime.Now > lastDownloadTime.AddSeconds(retryDelaySeconds))
  260.                 {
  261.                     StartDownload(pluginPath, "clouds_" + DateTimeStamp(DateTime.Now) + ".jpg");
  262.                 }
  263.             }
  264.  
  265.             // Camera & Device shortcuts ;)
  266.             CameraBase camera = drawArgs.WorldCamera;
  267.             //Device device = drawArgs.device;
  268.  
  269.             // Render cloud layer
  270.             if(texture != null)
  271.             {
  272.                 double cloudAlt = 20e3; // clouds altitude in meters (20 x 10e3)
  273.  
  274.                 if(camera.Altitude < 4000e3) return;
  275.  
  276.                 double sphereRadius = camera.WorldRadius + cloudAlt; 
  277.             
  278.                 // Create sphere
  279.                 if(layerMesh == null) 
  280.                     layerMesh = TexturedSphere(drawArgs.device, (float)sphereRadius, 64, 64);
  281.             
  282.                 // set texture
  283.                 drawArgs.device.SetTexture(0,texture);
  284.                 drawArgs.device.TextureState[0].ColorOperation = TextureOperation.BlendCurrentAlpha;
  285.                 drawArgs.device.VertexFormat = CustomVertex.PositionNormalTextured.Format;
  286.             
  287.                 // save world and projection transform
  288.                 Matrix origWorld = drawArgs.device.Transform.World;
  289.                 Matrix origProjection = drawArgs.device.Transform.Projection;
  290.  
  291.                 // Save fog status and disable fog
  292.                 bool origFog = drawArgs.device.RenderState.FogEnable;
  293.                 drawArgs.device.RenderState.FogEnable = false;
  294.  
  295.                 // Set new projection (to avoid being clipped) - probably better ways of doing this?
  296.                 float aspectRatio =  (float)drawArgs.device.Viewport.Width / drawArgs.device.Viewport.Height;
  297.                 drawArgs.device.Transform.Projection = Matrix.PerspectiveFovRH((float)camera.Fov.Radians, aspectRatio, 1, float.MaxValue );
  298.  
  299.                 // draw
  300.                 drawArgs.device.RenderState.ZBufferEnable = false;
  301.                 layerMesh.DrawSubset(0);
  302.  
  303.                 // Restore device states
  304.                 drawArgs.device.Transform.World = origWorld;
  305.                 drawArgs.device.Transform.Projection = origProjection;
  306.                 drawArgs.device.RenderState.FogEnable = origFog;
  307.                 drawArgs.device.RenderState.ZBufferEnable = true;
  308.             }
  309.  
  310.             // Render progress bar if downloading
  311.             if(isDownloading)
  312.             {
  313.                 if(progressBar == null) progressBar = new WorldWind.VisualControl.ProgressBar(40,4);
  314.                 progressBar.Draw(drawArgs, drawArgs.screenWidth - 34, drawArgs.screenHeight - 10, ProgressPercent, downloadProgressColor);
  315.                 drawArgs.device.RenderState.ZBufferEnable = true;
  316.             }
  317.  
  318.         }
  319.  
  320.         /// <summary>
  321.         /// RenderableObject abstract member (needed) 
  322.         /// OBS: Worker thread (don't update UI directly from this thread)
  323.         /// </summary>
  324.         public override void Initialize(DrawArgs drawArgs)
  325.         {
  326.             if(textureFileName != "")
  327.             {
  328.                 try
  329.                 {
  330.                     texture = TextureLoader.FromFile(drawArgs.device, Path.Combine(pluginPath, textureFileName));
  331.                     isInitialized = true;    
  332.                 }
  333.                 catch
  334.                 {
  335.                     //isOn = false;
  336.                     //MessageBox.Show("Error loading texture " + Path.Combine(pluginPath, textureFileName) + ".","Layer initialization failed.", MessageBoxButtons.OK, MessageBoxIcon.Error );
  337.                     textureFileName = "";
  338.                 }
  339.             }
  340.             else
  341.             {
  342.                 StartDownload(pluginPath, "clouds_" + DateTimeStamp(DateTime.Now) + ".jpg");
  343.                 isInitialized = true;    
  344.             }
  345.         }
  346.  
  347.         /// <summary>
  348.         /// RenderableObject abstract member (needed)
  349.         /// OBS: Worker thread (don't update UI directly from this thread)
  350.         /// </summary>
  351.         public override void Update(DrawArgs drawArgs)
  352.         {
  353.             if(!isInitialized)
  354.                 Initialize(drawArgs);
  355.         }
  356.  
  357.         /// <summary>
  358.         /// RenderableObject abstract member (needed)
  359.         /// OBS: Worker thread (don't update UI directly from this thread)
  360.         /// </summary>
  361.         public override void Dispose()
  362.         {
  363.             isInitialized = false;
  364.             if(texture!=null)
  365.             {
  366.                 texture.Dispose();
  367.                 texture = null;
  368.             }
  369.  
  370.             if(layerMesh != null)
  371.             {
  372.                 layerMesh.Dispose();
  373.                 layerMesh = null;
  374.             }
  375.         }
  376.  
  377.         /// <summary>
  378.         /// Gets called when user left clicks.
  379.         /// RenderableObject abstract member (needed)
  380.         /// Called from UI thread = UI code safe in this function
  381.         /// </summary>
  382.         public override bool PerformSelectionAction(DrawArgs drawArgs)
  383.         {
  384.             return false;
  385.         }
  386.  
  387.          /// <summary>
  388.          /// Fills the context menu with menu items specific to the layer.
  389.          /// </summary>
  390.          public override void BuildContextMenu( ContextMenu menu )
  391.          {
  392.               menu.MenuItems.Add("Properties", new System.EventHandler(OnPropertiesClick));
  393.          }
  394.  
  395.          /// <summary>
  396.          /// Properties context menu clicked.
  397.          /// </summary>
  398.          public new void OnPropertiesClick(object sender, EventArgs e)
  399.          {
  400.             if(pDialog != null && ! pDialog.IsDisposed)
  401.                 // Already open
  402.                 return;
  403.  
  404.             // Display the dialog
  405.             pDialog = new propertiesDialog(this);
  406.             pDialog.Show();
  407.  
  408.          }
  409.  
  410.         /// <summary>
  411.         /// Properties Dialog
  412.         /// </summary>
  413.         public class propertiesDialog : System.Windows.Forms.Form
  414.         {
  415.             private System.Windows.Forms.Label lblTexture;
  416.             private System.Windows.Forms.ComboBox cboTexture;
  417.             private System.Windows.Forms.Button btnOK;
  418.             private System.Windows.Forms.Button btnCancel;
  419.             private System.Windows.Forms.Button btnPrevious;
  420.             private System.Windows.Forms.Button btnNext;
  421.             private GlobalCloudsLayer layer;
  422.             private string savedTextureFileName;
  423.  
  424.             public propertiesDialog( GlobalCloudsLayer layer )
  425.             {
  426.                 this.layer = layer;
  427.                 InitializeComponent();
  428.                 //this.Icon = WorldWind.PluginEngine.Plugin.Icon;
  429.                 // Init texture list with *.jpg and/or *.png
  430.                 DirectoryInfo di = new DirectoryInfo(layer.pluginPath);
  431.                 FileInfo[] imgFiles = di.GetFiles("*.png");                
  432.                 cboTexture.Items.AddRange(imgFiles);
  433.                 // select current bitmap
  434.                 int i = cboTexture.FindString(layer.textureFileName);
  435.                 if(i != -1) cboTexture.SelectedIndex = i;
  436.                 // Save current textureFileName
  437.                 savedTextureFileName = layer.textureFileName;
  438.                 //this.Text += layer.version;
  439.             }
  440.  
  441.             #region Windows Form Designer generated code
  442.             /// <summary>
  443.             /// Required method for Designer support - do not modify
  444.             /// the contents of this method with the code editor.
  445.             /// </summary>
  446.             private void InitializeComponent()
  447.             {
  448.                 this.btnCancel = new System.Windows.Forms.Button();
  449.                 this.btnOK = new System.Windows.Forms.Button();
  450.                 this.btnPrevious = new System.Windows.Forms.Button();
  451.                 this.btnNext = new System.Windows.Forms.Button();
  452.                 this.lblTexture = new System.Windows.Forms.Label();
  453.                 this.cboTexture = new System.Windows.Forms.ComboBox();
  454.                 this.SuspendLayout();
  455.                 // 
  456.                 // btnCancel
  457.                 // 
  458.                 this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
  459.                 this.btnCancel.Location = new System.Drawing.Point(311, 59);
  460.                 this.btnCancel.Name = "btnCancel";
  461.                 this.btnCancel.TabIndex = 0;
  462.                 this.btnCancel.Text = "Cancel";
  463.                 this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
  464.                 // 
  465.                 // btnOK
  466.                 // 
  467.                 this.btnOK.Location = new System.Drawing.Point(224, 59);
  468.                 this.btnOK.Name = "btnOK";
  469.                 this.btnOK.TabIndex = 1;
  470.                 this.btnOK.Text = "OK";
  471.                 this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
  472.                 // 
  473.                 // btnPrevious
  474.                 // 
  475.                 this.btnPrevious.Location = new System.Drawing.Point(20, 59);
  476.                 this.btnPrevious.Name = "btnPrevious";
  477.                 this.btnPrevious.TabIndex = 2;
  478.                 this.btnPrevious.Text = "Previous";
  479.                 this.btnPrevious.Click += new System.EventHandler(this.btnPrevious_Click);
  480.                 // 
  481.                 // btnNext
  482.                 // 
  483.                 this.btnNext.Location = new System.Drawing.Point(106, 59);
  484.                 this.btnNext.Name = "btnNext";
  485.                 this.btnNext.TabIndex = 3;
  486.                 this.btnNext.Text = "Next";
  487.                 this.btnNext.Click += new System.EventHandler(this.btnNext_Click);
  488.                 // 
  489.                 // lblTexture
  490.                 // 
  491.                 this.lblTexture.AutoSize = true;
  492.                 this.lblTexture.Location = new System.Drawing.Point(16, 28);
  493.                 this.lblTexture.Name = "lblTexture";
  494.                 this.lblTexture.Size = new System.Drawing.Size(82, 16);
  495.                 this.lblTexture.TabIndex = 4;
  496.                 this.lblTexture.Text = "Clouds map :";
  497.                 // 
  498.                 // cboTexture
  499.                 // 
  500.                 this.cboTexture.Location = new System.Drawing.Point(96, 25);
  501.                 this.cboTexture.Name = "cboTexture";
  502.                 this.cboTexture.Size = new System.Drawing.Size(296, 21);
  503.                 this.cboTexture.TabIndex = 5;
  504.                 this.cboTexture.Text = "Select texture file";
  505.                 this.cboTexture.DropDownStyle = ComboBoxStyle.DropDownList;
  506.                 this.cboTexture.MaxDropDownItems = 10;
  507.                 // 
  508.                 // frmFavorites
  509.                 // 
  510.                 this.AcceptButton = this.btnOK;
  511.                 this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
  512.                 this.CancelButton = this.btnCancel;
  513.                 this.ClientSize = new System.Drawing.Size(406, 94);
  514.                 this.ControlBox = false;
  515.                 this.Controls.Add(this.cboTexture);
  516.                 this.Controls.Add(this.lblTexture);
  517.                 this.Controls.Add(this.btnOK);
  518.                 this.Controls.Add(this.btnCancel);
  519.                 this.Controls.Add(this.btnPrevious);
  520.                 this.Controls.Add(this.btnNext);
  521.                 this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
  522.                 this.MaximizeBox = false;
  523.                 this.MinimizeBox = false;
  524.                 this.Name = "pDialog";
  525.                 this.ShowInTaskbar = false;
  526.                 this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
  527.                 //this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
  528.                 //this.Location = new System.Drawing.Point(layer.drawArgs.CurrentMousePosition.X + 10, layer.drawArgs.CurrentMousePosition.Y - 10);
  529.                 this.Text = "GlobalClouds properties ";
  530.                 this.TopMost = true;
  531.                 this.ResumeLayout(false);
  532.  
  533.             }
  534.             #endregion
  535.  
  536.             private void btnOK_Click(object sender, System.EventArgs e)
  537.             {
  538.                 if(cboTexture.SelectedItem != null) 
  539.                 {
  540.                     if(cboTexture.SelectedItem.ToString().IndexOf(".png") != -1) 
  541.                     {    // Update texture and save settings
  542.                         layer.Dispose();
  543.                         layer.textureFileName = cboTexture.SelectedItem.ToString();
  544.                         layer.Initialize(layer.drawArgs);
  545.                         layer.SaveSettings();
  546.                     }
  547.                 }
  548.                 // Close this form
  549.                 this.Close();
  550.             }
  551.  
  552.             private void btnCancel_Click(object sender, System.EventArgs e)
  553.             {
  554.                 if(layer.textureFileName != savedTextureFileName)
  555.                 {    // Rreset texture if it has changed
  556.                     layer.Dispose();
  557.                     layer.textureFileName = savedTextureFileName;
  558.                     layer.Initialize(layer.drawArgs);
  559.                 }
  560.                 // Close this form
  561.                 this.Close();
  562.             }
  563.  
  564.             private void btnPrevious_Click(object sender, System.EventArgs e)
  565.             {
  566.                 layer.GotoPrevious();
  567.                 // select current bitmap
  568.                 int i = cboTexture.FindString(layer.textureFileName);
  569.                 if(i != -1) cboTexture.SelectedIndex = i;
  570.             }
  571.  
  572.             private void btnNext_Click(object sender, System.EventArgs e)
  573.             {
  574.                 layer.GotoNext();
  575.                 // select current bitmap
  576.                 int i = cboTexture.FindString(layer.textureFileName);
  577.                 if(i != -1) cboTexture.SelectedIndex = i;
  578.             }
  579.         }
  580.  
  581.         // Switching cloud maps from history
  582.         // ---------------------------------
  583.  
  584.         public ArrayList historyList;
  585.         public void BuildHistoryList()
  586.         {
  587.             historyList = new ArrayList();
  588.             DirectoryInfo di = new DirectoryInfo(pluginPath);
  589.             FileInfo[] imgFiles = di.GetFiles("clouds*.png");
  590.             for(int i = 0; i < imgFiles.Length; i++)
  591.             {
  592.                 historyList.Add(imgFiles[i].Name);
  593.             }
  594.             historyList.Sort();
  595.         }
  596.  
  597.  
  598.         public void GotoPrevious()
  599.         {
  600.             if(historyList == null) BuildHistoryList();
  601.             int i = historyList.IndexOf(textureFileName);
  602.             if(i != -1)
  603.             {
  604.                 if(i > 0) i--;  else i = historyList.Count - 1;
  605.                 textureFileName = (string)historyList[i];
  606.                 Dispose();
  607.                 Initialize(drawArgs);
  608.             }
  609.         }
  610.  
  611.         public void GotoNext()
  612.         {
  613.             if(historyList == null) BuildHistoryList();
  614.             int i = historyList.IndexOf(textureFileName);
  615.             if(i != -1)
  616.             {
  617.                 if(i < historyList.Count - 1) i++;  else i = 0;
  618.                 textureFileName = (string)historyList[i];
  619.                 Dispose();
  620.                 Initialize(drawArgs);
  621.             }
  622.         }
  623.  
  624.  
  625.         // Downloading new cloud maps
  626.         // --------------------------
  627.  
  628.         public bool isDownloading = false;
  629.         public float ProgressPercent;
  630.         WebDownload download;
  631.         WorldWind.VisualControl.ProgressBar progressBar;
  632.         int downloadProgressColor = Color.FromArgb(180,200,200,200).ToArgb();
  633.         int maxRetry = 3;
  634.         int retryCount = 0;
  635.         int retryDelaySeconds = 60;
  636.         DateTime lastDownloadTime = DateTime.MinValue;
  637.         
  638.         private void DownloadCloudMap(string filePath, string fileName) // NOT USED (synchronous)
  639.         {
  640.             string url = GetServerUrl();
  641.             System.Net.WebClient wc = new System.Net.WebClient();
  642.             wc.DownloadFile(url, Path.Combine(filePath, fileName));
  643.             wc.Dispose();
  644.         }
  645.  
  646.         public virtual void StartDownload(string filePath, string fileName) // Asynch download here
  647.         {
  648.             string url = GetServerUrl();
  649.             download = new WebDownload(url);
  650.             download.SavedFilePath = Path.Combine(filePath, fileName);
  651.             download.ProgressCallback += new DownloadProgressHandler(UpdateProgress);
  652.             download.CompleteCallback += new DownloadCompleteHandler(DownloadComplete);
  653.             download.BackgroundDownloadFile();
  654.             isDownloading = true;
  655.         }
  656.  
  657.         // Read server list and pick one
  658.         public string GetServerUrl()
  659.         {
  660.             Random r = new Random();
  661.             ArrayList serverList = new ArrayList();
  662.             string line;
  663.             TextReader tr = File.OpenText(Path.Combine(pluginPath, serverListFileName));
  664.             while ((line = tr.ReadLine()) != null) 
  665.             {
  666.                 if(line.StartsWith("http://")) serverList.Add(line);
  667.             }
  668.             tr.Close();
  669.             string Url = (string)serverList[r.Next(serverList.Count - 1)];
  670.             return Url;
  671.         }
  672.  
  673.         void UpdateProgress( int pos, int total )
  674.         {
  675.             if(total==0)
  676.                 // When server doesn't provide content-length, use this dummy value to at least show some progress.
  677.                 total = 50*1024; 
  678.             pos = pos % (total+1);
  679.             ProgressPercent = (float)pos/total;
  680.         }
  681.  
  682.         // Download done: process image and update current texture (or deal with errors)
  683.         private void DownloadComplete(WebDownload downloadInfo)
  684.         {
  685.             try
  686.             {
  687.                 // Check for errors
  688.                 downloadInfo.Verify();
  689.                 // To do : read original cloud date in comment info inside jpg
  690.             
  691.                 // Process image and creat .png
  692.                 MakeAlphaPng(downloadInfo.SavedFilePath);
  693.                 //Delete jpg and cleanup history
  694.                 //File.Delete(downloadInfo.SavedFilePath);
  695.                 CleanupHistory();
  696.                 // Refresh latest info (date and filename)
  697.                 FindLatest();
  698.                 // Update texture with latest
  699.                 Dispose();
  700.                 textureFileName = latestFileName;
  701.                 Initialize(drawArgs);
  702.                 SaveSettings();
  703.                 retryCount = 0;
  704.  
  705.             }
  706.             catch(System.Net.WebException caught) // This doesnt work ;(
  707.             {
  708.                 System.Net.HttpWebResponse response = caught.Response as System.Net.HttpWebResponse;
  709.                 //if(response!=null && response.StatusCode==System.Net.HttpStatusCode.NotFound)
  710.                 if(response!=null)
  711.                 {
  712.                     // display response.StatusDescription;
  713.                     MessageBox.Show("Error downloading cloud map from " + downloadInfo.Url + " (" + response.StatusDescription + ").", "Download failed.", MessageBoxButtons.OK, MessageBoxIcon.Error );
  714.                     
  715.                     //return;
  716.                 }
  717.                 retryCount++;
  718.             }
  719.             catch(Exception caugth)
  720.             {
  721.                 MessageBox.Show("Error downloading cloud map from " + downloadInfo.Url + " (" + caugth.Message + ").", "Download failed.", MessageBoxButtons.OK, MessageBoxIcon.Error );
  722.                 if(File.Exists(downloadInfo.SavedFilePath))
  723.                     File.Delete(downloadInfo.SavedFilePath);
  724.                 retryCount++;
  725.             }
  726.             finally
  727.             {
  728.                 download.IsComplete = true;
  729.                 isDownloading = false;
  730.                 lastDownloadTime = DateTime.Now;
  731.             }
  732.         }
  733.  
  734.         // Return a date formated as YYYYMMDD-HHMM
  735.         public string DateTimeStamp(DateTime d) 
  736.         {
  737.             return d.Year.ToString() + d.Month.ToString("d2") + d.Day.ToString("d2") + "-" + d.Hour.ToString("d2") + d.Minute.ToString("d2");
  738.  
  739.         }
  740.  
  741.         /// <summary>
  742.         /// Creates a alpha channelled .png out of a B&W .jpg
  743.         /// </summary>
  744.         /// <param name="filePath">The path to the .jpg file.</param>
  745.         /// <param name="fileName">The file name of the .jpg.</param>
  746.         private void MakeAlphaPng(string filePath)
  747.         {
  748.             Bitmap b1, b2;
  749.             int x, y;
  750.             b1 = new Bitmap(filePath);
  751.             b2 = new Bitmap(b1.Width, b1.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  752.             for(x = 0; x < b1.Width; x++)
  753.             {
  754.                 for(y = 0; y < b1.Height; y++)
  755.                 {
  756.                     Color p = b1.GetPixel(x,y);
  757.                     b2.SetPixel(x, y, Color.FromArgb(p.R, p.R, p.G, p.B));
  758.                 }
  759.                 //ProgressPercent = (float)(x / (b1.Width - 1));
  760.             }
  761.             b2.Save(filePath.Replace(".jpg", ".png"), System.Drawing.Imaging.ImageFormat.Png);
  762.             b1.Dispose();
  763.             b2.Dispose();
  764.             b1 = null;
  765.             b2 = null;
  766.         }
  767.  
  768.  
  769.         /// <summary>
  770.         /// Creates a PositionNormalTextured sphere centered on zero
  771.         /// </summary>
  772.         /// <param name="device">The current direct3D drawing device.</param>
  773.         /// <param name="radius">The sphere's radius</param>
  774.         /// <param name="slices">Number of slices (Horizontal resolution).</param>
  775.         /// <param name="stacks">Number of stacks. (Vertical resolution)</param>
  776.         /// <returns></returns>
  777.         /// <remarks>
  778.         /// Number of vertices in the sphere will be (slices+1)*(stacks+1)<br/>
  779.         /// Number of faces    :slices*stacks*2
  780.         /// Number of Indexes    : Number of faces * 3;
  781.         /// </remarks>
  782.         private Mesh TexturedSphere(Device device, float radius, int slices, int stacks)
  783.         {
  784.             int numVertices = (slices+1)*(stacks+1);
  785.             int numFaces    = slices*stacks*2;
  786.             int indexCount    = numFaces * 3;
  787.  
  788.             Mesh mesh = new Mesh(numFaces,numVertices,MeshFlags.Managed,CustomVertex.PositionNormalTextured.Format,device);
  789.  
  790.             // Get the original sphere's vertex buffer.
  791.             int [] ranks = new int[1];
  792.             ranks[0] = mesh.NumberVertices;
  793.             System.Array arr = mesh.VertexBuffer.Lock(0,typeof(CustomVertex.PositionNormalTextured),LockFlags.None,ranks);
  794.  
  795.             // Set the vertex buffer
  796.             int vertIndex=0;
  797.             for(int stack=0;stack<=stacks;stack++)
  798.             {
  799.                 double latitude = -90 + ((float)stack/stacks*(float)180.0);
  800.                 for(int slice=0;slice<=slices;slice++)
  801.                 {
  802.                     CustomVertex.PositionNormalTextured pnt = new CustomVertex.PositionNormalTextured();
  803.                     double longitude = 180 - ((float)slice/slices*(float)360);
  804.                     Vector3 v = MathEngine.SphericalToCartesian( latitude, longitude, radius);
  805.                     pnt.X = v.X;
  806.                     pnt.Y = v.Y;
  807.                     pnt.Z = v.Z;
  808.                     pnt.Tu = 1.0f-(float)slice/slices;
  809.                     pnt.Tv = 1.0f-(float)stack/stacks;
  810.                     arr.SetValue(pnt,vertIndex++);
  811.                 }
  812.             }
  813.  
  814.             mesh.VertexBuffer.Unlock();
  815.             ranks[0]=indexCount;
  816.             arr = mesh.LockIndexBuffer(typeof(short),LockFlags.None,ranks);
  817.             int i=0;
  818.             short bottomVertex = 0;
  819.             short topVertex = 0;
  820.             for(short x=0;x<stacks;x++)
  821.             {
  822.                 bottomVertex = (short)((slices+1)*x);
  823.                 topVertex = (short)(bottomVertex + slices + 1);
  824.                 for(int y=0;y<slices;y++)
  825.                 {
  826.                     arr.SetValue(bottomVertex,i++);
  827.                     arr.SetValue(topVertex,i++);        // outside text.
  828.                     arr.SetValue((short)(topVertex+1),i++);    // outside text.
  829.                     arr.SetValue(bottomVertex,i++);
  830.                     arr.SetValue((short)(topVertex+1),i++);    // outside text.
  831.                     arr.SetValue((short)(bottomVertex+1),i++); // outside text.
  832.                     bottomVertex++;
  833.                     topVertex++;
  834.                 }
  835.             }
  836.             mesh.IndexBuffer.SetData(arr,0,LockFlags.None);
  837.             mesh.ComputeNormals();
  838.  
  839.             return mesh;
  840.         }
  841.  
  842.  
  843.         #endregion
  844.     }
  845. }
  846.