hswaw/signage: reuse compiled shader, better error handling

Shader will now only be recompiled whenever its code changes. This helps
with hangs on node transitions on underpowered devices.

If shader reload failed an error message will now be rendered over an
existing shader.

File load errors are properly handled.

Change-Id: I97a75b85620614252040b76e4f3aaa0ea1f0a7e3
Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1337
Reviewed-by: q3k <q3k@hackerspace.pl>
diff --git a/hswaw/signage/nodes/shadertoy.lua b/hswaw/signage/nodes/shadertoy.lua
index 871ef12..52c8f31 100644
--- a/hswaw/signage/nodes/shadertoy.lua
+++ b/hswaw/signage/nodes/shadertoy.lua
@@ -5,6 +5,7 @@
 function node:init(config)
   node.super.init(self, config)
 
+  self.prevShaderData = nil
   self.path = self.path or "test.glsl"
   self.resolution = self.resolution or {1280, 720}
 
@@ -13,6 +14,10 @@
 
 function node:beforeEnter()
   self:loadShader()
+  if self.iSystem and self.iSystem.iGlobalTime then
+    print("Resetting time")
+    self.iSystem.iGlobalTime = 0
+  end
 end
 
 function node:loadShader()
@@ -26,8 +31,20 @@
     }
     ]]
     local file = io.open(self.path, "r")
+
+    if file == nil then
+        self.shaderLoadError = self.path .. " does not exist"
+        return
+    end
+
     local shaderData = file:read("*all")
 
+    if self.prevShaderData == shaderData then
+      print("Shader didn't change, not reloading")
+      return
+    end
+
+    self.prevShaderData = shaderData
     shaderData = string.gsub(shaderData,"texture2D","Texel")
     shaderData = string.gsub(shaderData,"iTime","iGlobalTime")
     shaderData = string.gsub(shaderData,"precision highp float;","")
@@ -62,16 +79,16 @@
       shaderData = shaderData.."\n"..ender
     end
 
-    print('Shader loaded')
+    print("Shader loaded, compiling...")
 
     self.shaderLoadError = nil
-    shaderLoaded, self.shader = pcall(love.graphics.newShader, shaderData)
+    shaderLoaded, shader = pcall(love.graphics.newShader, shaderData)
     if not shaderLoaded then
-      print('Shader load failed:', self.shader)
-      self.shaderLoadError = self.shader
-      self.shader = nil
+      print("Shader compile failed:", shader)
+      self.shaderLoadError = shader
     else
-      print(shaderLoaded, self.shader)
+      self.shader = shader
+
       if iSystem.iResolution then
         self.shader:send("iResolution",iSystem.iResolution)
       end
@@ -95,12 +112,7 @@
   love.graphics.setColor( 0, 0, 0 )
   love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight())
 
-  if self.shaderLoadError ~= nil then
-    print('render!')
-    love.graphics.setColor(1.0, 0.0, 0.0, 1.0)
-    love.graphics.setFont(smallFont)
-    love.graphics.printf(self.shaderLoadError, 0, 0.1*love.graphics.getHeight(), love.graphics.getWidth(), 'left');
-  elseif self.shader ~= nil then
+  if self.shader ~= nil then
     oldCanvas = love.graphics.getCanvas( )
     love.graphics.setColor( 1.0, 1.0, 1.0 )
     self.canvas:renderTo(function ()
@@ -112,6 +124,12 @@
 
     love.graphics.draw(self.canvas,0,0,math.pi,love.graphics.getWidth() / self.resolution[1], love.graphics.getHeight() / self.resolution[2], self.resolution[1], self.resolution[2])
   end
+
+  if self.shaderLoadError ~= nil then
+    love.graphics.setColor(1.0, 0.0, 0.0, 1.0)
+    love.graphics.setFont(smallFont)
+    love.graphics.printf(self.shaderLoadError, 0, 0.1*love.graphics.getHeight(), love.graphics.getWidth(), 'left');
+  end
 end
 
 return node