xamarin-macios/tests/common/TestProjects/MyOpenGLApp/EAGLView.cs

338 строки
8.1 KiB
C#

using System;
using OpenTK;
using OpenTK.Graphics.ES20;
using GL1 = OpenTK.Graphics.ES11.GL;
using All1 = OpenTK.Graphics.ES11.All;
using OpenTK.Platform.iPhoneOS;
using Foundation;
using CoreAnimation;
using ObjCRuntime;
using OpenGLES;
using UIKit;
namespace MyOpenGLApp
{
[Register ("EAGLView")]
public class EAGLView : iPhoneOSGameView
{
[Export ("initWithCoder:")]
public EAGLView (NSCoder coder) : base (coder)
{
LayerRetainsBacking = true;
LayerColorFormat = EAGLColorFormat.RGBA8;
}
[Export ("layerClass")]
public static new Class GetLayerClass ()
{
return iPhoneOSGameView.GetLayerClass ();
}
protected override void ConfigureLayer (CAEAGLLayer eaglLayer)
{
eaglLayer.Opaque = true;
}
protected override void CreateFrameBuffer ()
{
try {
ContextRenderingApi = EAGLRenderingAPI.OpenGLES2;
base.CreateFrameBuffer ();
} catch (Exception) {
ContextRenderingApi = EAGLRenderingAPI.OpenGLES1;
base.CreateFrameBuffer ();
}
if (ContextRenderingApi == EAGLRenderingAPI.OpenGLES2)
LoadShaders ();
}
protected override void DestroyFrameBuffer ()
{
base.DestroyFrameBuffer ();
DestroyShaders ();
}
#region DisplayLink support
int frameInterval;
CADisplayLink displayLink;
public bool IsAnimating { get; private set; }
// How many display frames must pass between each time the display link fires.
public int FrameInterval {
get {
return frameInterval;
}
set {
if (value <= 0)
throw new ArgumentException ();
frameInterval = value;
if (IsAnimating) {
StopAnimating ();
StartAnimating ();
}
}
}
public void StartAnimating ()
{
if (IsAnimating)
return;
CreateFrameBuffer ();
displayLink = UIScreen.MainScreen.CreateDisplayLink (this, new Selector ("drawFrame"));
displayLink.FrameInterval = frameInterval;
displayLink.AddToRunLoop (NSRunLoop.Current, NSRunLoop.NSDefaultRunLoopMode);
IsAnimating = true;
}
public void StopAnimating ()
{
if (!IsAnimating)
return;
displayLink.Invalidate ();
displayLink = null;
DestroyFrameBuffer ();
IsAnimating = false;
}
[Export ("drawFrame")]
void DrawFrame ()
{
OnRenderFrame (new FrameEventArgs ());
}
#endregion
static readonly float[] squareVertices = {
-0.5f, -0.33f,
0.5f, -0.33f,
-0.5f, 0.33f,
0.5f, 0.33f,
};
static readonly byte[] squareColors = {
255, 255, 0, 255,
0, 255, 255, 255,
0, 0, 0, 0,
255, 0, 255, 255,
};
static float transY = 0.0f;
const int UNIFORM_TRANSLATE = 0;
const int UNIFORM_COUNT = 1;
readonly int[] uniforms = new int [UNIFORM_COUNT];
const int ATTRIB_VERTEX = 0;
const int ATTRIB_COLOR = 1;
const int ATTRIB_COUNT = 2;
int program;
protected override void OnRenderFrame (FrameEventArgs e)
{
base.OnRenderFrame (e);
MakeCurrent ();
// Replace the implementation of this method to do your own custom drawing.
GL.ClearColor (0.5f, 0.5f, 0.5f, 1.0f);
GL.Clear (ClearBufferMask.ColorBufferBit);
if (ContextRenderingApi == EAGLRenderingAPI.OpenGLES2) {
// Use shader program.
GL.UseProgram (program);
// Update uniform value.
GL.Uniform1 (uniforms [UNIFORM_TRANSLATE], transY);
transY += 0.075f;
// Update attribute values.
GL.VertexAttribPointer (ATTRIB_VERTEX, 2, VertexAttribPointerType.Float, false, 0, squareVertices);
GL.EnableVertexAttribArray (ATTRIB_VERTEX);
GL.VertexAttribPointer (ATTRIB_COLOR, 4, VertexAttribPointerType.UnsignedByte, true, 0, squareColors);
GL.EnableVertexAttribArray (ATTRIB_COLOR);
// Validate program before drawing. This is a good check, but only really necessary in a debug build.
#if DEBUG
if (!ValidateProgram (program)) {
Console.WriteLine ("Failed to validate program {0:x}", program);
return;
}
#endif
} else {
GL1.MatrixMode (All1.Projection);
GL1.LoadIdentity ();
GL1.MatrixMode (All1.Modelview);
GL1.LoadIdentity ();
GL1.Translate (0.0f, (float)Math.Sin (transY) / 2.0f, 0.0f);
transY += 0.075f;
GL1.VertexPointer (2, All1.Float, 0, squareVertices);
GL1.EnableClientState (All1.VertexArray);
GL1.ColorPointer (4, All1.UnsignedByte, 0, squareColors);
GL1.EnableClientState (All1.ColorArray);
}
GL.DrawArrays (BeginMode.TriangleStrip, 0, 4);
SwapBuffers ();
}
bool LoadShaders ()
{
int vertShader, fragShader;
// Create shader program.
program = GL.CreateProgram ();
// Create and compile vertex shader.
var vertShaderPathname = NSBundle.MainBundle.PathForResource ("Shader", "vsh");
if (!CompileShader (ShaderType.VertexShader, vertShaderPathname, out vertShader)) {
Console.WriteLine ("Failed to compile vertex shader");
return false;
}
// Create and compile fragment shader.
var fragShaderPathname = NSBundle.MainBundle.PathForResource ("Shader", "fsh");
if (!CompileShader (ShaderType.FragmentShader, fragShaderPathname, out fragShader)) {
Console.WriteLine ("Failed to compile fragment shader");
return false;
}
// Attach vertex shader to program.
GL.AttachShader (program, vertShader);
// Attach fragment shader to program.
GL.AttachShader (program, fragShader);
// Bind attribute locations.
// This needs to be done prior to linking.
GL.BindAttribLocation (program, ATTRIB_VERTEX, "position");
GL.BindAttribLocation (program, ATTRIB_COLOR, "color");
// Link program.
if (!LinkProgram (program)) {
Console.WriteLine ("Failed to link program: {0:x}", program);
if (vertShader != 0)
GL.DeleteShader (vertShader);
if (fragShader != 0)
GL.DeleteShader (fragShader);
if (program != 0) {
GL.DeleteProgram (program);
program = 0;
}
return false;
}
// Get uniform locations.
uniforms [UNIFORM_TRANSLATE] = GL.GetUniformLocation (program, "translate");
// Release vertex and fragment shaders.
if (vertShader != 0) {
GL.DetachShader (program, vertShader);
GL.DeleteShader (vertShader);
}
if (fragShader != 0) {
GL.DetachShader (program, fragShader);
GL.DeleteShader (fragShader);
}
return true;
}
void DestroyShaders ()
{
if (program != 0) {
GL.DeleteProgram (program);
program = 0;
}
}
#region Shader utilities
static bool CompileShader (ShaderType type, string file, out int shader)
{
string src = System.IO.File.ReadAllText (file);
shader = GL.CreateShader (type);
GL.ShaderSource (shader, 1, new string[] { src }, (int[])null);
GL.CompileShader (shader);
#if DEBUG
int logLength;
GL.GetShader (shader, ShaderParameter.InfoLogLength, out logLength);
if (logLength > 0) {
var infoLog = new System.Text.StringBuilder ();
GL.GetShaderInfoLog (shader, logLength, out logLength, infoLog);
Console.WriteLine ("Shader compile log:\n{0}", infoLog);
}
#endif
int status;
GL.GetShader (shader, ShaderParameter.CompileStatus, out status);
if (status == 0) {
GL.DeleteShader (shader);
return false;
}
return true;
}
static bool LinkProgram (int program)
{
GL.LinkProgram (program);
#if DEBUG
int logLength;
GL.GetProgram (program, ProgramParameter.InfoLogLength, out logLength);
if (logLength > 0) {
var infoLog = new System.Text.StringBuilder ();
GL.GetProgramInfoLog (program, logLength, out logLength, infoLog);
Console.WriteLine ("Program link log:\n{0}", infoLog);
}
#endif
int status;
GL.GetProgram (program, ProgramParameter.LinkStatus, out status);
if (status == 0)
return false;
return true;
}
static bool ValidateProgram (int program)
{
GL.ValidateProgram (program);
int logLength;
GL.GetProgram (program, ProgramParameter.InfoLogLength, out logLength);
if (logLength > 0) {
var infoLog = new System.Text.StringBuilder ();
GL.GetProgramInfoLog (program, logLength, out logLength, infoLog);
Console.WriteLine ("Program validate log:\n{0}", infoLog);
}
int status;
GL.GetProgram (program, ProgramParameter.LinkStatus, out status);
if (status == 0)
return false;
return true;
}
#endregion
}
}