mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-01-11 09:05:34 +00:00
352 lines
11 KiB
C#
352 lines
11 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 ES11
|
|
{
|
|
|
|
[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 e)
|
|
{
|
|
System.Diagnostics.Debug.Print(e.ToString());
|
|
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
|
|
}
|
|
}
|