2011-07-25 01:27:58 +04:00
|
|
|
using System;
|
2015-01-19 18:09:40 +03:00
|
|
|
using ObjCRuntime;
|
|
|
|
using Foundation;
|
2011-07-25 01:27:58 +04:00
|
|
|
using System.Runtime.InteropServices;
|
2015-01-19 18:09:40 +03:00
|
|
|
using CoreGraphics;
|
2016-06-16 13:55:12 +03:00
|
|
|
using OpenTK.Platform.iPhoneOS;
|
2011-07-25 01:27:58 +04:00
|
|
|
using OpenTK.Platform;
|
2015-01-19 18:09:40 +03:00
|
|
|
using CoreAnimation;
|
2011-07-25 01:27:58 +04:00
|
|
|
using OpenTK.Graphics.ES11;
|
2015-01-19 18:09:40 +03:00
|
|
|
using UIKit;
|
2016-06-16 13:55:12 +03:00
|
|
|
using OpenGLES;
|
2011-07-25 01:27:58 +04:00
|
|
|
|
|
|
|
namespace LowLevelGLPaint
|
|
|
|
{
|
2016-06-16 13:55:12 +03:00
|
|
|
public class PaintingView : iPhoneOSGameView
|
2011-07-25 01:27:58 +04:00
|
|
|
{
|
|
|
|
public const float BrushOpacity = 1.0f / 3.0f;
|
|
|
|
public const int BrushPixelStep = 3;
|
|
|
|
public const int BrushScale = 2;
|
|
|
|
public const float Luminosity = 0.75f;
|
|
|
|
public const float Saturation = 1.0f;
|
|
|
|
|
|
|
|
uint brushTexture, drawingTexture, drawingFramebuffer;
|
|
|
|
bool firstTouch;
|
|
|
|
|
2015-01-19 18:09:40 +03:00
|
|
|
CGPoint Location;
|
|
|
|
CGPoint PreviousLocation;
|
|
|
|
|
2011-07-25 01:27:58 +04:00
|
|
|
[Export ("layerClass")]
|
2016-06-16 13:55:12 +03:00
|
|
|
public static Class LayerClass ()
|
2011-07-25 01:27:58 +04:00
|
|
|
{
|
|
|
|
return new Class (typeof (CAEAGLLayer));
|
|
|
|
}
|
|
|
|
|
2015-01-19 18:09:40 +03:00
|
|
|
public PaintingView (CGRect frame)
|
2016-06-16 13:55:12 +03:00
|
|
|
: base (frame)//base (frame, All.Rgb565Oes, 0, true)
|
2011-07-25 01:27:58 +04:00
|
|
|
{
|
2016-06-16 13:55:12 +03:00
|
|
|
//SetCurrentContext ();
|
|
|
|
LayerRetainsBacking = true;
|
|
|
|
LayerColorFormat = EAGLColorFormat.RGBA8;
|
|
|
|
ContextRenderingApi = EAGLRenderingAPI.OpenGLES1;
|
|
|
|
CreateFrameBuffer ();
|
|
|
|
MakeCurrent ();
|
2011-07-25 01:27:58 +04:00
|
|
|
var brushImage = UIImage.FromFile ("Particle.png").CGImage;
|
2015-01-19 18:09:40 +03:00
|
|
|
var width = (int)brushImage.Width;
|
|
|
|
var height = (int)brushImage.Height;
|
2011-07-25 01:27:58 +04:00
|
|
|
if (brushImage != null) {
|
|
|
|
IntPtr brushData = Marshal.AllocHGlobal (width * height * 4);
|
|
|
|
if (brushData == IntPtr.Zero)
|
|
|
|
throw new OutOfMemoryException ();
|
|
|
|
try {
|
|
|
|
using (var brushContext = new CGBitmapContext (brushData,
|
2015-01-19 18:09:40 +03:00
|
|
|
(int)width, width, 8, width * 4, brushImage.ColorSpace, CGImageAlphaInfo.PremultipliedLast)) {
|
|
|
|
brushContext.DrawImage (new CGRect (0.0f, 0.0f, (float) width, (float) height), brushImage);
|
2011-07-25 01:27:58 +04:00
|
|
|
}
|
|
|
|
|
2015-01-19 18:09:40 +03:00
|
|
|
GL.GenTextures (1, out brushTexture);
|
2011-07-25 01:27:58 +04:00
|
|
|
GL.BindTexture (All.Texture2D, brushTexture);
|
2015-01-19 18:09:40 +03:00
|
|
|
GL.TexImage2D (All.Texture2D, 0, (int) All.Rgba, (int)width, height, 0, All.Rgba, All.UnsignedByte, brushData);
|
2011-07-25 01:27:58 +04:00
|
|
|
}
|
|
|
|
finally {
|
|
|
|
Marshal.FreeHGlobal (brushData);
|
|
|
|
}
|
|
|
|
GL.TexParameter (All.Texture2D, All.TextureMinFilter, (int) All.Linear);
|
|
|
|
GL.Enable (All.Texture2D);
|
|
|
|
GL.BlendFunc (All.SrcAlpha, All.One);
|
|
|
|
GL.Enable (All.Blend);
|
|
|
|
}
|
|
|
|
GL.Disable (All.Dither);
|
|
|
|
GL.MatrixMode (All.Projection);
|
2015-01-19 18:09:40 +03:00
|
|
|
GL.Ortho (0, (float)frame.Width, 0, (float)frame.Height, -1, 1);
|
2011-07-25 01:27:58 +04:00
|
|
|
GL.MatrixMode (All.Modelview);
|
|
|
|
GL.Enable (All.Texture2D);
|
|
|
|
GL.EnableClientState (All.VertexArray);
|
|
|
|
GL.Enable (All.Blend);
|
|
|
|
GL.BlendFunc (All.SrcAlpha, All.One);
|
|
|
|
GL.Enable (All.PointSpriteOes);
|
|
|
|
GL.TexEnv (All.PointSpriteOes, All.CoordReplaceOes, (float) All.True);
|
|
|
|
GL.PointSize (width / BrushScale);
|
|
|
|
|
|
|
|
Erase ();
|
|
|
|
|
|
|
|
PerformSelector (new Selector ("playback"), null, 0.2f);
|
|
|
|
}
|
|
|
|
|
|
|
|
~PaintingView ()
|
|
|
|
{
|
|
|
|
Dispose (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void Dispose (bool disposing)
|
|
|
|
{
|
|
|
|
GL.Oes.DeleteFramebuffers (1, ref drawingFramebuffer);
|
|
|
|
GL.DeleteTextures (1, ref drawingTexture);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Erase ()
|
|
|
|
{
|
2015-01-19 18:09:40 +03:00
|
|
|
GL.Clear (ClearBufferMask.ColorBufferBit);
|
2011-07-25 01:27:58 +04:00
|
|
|
|
|
|
|
SwapBuffers ();
|
|
|
|
}
|
|
|
|
|
2015-01-19 18:09:40 +03:00
|
|
|
nfloat[] vertexBuffer;
|
2011-07-25 01:27:58 +04:00
|
|
|
int vertexMax = 64;
|
|
|
|
|
2015-01-19 18:09:40 +03:00
|
|
|
private void RenderLineFromPoint (CGPoint start, CGPoint end)
|
2011-07-25 01:27:58 +04:00
|
|
|
{
|
|
|
|
int vertexCount = 0;
|
|
|
|
if (vertexBuffer == null) {
|
2015-01-19 18:09:40 +03:00
|
|
|
vertexBuffer = new nfloat [vertexMax * 2];
|
2011-07-25 01:27:58 +04:00
|
|
|
}
|
|
|
|
var count = Math.Max (Math.Ceiling (Math.Sqrt ((end.X - start.X) * (end.X - start.X) + (end.Y - start.Y) * (end.Y - start.Y)) / BrushPixelStep),
|
|
|
|
1);
|
|
|
|
for (int i = 0; i < count; ++i, ++vertexCount) {
|
|
|
|
if (vertexCount == vertexMax) {
|
|
|
|
vertexMax *= 2;
|
|
|
|
Array.Resize (ref vertexBuffer, vertexMax * 2);
|
|
|
|
}
|
|
|
|
vertexBuffer [2 * vertexCount + 0] = start.X + (end.X - start.X) * (float) i / (float) count;
|
|
|
|
vertexBuffer [2 * vertexCount + 1] = start.Y + (end.Y - start.Y) * (float) i / (float) count;
|
|
|
|
}
|
|
|
|
GL.VertexPointer (2, All.Float, 0, vertexBuffer);
|
|
|
|
GL.DrawArrays (All.Points, 0, vertexCount);
|
|
|
|
|
|
|
|
SwapBuffers ();
|
|
|
|
}
|
|
|
|
|
|
|
|
int dataofs = 0;
|
|
|
|
|
|
|
|
[Export ("playback")]
|
|
|
|
void Playback ()
|
|
|
|
{
|
2015-01-19 18:09:40 +03:00
|
|
|
CGPoint [] points = ShakeMe.Data [dataofs];
|
2011-07-25 01:27:58 +04:00
|
|
|
|
|
|
|
for (int i = 0; i < points.Length - 1; i++)
|
|
|
|
RenderLineFromPoint (points [i], points [i + 1]);
|
|
|
|
|
|
|
|
if (dataofs < ShakeMe.Data.Count - 1) {
|
|
|
|
dataofs ++;
|
|
|
|
PerformSelector (new Selector ("playback"), null, 0.01f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-19 18:09:40 +03:00
|
|
|
public override void TouchesBegan (NSSet touches, UIEvent e)
|
2011-07-25 01:27:58 +04:00
|
|
|
{
|
|
|
|
var bounds = Bounds;
|
|
|
|
var touch = (UITouch) e.TouchesForView (this).AnyObject;
|
|
|
|
firstTouch = true;
|
|
|
|
Location = touch.LocationInView (this);
|
|
|
|
Location.Y = bounds.Height - Location.Y;
|
|
|
|
}
|
|
|
|
|
2015-01-19 18:09:40 +03:00
|
|
|
public override void TouchesMoved (NSSet touches, UIEvent e)
|
2011-07-25 01:27:58 +04:00
|
|
|
{
|
|
|
|
var bounds = Bounds;
|
|
|
|
var touch = (UITouch) e.TouchesForView (this).AnyObject;
|
|
|
|
|
|
|
|
if (firstTouch) {
|
|
|
|
firstTouch = false;
|
|
|
|
PreviousLocation = touch.PreviousLocationInView (this);
|
|
|
|
PreviousLocation.Y = bounds.Height - PreviousLocation.Y;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Location = touch.LocationInView (this);
|
|
|
|
Location.Y = bounds.Height - Location.Y;
|
|
|
|
PreviousLocation = touch.PreviousLocationInView (this);
|
|
|
|
PreviousLocation.Y = bounds.Height - PreviousLocation.Y;
|
|
|
|
}
|
|
|
|
RenderLineFromPoint (PreviousLocation, Location);
|
|
|
|
}
|
|
|
|
|
2015-01-19 18:09:40 +03:00
|
|
|
public override void TouchesEnded (NSSet touches, UIEvent e)
|
2011-07-25 01:27:58 +04:00
|
|
|
{
|
|
|
|
var bounds = Bounds;
|
|
|
|
var touch = (UITouch) e.TouchesForView (this).AnyObject;
|
|
|
|
if (firstTouch) {
|
|
|
|
firstTouch = false;
|
|
|
|
PreviousLocation = touch.PreviousLocationInView (this);
|
|
|
|
PreviousLocation.Y = bounds.Height - PreviousLocation.Y;
|
|
|
|
RenderLineFromPoint (PreviousLocation, Location);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-19 18:09:40 +03:00
|
|
|
public override void TouchesCancelled (NSSet touches, UIEvent e)
|
2011-07-25 01:27:58 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|