1
|
package org.distorted.examples.feedback;
|
2
|
|
3
|
import android.opengl.EGL14;
|
4
|
import android.opengl.GLES30;
|
5
|
import android.util.Log;
|
6
|
|
7
|
import java.nio.Buffer;
|
8
|
import java.nio.ByteBuffer;
|
9
|
import java.nio.ByteOrder;
|
10
|
import java.nio.FloatBuffer;
|
11
|
|
12
|
/**
|
13
|
* Created by izzy on 6/24/15. TransformFeedback is a example of how
|
14
|
* to do transform feedback on Android using OpenGLES 3.0. Closely
|
15
|
* follows the example found at https://open.gl/feedback.
|
16
|
*
|
17
|
* Assumes you have a working instance of GLSurfaceVew. Remember to call
|
18
|
* setEGLContextClientVersion(3) to set the OpenGLES context to API 3.0
|
19
|
* and have the appropriate OpenGLES specified in the Android manifest file.
|
20
|
*/
|
21
|
|
22
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
23
|
|
24
|
|
25
|
public class TransformFeedback {
|
26
|
private final String TAG = "TransformFeedback";
|
27
|
|
28
|
|
29
|
// Vertex shader
|
30
|
private final String vertexShaderSrc =
|
31
|
"#version 300 es \n" +
|
32
|
"in float inValue;\n" +
|
33
|
"out float outValue;\n" +
|
34
|
|
35
|
"void main() {\n" +
|
36
|
" outValue = sqrt(inValue);\n" +
|
37
|
"}";
|
38
|
|
39
|
// Need a fragmentShader or glLinkProgram will throw
|
40
|
private final String fragmentShaderCode =
|
41
|
"#version 300 es \n" +
|
42
|
"precision mediump float;\n" +
|
43
|
"out vec4 fragColor;\n" +
|
44
|
"void main() {\n" +
|
45
|
" fragColor = vec4(1.0,1.0,1.0,1.0);\n" +
|
46
|
"}";
|
47
|
|
48
|
private final int mProgram;
|
49
|
|
50
|
/**
|
51
|
* The TransformFeedback constructor contains all the code to initialize
|
52
|
* and draw the TransformFeedback, so create an instance of TransformFeedback
|
53
|
* i.e. 'new TransformFeedBack()' in your 'GLRenderer.OnDrawFrame()' method.
|
54
|
*/
|
55
|
public TransformFeedback(){
|
56
|
|
57
|
// Compile shaders
|
58
|
int vertexShader = loadShader(GLES30.GL_VERTEX_SHADER , vertexShaderSrc );
|
59
|
int fragmentShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode);
|
60
|
|
61
|
// Create program and attach shaders
|
62
|
mProgram = GLES30.glCreateProgram();
|
63
|
GLES30.glAttachShader(mProgram, vertexShader);
|
64
|
GLES30.glAttachShader(mProgram, fragmentShader);
|
65
|
|
66
|
// Tell GL where the feedbackVaryings are in the shader before Linking
|
67
|
// the shaders together to form a program.
|
68
|
final String[] feedbackVaryings = { "outValue" };
|
69
|
GLES30.glTransformFeedbackVaryings(mProgram, feedbackVaryings, GLES30.GL_INTERLEAVED_ATTRIBS);
|
70
|
checkGlError(TAG + " glTransformFeedbackVaryings");
|
71
|
|
72
|
// Link program and look for errors
|
73
|
GLES30.glLinkProgram(mProgram);
|
74
|
|
75
|
int[] linkSuccessful = new int[1];
|
76
|
GLES30.glGetProgramiv(mProgram, GLES30.GL_LINK_STATUS, linkSuccessful, 0);
|
77
|
|
78
|
if (linkSuccessful[0] != 1){
|
79
|
Log.d(TAG, "glLinkProgram failed");
|
80
|
}
|
81
|
checkGlError(TAG + " glLinkProgram");
|
82
|
|
83
|
/***********
|
84
|
* Begin Rendering process
|
85
|
* everything before this can be moved to an initialization stage
|
86
|
***********/
|
87
|
|
88
|
// Bring the program into use
|
89
|
GLES30.glUseProgram(mProgram);
|
90
|
checkGlError(TAG + " glUseProgram");
|
91
|
|
92
|
// Create data to fill VBO
|
93
|
float[] floatData = { 1.0f, 4.0f, 9.0f, 16.0f, 25.0f, 100.0f };
|
94
|
int bufferLength = floatData.length * 4;
|
95
|
FloatBuffer data = ByteBuffer.allocateDirect(bufferLength)
|
96
|
.order(ByteOrder.nativeOrder()).asFloatBuffer();
|
97
|
data.put(floatData).position(0);
|
98
|
|
99
|
// Create VBO and fill with data
|
100
|
int[] vbo = new int[1];
|
101
|
GLES30.glGenBuffers(1, vbo, 0);
|
102
|
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0]);
|
103
|
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, bufferLength, data, GLES30.GL_STATIC_READ);
|
104
|
checkGlError(TAG + " glBufferData GL_ARRAY_BUFFER");
|
105
|
|
106
|
// Link created VBO to shader attribute "inValue"
|
107
|
int inputAttrib = GLES30.glGetAttribLocation(mProgram, "inValue");
|
108
|
GLES30.glEnableVertexAttribArray(inputAttrib);
|
109
|
GLES30.glVertexAttribPointer(inputAttrib, 1, GLES30.GL_FLOAT, false, 4, 0);
|
110
|
checkGlError(TAG + " glVertexAttribPointer");
|
111
|
|
112
|
// Create transform feedback buffer object and bind to transform feedback
|
113
|
// this creates space in a buffer object for the TransformFeedback.
|
114
|
int[] tbo = new int[1];
|
115
|
GLES30.glGenBuffers(1, tbo, 0);
|
116
|
GLES30.glBindBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, tbo[0]);
|
117
|
GLES30.glBufferData(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, bufferLength, null, GLES30.GL_STATIC_READ);
|
118
|
GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo[0]); //very important
|
119
|
|
120
|
checkGlError(TAG + " glBindBufferBase");
|
121
|
|
122
|
// Disable Rasterizer if you just need the data
|
123
|
GLES30.glEnable(GLES30.GL_RASTERIZER_DISCARD);
|
124
|
|
125
|
// Start the TransformFeedback, Draw the Arrays, then End the Transform Feedback
|
126
|
GLES30.glBeginTransformFeedback(GLES30.GL_POINTS);
|
127
|
GLES30.glDrawArrays(GLES30.GL_POINTS, 0, bufferLength);
|
128
|
checkGlError(TAG + " glDrawArrays");
|
129
|
GLES30.glEndTransformFeedback();
|
130
|
|
131
|
// Reenable Rasterizer if you need it, which you do if you are drawing anything.
|
132
|
GLES30.glDisable(GLES30.GL_RASTERIZER_DISCARD);
|
133
|
|
134
|
// Flush out anything in GL before mapping the buffer.
|
135
|
GLES30.glFlush();
|
136
|
checkGlError(TAG + " pre-glMapBufferRange ");
|
137
|
|
138
|
// Map the transform feedback buffer to local address space.
|
139
|
Buffer mappedBuffer = GLES30.glMapBufferRange(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER,
|
140
|
0, bufferLength, GLES30.GL_MAP_READ_BIT);
|
141
|
checkGlError(TAG + " glMapBufferRange");
|
142
|
|
143
|
// Read out the data, here we write to logcat.
|
144
|
if (mappedBuffer!=null){
|
145
|
ByteBuffer bb = ((ByteBuffer) mappedBuffer);
|
146
|
bb.order(ByteOrder.nativeOrder());
|
147
|
FloatBuffer transformedData = bb.asFloatBuffer();
|
148
|
|
149
|
Log.d(TAG, String.format("output values = %f %f %f %f %f %f\n",
|
150
|
transformedData.get(), transformedData.get(), transformedData.get(),
|
151
|
transformedData.get(), transformedData.get(), transformedData.get() ));
|
152
|
}
|
153
|
// Don't forget to Unmap the Transform Feeback Buffer.
|
154
|
GLES30.glUnmapBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER);
|
155
|
}
|
156
|
|
157
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
158
|
|
159
|
private static void checkGlError(String op)
|
160
|
{
|
161
|
int error = GLES30.glGetError();
|
162
|
|
163
|
if (error != GLES30.GL_NO_ERROR)
|
164
|
{
|
165
|
String msg = op + ": glError 0x" + Integer.toHexString(error);
|
166
|
throw new RuntimeException(msg);
|
167
|
}
|
168
|
}
|
169
|
|
170
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
171
|
|
172
|
private static int loadShader(final int shaderType, final String shaderSource)
|
173
|
{
|
174
|
int shaderHandle = GLES30.glCreateShader(shaderType);
|
175
|
|
176
|
if (shaderHandle != 0)
|
177
|
{
|
178
|
GLES30.glShaderSource(shaderHandle, shaderSource);
|
179
|
GLES30.glCompileShader(shaderHandle);
|
180
|
final int[] compileStatus = new int[1];
|
181
|
GLES30.glGetShaderiv(shaderHandle, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
|
182
|
|
183
|
if (compileStatus[0] != GLES30.GL_TRUE )
|
184
|
{
|
185
|
GLES30.glDeleteShader(shaderHandle);
|
186
|
shaderHandle = 0;
|
187
|
}
|
188
|
}
|
189
|
|
190
|
if (shaderHandle == 0)
|
191
|
{
|
192
|
String error = GLES30.glGetShaderInfoLog(shaderHandle);
|
193
|
android.util.Log.e("Program", "error compiling :"+error);
|
194
|
}
|
195
|
|
196
|
return shaderHandle;
|
197
|
}
|
198
|
}
|