mirror of https://github.com/emgucv/emgucv.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2082 lines
76 KiB
2082 lines
76 KiB
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using OpenTK;
|
|
using OpenTK.Graphics;
|
|
using OpenTK.Platform;
|
|
using System.Text;
|
|
//using System.Threading.Tasks;
|
|
using ES20 = OpenTK.Graphics.ES20;
|
|
using ES11 = OpenTK.Graphics.ES11;
|
|
|
|
|
|
#if IOS
|
|
using OpenTK.Platform.iPhoneOS;
|
|
using MonoTouch.Foundation;
|
|
using MonoTouch.ObjCRuntime;
|
|
#elif ANDROID
|
|
using OpenTK.Platform.Android;
|
|
using Android.Views;
|
|
using Android.Util;
|
|
using Android.Content;
|
|
#else
|
|
|
|
#endif
|
|
using Emgu.CV;
|
|
using Emgu.CV.Structure;
|
|
|
|
namespace Emgu.CV.UI.GLView
|
|
{
|
|
#if IOS
|
|
[Register("GLImageView")]
|
|
#endif
|
|
public class GLImageView
|
|
#if IOS
|
|
: iPhoneOSGameView
|
|
#elif ANDROID
|
|
: AndroidGameView
|
|
#else
|
|
: GLControl
|
|
#endif
|
|
{
|
|
|
|
private const int _glTextureDimension = 512;
|
|
|
|
public enum OpenGLVersion
|
|
{
|
|
ES1,
|
|
ES2,
|
|
GL3
|
|
}
|
|
|
|
#if ANDROID || IOS
|
|
private OpenGLVersion _glVersion = OpenGLVersion.ES1;
|
|
#else
|
|
private OpenGLVersion _glVersion = OpenGLVersion.GL3;
|
|
#endif
|
|
public OpenGLVersion GlVersion
|
|
{
|
|
get
|
|
{
|
|
return _glVersion;
|
|
}
|
|
}
|
|
|
|
//int _viewPortWidth, _viewPortHeight;
|
|
private String PackageName;
|
|
private System.Drawing.Size _imageSize;
|
|
|
|
int[] _textureIds;
|
|
private System.Drawing.Size[] _textureSizes;
|
|
private TextureColor[] _textureColor;
|
|
private bool[] _textureEnabled;
|
|
|
|
/// <summary>
|
|
/// Individual texture rotations
|
|
/// </summary>
|
|
private float[] _textureRotations;
|
|
private Emgu.CV.CvEnum.FlipType[] _textureFlipMode;
|
|
private bool[] _textureRequiresReset;
|
|
|
|
private ImageBufferFactory<Image<Bgr, Byte>> _bgrBuffers;
|
|
private String _frameFileName;
|
|
|
|
private int _gridLines;
|
|
private float[] _verticalGridLines;
|
|
private float[] _horizontalGridLines;
|
|
|
|
#region GL_20
|
|
private Matrix4 _projectionMatrix;
|
|
private int _textureRenderRGBAProgramHandle;
|
|
private int _textureRenderBGRAProgramHandle;
|
|
private int _lineRenderProgramHandle;
|
|
#endregion
|
|
|
|
private static readonly float _degreeToRadian = (float)(Math.PI / 180.0);
|
|
private RectangleF[] _rectangles;
|
|
|
|
private const float _expectedLeft = -1.0f;
|
|
private const float _expectedRight = 1.0f;
|
|
private const float _expectedBottom = -1.0f;
|
|
private const float _expectedTop = 1.0f;
|
|
|
|
private float _left = _expectedLeft;
|
|
private float _right = _expectedRight;
|
|
private float _top = _expectedTop;
|
|
private float _bottom = _expectedBottom;
|
|
private float _zNear = 0.01f;
|
|
private float _zFar = 1.0f;
|
|
|
|
static float Min = -1;
|
|
static float Max = 1;
|
|
|
|
static float RectanglesVertexDepth = 0.1f;
|
|
static float GridVertexDepth = 0.2f;
|
|
static float FrameVertexDepth = 0.3f;
|
|
static float ImageVertexDepth = 0.4f;
|
|
|
|
static float[][] _textureVertexCoords = new float[][]
|
|
{
|
|
new float[] {
|
|
Max, Max, ImageVertexDepth,
|
|
Min, Max, ImageVertexDepth,
|
|
Min, Min, ImageVertexDepth,
|
|
Max, Min, ImageVertexDepth
|
|
},
|
|
new float[] {
|
|
Max, Max, FrameVertexDepth,
|
|
Min, Max, FrameVertexDepth,
|
|
Min, Min, FrameVertexDepth,
|
|
Max, Min, FrameVertexDepth
|
|
}
|
|
};
|
|
|
|
static float[] squareTextureCoords =
|
|
new float[] {
|
|
1, 0,
|
|
0, 0,
|
|
0, 1,
|
|
1, 1
|
|
};
|
|
|
|
static float[] squareTextureCoordsFlipHorizontal =
|
|
new float[] {
|
|
0, 0,
|
|
1, 0,
|
|
1, 1,
|
|
0, 1
|
|
};
|
|
|
|
static float[] squareTextureCoordsFlipVetical =
|
|
new float[] {
|
|
1, 1,
|
|
0, 1,
|
|
0, 0,
|
|
1, 0
|
|
};
|
|
|
|
private float[] MergeArray(float[] lines, float[] newLines)
|
|
{
|
|
if (lines == null)
|
|
return newLines;
|
|
|
|
if (newLines == null)
|
|
return lines;
|
|
|
|
int oldLength = lines.Length;
|
|
Array.Resize(ref lines, lines.Length + newLines.Length);
|
|
Array.Copy(newLines, 0, lines, oldLength, newLines.Length);
|
|
return lines;
|
|
}
|
|
|
|
public void GetGridLines(out float[] lines, out float[] colors)
|
|
{
|
|
float[] color = new float[] { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
|
|
lines = MergeArray(null, _verticalGridLines);
|
|
lines = MergeArray(lines, _horizontalGridLines);
|
|
|
|
colors = null;
|
|
if (lines == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//every 3 float represent one point, each point need 4 values for color;
|
|
colors = new float[4 * (lines.Length / 3)];
|
|
for (int i = 0, idx = 0; i < lines.Length / 3; i++)
|
|
{
|
|
colors[idx++] = color[0];
|
|
colors[idx++] = color[1];
|
|
colors[idx++] = color[2];
|
|
colors[idx++] = color[3];
|
|
}
|
|
}
|
|
|
|
public void GetRectangleLines(out float[] lines, out float[] colors)
|
|
{
|
|
float[] color = new float[] { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
|
|
colors = null;
|
|
lines = null;
|
|
if (_rectangles == null)
|
|
return;
|
|
|
|
int pointsCount = _rectangles.Length * 8;
|
|
|
|
lines = new float[pointsCount * 3];
|
|
int idx = 0;
|
|
foreach (RectangleF rect in _rectangles)
|
|
{
|
|
lines[idx++] = rect.Location.X;
|
|
lines[idx++] = rect.Location.Y;
|
|
lines[idx++] = RectanglesVertexDepth;
|
|
lines[idx++] = rect.Location.X + rect.Width;
|
|
lines[idx++] = rect.Location.Y;
|
|
lines[idx++] = RectanglesVertexDepth;
|
|
|
|
lines[idx++] = rect.Location.X + rect.Width;
|
|
lines[idx++] = rect.Location.Y;
|
|
lines[idx++] = RectanglesVertexDepth;
|
|
lines[idx++] = rect.Location.X + rect.Width;
|
|
lines[idx++] = rect.Location.Y + rect.Height;
|
|
lines[idx++] = RectanglesVertexDepth;
|
|
|
|
lines[idx++] = rect.Location.X + rect.Width;
|
|
lines[idx++] = rect.Location.Y + rect.Height;
|
|
lines[idx++] = RectanglesVertexDepth;
|
|
lines[idx++] = rect.Location.X;
|
|
lines[idx++] = rect.Location.Y + rect.Height;
|
|
lines[idx++] = RectanglesVertexDepth;
|
|
|
|
lines[idx++] = rect.Location.X;
|
|
lines[idx++] = rect.Location.Y + rect.Height;
|
|
lines[idx++] = RectanglesVertexDepth;
|
|
lines[idx++] = rect.Location.X;
|
|
lines[idx++] = rect.Location.Y;
|
|
lines[idx++] = RectanglesVertexDepth;
|
|
}
|
|
|
|
idx = 0;
|
|
//change the X and Y coordinate such that they range from [-1.0, 1.0] instead of [0.0, 1.0];
|
|
for (int i = 0; i < pointsCount; i++)
|
|
{
|
|
lines[idx] = lines[idx] * 2.0f -1.0f;
|
|
idx++;
|
|
lines[idx] = lines[idx] * 2.0f -1.0f;
|
|
idx += 2;
|
|
}
|
|
|
|
colors = new float[4 * pointsCount];
|
|
idx = 0;
|
|
for (int i = 0; i < pointsCount; i++)
|
|
{
|
|
colors[idx++] = color[0];
|
|
colors[idx++] = color[1];
|
|
colors[idx++] = color[2];
|
|
colors[idx++] = color[3];
|
|
}
|
|
}
|
|
|
|
public int GridLines
|
|
{
|
|
get
|
|
{
|
|
return _gridLines;
|
|
}
|
|
set
|
|
{
|
|
_gridLines = value;
|
|
if (_gridLines <= 0)
|
|
{
|
|
_verticalGridLines = null;
|
|
_horizontalGridLines = null;
|
|
_gridLines = 0;
|
|
}
|
|
else
|
|
{
|
|
_verticalGridLines = new float[GridLines * 6];
|
|
_horizontalGridLines = new float[GridLines * 6];
|
|
int idx = 0;
|
|
|
|
float increment = (Max - Min) / (GridLines + 1);
|
|
float current = Min + increment;
|
|
for (int i = 0; i < GridLines; ++i)
|
|
{
|
|
_verticalGridLines[idx] = Min;
|
|
_horizontalGridLines[idx] = current;
|
|
idx++;
|
|
_verticalGridLines[idx] = current;
|
|
_horizontalGridLines[idx] = Min;
|
|
idx++;
|
|
_verticalGridLines[idx] = GridVertexDepth;
|
|
_horizontalGridLines[idx] = GridVertexDepth;
|
|
idx++;
|
|
_verticalGridLines[idx] = Max;
|
|
_horizontalGridLines[idx] = current;
|
|
idx++;
|
|
_verticalGridLines[idx] = current;
|
|
_horizontalGridLines[idx] = Max;
|
|
idx++;
|
|
_verticalGridLines[idx] = GridVertexDepth;
|
|
_horizontalGridLines[idx] = GridVertexDepth;
|
|
idx++;
|
|
current += increment;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The rectangles to be drawed. (0,0) point should be the image texture origin where (1,1) should match the opposite corner of the image.
|
|
/// </summary>
|
|
public RectangleF[] Rectangles
|
|
{
|
|
get
|
|
{
|
|
return _rectangles;
|
|
}
|
|
set
|
|
{
|
|
_rectangles = value;
|
|
}
|
|
}
|
|
|
|
public enum TouchType
|
|
{
|
|
Down,
|
|
Fling,
|
|
Scroll,
|
|
SingleTapUp
|
|
}
|
|
|
|
private PointF ViewportPointToWorldPoint(PointF viewportPoint)
|
|
{
|
|
return new PointF(
|
|
(viewportPoint.X / ViewPortWidth) * (_right - _left) + _left,
|
|
( (ViewPortHeight - viewportPoint.Y) / ViewPortHeight) * (_top - _bottom) + _bottom);
|
|
}
|
|
|
|
private PointF WorldPointToImagePoint(PointF worldPoint)
|
|
{
|
|
return new PointF((worldPoint.X + 1.0f) / 2.0f, (worldPoint.Y + 1.0f) / 2.0f);
|
|
}
|
|
|
|
private static float Dist(PointF p1, PointF p2)
|
|
{
|
|
float dx = p1.X - p2.X;
|
|
float dy = p1.Y - p2.Y;
|
|
return (float) Math.Sqrt(dx * dx + dy * dy);
|
|
}
|
|
|
|
private static PointF RestrictRange(PointF point, float minX, float maxX, float minY, float maxY)
|
|
{
|
|
if (point.X < minX)
|
|
point.X = minX;
|
|
if (point.X > maxX)
|
|
point.X = maxX;
|
|
if (point.Y < minY)
|
|
point.Y = minY;
|
|
if (point.Y > maxY)
|
|
point.Y = maxY;
|
|
return point;
|
|
}
|
|
|
|
public System.Drawing.Rectangle GetRectangleInImageCoordinate(int rectangleIndex, System.Drawing.Size imageSize)
|
|
{
|
|
if (_rectangles == null || rectangleIndex >= _rectangles.Length)
|
|
return System.Drawing.Rectangle.Empty;
|
|
System.Drawing.RectangleF rect = _rectangles[rectangleIndex];
|
|
System.Drawing.Rectangle roi = new System.Drawing.Rectangle(
|
|
new System.Drawing.Point((int)(rect.Location.X * imageSize.Width), (int)((1.0 - rect.Location.Y) * imageSize.Height)),
|
|
new System.Drawing.Size((int)(rect.Width * imageSize.Width), (int)(rect.Height * imageSize.Height)));
|
|
roi.Location = new System.Drawing.Point(roi.Location.X, roi.Location.Y - roi.Height);
|
|
return roi;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update the rectangles location by a touch event
|
|
/// </summary>
|
|
/// <param name="type">The type of touch</param>
|
|
/// <param name="viewportStartPoint">The start point of the touch, may be PointF.Empty if touch type is down</param>
|
|
/// <param name="viewportEndPoint">The end point of the touch</param>
|
|
/// <param name="rectangleIndex">The index of the rectangle when the shape is to be updated.</param>
|
|
public void UpdateRectangleByTouch(TouchType type, PointF viewportStartPoint, PointF viewportEndPoint, int rectangleIndex)
|
|
{
|
|
if (_rectangles == null || rectangleIndex >= _rectangles.Length)
|
|
return;
|
|
|
|
//PointF startPoint = RestrictRange( WorldPointToImagePoint( ViewportPointToWorldPoint(viewportStartPoint)), 0.0f, 1.0f, 0.0f, 1.0f);
|
|
PointF endPoint = RestrictRange( WorldPointToImagePoint( ViewportPointToWorldPoint(viewportEndPoint) ), 0.0f, 1.0f, 0.0f, 1.0f);
|
|
|
|
RectangleF rect = _rectangles[rectangleIndex];
|
|
|
|
float scale = 0.6f;
|
|
RectangleF rectCenterRegion = new RectangleF(new PointF(rect.Location.X + (rect.Width - rect.Width * scale) / 2.0f, rect.Location.Y + (rect.Height -rect.Height * scale) / 2.0f), new SizeF(rect.Width * scale, rect.Height * scale));
|
|
|
|
if (rectCenterRegion.Contains(endPoint))
|
|
{ // move the center to the end point while keeping the width and height
|
|
float newX = endPoint.X - rect.Width / 2.0f;
|
|
if (newX <= 0)
|
|
newX = 0;
|
|
if (newX + rect.Width > 1.0f)
|
|
newX = 1.0f - rect.Width;
|
|
|
|
float newY = endPoint.Y - rect.Height / 2.0f;
|
|
if (newY <= 0)
|
|
newY = 0;
|
|
if (newY + rect.Height > 1.0f)
|
|
newY = 1.0f - rect.Height;
|
|
rect.Location = new PointF(newX, newY);
|
|
|
|
_rectangles[rectangleIndex] = rect;
|
|
return;
|
|
}
|
|
|
|
PointF point0 = rect.Location;
|
|
PointF point1 = new PointF(point0.X + rect.Width, point0.Y);
|
|
PointF point2 = new PointF(point0.X + rect.Width, point0.Y + rect.Height);
|
|
PointF point3 = new PointF(point0.X, point0.Y + rect.Height);
|
|
|
|
float d0 = Dist(endPoint, point0);
|
|
float d1 = Dist(endPoint, point1);
|
|
float d2 = Dist(endPoint, point2);
|
|
float d3 = Dist(endPoint, point3);
|
|
|
|
float min = Math.Min(Math.Min(d0, d1), Math.Min(d2, d3));
|
|
if (min == d0)
|
|
{
|
|
//PointF newLoc = endPoint;
|
|
//if (newLoc.X < 0)
|
|
// newLoc.X = 0;
|
|
//if (newLoc.X > 1.0f)
|
|
// newLoc.X = 1.0f;
|
|
rect.Width = point2.X - endPoint.X;
|
|
//rect.Location = endPoint;
|
|
|
|
//if (newLoc.Y < 0)
|
|
// newLoc.Y = 0;
|
|
//if (newLoc.Y > 1.0f)
|
|
// newLoc.Y = 1.0f;
|
|
rect.Height = point2.Y - endPoint.Y;
|
|
rect.Location = endPoint;
|
|
}
|
|
else if (min == d1)
|
|
{
|
|
rect.Width = endPoint.X - point0.X;
|
|
if (rect.Width <= 0)
|
|
rect.Width = 1.0e-5f;
|
|
|
|
|
|
rect.Height = point3.Y - endPoint.Y;
|
|
if (rect.Height <= 0)
|
|
rect.Height = 1.0e-5f;
|
|
rect.Location = new PointF(rect.Location.X, endPoint.Y);
|
|
|
|
//if (rect.Width + point0.X > 1.0f)
|
|
// rect.Width = 1.0f - point0.X;
|
|
}
|
|
else if (min == d2)
|
|
{
|
|
rect.Width = endPoint.X - point0.X;
|
|
if (rect.Width <= 0)
|
|
rect.Width = 1.0e-5f;
|
|
//if (rect.Width + point0.X > 1.0f)
|
|
// rect.Width = 1.0f - point0.X;
|
|
|
|
rect.Height = endPoint.Y - point0.Y;
|
|
if (rect.Height <= 0)
|
|
rect.Height = 1.0e-5f;
|
|
//if (rect.Height + point0.Y > 1.0f)
|
|
// rect.Height = 1.0f - point0.Y;
|
|
|
|
}
|
|
else if (min == d3)
|
|
{
|
|
rect.Height = endPoint.Y - point0.Y;
|
|
if (rect.Height <= 0)
|
|
rect.Height = 1.0e-5f;
|
|
|
|
rect.Width = point1.X - endPoint.X;
|
|
if (rect.Width <= 0)
|
|
rect.Width= 1.0e-5f;
|
|
rect.Location = new PointF(endPoint.X, rect.Location.Y);
|
|
//if (rect.Height + point0.Y > 1.0)
|
|
// rect.Height = 1.0f - point0.Y;
|
|
}
|
|
_rectangles[rectangleIndex] = rect;
|
|
}
|
|
|
|
public bool[] TextureEnabled
|
|
{
|
|
get { return _textureEnabled; }
|
|
}
|
|
|
|
/*
|
|
public void SetTextureRotation(int textureIdx, int rotation)
|
|
{
|
|
float oldRotation = _textureRotation[textureIdx];
|
|
if (((oldRotation == 0 || oldRotation == 180) && (rotation == 90 || rotation == 270))
|
|
|| ((oldRotation == 90 || oldRotation == 270) && (rotation == 0 || rotation == 180)))
|
|
{
|
|
Size s = _imageSize;
|
|
_imageSize.Width = s.Height;
|
|
_imageSize.Height = s.Width;
|
|
}
|
|
|
|
_textureRotation[textureIdx] = rotation;
|
|
}*/
|
|
|
|
public Emgu.CV.CvEnum.FlipType[] TextureFlipMode
|
|
{
|
|
get
|
|
{
|
|
return _textureFlipMode;
|
|
}
|
|
}
|
|
|
|
/*
|
|
public bool TextureRequiresReset
|
|
{
|
|
get { return _textureRequiresReset; }
|
|
set { _textureRequiresReset = value; }
|
|
}*/
|
|
|
|
#if IOS
|
|
public GLImageView(RectangleF frame)
|
|
: base(frame)
|
|
{
|
|
Initialize();
|
|
}
|
|
|
|
/*
|
|
[Export("initWithCoder:")]
|
|
public GLImageView(NSCoder coder)
|
|
: base(coder)
|
|
{
|
|
Initialize();
|
|
}*/
|
|
|
|
[Export ("layerClass")]
|
|
public static Class LayerClass()
|
|
{
|
|
return iPhoneOSGameView.GetLayerClass();
|
|
}
|
|
#elif ANDROID
|
|
public GLImageView(Context context, GLVersion glVersion)
|
|
: base(context)
|
|
{
|
|
_glVersion = glVersion;
|
|
Initialize();
|
|
}
|
|
|
|
public GLImageView(Context context, IAttributeSet attrs, GLVersion glVersion) :
|
|
base(context, attrs)
|
|
{
|
|
_glVersion = glVersion;
|
|
Initialize();
|
|
}
|
|
|
|
public GLImageView(IntPtr handle, Android.Runtime.JniHandleOwnership transfer, GLVersion glVersion)
|
|
: base(handle, transfer)
|
|
{
|
|
_glVersion = glVersion;
|
|
Initialize();
|
|
}
|
|
#else
|
|
public GLImageView()
|
|
:base()
|
|
{
|
|
Initialize();
|
|
}
|
|
#endif
|
|
|
|
#if IOS || ANDROID
|
|
public override void Pause()
|
|
{
|
|
base.Pause();
|
|
DeleteTextures();
|
|
}
|
|
|
|
public override void Resume()
|
|
{
|
|
base.Resume();
|
|
GenTextures();
|
|
}
|
|
#endif
|
|
|
|
private void Initialize()
|
|
{
|
|
#if IOS
|
|
LayerRetainsBacking = true;
|
|
LayerColorFormat = MonoTouch.OpenGLES.EAGLColorFormat.RGBA8;
|
|
CreateFrameBuffer();
|
|
#elif ANDROID
|
|
PackageName = Context.PackageName;
|
|
#else
|
|
#endif
|
|
|
|
_textureSizes = new System.Drawing.Size[2];
|
|
_textureColor = new TextureColor[2] {
|
|
TextureColor.NotSupported,
|
|
TextureColor.NotSupported
|
|
};
|
|
_textureEnabled = new bool[2];
|
|
_textureRotations = new float[2];
|
|
|
|
_textureFlipMode = new Emgu.CV.CvEnum.FlipType[2];
|
|
for (int i = 0; i < _textureFlipMode.Length; i++)
|
|
{
|
|
_textureFlipMode[i] = Emgu.CV.CvEnum.FlipType.None;
|
|
}
|
|
|
|
_textureRequiresReset = new bool[2];
|
|
for (int i = 0; i < _textureRequiresReset.Length; i++)
|
|
_textureRequiresReset[i] = true;
|
|
|
|
if (_glVersion == OpenGLVersion.ES1)
|
|
_bgrBuffers = new ImageBufferFactory<Image<Bgr, byte>>(s => new Image<Bgr, byte>(s));
|
|
|
|
_textureIds = new int[2];
|
|
//context = Context;
|
|
//xangle = 45;
|
|
//yangle = 45;
|
|
|
|
#if IOS
|
|
OnLoad(null);
|
|
#endif
|
|
|
|
Resize += delegate
|
|
{
|
|
//_viewPortHeight = Height;
|
|
//_viewPortWidth = Width;
|
|
//SetupCamera();
|
|
PerformRenderAll();
|
|
};
|
|
|
|
}
|
|
|
|
#if IOS || ANDROID
|
|
// This method is called everytime the context needs
|
|
// to be recreated. Use it to set any egl-specific settings
|
|
// prior to context creation
|
|
protected override void CreateFrameBuffer()
|
|
{
|
|
#if IOS
|
|
ContextRenderingApi = MonoTouch.OpenGLES.EAGLRenderingAPI.OpenGLES1;
|
|
#elif ANDROID
|
|
ContextRenderingApi = _glVersion;
|
|
#endif
|
|
// the default GraphicsMode that is set consists of (16, 16, 0, 0, 2, false)
|
|
try
|
|
{
|
|
Report.Debug(PackageName, "Loading with GL Image View with default settings");
|
|
//if (GraphicsContext == null)
|
|
// if you don't call this, the context won't be created
|
|
base.CreateFrameBuffer();
|
|
|
|
return;
|
|
} catch (Exception ex)
|
|
{
|
|
Report.Error(PackageName, ex.Message);
|
|
}
|
|
|
|
// Fallback modes
|
|
// If the first attempt at initializing the surface with a default graphics
|
|
// mode fails, then the app can try different configurations. Devices will
|
|
// support different modes, and what is valid for one might not be valid for
|
|
// another. If all options fail, you can set all values to 0, which will
|
|
// ask for the first available configuration the device has without any
|
|
// filtering.
|
|
// After a successful call to base.CreateFrameBuffer(), the GraphicsMode
|
|
// object will have its values filled with the actual values that the
|
|
// device returned.
|
|
|
|
|
|
// This is a setting that asks for any available 16-bit color mode with no
|
|
// other filters. It passes 0 to the buffers parameter, which is an invalid
|
|
// setting in the default OpenTK implementation but is valid in some
|
|
// Android implementations, so the AndroidGraphicsMode object allows it.
|
|
try
|
|
{
|
|
#if IOS
|
|
#elif ANDROID
|
|
Report.Debug(PackageName, "Loading with custom Android settings (low mode)");
|
|
GraphicsMode = new AndroidGraphicsMode(16, 0, 0, 0, 0, false);
|
|
#endif
|
|
//if (GraphicsContext == null)
|
|
// if you don't call this, the context won't be created
|
|
base.CreateFrameBuffer();
|
|
return;
|
|
} catch (Exception ex)
|
|
{
|
|
Report.Error(PackageName, ex.Message);
|
|
}
|
|
|
|
// this is a setting that doesn't specify any color values. Certain devices
|
|
// return invalid graphics modes when any color level is requested, and in
|
|
// those cases, the only way to get a valid mode is to not specify anything,
|
|
// even requesting a default value of 0 would return an invalid mode.
|
|
try
|
|
{
|
|
#if IOS
|
|
#elif ANDROID
|
|
Report.Debug(PackageName, "Loading with no Android settings");
|
|
GraphicsMode = new AndroidGraphicsMode(0, 4, 0, 0, 0, false);
|
|
#endif
|
|
//if (GraphicsContext == null)
|
|
// if you don't call this, the context won't be created
|
|
base.CreateFrameBuffer();
|
|
return;
|
|
} catch (Exception ex)
|
|
{
|
|
Report.Error(PackageName, ex.Message);
|
|
}
|
|
throw new Exception("Can't load egl, aborting");
|
|
}
|
|
#endif
|
|
|
|
protected override void OnLoad(EventArgs e)
|
|
{
|
|
base.OnLoad(e);
|
|
|
|
#if ANDROID || IOS
|
|
if (_glVersion == OpenGLVersion.ES2)
|
|
{
|
|
ES20.All error = ES20.GL.GetError();
|
|
if (error != ES20.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("GL Error before onLoad: {0}", error));
|
|
}
|
|
_textureRenderRGBAProgramHandle = GetRenderRGBATextureProgram();
|
|
_textureRenderBGRAProgramHandle = GetRenderBGRATextureProgram();
|
|
|
|
_lineRenderProgramHandle = GetRenderLineProgram();
|
|
error = ES20.GL.GetError();
|
|
if (error != ES20.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("GL Error during onLoad 0: {0}", error));
|
|
}
|
|
|
|
GenTextures();
|
|
|
|
error = ES20.GL.GetError();
|
|
if (error != ES20.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("GL Error during onLoad 2: {0}", error));
|
|
}
|
|
for (int i = 0; i < _textureRequiresReset.Length; i++)
|
|
_textureRequiresReset[i] = true;
|
|
|
|
if (_textureEnabled[1])
|
|
LoadFrame();
|
|
|
|
/*
|
|
if (_textureEnabled[0])
|
|
{
|
|
Image<Bgr, Byte> img = _bgrBuffers.GetBuffer(0);
|
|
if (img != null)
|
|
{
|
|
LoadTexture(img.Size, img.MIplImage.imageData, TextureColor.RGB, 0);
|
|
}
|
|
}*/
|
|
|
|
error = ES20.GL.GetError();
|
|
if (error != ES20.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("GL Error during onLoad 3: {0}", error));
|
|
}
|
|
|
|
ES20.GL.BlendFunc(ES20.All.SrcAlpha, ES20.All.OneMinusSrcAlpha);
|
|
ES20.GL.Enable(ES20.All.Blend);
|
|
|
|
error = ES20.GL.GetError();
|
|
if (error != ES20.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("GL Error during onLoad 4: {0}", error));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ES11.All error = ES11.GL.GetError();
|
|
if (error != ES11.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("GL Error before onLoad: {0}", error));
|
|
}
|
|
ES11.GL.ShadeModel(ES11.All.Smooth);
|
|
ES11.GL.ClearColor(0, 0, 0, 1);
|
|
|
|
ES11.GL.ClearDepth(1.0f);
|
|
ES11.GL.Enable(ES11.All.DepthTest);
|
|
ES11.GL.DepthFunc(ES11.All.Lequal);
|
|
|
|
ES11.GL.Enable(ES11.All.CullFace);
|
|
ES11.GL.CullFace(ES11.All.Back);
|
|
|
|
error = ES11.GL.GetError();
|
|
if (error != ES11.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("GL Error during onLoad 0: {0}", error));
|
|
}
|
|
|
|
ES11.GL.Hint(ES11.All.PerspectiveCorrectionHint, ES11.All.Nicest);
|
|
// create texture ids
|
|
ES11.GL.Enable(ES11.All.Texture2D);
|
|
|
|
GenTextures();
|
|
|
|
error = ES11.GL.GetError();
|
|
if (error != ES11.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("GL Error during onLoad 2: {0}", error));
|
|
}
|
|
for (int i = 0; i < _textureRequiresReset.Length; i++)
|
|
_textureRequiresReset[i] = true;
|
|
|
|
if (_textureEnabled[1])
|
|
LoadFrame();
|
|
|
|
if (_textureEnabled[0])
|
|
{
|
|
Image<Bgr, Byte> img = _bgrBuffers.GetBuffer(0);
|
|
if (img != null)
|
|
{
|
|
LoadTexture(img.Size, img.MIplImage.imageData, TextureColor.RGB, 0);
|
|
}
|
|
}
|
|
|
|
error = ES11.GL.GetError();
|
|
if (error != ES11.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("GL Error during onLoad 3: {0}", error));
|
|
}
|
|
|
|
ES11.GL.BlendFunc(ES11.All.SrcAlpha, ES11.All.OneMinusSrcAlpha);
|
|
ES11.GL.Enable(ES11.All.Blend);
|
|
|
|
error = ES11.GL.GetError();
|
|
if (error != ES11.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("GL Error during onLoad 4: {0}", error));
|
|
}
|
|
}
|
|
#else
|
|
if (_glVersion == OpenGLVersion.GL3)
|
|
{
|
|
|
|
_textureRenderRGBAProgramHandle = GetRenderRGBATextureProgram();
|
|
_textureRenderBGRAProgramHandle = GetRenderBGRATextureProgram();
|
|
|
|
_lineRenderProgramHandle = GetRenderLineProgram();
|
|
|
|
|
|
GenTextures();
|
|
|
|
|
|
for (int i = 0; i < _textureRequiresReset.Length; i++)
|
|
_textureRequiresReset[i] = true;
|
|
|
|
if (_textureEnabled[1])
|
|
LoadFrame();
|
|
|
|
/*
|
|
if (_textureEnabled[0])
|
|
{
|
|
Image<Bgr, Byte> img = _bgrBuffers.GetBuffer(0);
|
|
if (img != null)
|
|
{
|
|
LoadTexture(img.Size, img.MIplImage.imageData, TextureColor.RGB, 0);
|
|
}
|
|
}*/
|
|
|
|
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
|
|
GL.Enable(EnableCap.Blend);
|
|
}
|
|
|
|
#endif
|
|
PerformRenderAll();
|
|
}
|
|
|
|
private void PerformRenderAll()
|
|
{
|
|
#if IOS
|
|
PerformSelector(new Selector("RenderAll"), null, 0.2f);
|
|
#else
|
|
RenderAll();
|
|
#endif
|
|
}
|
|
|
|
#region ES20
|
|
int ES2LoadShader(ES20.All type, string source)
|
|
{
|
|
int shader = ES20.GL.CreateShader(type);
|
|
if (shader == 0)
|
|
{
|
|
throw new InvalidOperationException(String.Format("Unable to create shader {0}", ES20.GL.GetError()));
|
|
}
|
|
|
|
int length = 0;
|
|
ES20.GL.ShaderSource(shader, 1, new string[] { source }, (int[])null);
|
|
ES20.GL.CompileShader(shader);
|
|
|
|
int compiled = 0;
|
|
ES20.GL.GetShader(shader, ES20.All.CompileStatus, out compiled);
|
|
if (compiled == 0)
|
|
{
|
|
length = 0;
|
|
ES20.GL.GetShader(shader, ES20.All.InfoLogLength, out length);
|
|
if (length > 0)
|
|
{
|
|
var log = new StringBuilder(length);
|
|
ES20.GL.GetShaderInfoLog(shader, length, out length, log);
|
|
Report.Debug("GL2", "Couldn't compile shader: " + log.ToString());
|
|
}
|
|
|
|
ES20.GL.DeleteShader(shader);
|
|
throw new InvalidOperationException("Unable to compile shader of type : " + type.ToString());
|
|
}
|
|
|
|
return shader;
|
|
}
|
|
#endregion
|
|
|
|
int GLLoadShader(ShaderType type, string source)
|
|
{
|
|
int shader = GL.CreateShader(type);
|
|
if (shader == 0)
|
|
{
|
|
throw new InvalidOperationException(String.Format("Unable to create shader {0}", GL.GetError()));
|
|
}
|
|
|
|
int length = 0;
|
|
GL.ShaderSource(shader, source);
|
|
GL.CompileShader(shader);
|
|
|
|
int compiled = 0;
|
|
GL.GetShader(shader, ShaderParameter.CompileStatus, out compiled);
|
|
if (compiled == 0)
|
|
{
|
|
length = 0;
|
|
GL.GetShader(shader, ShaderParameter.InfoLogLength, out length);
|
|
if (length > 0)
|
|
{
|
|
var log = new StringBuilder(length);
|
|
GL.GetShaderInfoLog(shader, length, out length, log);
|
|
Report.Debug("GL", "Couldn't compile shader: " + log.ToString());
|
|
}
|
|
|
|
GL.DeleteShader(shader);
|
|
throw new InvalidOperationException("Unable to compile shader of type : " + type.ToString());
|
|
}
|
|
|
|
return shader;
|
|
}
|
|
|
|
private int ViewPortWidth
|
|
{
|
|
get
|
|
{
|
|
#if IOS
|
|
return Size.Width;
|
|
#else
|
|
return Width;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
private int ViewPortHeight
|
|
{
|
|
get
|
|
{
|
|
#if IOS
|
|
return Size.Height;
|
|
#else
|
|
return Height;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
public void SetupCamera()
|
|
{
|
|
|
|
|
|
}*/
|
|
|
|
/*
|
|
public override bool OnTouchEvent(MotionEvent e)
|
|
{
|
|
base.OnTouchEvent(e);
|
|
if (e.Action == MotionEventActions.Down)
|
|
{
|
|
prevx = e.GetX();
|
|
prevy = e.GetY();
|
|
}
|
|
if (e.Action == MotionEventActions.Move)
|
|
{
|
|
float e_x = e.GetX();
|
|
float e_y = e.GetY();
|
|
|
|
float xdiff = (prevx - e_x);
|
|
float ydiff = (prevy - e_y);
|
|
xangle = xangle + ydiff;
|
|
yangle = yangle + xdiff;
|
|
prevx = e_x;
|
|
prevy = e_y;
|
|
}
|
|
if (e.Action == MotionEventActions.Down || e.Action == MotionEventActions.Move)
|
|
RenderTexture();
|
|
return true;
|
|
}*/
|
|
|
|
#if IOS || ANDROID
|
|
protected override void OnUnload(EventArgs e)
|
|
{
|
|
base.OnUnload(e);
|
|
DeleteTextures();
|
|
}
|
|
#endif
|
|
|
|
private void DeleteTextures()
|
|
{
|
|
for (int i = 0; i < _textureSizes.Length; i++)
|
|
{
|
|
_textureSizes[i] = Size.Empty;
|
|
_textureRequiresReset[i] = true;
|
|
_textureEnabled[i] = false;
|
|
}
|
|
if (_glVersion == OpenGLVersion.ES2)
|
|
{
|
|
ES20.GL.DeleteTextures(2, _textureIds);
|
|
}
|
|
else if (_glVersion == OpenGLVersion.ES1)
|
|
{
|
|
ES11.GL.DeleteTextures(2, _textureIds);
|
|
} else
|
|
{
|
|
GL.DeleteTextures(2, _textureIds);
|
|
}
|
|
}
|
|
|
|
private void GenTextures()
|
|
{
|
|
for (int i = 0; i < _textureSizes.Length; i++)
|
|
{
|
|
_textureSizes[i] = Size.Empty;
|
|
_textureRequiresReset[i] = true;
|
|
_textureEnabled[i] = false;
|
|
}
|
|
|
|
if (_glVersion == OpenGLVersion.ES2)
|
|
{
|
|
ES20.GL.GenTextures(_textureIds.Length, _textureIds);
|
|
}
|
|
else if (_glVersion == OpenGLVersion.ES1)
|
|
{
|
|
ES11.GL.GenTextures(_textureIds.Length, _textureIds);
|
|
} else
|
|
{
|
|
GL.GenTextures(_textureIds.Length, _textureIds);
|
|
}
|
|
}
|
|
|
|
|
|
private float _rotation;
|
|
|
|
/// <summary>
|
|
/// Get or set the rotation of the whole GLImageView in degree
|
|
/// </summary>
|
|
public float Rotation
|
|
{
|
|
get
|
|
{
|
|
return _rotation;
|
|
}
|
|
set
|
|
{
|
|
_rotation = value;
|
|
}
|
|
}
|
|
|
|
private void ResetScreen()
|
|
{
|
|
// setup the projection matrix to compensate for the aspect ratio of the imageSize;
|
|
float widthScale = 1.0f;
|
|
float heightScale = 1.0f;
|
|
int viewPortWidth = ViewPortWidth;
|
|
int viewPortHeight = ViewPortHeight;
|
|
|
|
if (!(_textureSizes[0].IsEmpty || viewPortHeight == 0))
|
|
{
|
|
double viewPortWidthHeight = (double)viewPortWidth / (double)viewPortHeight;
|
|
double imageWidthHeight = (double)_imageSize.Width / (double)_imageSize.Height;
|
|
if (viewPortWidthHeight > imageWidthHeight)
|
|
{
|
|
//view port is too wide
|
|
widthScale = (float)(viewPortWidthHeight / imageWidthHeight);
|
|
float compensation = (float)(viewPortWidthHeight - imageWidthHeight) / 2.0f;
|
|
_left = _expectedLeft - compensation;
|
|
_right = _expectedRight + compensation;
|
|
_top = _expectedTop;
|
|
_bottom = _expectedBottom;
|
|
|
|
}
|
|
else
|
|
{
|
|
heightScale = 1.0f / (float)(viewPortWidthHeight / imageWidthHeight);
|
|
float compensation = (float)((1.0 / viewPortWidthHeight) - (1.0 / imageWidthHeight)) / 2.0f;
|
|
//viewport is too tall
|
|
_bottom = _expectedBottom - compensation;
|
|
_top = _expectedTop + compensation;
|
|
_left = _expectedLeft;
|
|
_right = _expectedRight;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_bottom = _expectedBottom;
|
|
_top = _expectedTop;
|
|
_left = _expectedLeft;
|
|
_right = _expectedRight;
|
|
}
|
|
|
|
#if ANDROID || IOS
|
|
if (_glVersion == OpenGLVersion.ES2)
|
|
{
|
|
//_zNear = -10.0f;
|
|
ES20.GL.Viewport(0, 0, viewPortWidth, viewPortHeight);
|
|
_projectionMatrix = OpenTK.Matrix4.Scale(1.0f / widthScale, 1.0f / heightScale, 1.0f);
|
|
//_projectionMatrix = OpenTK.Matrix4.CreateOrthographicOffCenter(_left, _right, _bottom, _top, _zNear, _zFar);
|
|
//_projectionMatrix = OpenTK.Matrix4.Frustum(_left, _right, _bottom, _top, _zNear, _zFar);
|
|
//_projectionMatrix = OpenTK.Matrix4.Frustum(-1, 1, -1, 1, 3, 7);
|
|
|
|
ES20.All glError = ES20.GL.GetError();
|
|
if (glError != ES20.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error after setup camera: {0}", glError));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ES11.GL.Viewport(0, 0, viewPortWidth, viewPortHeight);
|
|
|
|
ES11.All glError = ES11.GL.GetError();
|
|
if (glError != ES11.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error after setup camera: {0}", glError));
|
|
}
|
|
}
|
|
|
|
if (_glVersion == OpenGLVersion.ES2)
|
|
{
|
|
ES20.All glError = ES20.GL.GetError();
|
|
if (glError != ES20.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error before clearing screen: {0}", glError));
|
|
}
|
|
|
|
#if DEBUG
|
|
ES20.GL.ClearColor(1.0f, 0.0f, 0.0f, 1);
|
|
#else
|
|
ES20.GL.ClearColor(0.0f, 0.0f, 0.0f, 1);
|
|
#endif
|
|
ES20.GL.Clear(
|
|
#if IOS
|
|
(int)
|
|
#endif
|
|
(ES20.ClearBufferMask.ColorBufferBit | ES20.ClearBufferMask.DepthBufferBit));
|
|
}
|
|
else //ES 1.1
|
|
{
|
|
ES11.All glError = ES11.GL.GetError();
|
|
if (glError != ES11.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error before clearing screen: {0}", glError));
|
|
}
|
|
#if DEBUG
|
|
ES11.GL.ClearColor(1.0f, 0.0f, 0.0f, 1);
|
|
#else
|
|
ES11.GL.ClearColor(0.0f, 0.0f, 0.0f, 1);
|
|
#endif
|
|
ES11.GL.Clear(
|
|
#if IOS
|
|
(int)
|
|
#endif
|
|
(ES11.ClearBufferMask.ColorBufferBit | ES11.ClearBufferMask.DepthBufferBit));
|
|
|
|
ES11.GL.MatrixMode(ES11.All.Projection);
|
|
ES11.GL.LoadIdentity();
|
|
|
|
//ES11.GL.Ortho(_expectedLeft, _expectedRight, _expectedBottom, _expectedTop, _zNear, _zFar);
|
|
//ES11.GL.Scale(1.0f / widthScale, 1.0f / heightScale, 1.0f);
|
|
_zNear = -10.0f;
|
|
ES11.GL.Ortho(_left, _right, _bottom, _top, _zNear, _zFar);
|
|
}
|
|
#else
|
|
if (_glVersion == OpenGLVersion.GL3)
|
|
{
|
|
//_zNear = -10.0f;
|
|
GL.Viewport(0, 0, viewPortWidth, viewPortHeight);
|
|
_projectionMatrix = OpenTK.Matrix4.Scale(1.0f / widthScale, 1.0f / heightScale, 1.0f);
|
|
//_projectionMatrix = OpenTK.Matrix4.CreateOrthographicOffCenter(_left, _right, _bottom, _top, _zNear, _zFar);
|
|
//_projectionMatrix = OpenTK.Matrix4.Frustum(_left, _right, _bottom, _top, _zNear, _zFar);
|
|
//_projectionMatrix = OpenTK.Matrix4.Frustum(-1, 1, -1, 1, 3, 7);
|
|
|
|
|
|
#if DEBUG
|
|
GL.ClearColor(1.0f, 0.0f, 0.0f, 1);
|
|
#else
|
|
GL.ClearColor(0.0f, 0.0f, 0.0f, 1);
|
|
#endif
|
|
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
private void RenderLines(float[] lines, float[] colors, float lineWidth)
|
|
{
|
|
if (lines == null)
|
|
return;
|
|
#if (ANDROID || IOS)
|
|
if (_glVersion == OpenGLVersion.ES2)
|
|
{
|
|
ES20.GL.UseProgram(_lineRenderProgramHandle);
|
|
// get handle to vertex shader's vPosition member
|
|
int linePositionHandle = ES20.GL.GetAttribLocation(_lineRenderProgramHandle, new StringBuilder("vPosition"));
|
|
|
|
// Enable a handle to the triangle vertices
|
|
ES20.GL.EnableVertexAttribArray(linePositionHandle);
|
|
|
|
// Prepare the line data
|
|
ES20.GL.VertexAttribPointer(linePositionHandle, 3, ES20.All.Float, false, 0, lines);
|
|
|
|
// get handle to fragment shader's vColor member
|
|
int colorHandle = ES20.GL.GetAttribLocation(_lineRenderProgramHandle, new StringBuilder("vColor"));
|
|
ES20.GL.EnableVertexAttribArray(colorHandle);
|
|
ES20.GL.VertexAttribPointer(colorHandle, 4, ES20.All.Float, false, 0, colors);
|
|
|
|
// get handle to shape's transformation matrix
|
|
int lineMatrixHandle = ES20.GL.GetUniformLocation(_lineRenderProgramHandle, new StringBuilder("uMVPMatrix"));
|
|
|
|
// Apply the projection and view transformation
|
|
Matrix4 projectionMatrix = Matrix4.Mult(_projectionMatrix, Matrix4.CreateRotationZ(_rotation * _degreeToRadian));
|
|
|
|
ES20.GL.UniformMatrix4(lineMatrixHandle, false, ref projectionMatrix);
|
|
|
|
|
|
ES20.GL.LineWidth(lineWidth);
|
|
ES20.GL.DrawArrays(ES20.All.Lines, 0, lines.Length / 3);
|
|
|
|
ES20.All glError = ES20.GL.GetError();
|
|
if (glError != ES20.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error after drawing lines: {0}", glError));
|
|
}
|
|
|
|
ES20.GL.DisableVertexAttribArray(linePositionHandle);
|
|
ES20.GL.DisableVertexAttribArray(colorHandle);
|
|
}
|
|
else //ES1.1
|
|
{
|
|
ES11.GL.Disable(ES11.All.Texture2D);
|
|
ES11.GL.EnableClientState(ES11.All.VertexArray);
|
|
ES11.GL.EnableClientState(ES11.All.ColorArray);
|
|
|
|
ES11.GL.PushMatrix();
|
|
ES11.GL.Rotate(_rotation, 0, 0, 1);
|
|
|
|
//ES11.GL.LineWidth(lineWidth);
|
|
ES11.GL.VertexPointer(3, ES11.All.Float, 0, lines);
|
|
ES11.GL.ColorPointer(4, ES11.All.Float, 0, colors);
|
|
ES11.GL.DrawArrays(ES11.All.Lines, 0, lines.Length / 3);
|
|
|
|
ES11.GL.DisableClientState(ES11.All.VertexArray);
|
|
ES11.GL.DisableClientState(ES11.All.ColorArray);
|
|
//GL.Color4(0, 0, 0, 0);
|
|
|
|
ES11.GL.PopMatrix();
|
|
|
|
ES11.GL.Enable(ES11.All.Texture2D);
|
|
|
|
ES11.All glError = ES11.GL.GetError();
|
|
if (glError != ES11.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error after drawing lines: {0}", glError));
|
|
}
|
|
|
|
}
|
|
#else
|
|
if (_glVersion == OpenGLVersion.GL3)
|
|
{
|
|
GL.UseProgram(_lineRenderProgramHandle);
|
|
// get handle to vertex shader's vPosition member
|
|
int linePositionHandle = GL.GetAttribLocation(_lineRenderProgramHandle, "vPosition");
|
|
|
|
// Enable a handle to the triangle vertices
|
|
GL.EnableVertexAttribArray(linePositionHandle);
|
|
|
|
// Prepare the line data
|
|
GL.VertexAttribPointer(linePositionHandle, 3, VertexAttribPointerType.Float, false, 0, lines);
|
|
|
|
// get handle to fragment shader's vColor member
|
|
int colorHandle = GL.GetAttribLocation(_lineRenderProgramHandle, "vColor");
|
|
GL.EnableVertexAttribArray(colorHandle);
|
|
GL.VertexAttribPointer(colorHandle, 4, VertexAttribPointerType.Float, false, 0, colors);
|
|
|
|
// get handle to shape's transformation matrix
|
|
int lineMatrixHandle = GL.GetUniformLocation(_lineRenderProgramHandle, "uMVPMatrix");
|
|
|
|
// Apply the projection and view transformation
|
|
Matrix4 projectionMatrix = Matrix4.Mult(_projectionMatrix, Matrix4.CreateRotationZ(_rotation * _degreeToRadian));
|
|
|
|
GL.UniformMatrix4(lineMatrixHandle, false, ref projectionMatrix);
|
|
|
|
|
|
GL.LineWidth(lineWidth);
|
|
GL.DrawArrays(BeginMode.Lines, 0, lines.Length / 3);
|
|
|
|
GL.DisableVertexAttribArray(linePositionHandle);
|
|
GL.DisableVertexAttribArray(colorHandle);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
private void RenderTextures()
|
|
{
|
|
#if ANDROID || IOS
|
|
if (_glVersion == OpenGLVersion.ES2)
|
|
{
|
|
Matrix4 projectionMatrix = Matrix4.Mult(_projectionMatrix, Matrix4.CreateRotationZ(_rotation * _degreeToRadian));
|
|
|
|
for (int i = 0; i <= 1; i++)
|
|
{
|
|
if (_textureEnabled[i] && ES20.GL.IsTexture(_textureIds[i]))
|
|
{
|
|
if (_textureColor[i] == TextureColor.RGB || _textureColor[i] == TextureColor.RGBA)
|
|
{
|
|
ES20.GL.UseProgram(_textureRenderRGBAProgramHandle);
|
|
}
|
|
else if (_textureColor[i] == TextureColor.BGR || _textureColor[i] == TextureColor.BGRA)
|
|
{
|
|
ES20.GL.UseProgram(_textureRenderBGRAProgramHandle);
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
// get handle to vertex shader's vPosition member
|
|
int positionHandle = ES20.GL.GetAttribLocation(_textureRenderRGBAProgramHandle, new StringBuilder("vPosition"));
|
|
// Enable a handle to the rectangle vertices
|
|
ES20.GL.EnableVertexAttribArray(positionHandle);
|
|
|
|
int textureCoordHandle = ES20.GL.GetAttribLocation(_textureRenderRGBAProgramHandle, new StringBuilder("TexCoordIn"));
|
|
ES20.GL.EnableVertexAttribArray(textureCoordHandle);
|
|
|
|
// Prepare the rectangle coordinate data
|
|
ES20.GL.VertexAttribPointer(positionHandle, 3, ES20.All.Float, false, 0, _textureVertexCoords[i]);
|
|
|
|
// get handle to fragment shader's vColor member
|
|
//int colorHandle = GL.GetUniformLocation(_programHandle, new StringBuilder("vColor"));
|
|
|
|
// Set color with red, green, blue and alpha (opacity) values
|
|
//float[] color = new float[] { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
|
|
|
|
// Set color for drawing the triangle
|
|
//GL.Uniform4(colorHandle, 1, color);
|
|
|
|
ES20.All glError = ES20.GL.GetError();
|
|
if (glError != ES20.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error after setting texture position: {0}", glError));
|
|
}
|
|
|
|
if (_textureFlipMode[i] == Emgu.CV.CvEnum.FLIP.None)
|
|
{
|
|
ES20.GL.VertexAttribPointer(textureCoordHandle, 2, ES20.All.Float, false, 0, squareTextureCoords);
|
|
}
|
|
else if (_textureFlipMode[i] == Emgu.CV.CvEnum.FLIP.HORIZONTAL)
|
|
{
|
|
ES20.GL.VertexAttribPointer(textureCoordHandle, 2, ES20.All.Float, false, 0, squareTextureCoordsFlipHorizontal);
|
|
}
|
|
else
|
|
{
|
|
throw new NotImplementedException(String.Format("Flip mode of {0} in GLImageView is not implemented", _textureFlipMode[i].ToString()));
|
|
}
|
|
|
|
glError = ES20.GL.GetError();
|
|
if (glError != ES20.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error after setting texture vertex: {0}", glError));
|
|
}
|
|
|
|
int textureHandle = ES20.GL.GetUniformLocation(_textureRenderRGBAProgramHandle, new StringBuilder("Texture"));
|
|
ES20.GL.ActiveTexture(ES20.All.Texture0);
|
|
ES20.GL.BindTexture(ES20.All.Texture2D, _textureIds[i]);
|
|
ES20.GL.Uniform1(textureHandle, 0);
|
|
|
|
glError = ES20.GL.GetError();
|
|
if (glError != ES20.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error after setting texture: {0}", glError));
|
|
}
|
|
|
|
// get handle to shape's transformation matrix
|
|
int MVPMatrixHandle = ES20.GL.GetUniformLocation(_textureRenderRGBAProgramHandle, new StringBuilder("uMVPMatrix"));
|
|
|
|
if (_textureRotations[i] != 0)
|
|
{
|
|
Matrix4 rotationMat = Matrix4.Mult(Matrix4.CreateRotationZ(_textureRotations[i] * _degreeToRadian), projectionMatrix);
|
|
ES20.GL.UniformMatrix4(MVPMatrixHandle, false, ref rotationMat);
|
|
}
|
|
else
|
|
{
|
|
// Apply the projection and view transformation
|
|
ES20.GL.UniformMatrix4(MVPMatrixHandle, false, ref projectionMatrix);
|
|
}
|
|
|
|
glError = ES20.GL.GetError();
|
|
if (glError != ES20.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error after setting transformation: {0}", glError));
|
|
}
|
|
|
|
ES20.GL.DrawArrays(ES20.All.TriangleFan, 0, 4);
|
|
|
|
glError = ES20.GL.GetError();
|
|
if (glError != ES20.All.NoError)
|
|
{
|
|
Report.Warn(PackageName, String.Format("Error after draw array: {0}", glError));
|
|
}
|
|
|
|
ES20.GL.DisableVertexAttribArray(positionHandle);
|
|
ES20.GL.DisableVertexAttribArray(textureCoordHandle);
|
|
}
|
|
}
|
|
}
|
|
else //GLES 1.1
|
|
{
|
|
//ES11.GL.PushMatrix();
|
|
//ES11.GL.Rotate(_rotation, 0, 0, 1);
|
|
|
|
ES11.GL.EnableClientState(ES11.All.VertexArray);
|
|
ES11.GL.EnableClientState(ES11.All.TextureCoordArray);
|
|
|
|
for (int i = 0; i <= 1; i++)
|
|
{
|
|
if (_textureEnabled[i] && ES11.GL.IsTexture(_textureIds[i]))
|
|
{
|
|
//if (_textureRotations[i] != 0)
|
|
{
|
|
ES11.GL.PushMatrix();
|
|
ES11.GL.Rotate(_rotation + _textureRotations[i], 0, 0, 1.0f);
|
|
}
|
|
ES11.GL.BindTexture(ES11.All.Texture2D, _textureIds[i]);
|
|
ES11.GL.VertexPointer(3, ES11.All.Float, 0, _textureVertexCoords[i]);
|
|
|
|
if (_textureFlipMode[i] == Emgu.CV.CvEnum.FLIP.None)
|
|
{
|
|
ES11.GL.TexCoordPointer(2, ES11.All.Float, 0, squareTextureCoords);
|
|
}
|
|
else if (_textureFlipMode[i] == Emgu.CV.CvEnum.FLIP.HORIZONTAL)
|
|
{
|
|
ES11.GL.TexCoordPointer(2, ES11.All.Float, 0, squareTextureCoordsFlipHorizontal);
|
|
}
|
|
else
|
|
{
|
|
throw new NotImplementedException(String.Format("Flip mode of {0} in GLImageView is not implemented", _textureFlipMode[i].ToString()));
|
|
}
|
|
|
|
ES11.GL.DrawArrays(ES11.All.TriangleFan, 0, 4);
|
|
//if (_textureRotations[i] != 0)
|
|
{
|
|
ES11.GL.PopMatrix();
|
|
}
|
|
}
|
|
}
|
|
|
|
ES11.GL.DisableClientState(ES11.All.VertexArray);
|
|
ES11.GL.DisableClientState(ES11.All.TextureCoordArray);
|
|
//ES11.GL.PopMatrix();
|
|
}
|
|
#else
|
|
if (_glVersion == OpenGLVersion.GL3)
|
|
{
|
|
Matrix4 projectionMatrix = Matrix4.Mult(_projectionMatrix, Matrix4.CreateRotationZ(_rotation * _degreeToRadian));
|
|
|
|
for (int i = 0; i <= 1; i++)
|
|
{
|
|
if (_textureEnabled[i] && GL.IsTexture(_textureIds[i]))
|
|
{
|
|
if (_textureColor[i] == TextureColor.RGB || _textureColor[i] == TextureColor.RGBA)
|
|
{
|
|
GL.UseProgram(_textureRenderRGBAProgramHandle);
|
|
}
|
|
else if (_textureColor[i] == TextureColor.BGR || _textureColor[i] == TextureColor.BGRA)
|
|
{
|
|
GL.UseProgram(_textureRenderBGRAProgramHandle);
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
// get handle to vertex shader's vPosition member
|
|
int positionHandle = GL.GetAttribLocation(_textureRenderRGBAProgramHandle, "vPosition");
|
|
// Enable a handle to the rectangle vertices
|
|
GL.EnableVertexAttribArray(positionHandle);
|
|
|
|
int textureCoordHandle = GL.GetAttribLocation(_textureRenderRGBAProgramHandle, "TexCoordIn");
|
|
GL.EnableVertexAttribArray(textureCoordHandle);
|
|
|
|
// Prepare the rectangle coordinate data
|
|
GL.VertexAttribPointer(positionHandle, 3, VertexAttribPointerType.Float, false, 0, _textureVertexCoords[i]);
|
|
|
|
// get handle to fragment shader's vColor member
|
|
//int colorHandle = GL.GetUniformLocation(_programHandle, new StringBuilder("vColor"));
|
|
|
|
// Set color with red, green, blue and alpha (opacity) values
|
|
//float[] color = new float[] { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
|
|
|
|
// Set color for drawing the triangle
|
|
//GL.Uniform4(colorHandle, 1, color);
|
|
|
|
if (_textureFlipMode[i] == Emgu.CV.CvEnum.FlipType.None)
|
|
{
|
|
GL.VertexAttribPointer(textureCoordHandle, 2, VertexAttribPointerType.Float, false, 0, squareTextureCoords);
|
|
}
|
|
else if (_textureFlipMode[i] == Emgu.CV.CvEnum.FlipType.Horizontal)
|
|
{
|
|
GL.VertexAttribPointer(textureCoordHandle, 2, VertexAttribPointerType.Float, false, 0, squareTextureCoordsFlipHorizontal);
|
|
}
|
|
else
|
|
{
|
|
throw new NotImplementedException(String.Format("Flip mode of {0} in GLImageView is not implemented", _textureFlipMode[i].ToString()));
|
|
}
|
|
|
|
int textureHandle = GL.GetUniformLocation(_textureRenderRGBAProgramHandle, "Texture");
|
|
GL.ActiveTexture(TextureUnit.Texture0);
|
|
GL.BindTexture(TextureTarget.Texture2D, _textureIds[i]);
|
|
GL.Uniform1(textureHandle, 0);
|
|
|
|
|
|
// get handle to shape's transformation matrix
|
|
int MVPMatrixHandle = GL.GetUniformLocation(_textureRenderRGBAProgramHandle, "uMVPMatrix");
|
|
|
|
if (_textureRotations[i] != 0)
|
|
{
|
|
Matrix4 rotationMat = Matrix4.Mult(Matrix4.CreateRotationZ(_textureRotations[i] * _degreeToRadian), projectionMatrix);
|
|
GL.UniformMatrix4(MVPMatrixHandle, false, ref rotationMat);
|
|
}
|
|
else
|
|
{
|
|
// Apply the projection and view transformation
|
|
GL.UniformMatrix4(MVPMatrixHandle, false, ref projectionMatrix);
|
|
}
|
|
|
|
GL.DrawArrays(BeginMode.TriangleFan, 0, 4);
|
|
|
|
GL.DisableVertexAttribArray(positionHandle);
|
|
GL.DisableVertexAttribArray(textureCoordHandle);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if IOS
|
|
[Export("RenderAll")]
|
|
#endif
|
|
public void RenderAll()
|
|
{
|
|
this.MakeCurrent();
|
|
ResetScreen();
|
|
|
|
RenderTextures();
|
|
|
|
float[] lines, colors;
|
|
GetGridLines(out lines, out colors);
|
|
RenderLines(lines, colors, 1.0f);
|
|
|
|
GetRectangleLines(out lines, out colors);
|
|
RenderLines(lines, colors, 2.0f);
|
|
|
|
SwapBuffers();
|
|
}
|
|
|
|
|
|
#region GL_20
|
|
public int GetRenderLineProgram()
|
|
{
|
|
// Vertex and fragment shaders
|
|
string vertexShaderSrc = "uniform mat4 uMVPMatrix; \n" +
|
|
"attribute vec4 vPosition; \n" +
|
|
"attribute vec4 vColor; \n" +
|
|
"varying vec4 color; \n" +
|
|
"void main() \n" +
|
|
"{ \n" +
|
|
" gl_Position = uMVPMatrix * vPosition; \n" +
|
|
" color = vColor; \n" +
|
|
"} \n";
|
|
|
|
string fragmentShaderSrc =
|
|
|
|
"varying vec4 color; \n" +
|
|
"void main() \n" +
|
|
"{ \n" +
|
|
" gl_FragColor = color; \n" +
|
|
"} \n";
|
|
if (_glVersion == OpenGLVersion.ES2 || _glVersion == OpenGLVersion.ES1)
|
|
{
|
|
fragmentShaderSrc = "precision mediump float; \n" + fragmentShaderSrc;
|
|
}
|
|
return GetRenderProgram(vertexShaderSrc, fragmentShaderSrc);
|
|
}
|
|
|
|
public int GetRenderProgram(String vertexShaderSrc, String fragmentShaderSrc)
|
|
{
|
|
if (_glVersion == OpenGLVersion.ES2)
|
|
{
|
|
int vertexShader = ES2LoadShader(ES20.All.VertexShader, vertexShaderSrc);
|
|
int fragmentShader = ES2LoadShader(ES20.All.FragmentShader, fragmentShaderSrc);
|
|
int programHandle = ES20.GL.CreateProgram();
|
|
if (programHandle == 0)
|
|
throw new InvalidOperationException("Unable to create program");
|
|
|
|
ES20.GL.AttachShader(programHandle, vertexShader);
|
|
ES20.GL.AttachShader(programHandle, fragmentShader);
|
|
|
|
ES20.GL.BindAttribLocation(programHandle, 0, "vPosition");
|
|
ES20.GL.LinkProgram(programHandle);
|
|
|
|
int linked;
|
|
ES20.GL.GetProgram(programHandle, ES20.All.LinkStatus, out linked);
|
|
if (linked == 0)
|
|
{
|
|
// link failed
|
|
int length;
|
|
ES20.GL.GetProgram(programHandle, ES20.All.InfoLogLength, out length);
|
|
if (length > 0)
|
|
{
|
|
var log = new StringBuilder(length);
|
|
ES20.GL.GetProgramInfoLog(programHandle, length, out length, log);
|
|
Report.Debug("GL2", "Couldn't link program: " + log.ToString());
|
|
}
|
|
|
|
ES20.GL.DeleteProgram(programHandle);
|
|
throw new InvalidOperationException("Unable to link program");
|
|
}
|
|
return programHandle;
|
|
} else
|
|
{
|
|
int vertexShader = GLLoadShader(ShaderType.VertexShader, vertexShaderSrc);
|
|
int fragmentShader = GLLoadShader(ShaderType.FragmentShader, fragmentShaderSrc);
|
|
int programHandle = GL.CreateProgram();
|
|
if (programHandle == 0)
|
|
throw new InvalidOperationException("Unable to create program");
|
|
|
|
GL.AttachShader(programHandle, vertexShader);
|
|
GL.AttachShader(programHandle, fragmentShader);
|
|
|
|
GL.BindAttribLocation(programHandle, 0, "vPosition");
|
|
GL.LinkProgram(programHandle);
|
|
|
|
int linked;
|
|
GL.GetProgram(programHandle, ProgramParameter.LinkStatus, out linked);
|
|
if (linked == 0)
|
|
{
|
|
// link failed
|
|
int length;
|
|
GL.GetProgram(programHandle, ProgramParameter.InfoLogLength, out length);
|
|
if (length > 0)
|
|
{
|
|
var log = new StringBuilder(length);
|
|
GL.GetProgramInfoLog(programHandle, length, out length, log);
|
|
Report.Debug("GL", "Couldn't link program: " + log.ToString());
|
|
}
|
|
|
|
GL.DeleteProgram(programHandle);
|
|
throw new InvalidOperationException("Unable to link program");
|
|
}
|
|
return programHandle;
|
|
}
|
|
|
|
}
|
|
|
|
public int GetRenderRGBATextureProgram()
|
|
{
|
|
// Vertex and fragment shaders
|
|
string vertexShaderSrc = "uniform mat4 uMVPMatrix; \n" +
|
|
"attribute vec4 vPosition; \n" +
|
|
"attribute vec2 TexCoordIn; \n" +
|
|
"varying vec2 TexCoordOut; \n" +
|
|
"void main() \n" +
|
|
"{ \n" +
|
|
" gl_Position = uMVPMatrix * vPosition; \n" +
|
|
" TexCoordOut = TexCoordIn; \n" +
|
|
"} \n";
|
|
|
|
string fragmentShaderSrc =
|
|
//"varying lowp vec2 TexCoordOut; \n" +
|
|
"uniform sampler2D Texture; \n" +
|
|
"void main() \n" +
|
|
"{ \n" +
|
|
" gl_FragColor = texture2D(Texture, TexCoordOut); \n" +
|
|
"} \n";
|
|
if (_glVersion == OpenGLVersion.ES1 || _glVersion == OpenGLVersion.ES2)
|
|
{
|
|
fragmentShaderSrc = "precision mediump float; \n" +
|
|
"varying lowp vec2 TexCoordOut; \n" + fragmentShaderSrc;
|
|
}
|
|
else
|
|
{
|
|
fragmentShaderSrc = "in vec2 TexCoordOut;\n" + fragmentShaderSrc;
|
|
}
|
|
return GetRenderProgram(vertexShaderSrc, fragmentShaderSrc);
|
|
}
|
|
|
|
public int GetRenderBGRATextureProgram()
|
|
{
|
|
// Vertex and fragment shaders
|
|
string vertexShaderSrc = "uniform mat4 uMVPMatrix; \n" +
|
|
"attribute vec4 vPosition; \n" +
|
|
"attribute vec2 TexCoordIn; \n" +
|
|
"varying vec2 TexCoordOut; \n" +
|
|
"void main() \n" +
|
|
"{ \n" +
|
|
" gl_Position = uMVPMatrix * vPosition; \n" +
|
|
" TexCoordOut = TexCoordIn; \n" +
|
|
"} \n";
|
|
|
|
string fragmentShaderSrc =
|
|
|
|
"uniform sampler2D Texture; \n" +
|
|
"void main() \n" +
|
|
"{ \n" +
|
|
" vec4 color = texture2D(Texture, TexCoordOut); \n" +
|
|
" gl_FragColor = vec4(color.b, color.g, color.r, color.a); \n" +
|
|
"} \n";
|
|
if (_glVersion == OpenGLVersion.ES1 || _glVersion == OpenGLVersion.ES2)
|
|
{
|
|
fragmentShaderSrc = "precision mediump float; \n" +
|
|
"varying lowp vec2 TexCoordOut; \n" + fragmentShaderSrc;
|
|
} else
|
|
{
|
|
fragmentShaderSrc = "in vec2 TexCoordOut;\n" + fragmentShaderSrc;
|
|
}
|
|
return GetRenderProgram(vertexShaderSrc, fragmentShaderSrc);
|
|
}
|
|
#endregion
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
base.Dispose(disposing);
|
|
if (_glVersion == OpenGLVersion.ES2)
|
|
{
|
|
ES20.GL.DeleteTextures(2, _textureIds);
|
|
}
|
|
else if (_glVersion == OpenGLVersion.ES1)
|
|
{
|
|
ES11.GL.DeleteTextures(2, _textureIds);
|
|
} else
|
|
{
|
|
//GL.DeleteTextures(2, _textureIds);
|
|
}
|
|
|
|
if (_bgrBuffers != null)
|
|
_bgrBuffers.Dispose();
|
|
}
|
|
|
|
public static float ToRadians(float degrees)
|
|
{
|
|
//pi/180
|
|
//FIXME: precalc pi/180
|
|
return (float) (degrees * (System.Math.PI / 180.0));
|
|
}
|
|
|
|
public enum TextureColor
|
|
{
|
|
NotSupported,
|
|
BGR,
|
|
BGRA,
|
|
RGBA,
|
|
RGB
|
|
}
|
|
|
|
public void SetFrame(String fileName)
|
|
{
|
|
_frameFileName = fileName;
|
|
LoadFrame();
|
|
}
|
|
|
|
private void LoadFrame()
|
|
{
|
|
if (_frameFileName == null)
|
|
{
|
|
_textureEnabled[1] = false;
|
|
}
|
|
else
|
|
{
|
|
_textureEnabled[1] = true;
|
|
|
|
Size textureSize = new Size(_glTextureDimension, _glTextureDimension);
|
|
using (Image<Bgra, Byte> tmp = new Image<Bgra, byte>(_frameFileName))
|
|
{
|
|
if (_glVersion == OpenGLVersion.ES1)
|
|
{
|
|
if (tmp.Size == textureSize)
|
|
{
|
|
CvInvoke.CvtColor(tmp, tmp, Emgu.CV.CvEnum.ColorConversion.Bgra2Rgba);
|
|
LoadTexture(tmp.Size, tmp.MIplImage.ImageData, GLImageView.TextureColor.RGBA, 1);
|
|
}
|
|
else
|
|
using (
|
|
Image<Bgra, Byte> resize = tmp.Resize(_glTextureDimension,
|
|
_glTextureDimension,
|
|
Emgu.CV.CvEnum.Inter.Nearest))
|
|
{
|
|
CvInvoke.CvtColor(resize, resize, Emgu.CV.CvEnum.ColorConversion.Bgra2Rgba);
|
|
LoadTexture(resize.Size, resize.MIplImage.ImageData, GLImageView.TextureColor.RGBA, 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LoadTexture(tmp.Size, tmp.MIplImage.ImageData, TextureColor.BGRA, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetImage(Image<Bgr, Byte> image, GeometricChange geometricChange)
|
|
{
|
|
SetImage(image, geometricChange, Size.Empty);
|
|
}
|
|
|
|
public void SetImage(Image<Bgr, Byte> image, GeometricChange geometricChange, Size imageDisplaySize)
|
|
{
|
|
if (_glVersion == OpenGLVersion.GL3)
|
|
{
|
|
//Desktop GL requires the image to be rotated 90 degree
|
|
geometricChange.Rotation = (geometricChange.Rotation + 270) % 360;
|
|
}
|
|
if (image == null)
|
|
{
|
|
TextureEnabled[0] = false;
|
|
_imageSize = Size.Empty;
|
|
}
|
|
else
|
|
{
|
|
if (geometricChange.Rotation == 0 || geometricChange.Rotation == 180)
|
|
{
|
|
_imageSize = imageDisplaySize.IsEmpty ? image.Size : imageDisplaySize;
|
|
}
|
|
else if (geometricChange.Rotation == 90 || geometricChange.Rotation == 270)
|
|
{
|
|
_imageSize = imageDisplaySize.IsEmpty ? new Size(image.Height, image.Width) : new Size(imageDisplaySize.Height, imageDisplaySize.Width);
|
|
}
|
|
else
|
|
{
|
|
throw new Exception(String.Format("Unsupported geometricChange: {0}", geometricChange));
|
|
}
|
|
_textureRotations[0] = geometricChange.Rotation;
|
|
_textureFlipMode[0] = geometricChange.FlipMode;
|
|
|
|
if (_glVersion == OpenGLVersion.ES1)
|
|
{
|
|
Image<Bgr, Byte> resized = _bgrBuffers.GetBuffer(new Size(_glTextureDimension, _glTextureDimension), 0);
|
|
|
|
CvInvoke.Resize(image, resized, resized.Size, 0, 0, Emgu.CV.CvEnum.Inter.Nearest);
|
|
CvInvoke.CvtColor(resized, resized, Emgu.CV.CvEnum.ColorConversion.Bgr2Rgb);
|
|
LoadTexture(resized.Size, resized.MIplImage.ImageData, TextureColor.RGB, 0);
|
|
}
|
|
else
|
|
{
|
|
LoadTexture(image.Size, image.MIplImage.ImageData, TextureColor.BGR, 0);
|
|
}
|
|
|
|
TextureEnabled[0] = true;
|
|
}
|
|
//SetupCamera();
|
|
PerformRenderAll();
|
|
}
|
|
|
|
public void LoadTexture(System.Drawing.Size imageSize, IntPtr data, TextureColor textureColor, int textureIndex)
|
|
{
|
|
bool reuseTexture = (!_textureSizes[textureIndex].IsEmpty && _textureSizes[textureIndex].Equals(imageSize) && _textureColor[textureIndex] == textureColor && !_textureRequiresReset[textureIndex]);
|
|
LoadTexture(imageSize, data, textureColor, textureIndex, reuseTexture);
|
|
}
|
|
|
|
private void LoadTexture(System.Drawing.Size imageSize, IntPtr data, TextureColor textureColor, int textureIndex, bool reuseTexture)
|
|
{
|
|
#if ANDROID || IOS
|
|
if (_glVersion == OpenGLVersion.ES2)
|
|
{
|
|
ES20.All error = ES20.GL.GetError();
|
|
if (error != ES20.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("Error before attemps to bind Texture: {0}", error));
|
|
return;
|
|
}
|
|
|
|
ES20.GL.BindTexture(ES20.All.Texture2D, _textureIds[textureIndex]);
|
|
|
|
error = ES20.GL.GetError();
|
|
if (error != ES20.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("Failed to bind Texture: {0}", error));
|
|
return;
|
|
}
|
|
ES20.GL.TexParameter(ES20.All.Texture2D, ES20.All.TextureMagFilter, (int)ES20.All.Linear);
|
|
ES20.GL.TexParameter(ES20.All.Texture2D, ES20.All.TextureMinFilter, (int)ES20.All.Linear);
|
|
ES20.GL.TexParameter(ES20.All.Texture2D, ES20.All.TextureWrapS, (int)ES20.All.ClampToEdge);
|
|
ES20.GL.TexParameter(ES20.All.Texture2D, ES20.All.TextureWrapT, (int)ES20.All.ClampToEdge);
|
|
|
|
error = ES20.GL.GetError();
|
|
if (error != ES20.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("Failed to set Texture Parameter: {0}", error));
|
|
return;
|
|
}
|
|
|
|
if (reuseTexture)
|
|
{
|
|
//if (textureColor == TextureColor.BGRA)
|
|
// ES20.GL.TexSubImage2D(ES20.All.Texture2D, 0, 0, 0, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, ES20.All.BgraExt, ES20.All.UnsignedByte, data);
|
|
//else
|
|
if (textureColor == TextureColor.RGBA || textureColor == TextureColor.BGRA)
|
|
ES20.GL.TexSubImage2D(ES20.All.Texture2D, 0, 0, 0, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, ES20.All.Rgba, ES20.All.UnsignedByte, data);
|
|
else if (textureColor == TextureColor.RGB || textureColor == TextureColor.BGR)
|
|
ES20.GL.TexSubImage2D(ES20.All.Texture2D, 0, 0, 0, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, ES20.All.Rgb, ES20.All.UnsignedByte, data);
|
|
}
|
|
else
|
|
{
|
|
_textureSizes[textureIndex] = imageSize;
|
|
_textureColor[textureIndex] = textureColor;
|
|
//if (textureColor == TextureColor.BGRA)
|
|
//ES20.GL.TexImage2D(ES20.All.Texture2D, 0, (int)ES20.All.BgraExt, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, 0, ES20.All.BgraExt, ES20.All.UnsignedByte, data);
|
|
//else
|
|
if (textureColor == TextureColor.RGBA || textureColor == TextureColor.BGRA)
|
|
ES20.GL.TexImage2D(ES20.All.Texture2D, 0, (int)ES20.All.Rgba, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, 0, ES20.All.Rgba, ES20.All.UnsignedByte, data);
|
|
else if (textureColor == TextureColor.RGB || textureColor == TextureColor.BGR)
|
|
ES20.GL.TexImage2D(ES20.All.Texture2D, 0, (int)ES20.All.Rgb, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, 0, ES20.All.Rgb, ES20.All.UnsignedByte, data);
|
|
else
|
|
{
|
|
throw new Exception(String.Format("The specific texture color is not supported: {0}", textureColor));
|
|
}
|
|
_textureRequiresReset[textureIndex] = false;
|
|
}
|
|
error = ES20.GL.GetError();
|
|
if (error != ES20.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("Failed to load Texture {0} (Texture ID {1}): {2}; reuseTexture: {3}", textureIndex, _textureIds[textureIndex], error, reuseTexture));
|
|
if (reuseTexture)
|
|
{
|
|
//try again without reusing the texture
|
|
LoadTexture(imageSize, data, textureColor, textureIndex, false);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ES11.All error = ES11.GL.GetError();
|
|
if (error != ES11.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("Error before attemps to bind Texture: {0}", error));
|
|
return;
|
|
}
|
|
|
|
ES11.GL.BindTexture(ES11.All.Texture2D, _textureIds[textureIndex]);
|
|
|
|
error = ES11.GL.GetError();
|
|
if (error != ES11.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("Failed to bing Texture: {0}", error));
|
|
return;
|
|
}
|
|
// setup texture parameters
|
|
ES11.GL.TexParameterx(ES11.All.Texture2D, ES11.All.TextureMagFilter, (int)ES11.All.Linear);
|
|
ES11.GL.TexParameterx(ES11.All.Texture2D, ES11.All.TextureMinFilter, (int)ES11.All.Linear);
|
|
ES11.GL.TexParameterx(ES11.All.Texture2D, ES11.All.TextureWrapS, (int)ES11.All.ClampToEdge);
|
|
ES11.GL.TexParameterx(ES11.All.Texture2D, ES11.All.TextureWrapT, (int)ES11.All.ClampToEdge);
|
|
|
|
error = ES11.GL.GetError();
|
|
if (error != ES11.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("Failed to set Texture Parameter: {0}", error));
|
|
return;
|
|
}
|
|
|
|
if (reuseTexture)
|
|
{
|
|
if (textureColor == TextureColor.BGRA)
|
|
ES11.GL.TexSubImage2D(ES11.All.Texture2D, 0, 0, 0, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, ES11.All.BgraExt, ES11.All.UnsignedByte, data);
|
|
else if (textureColor == TextureColor.RGBA)
|
|
ES11.GL.TexSubImage2D(ES11.All.Texture2D, 0, 0, 0, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, ES11.All.Rgba, ES11.All.UnsignedByte, data);
|
|
else if (textureColor == TextureColor.RGB)
|
|
ES11.GL.TexSubImage2D(ES11.All.Texture2D, 0, 0, 0, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, ES11.All.Rgb, ES11.All.UnsignedByte, data);
|
|
}
|
|
else
|
|
{
|
|
_textureSizes[textureIndex] = imageSize;
|
|
_textureColor[textureIndex] = textureColor;
|
|
if (textureColor == TextureColor.BGRA)
|
|
ES11.GL.TexImage2D(ES11.All.Texture2D, 0, (int)ES11.All.BgraExt, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, 0, ES11.All.BgraExt, ES11.All.UnsignedByte, data);
|
|
else if (textureColor == TextureColor.RGBA)
|
|
ES11.GL.TexImage2D(ES11.All.Texture2D, 0, (int)ES11.All.Rgba, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, 0, ES11.All.Rgba, ES11.All.UnsignedByte, data);
|
|
else if (textureColor == TextureColor.RGB)
|
|
ES11.GL.TexImage2D(ES11.All.Texture2D, 0, (int)ES11.All.Rgb, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, 0, ES11.All.Rgb, ES11.All.UnsignedByte, data);
|
|
else
|
|
{
|
|
throw new Exception(String.Format("The specific texture color is not supported: {0}", textureColor));
|
|
}
|
|
_textureRequiresReset[textureIndex] = false;
|
|
}
|
|
error = ES11.GL.GetError();
|
|
if (error != ES11.All.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("Failed to load Texture {0} (Texture ID {1}): {2}; reuseTexture: {3}", textureIndex, _textureIds[textureIndex], error, reuseTexture));
|
|
if (reuseTexture)
|
|
{
|
|
//try again without reusing the texture
|
|
LoadTexture(imageSize, data, textureColor, textureIndex, false);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
#else
|
|
if (_glVersion == OpenGLVersion.GL3)
|
|
{
|
|
GL.BindTexture(TextureTarget.Texture2D, _textureIds[textureIndex]);
|
|
|
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Linear);
|
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Linear);
|
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
|
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
|
|
|
|
if (reuseTexture)
|
|
{
|
|
//if (textureColor == TextureColor.BGRA)
|
|
// ES20.GL.TexSubImage2D(ES20.All.Texture2D, 0, 0, 0, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, ES20.All.BgraExt, ES20.All.UnsignedByte, data);
|
|
//else
|
|
if (textureColor == TextureColor.RGBA || textureColor == TextureColor.BGRA)
|
|
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, PixelFormat.Rgba, PixelType.UnsignedByte, data);
|
|
else if (textureColor == TextureColor.RGB || textureColor == TextureColor.BGR)
|
|
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, PixelFormat.Rgb, PixelType.UnsignedByte, data);
|
|
}
|
|
else
|
|
{
|
|
_textureSizes[textureIndex] = imageSize;
|
|
_textureColor[textureIndex] = textureColor;
|
|
//if (textureColor == TextureColor.BGRA)
|
|
//ES20.GL.TexImage2D(ES20.All.Texture2D, 0, (int)ES20.All.BgraExt, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, 0, ES20.All.BgraExt, ES20.All.UnsignedByte, data);
|
|
//else
|
|
if (textureColor == TextureColor.RGBA || textureColor == TextureColor.BGRA)
|
|
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, data);
|
|
else if (textureColor == TextureColor.RGB || textureColor == TextureColor.BGR)
|
|
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, _textureSizes[textureIndex].Width, _textureSizes[textureIndex].Height, 0, PixelFormat.Rgb, PixelType.UnsignedByte, data);
|
|
else
|
|
{
|
|
throw new Exception(String.Format("The specific texture color is not supported: {0}", textureColor));
|
|
}
|
|
_textureRequiresReset[textureIndex] = false;
|
|
}
|
|
ErrorCode error = GL.GetError();
|
|
if (error != ErrorCode.NoError)
|
|
{
|
|
Report.Error(PackageName, String.Format("Failed to load Texture {0} (Texture ID {1}): {2}; reuseTexture: {3}", textureIndex, _textureIds[textureIndex], error, reuseTexture));
|
|
if (reuseTexture)
|
|
{
|
|
//try again without reusing the texture
|
|
LoadTexture(imageSize, data, textureColor, textureIndex, false);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
_textureEnabled[textureIndex] = true;
|
|
}
|
|
|
|
}
|
|
}
|