Created
August 11, 2020 19:25
-
-
Save KrabCode/a05ad1d299f32d5af307ce10d131f840 to your computer and use it in GitHub Desktop.
Reload shaders at runtime
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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