-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathShaderProgram.java
More file actions
executable file
·285 lines (242 loc) · 10.7 KB
/
ShaderProgram.java
File metadata and controls
executable file
·285 lines (242 loc) · 10.7 KB
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
package jToolkit4FixedPipeline.common;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;
/**
* Class for loading and manipulating shader through openGL fixed pipeline
* @author Astemir Eleev
*/
public final class ShaderProgram {
private int program;
private int vertexShader;
private int fragmentShader;
private StringBuilder vBuilder;
private StringBuilder fBuilder;
/**
* This constructor creates the minimum required GL pipeline for rendering
* @param pathToVertexShader - vertex shader source file
* @param pathToFragmentShader - fragment shader source file
*/
public ShaderProgram(String pathToVertexShader, String pathToFragmentShader) {
this.program = glCreateProgram();
this.vertexShader = glCreateShader(GL_VERTEX_SHADER);
this.fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
initialize (pathToVertexShader, pathToFragmentShader);
compileVertexShader();
compileFragmentShader();
attachShaderAndValidate();
}
// after implementing these constructors the code below must be modified as well
@Deprecated
public ShaderProgram(String pathToVertexShader, String pathToGeometryShader, String pathToFragmentShader) {
// implement this constructor
throw new RuntimeException(ShaderProgram.class.getName() + " : this constructor is in development");
}
@Deprecated
public ShaderProgram(String pathToVertexShder, String pathToTesselationControlShader, String pathToTesselationEvaluatioShader, String pathFragmentShder) {
// implement this constructor
throw new RuntimeException(ShaderProgram.class.getName() + " : this constructor is in development");
}
@Deprecated
public ShaderProgram(String pathToVertexShder, String pathToTesselationControlShader, String pathToTesselationEvaluatioShader, String pathToGeometryShader, String pathFragmentShder) {
// implement this constructor
throw new RuntimeException(ShaderProgram.class.getName() + " : this constructor is in development");
}
/**
* Use this method and useShaderEnd method as a body for some other program code
* It's like body for if construction. put some code between useShadefBegin and
* useShaderEnd methods
*/
public void useShaderBegin () {
glUseProgram(this.program);
}
/*
* Use this method as end of body of shader.
* Requires to use it with useShaderBedin method
* NOTE: Actually we have to sent 0 to function glUseProgram for disabling using shader. Originally there was this.program
*/
public void useShaderEnd () {
// glUseProgram(this.program);
glUseProgram(0);
}
/*
* Delete shader program from RAM
*/
public void deleteShader () {
glDeleteShader(this.vertexShader);
glDeleteShader(this.fragmentShader);
glDeleteProgram(this.program);
}
/**
* Set some float uniform variable to shader program
* The length of array should be between 1 to 4
*
* If your shader doesn't use any uniform variables you must not use
* this method
* @param variableFromShader - some value from shader program
* @param array - some float data
*/
public void setUniformf (String variableFromShader, float[] array) {
int id = glGetUniformLocation(program, variableFromShader);
if (array.length == 1) {
glUniform1f(id, array[0]);
} else if (array.length == 2) {
glUniform2f(id, array[0], array[1]);
} else if (array.length == 3) {
glUniform3f(id, array[0], array[1], array[2]);
} else if (array.length == 4) {
glUniform4f(id, array[0], array[1], array[2], array[3]);
} else {
Logger.getLogger(ShaderProgram.class.getName()).log(Level.WARNING, "setUniformf method \n array lenght is wrong");
}
}
/**
* Set some integer uniform variable to shader program
* The length of array should be between 1 and 4
*
* If your shader doesn't use any uniform variables you must not use
* this method
* @param variableFromShader - some value from shader program
* @param array - some integer data
*/
public void setUniformi (String variableFromShader, int[] array) {
int id = glGetUniformLocation(program, variableFromShader);
if (array.length == 1) {
glUniform1i(id, array[0]);
} else if (array.length == 2) {
glUniform2i(id, array[0], array[1]);
} else if (array.length == 3) {
glUniform3i(id, array[0], array[1], array[2]);
} else if (array.length == 4) {
glUniform4i(id, array[0], array[1], array[2], array[3]);
} else {
Logger.getLogger(ShaderProgram.class.getName()).log(Level.WARNING, "setUniformi \n array lenght is wrong");
}
}
/**
* Set some matrix uniform variable to shader program
* The capacity of float buffer should be 4, 9 or 16 (matrix 2x2, 3x3, 4x4)
*
* If your shader doesn't use any uniform variables you must not use
* this method
* @param variableFromShader - some value from shader program
* @param matrix - some float buffer data
*/
public void setUniformMatrixf (String variableFromShader, boolean transpose, FloatBuffer matrix) {
int id = glGetUniformLocation(program, variableFromShader);
if (matrix.capacity() == 4) {
glUniformMatrix2(id, transpose, matrix);
} else if (matrix.capacity() == 9) {
glUniformMatrix3(id, transpose, matrix);
} else if (matrix.capacity() == 16) {
glUniformMatrix4(id, transpose, matrix);
} else {
Logger.getLogger(ShaderProgram.class.getName()).log(Level.WARNING, "FloatBuffer capacity is wrong");
}
}
/**
* Get id of shader program
* @return id of program
*/
public int getProgram() {
return program;
}
/**
* Get id of fragment shader
* @return id of fragment shader
*/
public int getFragmentShader() {
return fragmentShader;
}
/**
* Get id of vertex shader
* @return id of vertex shader
*/
public int getVertexShader() {
return vertexShader;
}
/***
* Initialize shader program
* @param pathToVertexShader - local path to vertex shader
* @param pathToFragmentShader - local path to fragment shader
*/
private void initialize (String pathToVertexShader, String pathToFragmentShader) {
this.fBuilder = loadFromFile(pathToFragmentShader);
this.vBuilder = loadFromFile(pathToVertexShader);
}
private StringBuilder loadFromFile (String path) {
BufferedReader breader = null;
StringBuilder sb = new StringBuilder();
String tmp = "";
try {
breader = new BufferedReader(new FileReader(new File(path)));
while ((tmp = breader.readLine())!= null) {
sb.append(tmp).append("\n");
}
breader.close();
} catch (IOException e) {
Logger.getLogger(ShaderProgram.class.getName()).log(Level.WARNING, "loading shader exception", e);
e.printStackTrace();
}
return sb;
}
private void compileVertexShader () {
glShaderSource(vertexShader, vBuilder);
glCompileShader(vertexShader);
}
private void compileFragmentShader () {
glShaderSource(fragmentShader, fBuilder);
glCompileShader(fragmentShader);
}
public void printVertexShaderCompilationStatus() {
if (glGetShaderi(vertexShader, GL_COMPILE_STATUS) == GL_FALSE) {
int infoLength = glGetShaderi(vertexShader, GL_INFO_LOG_LENGTH);
String log = glGetShaderInfoLog(vertexShader, infoLength);
System.err.println("Vertex shader: GL_COMPILE_STATUS: ERROR\n" + log);
} else System.err.println("Vertex shader: GL_COMPILE_STATUS: Success");
if (glGetShaderi(vertexShader, GL_LINK_STATUS) == GL_FALSE) {
int infoLength = glGetProgrami(vertexShader, GL_INFO_LOG_LENGTH);
String linkingLog = glGetProgramInfoLog(vertexShader, infoLength);
System.err.println("Vertex shader: GL_LINK_STATUS: ERROR\n" + linkingLog);
} else System.err.println("Vertex shader: GL_LINK_STATUS: Success");
if (glGetShaderi(vertexShader, GL_VALIDATE_STATUS) == GL_FALSE) {
System.err.println("Vertex shader: GL_VALIDATE_STATUS: ERROR");
} else System.err.println("Vertex shader: GL_VALIDATE_STATUS: Success");
}
public void printFragmentShaderCompilationStatus() {
if (glGetShaderi(fragmentShader, GL_COMPILE_STATUS) == GL_FALSE) {
int infoLength = glGetShaderi(fragmentShader, GL_INFO_LOG_LENGTH);
String log = glGetShaderInfoLog(fragmentShader, infoLength);
System.err.println("Fragment shader: GL_COMPILE_STATUS: ERROR\n" + log);
} else System.err.println("Fragment shader: GL_COMPILE_STATUS: Success");
if (glGetShaderi(fragmentShader, GL_LINK_STATUS) == GL_FALSE) {
System.err.println("Fragment shader: GL_LINK_STATUS: ERROR");
} else System.err.println("Fragment shader: GL_LINK_STATUS: Success");
if (glGetShaderi(fragmentShader, GL_VALIDATE_STATUS) == GL_FALSE) {
System.err.println("Fragment shader: GL_VALIDATE_STATUS: ERROR");
} else System.err.println("Fragment shader: GL_VALIDATE_STATUS: Success");
}
private void getGLError() {
int err = glGetError();
while(err != GL_NO_ERROR) {
Logger.getLogger(ShaderProgram.class.getCanonicalName()).log(Level.INFO, glGetString(err));
err = glGetError();
}
}
/**
* connect shaders between each other, as a result you will have a shader program instead of
* two types of different shaders
*/
private void attachShaderAndValidate () {
glAttachShader(this.program, this.vertexShader);
glAttachShader(this.program, this.fragmentShader);
glLinkProgram(this.program);
glValidateProgram(this.program);
}
}