/**
* This class was created by <Vazkii>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [Apr 9, 2014, 11:20:26 PM (GMT)]
*/
package vazkii.botania.client.core.helper;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import org.lwjgl.opengl.ARBFragmentShader;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.ARBVertexShader;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.renderer.OpenGlHelper;
import vazkii.botania.api.internal.ShaderCallback;
import vazkii.botania.client.core.handler.ClientTickHandler;
import vazkii.botania.client.lib.LibResources;
import vazkii.botania.common.Botania;
import vazkii.botania.common.core.handler.ConfigHandler;
public final class ShaderHelper {
private static final int VERT = ARBVertexShader.GL_VERTEX_SHADER_ARB;
private static final int FRAG = ARBFragmentShader.GL_FRAGMENT_SHADER_ARB;
public static int pylonGlow = 0;
public static int enchanterRune = 0;
public static int manaPool = 0;
public static int doppleganger = 0;
public static int halo = 0;
public static int dopplegangerBar = 0;
public static int terraPlateRune = 0;
public static int filmGrain = 0;
public static int gold = 0;
public static int categoryButton = 0;
public static int alpha = 0;
public static void initShaders() {
if(!useShaders())
return;
pylonGlow = createProgram(null, LibResources.SHADER_PYLON_GLOW_FRAG);
enchanterRune = createProgram(null, LibResources.SHADER_ENCHANTER_RUNE_FRAG);
manaPool = createProgram(null, LibResources.SHADER_MANA_POOL_FRAG);
doppleganger = createProgram(LibResources.SHADER_DOPLLEGANGER_VERT, LibResources.SHADER_DOPLLEGANGER_FRAG);
halo = createProgram(null, LibResources.SHADER_HALO_FRAG);
dopplegangerBar = createProgram(null, LibResources.SHADER_DOPLLEGANGER_BAR_FRAG);
terraPlateRune = createProgram(null, LibResources.SHADER_TERRA_PLATE_RUNE_FRAG);
filmGrain = createProgram(null, LibResources.SHADER_FILM_GRAIN_FRAG);
gold = createProgram(null, LibResources.SHADER_GOLD_FRAG);
categoryButton = createProgram(null, LibResources.SHADER_CATEGORY_BUTTON_FRAG);
alpha = createProgram(LibResources.SHADER_ALPHA_VERT, LibResources.SHADER_ALPHA_FRAG);
}
public static void useShader(int shader, ShaderCallback callback) {
if(!useShaders())
return;
ARBShaderObjects.glUseProgramObjectARB(shader);
if(shader != 0) {
int time = ARBShaderObjects.glGetUniformLocationARB(shader, "time");
ARBShaderObjects.glUniform1iARB(time, ClientTickHandler.ticksInGame);
if(callback != null)
callback.call(shader);
}
}
public static void useShader(int shader) {
useShader(shader, null);
}
public static void releaseShader() {
useShader(0);
}
public static boolean useShaders() {
return ConfigHandler.useShaders && OpenGlHelper.shadersSupported;
}
// Most of the code taken from the LWJGL wiki
// http://lwjgl.org/wiki/index.php?title=GLSL_Shaders_with_LWJGL
private static int createProgram(String vert, String frag) {
int vertId = 0, fragId = 0, program;
if(vert != null)
vertId = createShader(vert, VERT);
if(frag != null)
fragId = createShader(frag, FRAG);
program = ARBShaderObjects.glCreateProgramObjectARB();
if(program == 0)
return 0;
if(vert != null)
ARBShaderObjects.glAttachObjectARB(program, vertId);
if(frag != null)
ARBShaderObjects.glAttachObjectARB(program, fragId);
ARBShaderObjects.glLinkProgramARB(program);
if(ARBShaderObjects.glGetObjectParameteriARB(program, ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB) == GL11.GL_FALSE) {
Botania.LOGGER.error(getLogInfo(program));
return 0;
}
ARBShaderObjects.glValidateProgramARB(program);
if (ARBShaderObjects.glGetObjectParameteriARB(program, ARBShaderObjects.GL_OBJECT_VALIDATE_STATUS_ARB) == GL11.GL_FALSE) {
Botania.LOGGER.error(getLogInfo(program));
return 0;
}
return program;
}
private static int createShader(String filename, int shaderType){
int shader = 0;
try {
shader = ARBShaderObjects.glCreateShaderObjectARB(shaderType);
if(shader == 0)
return 0;
ARBShaderObjects.glShaderSourceARB(shader, readFileAsString(filename));
ARBShaderObjects.glCompileShaderARB(shader);
if (ARBShaderObjects.glGetObjectParameteriARB(shader, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE)
throw new RuntimeException("Error creating shader: " + getLogInfo(shader));
return shader;
}
catch(Exception e) {
ARBShaderObjects.glDeleteObjectARB(shader);
e.printStackTrace();
return -1;
}
}
private static String getLogInfo(int obj) {
return ARBShaderObjects.glGetInfoLogARB(obj, ARBShaderObjects.glGetObjectParameteriARB(obj, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB));
}
private static String readFileAsString(String filename) throws Exception {
InputStream in = ShaderHelper.class.getResourceAsStream(filename);
if(in == null)
return "";
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"))) {
return reader.lines().collect(Collectors.joining("\n"));
}
}
}