using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; using System.Runtime.InteropServices; public class TextureArea : IDisposable { [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] private static extern short GetKeyState(int keyCode); //----------------------------------------------------------------------------------------- // members // Image _texture = null; Color _backColor = Color.Black; bool _bilinearFilter = true; Rectangle _winRect = new Rectangle(); // window rect to display atlas Rectangle _winTextureRect = new Rectangle(); // window rect to display texture (keeping texture ratio) RectangleF _textureRect = new RectangleF(); // rect of texture to be displayed RectangleF _capturedTextureRect; Point _captureStart; RectangleF _allTextureRectRatio = new RectangleF(); Rectangle _allTextureRect = new Rectangle(); Rectangle _capturedAllTextureRect; //----------------------------------------------------------------------------------------- Bitmap _TextureCache = null; Rectangle _TextureCacheTextureRect = Rectangle.FromLTRB(0, 0, 0, 0); Rectangle _TextureCacheWindowRect = Rectangle.FromLTRB(0, 0, 0, 0); Rectangle _TextureCacheRect = Rectangle.FromLTRB(0, 0, 0, 0); //----------------------------------------------------------------------------------------- // init // public void init() { _textureRect = new RectangleF(0, 0, 1.0f, 1.0f); _allTextureRectRatio = new RectangleF(0, 0, 1.0f, 1.0f); } //----------------------------------------------------------------------------------------- // accessors // public void setTexture(Image texture) { _texture = texture; } public void setBackColor( Color backColor ) { _backColor = backColor; } public void setBilinearFilter(bool bilinearFilter) { _bilinearFilter = bilinearFilter; } public void setWinRect(Rectangle rectangle) { _winRect = rectangle; _winTextureRect = rectangle; if (_texture == null) return; int y = (_winTextureRect.Width * _texture.Height) / _texture.Width; if (y < _winTextureRect.Height) { _winTextureRect.Y = _winTextureRect.Y + (_winTextureRect.Height - y) / 2; _winTextureRect.Height = y; } else { int x = (_winTextureRect.Height * _texture.Width) / _texture.Height; _winTextureRect.X = _winTextureRect.X + (_winTextureRect.Width - x) / 2; _winTextureRect.Width = x; } _allTextureRectRatio.X = (float)(_winTextureRect.Left - _winRect.Left) / (float) _winRect.Width; _allTextureRectRatio.Width = (float)_winTextureRect.Width / (float)_winRect.Width; _allTextureRectRatio.Y = (float)(_winTextureRect.Top - _winRect.Top) / (float)_winRect.Height; _allTextureRectRatio.Height = (float)_winTextureRect.Height / (float)_winRect.Height; } public Rectangle getWinRect() { return _winRect; } public Rectangle getWinTextureRect() { return _winTextureRect; } public void setSubRect(RectangleF rectangleF) { _textureRect = rectangleF; } public RectangleF getSubRect() { return _textureRect; } public int getTextureWidth() { return _texture != null ? _texture.Width : 0; } public int getTextureHeight() { return _texture != null ? _texture.Height: 0; } readonly bool _methodOld = false; //----------------------------------------------------------------------------------------- // clip painting region // public void clip(ref Graphics graphics) { if (_methodOld) graphics.Clip = new Region(getWinTextureRect()); else graphics.Clip = new Region(getWinRect()); } //----------------------------------------------------------------------------------------- // paint // public void paintOld(Graphics graphics) { // display background Region region = new Region(getWinRect()); region.Exclude(getWinTextureRect()); graphics.Clip = region; graphics.FillRectangle(new SolidBrush(Color.Black), getWinRect()); graphics.Clip = new Region(getWinTextureRect()); // display image if (_texture != null) { Rectangle displayRectangle = new Rectangle(); displayRectangle.X = (int)(getSubRect().X * (_texture.Width)); displayRectangle.Y = (int)(getSubRect().Y * (_texture.Height)); displayRectangle.Width = (int)(getSubRect().Width * (_texture.Width)); displayRectangle.Height = (int)(getSubRect().Height * (_texture.Height)); Rectangle windowRect = getWinTextureRect(); if (_TextureCache == null || _TextureCacheTextureRect != displayRectangle || _TextureCacheWindowRect != windowRect || _TextureCache != _texture) { if (_TextureCacheWindowRect != windowRect || _TextureCache == null) { if (_TextureCache != null) _TextureCache.Dispose(); _TextureCache = new Bitmap(_texture, windowRect.Width, windowRect.Height); _TextureCacheWindowRect = windowRect; } Graphics g = Graphics.FromImage(_TextureCache); g.Clear(_backColor); if (_bilinearFilter) g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear; else g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; _TextureCacheRect.Width = windowRect.Width; _TextureCacheRect.Height = windowRect.Height; g.DrawImage(_texture, _TextureCacheRect, displayRectangle, GraphicsUnit.Pixel); g.Dispose(); _TextureCacheTextureRect = displayRectangle; } graphics.DrawImage(_TextureCache, windowRect.Left, windowRect.Top); } } //----------------------------------------------------------------------------------------- public void computeDisplayRect() { _allTextureRect.X = (int)(_allTextureRectRatio.X * _winRect.Width + _winRect.Left); _allTextureRect.Width = (int)(_allTextureRectRatio.Width * _winRect.Width); _allTextureRect.Y = (int)(_allTextureRectRatio.Y * _winRect.Height + _winRect.Top); _allTextureRect.Height = (int)(_allTextureRectRatio.Height * _winRect.Height); _winTextureRect = _allTextureRect; _winTextureRect.Intersect(_winRect); _textureRect.X = (float)(_winTextureRect.X - _allTextureRect.X) / (float)_allTextureRect.Width; _textureRect.Width = (float)_winTextureRect.Width / (float)_allTextureRect.Width; _textureRect.Y = (float)(_winTextureRect.Y - _allTextureRect.Y) / (float)_allTextureRect.Height; _textureRect.Height = (float)_winTextureRect.Height / (float)_allTextureRect.Height; } //----------------------------------------------------------------------------------------- public void computeAllTextureRect() { _allTextureRect.Width = (int) (_winTextureRect.Width / _textureRect.Width); _allTextureRect.Height = (int) (_winTextureRect.Height / _textureRect.Height); _allTextureRect.X = (int) (_winTextureRect.X - _textureRect.X * _allTextureRect.Width); _allTextureRect.Y = (int) (_winTextureRect.Y - _textureRect.Y * _allTextureRect.Height); computeAllTextureRectRatio(); } //----------------------------------------------------------------------------------------- public void computeAllTextureRectRatio() { _allTextureRectRatio.X = (float)(_allTextureRect.Left - _winRect.Left) / (float)_winRect.Width; _allTextureRectRatio.Width = (float)_allTextureRect.Width / (float)_winRect.Width; _allTextureRectRatio.Y = (float)(_allTextureRect.Top - _winRect.Top) / (float)_winRect.Height; _allTextureRectRatio.Height = (float)_allTextureRect.Height / (float)_winRect.Height; } //----------------------------------------------------------------------------------------- // paint // public void paintNew(Graphics graphics) { // display image if (_texture == null) { graphics.FillRectangle(new SolidBrush(Color.Black), getWinRect()); return; } computeDisplayRect(); if (_winTextureRect.IsEmpty) { graphics.FillRectangle(new SolidBrush(Color.Black), getWinRect()); return; } paintOld( graphics ); } //----------------------------------------------------------------------------------------- // paint // public void paint(Graphics graphics) { if (_methodOld) paintOld(graphics); else paintNew(graphics); } //----------------------------------------------------------------------------------------- // picking // public bool isWinPointInside(Point point) { return _winTextureRect.Contains(point); } //----------------------------------------------------------------------------------------- // edit sub rect // public void subRectZoom(Point pos, bool inOrOut) { float xwinratio = (float)(pos.X - _winTextureRect.Left) / (float)_winTextureRect.Width; float ywinratio = (float)(pos.Y - _winTextureRect.Top) / (float)_winTextureRect.Height; float xtextureratioBefore = _textureRect.Left + xwinratio * (_textureRect.Width); float ytextureratioBefore = _textureRect.Top + ywinratio * (_textureRect.Height); float w = (_textureRect.Width * 0.05f) * (inOrOut ? 1 : -1); float h = (_textureRect.Height * 0.05f) * (inOrOut ? 1 : -1); _textureRect.Inflate(w, h); float xtextureratioAfter = _textureRect.Left + xwinratio * (_textureRect.Width); float ytextureratioAfter = _textureRect.Top + ywinratio * (_textureRect.Height); _textureRect.X += xtextureratioBefore - xtextureratioAfter; _textureRect.Y += ytextureratioBefore - ytextureratioAfter; computeAllTextureRect(); } public void subRectStartPan(Point pos) { _captureStart = pos; _capturedTextureRect = getSubRect(); _capturedAllTextureRect = _allTextureRect; } public void subRectPan(Point pos) { if (_methodOld) { float ratiox = _capturedTextureRect.Width / (float)_winTextureRect.Width; _textureRect.X = _capturedTextureRect.X + (_captureStart.X - pos.X) * ratiox; float ratioy = _capturedTextureRect.Height / (float)_winTextureRect.Height; _textureRect.Y = _capturedTextureRect.Y + (_captureStart.Y - pos.Y) * ratioy; computeAllTextureRect(); } else { _allTextureRect.X = _capturedAllTextureRect.X - (_captureStart.X - pos.X); _allTextureRect.Y = _capturedAllTextureRect.Y - (_captureStart.Y - pos.Y); computeAllTextureRectRatio(); } } //----------------------------------------------------------------------------------------- // mouse function // bool _capturePan = false; public bool mouseDown(Point pos) { if (!isWinPointInside(pos)) return false; if (GetKeyState(32 /*VK_SPACE*/ ) >= 0) return false; _capturePan = true; subRectStartPan(pos); return true; } public void mouseMove( Point pos ) { if (!_capturePan) return; subRectPan(pos); } public void mouseUp( Point pos ) { _capturePan = false; } public bool mouseWheel(Point pos, bool inOrOut) { if (!isWinPointInside(pos)) return false; if (GetKeyState(32 /*VK_SPACE*/ ) >= 0) return false; subRectZoom(pos, inOrOut); return true; } public bool mouseSetCursor(Point pos, ref Cursor cursor ) { if (!isWinPointInside(pos)) return false; if (GetKeyState(32 /*VK_SPACE*/ ) >= 0) return false; cursor = Cursors.Hand; return true; } //----------------------------------------------------------------------------------------- // transformation function // public int x_atlas2win(float xAtlas) { int xTexture = (int)(xAtlas * _texture.Width + 0.5); float xTextureDisplayed = ((float)xTexture - _TextureCacheTextureRect.Left) / (float)_TextureCacheTextureRect.Width; int xTextureWindow = (int)_TextureCacheWindowRect.Left + (int)(_TextureCacheWindowRect.Width * xTextureDisplayed); return xTextureWindow; } public int y_atlas2win(float yAtlas) { int yTexture = (int)(yAtlas * _texture.Height + 0.5); float yTextureDisplayed = ((float) yTexture - _TextureCacheTextureRect.Top) / (float)_TextureCacheTextureRect.Height; int yTextureWindow = (int)_TextureCacheWindowRect.Top + (int)(_TextureCacheWindowRect.Height * yTextureDisplayed); return yTextureWindow; } public Point point_atlas2win(PointF pos) { return new Point(x_atlas2win(pos.X), y_atlas2win(pos.Y)); } public Rectangle rect_atlas2win(RectangleF rect) { int x0 = x_atlas2win(rect.X); int y0 = y_atlas2win(rect.Y); int x1 = x_atlas2win(rect.Right); int y1 = y_atlas2win(rect.Bottom); return Rectangle.FromLTRB(x0, y0, x1, y1); } public float x_win2atlas(int xWin) { float x = xWin - _winTextureRect.Left; x /= (float)_winTextureRect.Width; return x * _textureRect.Width + _textureRect.Left; } public float y_win2atlas(int yWin) { float y = yWin - _winTextureRect.Top; y /= (float)_winTextureRect.Height; return y * _textureRect.Height + _textureRect.Top; } public PointF point_win2atlas(Point pos) { return new PointF(x_win2atlas(pos.X), y_win2atlas(pos.Y)); } public RectangleF rect_win2atlas(Rectangle rect) { float x0 = x_win2atlas(rect.X); float y0 = y_win2atlas(rect.Y); float x1 = x_win2atlas(rect.Right); float y1 = y_win2atlas(rect.Bottom); return RectangleF.FromLTRB(x0, y0, x1, y1); } public void Dispose() { _texture?.Dispose(); _TextureCache?.Dispose(); } }