forked from dotnet/android-samples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPaintingView.cs
203 lines (168 loc) · 5.86 KB
/
PaintingView.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
using System;
using System.Runtime.InteropServices;
using System.Text;
using OpenTK.Graphics;
using OpenTK.Graphics.ES30;
using OpenTK.Platform;
using OpenTK.Platform.Android;
using Android.Util;
using Android.Views;
using Android.Content;
// Render a triangle using OpenGLES 3.0
namespace Mono.Samples.GLTriangle30 {
class PaintingView : AndroidGameView
{
int viewportWidth, viewportHeight;
int program;
float [] vertices;
public PaintingView (Context context, IAttributeSet attrs) :
base (context, attrs)
{
Init ();
}
public PaintingView (IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
: base (handle, transfer)
{
Init ();
}
void Init ()
{
}
// 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 ()
{
GLContextVersion = GLContextVersion.Gles3_0;
// the default GraphicsMode that is set consists of (16, 16, 0, 0, 2, false)
try {
Log.Verbose ("GLTriangle", "Loading with default settings");
// if you don't call this, the context won't be created
base.CreateFrameBuffer ();
return;
} catch (Exception ex) {
Log.Verbose ("GLTriangle", "{0}", ex);
}
// this is a graphics setting that sets everything to the lowest mode possible so
// the device returns a reliable graphics setting.
try {
Log.Verbose ("GLTriangle", "Loading with custom Android settings (low mode)");
GraphicsMode = new AndroidGraphicsMode ();//0, 0, 0, 0, 0, false);
// if you don't call this, the context won't be created
base.CreateFrameBuffer ();
return;
} catch (Exception ex) {
Log.Verbose ("GLTriangle", "{0}", ex);
}
throw new Exception ("Can't load egl, aborting");
}
// This gets called when the drawing surface has been created
// There is already a GraphicsContext and Surface at this point,
// following the standard OpenTK/GameWindow logic
//
// Android will only render when it refreshes the surface for
// the first time, so if you don't call Run, you need to hook
// up the Resize delegate or override the OnResize event to
// get the updated bounds and re-call your rendering code.
// This will also allow non-Run-loop code to update the screen
// when the device is rotated.
protected override void OnLoad (EventArgs e)
{
// This is completely optional and only needed
// if you've registered delegates for OnLoad
base.OnLoad (e);
viewportHeight = Height; viewportWidth = Width;
// Vertex and fragment shaders
string vertexShaderSrc = "attribute vec4 vPosition; \n" +
"void main() \n" +
"{ \n" +
" gl_Position = vPosition; \n" +
"} \n";
string fragmentShaderSrc = "precision mediump float;\n" +
"void main() \n" +
"{ \n" +
" gl_FragColor = vec4 (1.0, 0.0, 0.0, 1.0); \n" +
"} \n";
int vertexShader = LoadShader (All.VertexShader, vertexShaderSrc );
int fragmentShader = LoadShader (All.FragmentShader, fragmentShaderSrc );
program = GL.CreateProgram();
if (program == 0)
throw new InvalidOperationException ("Unable to create program");
GL.AttachShader (program, vertexShader);
GL.AttachShader (program, fragmentShader);
GL.BindAttribLocation (program, 0, "vPosition");
GL.LinkProgram (program);
int linked;
GL.GetProgram (program, All.LinkStatus, out linked);
if (linked == 0) {
// link failed
int length = 0;
GL.GetProgram (program, All.InfoLogLength, out length);
if (length > 0) {
var log = new StringBuilder (length);
GL.GetProgramInfoLog (program, length, out length, log);
Log.Debug ("GL2", "Couldn't link program: " + log.ToString ());
}
GL.DeleteProgram (program);
throw new InvalidOperationException ("Unable to link program");
}
RenderTriangle ();
}
int LoadShader (All type, string source)
{
int shader = GL.CreateShader (type);
if (shader == 0)
throw new InvalidOperationException ("Unable to create shader");
int length = 0;
GL.ShaderSource (shader, 1, new string [] {source}, (int[])null);
GL.CompileShader (shader);
int compiled = 0;
GL.GetShader (shader, All.CompileStatus, out compiled);
if (compiled == 0) {
length = 0;
GL.GetShader (shader, All.InfoLogLength, out length);
if (length > 0) {
var log = new StringBuilder (length);
GL.GetShaderInfoLog (shader, length, out length, log);
Log.Debug ("GL2", "Couldn't compile shader: " + log.ToString ());
}
GL.DeleteShader (shader);
throw new InvalidOperationException ("Unable to compile shader of type : " + type.ToString ());
}
return shader;
}
void RenderTriangle ()
{
vertices = new float [] {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
GL.ClearColor (0.7f, 0.7f, 0.7f, 1);
GL.Clear (ClearBufferMask.ColorBufferBit);
GL.Viewport (0, 0, viewportWidth, viewportHeight);
GL.UseProgram (program);
// pin the data, so that GC doesn't move them, while used
// by native code
unsafe {
fixed (float* pvertices = vertices) {
GL.VertexAttribPointer (0, 3, All.Float, false, 0, new IntPtr (pvertices));
GL.EnableVertexAttribArray (0);
GL.DrawArrays (All.Triangles, 0, 3);
GL.Finish ();
}
}
SwapBuffers ();
}
// this is called whenever android raises the SurfaceChanged event
protected override void OnResize (EventArgs e)
{
viewportHeight = Height;
viewportWidth = Width;
// the surface change event makes your context
// not be current, so be sure to make it current again
MakeCurrent ();
RenderTriangle ();
}
}
}