package openmods.renderer.shaders;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.minecraft.client.Minecraft;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.OpenGLException;
public class ShaderProgramBuilder {
private final Map<ResourceLocation, Integer> shadersToLoad = Maps.newLinkedHashMap();
public ShaderProgramBuilder() {}
public void addShader(ResourceLocation source, int type) {
shadersToLoad.put(source, type);
}
public ShaderProgram build() {
final int program = ShaderHelper.methods().glCreateProgram();
final List<Integer> shaders = Lists.newArrayList();
if (program == 0) throw new OpenGLException("Error creating program object");
for (Map.Entry<ResourceLocation, Integer> e : shadersToLoad.entrySet()) {
final int shader = createShader(e.getKey(), e.getValue());
ShaderHelper.methods().glAttachShader(program, shader);
shaders.add(shader);
}
ShaderHelper.methods().glLinkProgram(program);
if (ShaderHelper.methods().glGetProgrami(program, GL20.GL_LINK_STATUS) == GL11.GL_FALSE) throw new OpenGLException("Shader link error: " + ShaderHelper.methods().getProgramLogInfo(program));
for (Integer shader : shaders)
ShaderHelper.methods().glDetachShader(program, shader);
ShaderHelper.methods().glValidateProgram(program);
if (ShaderHelper.methods().glGetProgrami(program, GL20.GL_VALIDATE_STATUS) == GL11.GL_FALSE) throw new OpenGLException("Shader validate error: " + ShaderHelper.methods().getProgramLogInfo(program));
return new ShaderProgram(program, shaders);
}
private static int createShader(ResourceLocation source, int type) {
int shader = 0;
try {
shader = ShaderHelper.methods().glCreateShader(type);
if (shader == 0) throw new OpenGLException("Error creating shader object");
ShaderHelper.methods().glShaderSource(shader, readShaderSource(source));
ShaderHelper.methods().glCompileShader(shader);
if (ShaderHelper.methods().glGetShaderi(shader, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE) throw new OpenGLException("Shader compile error: " + ShaderHelper.methods().getShaderLogInfo(shader));
return shader;
} catch (Throwable t) {
ShaderHelper.methods().glDeleteShader(shader);
throw Throwables.propagate(t);
}
}
private static String readShaderSource(ResourceLocation source) {
try {
final InputStream is = Minecraft.getMinecraft().getResourceManager().getResource(source).getInputStream();
final Iterator<String> lines = IOUtils.lineIterator(is, Charsets.UTF_8);
final StringBuilder out = new StringBuilder();
Joiner.on('\n').appendTo(out, lines);
return out.toString();
} catch (IOException e) {
throw new OpenGLException("Failed to read resource " + source, e);
}
}
}