390 lines
14 KiB
C#
390 lines
14 KiB
C#
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();
|
|
}
|
|
}
|
|
|