OSDN Git Service

Working map with textures downloaded from lindens S3 repo.
authorLatif Khalifa <latifer@streamgrid.net>
Sun, 23 May 2010 01:50:06 +0000 (01:50 +0000)
committerLatif Khalifa <latifer@streamgrid.net>
Sun, 23 May 2010 01:50:06 +0000 (01:50 +0000)
git-svn-id: https://radegast.googlecode.com/svn/branches/legacy_map@646 f7a694da-4d33-11de-9ad6-1127a62b9fcd

Radegast/Core/Types/MapControl.Designer.cs
Radegast/Core/Types/MapControl.cs

index b981e48..294a367 100644 (file)
@@ -38,7 +38,6 @@
             this.Name = "MapControl";
             this.Size = new System.Drawing.Size(589, 409);
             this.Paint += new System.Windows.Forms.PaintEventHandler(this.MapControl_Paint);
-            this.Click += new System.EventHandler(this.MapControl_Click);
             this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.MapControl_MouseMove);
             this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MapControl_MouseDown);
             this.Resize += new System.EventHandler(this.MapControl_Resize);
index 748966a..f4a295a 100644 (file)
@@ -3,11 +3,15 @@ using System.Collections.Generic;
 using System.ComponentModel;
 using System.Drawing;
 using System.Data;
-using System.Linq;
+using System.Security.Cryptography.X509Certificates;
 using System.Text;
 using System.Windows.Forms;
-using System.Drawing.Drawing2D;
+using System.Net;
+using System.Text.RegularExpressions;
+using System.IO;
+using System.Threading;
 using OpenMetaverse;
