/// <summary> /// Unloads the current background and overlay images from memory. /// </summary> public void UnloadMap() { if (this.hdcSrcBackground != IntPtr.Zero) { Gdi32.DeleteDC(this.hdcSrcBackground); this.hdcSrcBackground = IntPtr.Zero; } if (this.hBmpSrcBackground != IntPtr.Zero) { Gdi32.DeleteObject(this.hBmpSrcBackground); this.hBmpSrcBackground = IntPtr.Zero; } if (this.hdcSrcOverlay != IntPtr.Zero) { Gdi32.DeleteDC(this.hdcSrcOverlay); this.hdcSrcOverlay = IntPtr.Zero; } if (this.hBmpSrcOverlay != IntPtr.Zero) { Gdi32.DeleteObject(this.hBmpSrcOverlay); this.hBmpSrcOverlay = IntPtr.Zero; } GC.Collect(); }
/// <summary> /// Signals the new overlay in finished being drawn and ready to be used. /// </summary> public void EndDrawNewOverlay() { if (this.newOverlay == null) { return; } // delete previous overlay if (this.hdcSrcOverlay != IntPtr.Zero) { Gdi32.DeleteDC(this.hdcSrcOverlay); this.hdcSrcOverlay = IntPtr.Zero; Gdi32.DeleteObject(this.hBmpSrcOverlay); this.hBmpSrcOverlay = IntPtr.Zero; } // convert managed Bitmap to unmanaged hBmp this.hdcSrcOverlay = Gdi32.CreateCompatibleDC(IntPtr.Zero); this.hBmpSrcOverlay = this.newOverlay.GetHbitmap(Color.FromArgb(0, 0, 0, 0)); Gdi32.SelectObject(this.hdcSrcOverlay, this.hBmpSrcOverlay); this.newOverlay.Dispose(); this.newOverlay = null; }
/// <summary> /// Repaint the control. /// </summary> /// <param name="zoomcenter">The point on which to center when zooming.</param> /// <param name="hdcDest">The DC handle to paint on.</param> private void Redraw(PointF zoomcenter, IntPtr hdcDest) { #if MAC return; #endif // no map loaded if (this.hdcSrcBackground == IntPtr.Zero) { Graphics gr = Graphics.FromHdc(hdcDest); try { gr.Clear(Color.FromArgb(60, 60, 60)); } catch { } // known bug in GDI: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=96873 gr.Dispose(); this.prevZoomFactor = this.zoomFactor; return; } // scale & letterbox this.Xout = false; this.Yout = false; if (this.Width > (fullWidth * this.zoomFactor)) { this.rectSrc.X = 0; this.rectSrc.Width = fullWidth; this.rectDest.X = (this.Width - (fullWidth * this.zoomFactor)) / 2F; this.rectDest.Width = fullWidth * this.zoomFactor; Gdi32.BitBlt(hdcDest, 0, 0, (int)Math.Round(this.rectDest.X), this.Height, this.hdcSrcBackground, 0, 0, Gdi32.TernaryRasterOperations.BLACKNESS); Gdi32.BitBlt(hdcDest, (int)Math.Round(this.rectDest.Right), 0, (int)Math.Round(this.rectDest.X), this.Height, this.hdcSrcBackground, 0, 0, Gdi32.TernaryRasterOperations.BLACKNESS); } else { this.rectSrc.X += ((this.Width / this.prevZoomFactor) - (this.Width / this.zoomFactor)) / ((this.Width + 0.001F) / zoomcenter.X); this.rectSrc.Width = this.Width / this.zoomFactor; this.rectDest.X = 0; this.rectDest.Width = this.Width; } if (this.Height > (fullHeight * this.zoomFactor)) { this.rectSrc.Y = 0; this.rectSrc.Height = fullHeight; this.rectDest.Y = (this.Height - (fullHeight * this.zoomFactor)) / 2F; this.rectDest.Height = fullHeight * this.zoomFactor; Gdi32.BitBlt(hdcDest, 0, 0, this.Width, (int)Math.Round(this.rectDest.Y), this.hdcSrcBackground, 0, 0, Gdi32.TernaryRasterOperations.BLACKNESS); Gdi32.BitBlt(hdcDest, 0, (int)Math.Round(this.rectDest.Bottom), this.Width, (int)Math.Round(this.rectDest.Y), this.hdcSrcBackground, 0, 0, Gdi32.TernaryRasterOperations.BLACKNESS); } else { this.rectSrc.Y += ((this.Height / this.prevZoomFactor) - (this.Height / this.zoomFactor)) / ((this.Height + 0.001F) / zoomcenter.Y); this.rectSrc.Height = this.Height / this.zoomFactor; this.rectDest.Y = 0; this.rectDest.Height = this.Height; } this.prevZoomFactor = this.zoomFactor; if (this.rectSrc.Right > fullWidth) { this.Xout = true; this.rectSrc.X = fullWidth - this.rectSrc.Width; } if (this.rectSrc.X < 0) { this.Xout = true; this.rectSrc.X = 0; } if (this.rectSrc.Bottom > fullHeight) { this.Yout = true; this.rectSrc.Y = fullHeight - this.rectSrc.Height; } if (this.rectSrc.Y < 0) { this.Yout = true; this.rectSrc.Y = 0; } // draw if (this.MapFastScaling) { Gdi32.SetStretchBltMode(hdcDest, Gdi32.StretchMode.STRETCH_DELETESCANS); } else { Gdi32.SetStretchBltMode(hdcDest, Gdi32.StretchMode.STRETCH_HALFTONE); } if (this.hdcSrcOverlay == IntPtr.Zero) { // no overlay, just draw resized Gdi32.StretchBlt(hdcDest, (int)Math.Round(rectDest.X), (int)Math.Round(rectDest.Y), (int)Math.Round(rectDest.Width), (int)Math.Round(rectDest.Height), this.hdcSrcBackground, (int)Math.Round(rectSrc.X), (int)Math.Round(rectSrc.Y), (int)Math.Round(rectSrc.Width), (int)Math.Round(rectSrc.Height), Gdi32.TernaryRasterOperations.SRCCOPY); } else { // overlay, create merged image and draw IntPtr hdcBuffer = Gdi32.CreateCompatibleDC(IntPtr.Zero); //Gdi32.SetStretchBltMode( hdcBuffer, Gdi32.StretchMode.STRETCH_HALFTONE ); IntPtr hBmpBuffer = Gdi32.CreateCompatibleBitmap(hdcSrcBackground, (int)Math.Round(rectSrc.Width), (int)Math.Round(rectSrc.Height)); Gdi32.SelectObject(hdcBuffer, hBmpBuffer); // copy background source rect into buffer Gdi32.BitBlt(hdcBuffer, 0, 0, (int)Math.Round(rectSrc.Width), (int)Math.Round(rectSrc.Height), hdcSrcBackground, (int)Math.Round(rectSrc.X), (int)Math.Round(rectSrc.Y), Gdi32.TernaryRasterOperations.SRCCOPY); // alpha blend overlay source rect into buffer Gdi32.AlphaBlend(hdcBuffer, 0, 0, (int)Math.Round(rectSrc.Width), (int)Math.Round(rectSrc.Height), hdcSrcOverlay, (int)Math.Round(rectSrc.X), (int)Math.Round(rectSrc.Y), (int)Math.Round(rectSrc.Width), (int)Math.Round(rectSrc.Height), new Gdi32.BLENDFUNCTION(Gdi32.AC_SRC_OVER, 0, 0xff, Gdi32.AC_SRC_ALPHA)); // draw buffer to destination resized Gdi32.StretchBlt(hdcDest, (int)Math.Round(rectDest.X), (int)Math.Round(rectDest.Y), (int)Math.Round(rectDest.Width), (int)Math.Round(rectDest.Height), hdcBuffer, 0, 0, (int)Math.Round(rectSrc.Width), (int)Math.Round(rectSrc.Height), Gdi32.TernaryRasterOperations.SRCCOPY); // clean up buffer Gdi32.DeleteDC(hdcBuffer); hdcBuffer = IntPtr.Zero; Gdi32.DeleteObject(hBmpBuffer); hBmpBuffer = IntPtr.Zero; } }
/// <summary> /// Load a new background map image into memory for display. /// </summary> /// <param name="image">The Bitmap to load (will be destroyed).</param> public void LoadMap(Bitmap image) { if (this.hdcSrcBackground != IntPtr.Zero) { Gdi32.DeleteDC(this.hdcSrcBackground); this.hdcSrcBackground = IntPtr.Zero; Gdi32.DeleteObject(this.hBmpSrcBackground); this.hBmpSrcBackground = IntPtr.Zero; Gdi32.DeleteDC(this.hdcSrcOverlay); this.hdcSrcOverlay = IntPtr.Zero; Gdi32.DeleteObject(this.hBmpSrcOverlay); this.hBmpSrcOverlay = IntPtr.Zero; } this.hdcSrcBackground = Gdi32.CreateCompatibleDC(IntPtr.Zero); if (this.hdcSrcBackground == IntPtr.Zero) { throw new ApplicationException("CreateCompatibleDC() failed"); } this.hBmpSrcBackground = image.GetHbitmap(); if (this.hBmpSrcBackground == IntPtr.Zero) { throw new ApplicationException("GetHbitmap() failed"); } IntPtr ret = Gdi32.SelectObject(this.hdcSrcBackground, this.hBmpSrcBackground); if (ret == IntPtr.Zero) { throw new ApplicationException("SelectObject() failed"); } Size newMapSize = new Size(image.Width, image.Height); this.fullHeight = newMapSize.Height; this.fullWidth = newMapSize.Width; if (newMapSize != prevMapSize) // recenter { PointF prevCenter = this.Center; // must have already called InitSize() this.Center = new PointF((prevCenter.X / prevMapSize.Width) * newMapSize.Width, (prevCenter.Y / prevMapSize.Height) * newMapSize.Height); this.prevMapSize = newMapSize; } image.Dispose(); image = null; GC.Collect(); // update map zoom this.Zoom(); }