package org.archstudio.bna.ui.jogl.utils; import java.io.IOException; import java.net.URL; import java.net.URLConnection; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLException; import org.archstudio.sysutils.Disposable; import com.google.common.io.ByteStreams; public final class GL2ES2Shader implements Disposable { public static GL2ES2Shader create(GL2ES2 gl, int type, URL url) throws GLException { return new GL2ES2Shader(gl, type, url); } private static void dispose(GL2ES2Shader shader) throws GLException { shader.gl.glDeleteShader(shader.shader); } private final GL2ES2 gl; private final int type; private final URL url; private final int shader; private GL2ES2Shader(GL2ES2 gl, int type, URL url) throws GLException { this.gl = gl; this.type = type; this.url = url; this.shader = load(); } private int load() { // verify capability to compile shaders { byte[] compiler = new byte[1]; gl.glGetBooleanv(GL2ES2.GL_SHADER_COMPILER, compiler, 0); if (compiler[0] != GL.GL_TRUE) { throw new GLException("Cannot compile shaders."); } } // obtain shader source String source; try { URLConnection connection = url.openConnection(); connection.setUseCaches(false); source = new String(ByteStreams.toByteArray(connection.getInputStream())).replaceAll("\r\n?", "\n"); String glVersion = gl.glGetString(GL.GL_VERSION); String glslVersion = gl.glGetString(GL2ES2.GL_SHADING_LANGUAGE_VERSION); String version; Matcher versionMatcher = Pattern.compile("[^0-9]*([0-9\\.]+)").matcher(glslVersion); if (versionMatcher.find()) { version = versionMatcher.group(1).replace(".", ""); } else { throw new GLException("Unrecognized GLSL Version: " + glslVersion); } source = "#version " + version // + "\n// GL Version: " + glVersion // + "\n// GLSL Version: " + glslVersion // + "\n\n" + source; } catch (IOException e) { throw new GLException(e); } // create shader int shader = gl.glCreateShader(type); if (shader == 0) { throw new GLException("Cannot create shader."); } try { // compile shader gl.glShaderSource(shader, 1, new String[] { source }, new int[] { source.length() }, 0); gl.glCompileShader(shader); int[] compiled = new int[1]; gl.glGetShaderiv(shader, GL2ES2.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] != GL.GL_TRUE) { int[] logLength = new int[1]; gl.glGetShaderiv(shader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0); byte[] logBytes = new byte[logLength[0]]; if (logLength[0] > 0) { gl.glGetShaderInfoLog(shader, logBytes.length, logLength, 0, logBytes, 0); } throw new GLException("URL:\n" + url + "\nCompiler error:\n" + new String(logBytes, 0, logLength[0]) + "\nSource:\n" + source); } } catch (GLException e) { dispose(this); throw e; } return shader; } @Override public void dispose() { try { dispose(this); } catch (Exception e) { } } public int getShader() { return shader; } }