Skip to content

Instantly share code, notes, and snippets.

@KrabCode
Created August 11, 2020 19:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KrabCode/a05ad1d299f32d5af307ce10d131f840 to your computer and use it in GitHub Desktop.
Save KrabCode/a05ad1d299f32d5af307ce10d131f840 to your computer and use it in GitHub Desktop.
Reload shaders at runtime
uniform sampler2D texture;
uniform vec2 resolution;
uniform float time;
void main(){
vec2 uv = (gl_FragCoord.xy-.5*resolution) / resolution.y;
vec3 col = 0.5 + 0.5*cos(time+uv.xyx+vec3(0,2,4));
gl_FragColor = vec4(col, 1.);
}
import static java.lang.System.currentTimeMillis;
void setup() {
size(600, 600, P2D);
}
void draw() {
float t = radians(frameCount);
String testShader = "frag.glsl";
uniform(testShader).set("time", t);
hotFilter(testShader);
}
ArrayList<ShaderSnapshot> snapshots = new ArrayList<ShaderSnapshot>();
int shaderRefreshRateInMillis = 100;
public PShader uniform(String fragPath) {
ShaderSnapshot snapshot = findSnapshotByPath(fragPath);
snapshot = initIfNull(snapshot, fragPath, null);
return snapshot.compiledShader;
}
public PShader uniform(String fragPath, String vertPath) {
ShaderSnapshot snapshot = findSnapshotByPath(fragPath);
snapshot = initIfNull(snapshot, fragPath, vertPath);
return snapshot.compiledShader;
}
public void hotFilter(String path, PGraphics canvas) {
hotShader(path, null, true, canvas);
}
public void hotFilter(String path) {
hotShader(path, null, true, g);
}
public void hotShader(String fragPath, String vertPath, PGraphics canvas) {
hotShader(fragPath, vertPath, false, canvas);
}
public void hotShader(String fragPath, String vertPath) {
hotShader(fragPath, vertPath, false, g);
}
public void hotShader(String fragPath, PGraphics canvas) {
hotShader(fragPath, null, false, canvas);
}
public void hotShader(String fragPath) {
hotShader(fragPath, null, false, g);
}
private void hotShader(String fragPath, String vertPath, boolean filter, PGraphics canvas) {
ShaderSnapshot snapshot = findSnapshotByPath(fragPath);
snapshot = initIfNull(snapshot, fragPath, vertPath);
snapshot.update(filter, canvas);
}
private ShaderSnapshot initIfNull(ShaderSnapshot snapshot, String fragPath, String vertPath) {
if (snapshot == null) {
snapshot = new ShaderSnapshot(fragPath, vertPath);
snapshots.add(snapshot);
}
return snapshot;
}
private ShaderSnapshot findSnapshotByPath(String path) {
for (ShaderSnapshot snapshot : snapshots) {
if (snapshot.fragPath.equals(path)) {
return snapshot;
}
}
return null;
}
protected class ShaderSnapshot {
String fragPath;
String vertPath;
File fragFile;
File vertFile;
PShader compiledShader;
long fragLastKnownModified, vertLastKnownModified, lastChecked;
boolean compiledOk = false;
long lastKnownUncompilable = -shaderRefreshRateInMillis;
ShaderSnapshot(String fragPath, String vertPath) {
if (vertPath != null) {
compiledShader = loadShader(fragPath, vertPath);
vertFile = dataFile(vertPath);
vertLastKnownModified = vertFile.lastModified();
if (!vertFile.isFile()) {
println("Could not find shader at " + vertFile.getPath());
}
} else {
compiledShader = loadShader(fragPath);
}
fragFile = dataFile(fragPath);
fragLastKnownModified = fragFile.lastModified();
lastChecked = currentTimeMillis();
if (!fragFile.isFile()) {
println("Could not find shader at " + fragFile.getPath());
}
this.fragPath = fragPath;
this.vertPath = vertPath;
}
long max(long a, long b) {
return Math.max(a, b);
}
void update(boolean filter, PGraphics pg) {
long currentTimeMillis = currentTimeMillis();
long lastModified = fragFile.lastModified();
if (vertFile != null) {
lastModified = max(lastModified, vertFile.lastModified());
}
if (compiledOk && currentTimeMillis < lastChecked + shaderRefreshRateInMillis) {
// println("working shader did not change, not checking, standard apply");
applyShader(compiledShader, filter, pg);
return;
}
if (!compiledOk && lastModified > lastKnownUncompilable) {
// println("file changed, trying to compile");
tryCompileNewVersion(lastModified);
return;
}
lastChecked = currentTimeMillis;
if (lastModified > fragLastKnownModified && lastModified > lastKnownUncompilable) {
// println("file changed, repeat try");
tryCompileNewVersion(lastModified);
} else if (compiledOk) {
// println("file didn't change, standard apply");
applyShader(compiledShader, filter, pg);
}
}
private void applyShader(PShader shader, boolean filter, PGraphics pg) {
if (filter) {
pg.filter(shader);
} else {
pg.shader(shader);
}
}
private void tryCompileNewVersion(long lastModified) {
try {
PShader candidate;
if (vertFile == null) {
candidate = loadShader(fragPath);
} else {
candidate = loadShader(fragPath, vertPath);
}
candidate.init();
compiledShader = candidate;
compiledOk = true;
fragLastKnownModified = lastModified;
println("compiled", fragPath != null ? fragFile.getName() : "",
vertPath != null ? vertFile.getName() : "");
}
catch (Exception ex) {
lastKnownUncompilable = lastModified;
println((fragPath != null ? " " + fragFile.getName() : ""),
(vertPath != null ? " or " + vertFile.getName() : "") + ":");
println(ex.getMessage());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment