Can anyone please help with the following?
Using Visual Studio 2019 Xamarin Forms project I am trying to display a rotating red square in the Android emulator. I have it working but my square is black:
Here's the code of my MainPage.xaml.cs (am using ES20 as ES10 does not have the OpenGL functions I need):
using OpenTK.Graphics.ES20;
using System;
using Xamarin.Forms;
namespace OGLMobile
{
public partial class MainPage : ContentPage
{
private float red = 1.0f;
private float green = 0.0f;
private float blue = 0.0f;
private const float halfWidth = 0.2f;
private float[] m_vertex_buffer_data = { 0.5f - halfWidth, 0.5f - halfWidth, 0.0f,
0.5f + halfWidth, 0.5f - halfWidth, 0.0f,
0.5f + halfWidth, 0.5f + halfWidth, 0.0f,
0.5f - halfWidth, 0.5f + halfWidth, 0.0f };
private string[] m_szVertexShader = null;
private string[] m_szFragmentShader = null;
private int m_nProgram = -1;
private int m_nVertexShaderHandle = -1;
private int m_nFragmentShaderHandle = -1;
private uint[] indices = { 0, 1, 2, 0, 2, 3 };
private int m_nVertexBuffer = -1;
bool m_bOGLParametersSet = false;
private void RotateSquare(float radians, float xRotationCentre, float yRotationCentre)
{
int[] nBaseIndices = { 0, 3, 6, 9 };
for (int nVertex = 0; nVertex <= 3 ; nVertex++)
{
int nIndex1 = nBaseIndices[nVertex];
int nIndex2 = nIndex1 + 1;
float offsetX = m_vertex_buffer_data[nIndex1] - xRotationCentre;
float offsetY = m_vertex_buffer_data[nIndex2] - yRotationCentre;
double xRotated = offsetX * Math.Cos(radians) - offsetY * Math.Sin(radians);
double yRotated = offsetX * Math.Sin(radians) + offsetY * Math.Cos(radians);
m_vertex_buffer_data[nIndex1] = (float)xRotated + xRotationCentre;
m_vertex_buffer_data[nIndex2] = (float)yRotated + yRotationCentre;
}
GL.BindBuffer(BufferTarget.ArrayBuffer, m_nVertexBuffer);
GL.BufferSubData(BufferTarget.ArrayBuffer, IntPtr.Zero, new IntPtr(m_vertex_buffer_data.Length * sizeof(float)), m_vertex_buffer_data);
}
public MainPage()
{
Title = "OpenGL";
var view = new OpenGLView { HasRenderLoop = true };
var toggle = new Switch { IsToggled = true };
m_szVertexShader = new string[1];
m_szFragmentShader = new string[1];
view.HeightRequest = 300;
view.WidthRequest = 300;
GL.Viewport(0, 0, 300, 300);
view.OnDisplay = r =>
{
if(!m_bOGLParametersSet) // Do this only on first rendering
{
CreateShader();
m_bOGLParametersSet = true;
GL.UseProgram(m_nProgram);
GL.GenBuffers(1, out m_nVertexBuffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, m_nVertexBuffer);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(m_vertex_buffer_data.Length * sizeof(float)), m_vertex_buffer_data, BufferUsage.StaticDraw);
}
GL.ClearColor(0.0f, 0.0f, 1.0f, 1.0f);
GL.Clear((ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit));
RotateSquare(0.0174533f, 0.5f, 0.5f);
GL.EnableVertexAttribArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, m_nVertexBuffer);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
GL.DrawElements(BeginMode.Triangles, indices.Length, DrawElementsType.UnsignedInt, indices);
GL.DisableVertexAttribArray(0);
};
toggle.Toggled += (s, a) =>
{
view.HasRenderLoop = toggle.IsToggled;
};
var stack = new StackLayout
{
Padding = new Size(20, 20),
Children = { view, toggle}
};
Content = stack;
}
private void SetShaderSource()
{
m_szVertexShader[0] = "void main()" +
"{" +
"gl_Position = ftransform();" +
"}";
m_szFragmentShader[0] = "void main()" +
"{" +
"gl_FragColor = vec4(1.0,0.0,0.0,1.0);" +
"}";
}
private void CreateShader()
{
SetShaderSource();
int nVertexShaderSourceLength = m_szVertexShader[0].Length;
int nFragmentShaderLength = m_szFragmentShader[0].Length;
m_nVertexShaderHandle = GL.CreateShader(ShaderType.VertexShader);
m_nFragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(m_nVertexShaderHandle, 1, m_szVertexShader, new int[] { nVertexShaderSourceLength });
GL.ShaderSource(m_nFragmentShaderHandle, 1, m_szFragmentShader, new int[] { nVertexShaderSourceLength });
GL.CompileShader(m_nVertexShaderHandle);
GL.CompileShader(m_nFragmentShaderHandle);
string szVertexShaderLog = GL.GetShaderInfoLog(m_nVertexShaderHandle);
string szFragmentShaderLog = GL.GetShaderInfoLog(m_nFragmentShaderHandle);
m_nProgram = GL.CreateProgram();
GL.AttachShader(m_nProgram, m_nVertexShaderHandle);
GL.AttachShader(m_nProgram, m_nFragmentShaderHandle);
GL.LinkProgram(m_nProgram);
}
}
}
My shaders must be incorrect, I get the same output if I replace them with junk strings, so the system must be defaulting to something.
I do have compile errors when I call GetShaderInfoLog, but my shaders are so trivial that I can't see the issue:
Thanks very much for any help, (been stuck on this for a while now. Have done plenty of OpenGL on desktop and with WebGL before, but not having any luck yet with mobile).
ADDITION: Thanks very much for you replies. I have replaced tha shaders with compliant ones, unfortunately I still have a black square:
(In the image it says mediump, I have also tried highp and lowp but I still get the same results).
I now get a different error on compilation of the vertex shader, and no error for the fragment shader - although I do have one warning for the latter:
Thank you for any further advice you may be able to offer.
These shaders do not meet any GLSL ES specification. See OpenGL ES Shading Language 1.00 Specification respectively. OpenGL ES Shading Language 3.00 Specification.
See a working shader with a vertex shader:
attribute vec3 a_position;
void main()
{
gl_Position = vec4(a_position, 1.0);
}
and fragment shader
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
I recommend to verify if the shader compiles with out errors:
GL.CompileShader(m_nVertexShaderHandle);
string infoLogFrag = GL.GetShaderInfoLog(m_nVertexShaderHandle);
if (infoLogFrag != System.String.Empty)
{
System.Console.WriteLine(infoLogFrag);
}
GL.CompileShader(m_nFragmentShaderHandle);
string infoLogVert = GL.GetShaderInfoLog(m_nFragmentShaderHandle);
if (infoLogVert != System.String.Empty)
{
System.Console.WriteLine(infoLogVert);
}
And the program links without errors:
GL.LinkProgram(m_nProgram);
string infoLogProg = GL.GetProgramInfoLog(m_nProgram );
if (infoLogProg != System.String.Empty)
{
System.Console.WriteLine(infoLogProg);
}