local gl = honey.gl local module = {} setmetatable(module, {__index=_G}) setfenv(1, module) Shader = {} Shader.__index = Shader local function compileShader(source, type) local shader = gl.CreateShader(type) gl.ShaderSource(shader, source) gl.CompileShader(shader) return shader end local function readFile(filename) local f, err = io.open(filename) if not f then error(err) end local str = f:read("*a") f:close() return str end function Shader.new(_, sources) local self = {} self.locations = {} self.links = {} if sources.vertexFile then sources.vertex = readFile(sources.vertexFile) end if sources.fragmentFile then sources.fragment = readFile(sources.fragmentFile) end local shaders = {} if sources.vertex then table.insert(shaders, compileShader(sources.vertex, gl.VERTEX_SHADER)) end if sources.fragment then table.insert(shaders, compileShader(sources.fragment, gl.FRAGMENT_SHADER)) end self.program = gl.CreateProgram() for _, shader in ipairs(shaders) do gl.AttachShader(self.program, shader) end gl.LinkProgram(self.program) for _, shader in ipairs(shaders) do gl.DeleteShader(shader) end self.__gc = honey.util.gc_canary(function() gl.DeleteProgram(self.program) end) setmetatable(self, Shader) return self end setmetatable(Shader, {__call=Shader.new}) function Shader.getLocation(self, name) if self.locations[name] then return self.locations[name] end local location = gl.GetUniformLocation(self.program, name) self.locations[name] = location return location end function Shader.use(self) gl.UseProgram(self.program) end function Shader.setInt(self, name, value) local location = self:getLocation(name) gl.Uniform1i(location, value) end function Shader.setFloat(self, name, value) local location = self:getLocation(name) gl.Uniform1f(location, value) end function Shader.setVec3(self, name, value) local location = self:getLocation(name) gl.Uniform3f(location, value[1], value[2], value[3]) end function Shader.setVec4(self, name, value) local location = self:getLocation(name) gl.Uniform3f(location, value[1], value[2], value[3], value[4]) end function Shader.setMatrix(self, name, matrix) local location = self:getLocation(name) gl.UniformMatrix4fv(location, false, matrix.data) end function Shader.configure(self, tbl) local processKey = function(key, set) local subtbl = tbl[key] if subtbl then for name, value in pairs(subtbl) do self[set](self, name, value) end end end processKey("int", "setInt") processKey("float", "setFloat") processKey("vec3", "setVec3") processKey("vec4", "setVec4") processKey("matrix", "setMatrix") end local shaderCache = {} function loadShader(vertex, fragment) local id = vertex .. "+" .. fragment if not shaderCache[id] then local shader = Shader{vertexFile=vertex, fragmentFile=fragment} shaderCache[id] = shader end return shaderCache[id] end function clearShaderCache() shaderCache = {} end return module