+using OpenMetaverse.Http;
 
 namespace Radegast
 {
@@ -15,6 +19,7 @@ namespace Radegast
     {
         RadegastInstance Instance;
         GridClient Client { get { return Instance.Client; } }
+        ParallelDownloader downloader;
         Color background;
         float zoom;
         Font textFont;
@@ -25,15 +30,17 @@ namespace Radegast
         double centerX;
         double centerY;
         bool centered = false;
+        int PixRegS;
 
         public MapControl(RadegastInstance instance)
         {
-            Zoom = 2f;
-
+            Zoom = 1.25f;
             InitializeComponent();
             Disposed += new EventHandler(MapControl_Disposed);
             this.Instance = instance;
 
+            downloader = new ParallelDownloader();
+
             background = Color.FromArgb(4, 4, 75);
             textFont = new Font(FontFamily.GenericSansSerif, 8.0f, FontStyle.Bold);
             textBrush = new SolidBrush(Color.FromArgb(255, 200, 200, 200));
@@ -43,6 +50,15 @@ namespace Radegast
 
         void MapControl_Disposed(object sender, EventArgs e)
         {
+            downloader.Dispose();
+
+            lock (regionTiles)
+            {
+                foreach (Image img in regionTiles.Values)
+                    if (img != null)
+                        img.Dispose();
+                regionTiles.Clear();
+            }
         }
 
         public float Zoom
@@ -50,10 +66,11 @@ namespace Radegast
             get { return zoom; }
             set
             {
-                if (value >= 1f && value <= 4f)
+                if (value >= 1f && value <= 6f)
                 {
                     zoom = value;
                     pixelsPerMeter = 1f / zoom;
+                    PixRegS = (int)(regionSize / zoom);
                     Invalidate();
                 }
             }
@@ -89,16 +106,141 @@ namespace Radegast
             g.DrawString(text, textFont, textBrush, x, y);
         }
 
+        Dictionary<ulong, string> regionNames = new Dictionary<ulong, string>();
+        Regex regName = new Regex("\"(?<regName>[^\"]+)", RegexOptions.Compiled);
+        List<ulong> nameRequests = new List<ulong>();
+
+        string GetRegionName(ulong handle)
+        {
+            if (regionNames.ContainsKey(handle))
+            {
+                return regionNames[handle];
+            }
+            else
+            {
+                lock (nameRequests)
+                {
+                    if (nameRequests.Contains(handle)) return RadegastInstance.INCOMPLETE_NAME;
+                    nameRequests.Add(handle);
+                }
+
+                uint regX, regY;
+                Utils.LongToUInts(handle, out regX, out regY);
+                regX /= regionSize;
+                regY /= regionSize;
+                WebClient req = new WebClient();
+                req.DownloadStringCompleted += (object sender, DownloadStringCompletedEventArgs e) =>
+                    {
+                        lock (nameRequests)
+                        {
+                            nameRequests.Remove(handle);
+                        }
+
+                        if (e.Error == null)
+                        {
+                            if (e.Result.Contains("error:"))
+                            {
+                                lock (regionNames)
+                                {
+                                    regionNames[handle] = string.Empty;
+                                    if (IsHandleCreated) BeginInvoke(new MethodInvoker(() => Invalidate()));
+                                }
+                            }
+                            else
+                            {
+                                Match m = regName.Match(e.Result);
+                                if (m.Success)
+                                {
+                                    lock (regionNames)
+                                    {
+                                        regionNames[handle] = m.Groups["regName"].Value;
+                                        if (IsHandleCreated) BeginInvoke(new MethodInvoker(() => Invalidate()));
+                                    }
+                                }
+                            }
+                        }
+                    };
+                req.DownloadStringAsync(new Uri(string.Format("http://slurl.com/get-region-name-by-coords?var=slRegionName&grid_x={0}&grid_y={1}", regX, regY)));
+
+                lock (regionNames)
+                {
+                    regionNames[handle] = RadegastInstance.INCOMPLETE_NAME;
+                }
+
+                return RadegastInstance.INCOMPLETE_NAME;
+            }
+        }
+
+        Dictionary<ulong, Image> regionTiles = new Dictionary<ulong, Image>();
+        List<ulong> tileRequests = new List<ulong>();
+
+        Image GetRegionTile(ulong handle)
+        {
+            if (regionTiles.ContainsKey(handle))
+            {
+                return regionTiles[handle];
+            }
+            else
+            {
+                lock (tileRequests)
+                {
+                    if (tileRequests.Contains(handle)) return null;
+                    tileRequests.Add(handle);
+                }
+
+                uint regX, regY;
+                Utils.LongToUInts(handle, out regX, out regY);
+                regX /= regionSize;
+                regY /= regionSize;
+
+                downloader.QueueDownlad(
+                    new Uri(string.Format("http://map.secondlife.com/map-1-{0}-{1}-objects.jpg", regX, regY)),
+                    null,
+                    20 * 1000,
+                    null,
+                    (HttpWebRequest request, HttpWebResponse response, byte[] responseData, Exception error) =>
+                    {
+                        if (error == null && responseData != null)
+                        {
+                            try
+                            {
+                                using (MemoryStream s = new MemoryStream(responseData))
+                                {
+                                    lock (regionTiles)
+                                    {
+                                        regionTiles[handle] = Image.FromStream(s);
+                                        if (IsHandleCreated) BeginInvoke(new MethodInvoker(() => Invalidate()));
+                                    }
+                                }
+                            }
+                            catch { }
+                        }
+                    }
+                );
+
+                lock (regionTiles)
+                {
+                    regionTiles[handle] = null;
+                }
+
+                return null;
+            }
+        }
+
         void DrawRegion(Graphics g, int x, int y, ulong handle)
         {
             uint regX, regY;
             Utils.LongToUInts(handle, out regX, out regY);
             regX /= regionSize;
             regY /= regionSize;
-            string name = string.Format("{0:0}, {1:0}", regX, regY);
-            Print(g, x + 2, y - 16, name);
-            float regS = regionSize / zoom;
-            g.DrawRectangle(SystemPens.Window, (float)x, y - regS, regS, regS);
+            string name = GetRegionName(handle);
+            Image tile = GetRegionTile(handle);
+
+            if (tile != null)
+                g.DrawImage(tile, new Rectangle(x, y - PixRegS, PixRegS, PixRegS));
+
+            //if (!string.IsNullOrEmpty(name))
+            //    Print(g, x + 2, y - 16, name);
         }
 
         private void MapControl_Paint(object sender, PaintEventArgs e)
@@ -121,53 +263,43 @@ namespace Radegast
             regX /= regionSize;
             regY /= regionSize;
 
-            int pixRegS = (int)(regionSize / zoom);
-            int regLeft = (int)regX - ((int)(pixCenterRegionX / pixRegS) + 1);
+            int regLeft = (int)regX - ((int)(pixCenterRegionX / PixRegS) + 1);
             if (regLeft < 0) regLeft = 0;
-            int regTop = (int)regY - ((int)(pixCenterRegionY / pixRegS));
-            if (regTop < 0) regTop = 0;
+            int regBottom = (int)regY - ((int)((e.ClipRectangle.Height - pixCenterRegionY) / PixRegS) + 1);
+            if (regBottom < 0) regBottom = 0;
 
-            for (int ry = regTop; ry < regTop + e.ClipRectangle.Height / pixRegS + 2; ry++)
+            for (int ry = regBottom; pixCenterRegionY - (ry - (int)regY) * PixRegS > 0; ry++)
             {
-                for (int rx = regLeft; rx < regLeft + e.ClipRectangle.Width / pixRegS + 2; rx++)
+                for (int rx = regLeft; pixCenterRegionX - ((int)regX - rx) * PixRegS < e.ClipRectangle.Width; rx++)
                 {
                     DrawRegion(g,
-                        pixCenterRegionX - ((int)regX - rx) * pixRegS,
-                        pixCenterRegionY + (ry - (int)regY) * pixRegS,
+                        pixCenterRegionX - ((int)regX - rx) * PixRegS,
+                        pixCenterRegionY - (ry - (int)regY) * PixRegS,
                         Utils.UIntsToLong((uint)rx * regionSize, (uint)ry * regionSize));
-                    //System.Console.Write("({0}, {1}) ", rx, ry);
                 }
-                //System.Console.WriteLine();
             }
-            //System.Console.WriteLine("Reg left: {0}, reg top {1}", regLeft, regTop);
-
-            //DrawRegion(g, pixCenterRegionX, pixCenterRegionY, centerRegion);
         }
 
         #region Mouse handling
-        private void MapControl_Click(object sender, EventArgs e)
-        {
-        }
-
         protected override void OnMouseWheel(MouseEventArgs e)
         {
             base.OnMouseWheel(e);
-            if (e.Delta > 0)
+            if (e.Delta < 0)
                 Zoom += 0.25f;
             else
                 Zoom -= 0.25f;
         }
 
         bool dragging = false;
-        int dragX, dragY;
+        int dragX, dragY, downX, downY;
 
         private void MapControl_MouseDown(object sender, MouseEventArgs e)
         {
             if (e.Button == MouseButtons.Left)
             {
                 dragging = true;
-                dragX = e.X;
-                dragY = e.Y;
+                downX = dragX = e.X;
+                downY = dragY = e.Y;
             }
         }
 
@@ -176,6 +308,11 @@ namespace Radegast
             if (e.Button == MouseButtons.Left)
             {
                 dragging = false;
+                if (e.X == downX && e.Y == downY) // click
+                {
+                    CenterMap(1130, 1071, 128, 128);
+                    Zoom = 1.25f;
+                }
             }
 
         }
