summaryrefslogtreecommitdiff
path: root/honey/asset
diff options
context:
space:
mode:
Diffstat (limited to 'honey/asset')
-rw-r--r--honey/asset/image.lua49
-rw-r--r--honey/asset/mesh.lua150
-rw-r--r--honey/asset/shader.lua143
3 files changed, 342 insertions, 0 deletions
diff --git a/honey/asset/image.lua b/honey/asset/image.lua
new file mode 100644
index 0000000..c5bd145
--- /dev/null
+++ b/honey/asset/image.lua
@@ -0,0 +1,49 @@
+local gl = honey.gl
+
+local module = {}
+setmetatable(module, {__index=_G})
+setfenv(1, module)
+
+
+local cache = {}
+
+-- load an image into a gl texture
+local function loadImage(filename)
+ local data, width, height = honey.image.load(filename, 4)
+ local texture = gl.GenTextures()
+ gl.BindTexture(gl.TEXTURE_2D, texture)
+ gl.TexImage2D(
+ gl.TEXTURE_2D, 0,
+ gl.RGBA, width, height,
+ gl.RGBA, gl.UNSIGNED_BYTE, data
+ )
+ gl.GenerateMipmap(gl.TEXTURE_2D)
+ honey.image.destroy(data)
+ return texture
+end
+
+-- cached get a texture
+get = function(filename)
+ if not cache[filename] then
+ cache[filename] = loadImage(filename)
+ end
+ return cache[filename]
+end
+
+-- remove a texture from the cache
+forget = function(filename)
+ local texture = cache[filename]
+ if texture then
+ gl.DeleteTextures(texture)
+ end
+ cache[filename] = nil
+end
+
+-- remove all textures from the cache
+clearCache = function(filename)
+ for key in pairs(cache) do
+ forget(key)
+ end
+end
+
+return module
diff --git a/honey/asset/mesh.lua b/honey/asset/mesh.lua
new file mode 100644
index 0000000..876c5e4
--- /dev/null
+++ b/honey/asset/mesh.lua
@@ -0,0 +1,150 @@
+local gl = honey.gl
+
+local module = {}
+setmetatable(module, {__index=_G})
+setfenv(1, module)
+
+
+-- append the 8 floats per vertex to the vertices table
+local function insertVertex(vertices, attrib, vertex)
+ local pos = 3*vertex.v_idx
+ for i=1,3 do
+ table.insert(vertices, attrib.vertices[pos+i])
+ end
+
+ local normal = 3*vertex.vn_idx
+ for i=1,3 do
+ table.insert(vertices, attrib.normals[normal+i])
+ end
+
+ local tex = 2*vertex.vt_idx
+ for i=1,2 do
+ table.insert(vertices, attrib.texcoords[tex+i])
+ end
+end
+
+
+-- creates a table of floats representing vertex data
+-- and a table of ints representing face indices within the vertices
+local function loadShape(shape, attrib, debug)
+ local vertices = {}
+ local indices = {}
+
+ local start = shape.face_offset
+ local finish = start + shape.length
+ for i=start,finish-1 do
+ assert(attrib.face_num_verts[i+1] == 3, "non-triangular face!")
+ for j=0,2 do
+ local vertex = attrib.faces[(3*i) + j + 1]
+ insertVertex(vertices, attrib, vertex, debug)
+ table.insert(indices, #indices)
+ end
+ end
+
+ return vertices, indices
+end
+
+
+-- public helper function (used in some other places, like trimesh construction)
+-- packages the vertices & indices tables from loadShape into a single array
+loadFile = function(filename)
+ local flags = honey.tinyobj.FLAG_TRIANGULATE
+ local attrib, shapes, materials = honey.tinyobj.parse_obj(filename, flags)
+
+ local meshes = {}
+ for _, shape in ipairs(shapes) do
+ local vertices, indices = loadShape(shape, attrib, debug)
+ table.insert(meshes, {vertices=vertices, indices=indices})
+ end
+ return meshes
+end
+
+
+-- helper function to create a gl vertex array object from (vertices, indices) pair
+local function createMesh(vertices, indices)
+ vao = gl.GenVertexArrays()
+ vbo = gl.GenBuffers()
+ ebo = gl.GenBuffers()
+
+ gl.BindVertexArray(vao)
+ gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
+ gl.BufferData(gl.ARRAY_BUFFER, gl.FLOAT, vertices, gl.STATIC_DRAW)
+
+ gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo)
+ gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_INT, indices, gl.STATIC_DRAW)
+
+ local stride = 8
+ local offset = 0
+
+ -- position
+ gl.VertexAttribPointer(0, 3, false, stride, offset)
+ gl.EnableVertexAttribArray(0)
+ offset = offset+3
+
+ -- normal
+ gl.VertexAttribPointer(1, 3, false, stride, offset)
+ gl.EnableVertexAttribArray(1)
+ offset = offset+3
+
+ -- texture
+ gl.VertexAttribPointer(2, 2, false, stride, offset)
+ gl.EnableVertexAttribArray(2)
+ offset = offset+2
+
+ return vao, vbo, ebo, #vertices
+end
+
+
+local cache = {}
+
+
+-- get a gl vertex array object + vertex count
+get = function(filename, index)
+ if not cache[filename] then
+ local c = {}
+ local meshes = loadFile(filename)
+ for _, m in ipairs(meshes) do
+ local vao, vbo, ebo, count = createMesh(m.vertices, m.indices)
+ table.insert(c, { vao=vao, vbo=vbo, ebo=ebo, count=count })
+ end
+ cache[filename] = c
+ end
+ local m = cache[filename][index]
+ return m.vao, m.count
+end
+
+
+-- forget a mesh
+forget = function(filename)
+ if not cache[filename] then return end
+ for _, m in ipairs(cache[filename]) do
+ gl.DeleteBuffers(m.vbo)
+ gl.DeleteBuffers(m.ebo)
+ gl.DeleteVertexArrays(m.vao)
+ end
+ cache[filename] = nil
+end
+
+
+-- clear the cache
+clearCache = function()
+ for key in pairs(cache) do
+ forget(key)
+ end
+end
+
+
+--===== builtin meshes =====--
+
+function createBuiltins()
+ cache["builtin.quad"] = {Mesh(
+ { 0, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0, 0, 1,
+ 1, 1, 0, 0, 1, 0, 1, 1 },
+ { 0, 1, 3, 0, 3, 2 }
+ )}
+end
+
+
+return module
diff --git a/honey/asset/shader.lua b/honey/asset/shader.lua
new file mode 100644
index 0000000..0e8c93a
--- /dev/null
+++ b/honey/asset/shader.lua
@@ -0,0 +1,143 @@
+local gl = honey.gl
+
+local module = {}
+setmetatable(module, {__index=_G})
+setfenv(1, module)
+
+-- compile glsl source code
+local function compileShader(source, type)
+ local shader = gl.CreateShader(type)
+ gl.ShaderSource(shader, source)
+ gl.CompileShader(shader)
+ return shader
+end
+
+-- helper function
+local builtin = {}
+local function readFile(filename)
+ -- support built-in shaders
+ if builtin[filename] then return builtin[filename] end
+
+ local f, err = io.open(filename)
+ if not f then error(err) end
+ local str = f:read("*a")
+ f:close()
+ return str
+end
+
+
+-- build a shader program from provided source files
+local function buildProgram(sources)
+ local shaders = {}
+
+ -- load & compile shaders
+ if sources.vertex then
+ local shader = compileShader(readFile(sources.vertex), gl.VERTEX_SHADER)
+ table.insert(shaders, shader)
+ end
+ if sources.vertex then
+ local shader = compileShader(readFile(sources.vertex), gl.VERTEX_SHADER)
+ table.insert(shaders, shader)
+ end
+
+ -- link shaders
+ local program = gl.CreateProgram()
+ for _, shader in ipairs(shaders) do
+ gl.AttachShader(program, shader)
+ end
+ gl.LinkProgram(program)
+
+ -- clean up
+ for _, shader in ipairs(shaders) do
+ gl.DeleteShader(shader)
+ end
+
+ return program
+end
+
+
+-- public uniform setters
+function setInt(program, name, value)
+ local location = gl.GetUniformLocation(program, name)
+ gl.Uniform1i(location, value)
+end
+function setFloat(program, name, value)
+ local location = gl.GetUniformLocation(program, name)
+ gl.Uniform1f(location, value)
+end
+function setVec3(program, name, value)
+ local location = gl.GetUniformLocation(program, name)
+ gl.Uniform3f(location, value[1], value[2], value[3])
+end
+function setVec4(program, name, value)
+ local location = gl.GetUniformLocation(program, name)
+ gl.Uniform3f(location, value[1], value[2], value[3], value[4])
+end
+function setMatrix(program, name, matrix)
+ local location = gl.GetUniformLocation(program, name)
+ gl.UniformMatrix4fv(location, false, matrix.data)
+end
+
+
+function configure(program, tbl)
+ local processKey = function(key, set)
+ local subtbl = tbl[key]
+ if subtbl then
+ for name, value in pairs(subtbl) do
+ set(program, name, value)
+ end
+ end
+ end
+
+ processKey("int", setInt)
+ processKey("float", setFloat)
+ processKey("vec3", setVec3)
+ processKey("vec4", setVec4)
+ processKey("matrix", setMatrix)
+end
+
+
+--===== public asset cache functions =====--
+
+local cache = {}
+
+
+-- generate id string based on shader sources
+local function shaderId(sources)
+ return string.format(
+ "%s;%s",
+ sources.vertex or "nil",
+ sources.fragment or "nil"
+ )
+end
+
+-- get a cached shader program
+get = function(sources)
+ local id = shaderId(sources)
+ if not cache[id] then
+ cache[id] = buildProgram(sources)
+ end
+ return cache[id]
+end
+
+
+-- remove a cached shader program
+forget = function(sources)
+ local id = shaderId(sources)
+ if cache[id] then
+ gl.DeleteProgram(cache[id])
+ cache[id] = nil
+ end
+end
+
+
+-- clear the cache
+clearCache = function()
+ for key, program in pairs(cache) do
+ gl.DeleteProgram(program)
+ cache[key] = nil
+ end
+end
+
+
+return module