@@ -198,4 +335,129 @@ namespace Radegast
         }
         #endregion Mouse handling
     }
+
+    public class ParallelDownloader : IDisposable
+    {
+        Thread worker;
+        int m_ParallelDownloads = 10;
+        bool done = false;
+        AutoResetEvent queueHold = new AutoResetEvent(false);
+        Queue<QueuedItem> queue = new Queue<QueuedItem>();
+        List<HttpWebRequest> activeDownloads = new List<HttpWebRequest>();
+
+        public int ParallelDownloads
+        {
+            get { return m_ParallelDownloads; }
+            set
+            {
+                m_ParallelDownloads = value;
+            }
+        }
+
+        public ParallelDownloader()
+        {
+            worker = new Thread(new ThreadStart(Worker));
+            worker.Name = "Parallel Downloader";
+            worker.IsBackground = true;
+            worker.Start();
+        }
+
+        public void Dispose()
+        {
+            done = true;
+            queueHold.Set();
+            queue.Clear();
+
+            lock (activeDownloads)
+            {
+                for (int i = 0; i < activeDownloads.Count; i++)
+                {
+                    try
+                    {
+                        activeDownloads[i].Abort();
+                    }
+                    catch { }
+                }
+            }
+
+            if (worker.IsAlive)
+                worker.Abort();
+        }
+
+        private void Worker()
+        {
+            Logger.DebugLog("Parallel dowloader starting");
+
+            while (!done)
+            {
+                lock (queue)
+                {
+                    if (queue.Count > 0)
+                    {
+                        int nr = 0;
+                        lock (activeDownloads) nr = activeDownloads.Count;
+
+                        for (int i = nr; i < ParallelDownloads && queue.Count > 0; i++)
+                        {
+                            QueuedItem item = queue.Dequeue();
+                            HttpWebRequest req = CapsBase.DownloadStringAsync(
+                                item.address,
+                                item.clientCert,
+                                item.millisecondsTimeout,
+                                item.downloadProgressCallback,
+                                (HttpWebRequest request, HttpWebResponse response, byte[] responseData, Exception error) =>
+                                {
+                                    lock (activeDownloads) activeDownloads.Remove(request);
+                                    item.completedCallback(request, response, responseData, error);
+                                    queueHold.Set();
+                                }
+                            );
+
+                            lock (activeDownloads) activeDownloads.Add(req);
+                        }
+                    }
+                }
+
+                queueHold.WaitOne();
+            }
+            
+            Logger.DebugLog("Parallel dowloader exiting");
+        }
+
+        public void QueueDownlad(Uri address, X509Certificate2 clientCert, int millisecondsTimeout,
+            CapsBase.DownloadProgressEventHandler downloadProgressCallback, CapsBase.RequestCompletedEventHandler completedCallback)
+        {
+            lock (queue)
+            {
+                queue.Enqueue(new QueuedItem(
+                    address,
+                    clientCert,
+                    millisecondsTimeout,
+                    downloadProgressCallback,
+                    completedCallback
+                    ));
+            }
+            queueHold.Set();
+        }
+
+        public class QueuedItem
+        {
+            public Uri address;
+            public X509Certificate2 clientCert;
+            public int millisecondsTimeout;
+            public CapsBase.DownloadProgressEventHandler downloadProgressCallback;
+            public CapsBase.RequestCompletedEventHandler completedCallback;
+
+            public QueuedItem(Uri address, X509Certificate2 clientCert, int millisecondsTimeout,
+            CapsBase.DownloadProgressEventHandler downloadProgressCallback, CapsBase.RequestCompletedEventHandler completedCallback)
+            {
+                this.address = address;
+                this.clientCert = clientCert;
+                this.millisecondsTimeout = millisecondsTimeout;
+                this.downloadProgressCallback = downloadProgressCallback;
+                this.completedCallback = completedCallback;
+            }
+        }
+
+    }
 }