diff options
-rw-r--r-- | fragment.glsl | 6 | ||||
-rw-r--r-- | honey/ecs.lua.bak | 228 | ||||
-rw-r--r-- | honey/image.lua | 50 | ||||
-rw-r--r-- | honey/ode.lua | 55 | ||||
-rw-r--r-- | honey/shader.lua | 20 | ||||
-rw-r--r-- | honey/std.lua | 9 | ||||
-rw-r--r-- | main.lua | 59 |
7 files changed, 400 insertions, 27 deletions
diff --git a/fragment.glsl b/fragment.glsl index 27dbbfa..c6ef691 100644 --- a/fragment.glsl +++ b/fragment.glsl @@ -5,11 +5,13 @@ in vec3 position; in vec3 normal;
in vec2 tex;
+uniform float time;
uniform sampler2D ourTexture;
void main()
{
- FragColor = vec4(normal, 1.0f);
+ //FragColor = vec4(sin(time), cos(time), -sin(time), 1.0f);
+ //FragColor = vec4(normal, 1.0f);
//FragColor = vec4(tex, 1.0f, 1.0f);
- //FragColor = texture(ourTexture, TexCoord);
+ FragColor = texture(ourTexture, tex);
}
diff --git a/honey/ecs.lua.bak b/honey/ecs.lua.bak new file mode 100644 index 0000000..3632f34 --- /dev/null +++ b/honey/ecs.lua.bak @@ -0,0 +1,228 @@ +local module = {} +setmetatable(module, {__index=_G}) +setfenv(1, module) + + +--===== filters =====-- + + +Filter = {} + +-- base filter creation +function Filter.new(_, operation, tbl) + local self = {} + self.keys = {} + self.filters = {} + self.op = operation + + for _, v in ipairs(tbl) do + if type(v) == "function" then + table.insert(self.filters, v) + elseif type(v) == "string" then + table.insert(self.keys, v) + end + end + + return function(entity, _self) + local entity = _self or entity -- able to call as . or : + return Filter.check(self, entity) + end +end +setmetatable(Filter, {__call=Filter.new}) + + +-- base filter checking +function Filter.check(self, entity) + local funcname = "check" .. self.op + return Filter[funcname](self, entity) +end + + +-- AND filter (all keys and subfilters must match) +function Filter.AND(tbl) + return Filter("AND", tbl) +end +function Filter.checkAND(self, entity) + for _, subfilter in ipairs(self.filters) do + if not subfilter(entity) then return false end + end + for _, key in ipairs(self.keys) do + if entity[key] == nil then return false end + end + return true +end + + +-- OR filter (at least one key or subfilter must match) +function Filter.OR(tbl) + return Filter("OR", tbl) +end +function Filter.checkOR(self, entity) + for _, subfilter in ipairs(self.filters) do + if subfilter(entity) then return true end + end + for _, key in ipairs(self.keys) do + if entity[key] ~= nil then return true end + end + return false +end + + +-- NAND filter (at least one key or subfilter must NOT match) +function Filter.NAND(tbl) + return Filter("NAND", tbl) +end +function Filter.checkNAND(self, entity) + for _, subfilter in ipairs(self.filters) do + if not subfilter(entity) then return true end + end + for _, key in ipairs(self.keys) do + if entity[key] == nil then return true end + end + return false +end + + +-- NOR filter (no keys or subfilters may match) +function Filter.NOR(tbl) + return Filter("NOR", tbl) +end +function Filter.checkNOR(self, entity) + for _, subfilter in ipairs(self.filters) do + if subfilter(entity) then return false end + end + for _, key in ipairs(self.keys) do + if entity[key] ~= nil then return false end + end + return true +end + + +--===== levels =====-- + +Level = {} +Level.__index = Level + +function Level.new(_) + local self = {} + self.systems = {} + self.entities = {} + self.nextId = 1 + setmetatable(self, Level) + return self +end +setmetatable(Level, {__call=Level.new}) + + +local function systemLt(a, b) + return (a.priority or 50) < (b.priority or 50) +end +function Level.addSystem(self, system) + assert(system.update, "systems must have an 'update' key") + assert(system.filter, "systems must have a 'filter' key") + system.entities = {} + table.insert(self.systems, system) + table.sort(self.systems, systemLt) + if system.setup then + system.setup(system) + end +end + + +local function addEntityToSystem(system, id, entity) + -- check if entity is already present + if system.entities[id] then return end + + if system.onAddEntity then + system:onAddEntity(id, entity) + end + system.entities[id] = true +end + + +local function removeEntityFromSystem(system, id, entity) + -- check if entity is already absent + if not system.entities[id] then return end + + if system.onRemoveEntity then + system:onRemoveEntity(id, entity) + end + system.entities[id] = nil +end + + +function Level.addEntity(self, entity) + local id = self.nextId + self.entities[id] = entity + self.nextId = id + 1 + + for _, system in ipairs(self.systems) do + if system.filter(entity) then + addEntityToSystem(system, id, entity) + end + end + + return id +end + + +function Level.reconfigureEntity(self, id) + local entity = self.entities[id] + + for _, system in ipairs(self.systems) do + if system.filter(entity) then + addEntityToSystem(system, id, entity) + else + removeEntityFromSystem(system, id, entity) + end + end +end + + +function Level.removeEntity(self, id) + local entity = self.entities[id] + if not entity then error("bad id: "..tostring(id)) end + for _, system in ipairs(self.systems) do + removeEntityFromSystem(system, id, entity) + end + self.entities[id] = nil +end + + +function Level.reconfigureAllEntities(self) + for id in ipairs(self.entities) do + self:reconfigureEntity(id) + end +end + + +function Level.update(self, dt, paused) + local paused = paused or false + for _, system in ipairs(self.systems) do + if (not paused) or (paused and system.nopause) then + if system.preUpdate then + system:preUpdate() + end + if system.prepareEntity then + for id in pairs(system.entities) do + local entity = self.entities[id] + if entity then + system:prepareEntity(entity) + end + end + end + for id in pairs(system.entities) do + local entity = self.entities[id] + if entity then + system:update(entity, dt) + end + end + if system.postUpdate then + system:postUpdate() + end + end + end +end + + +return module diff --git a/honey/image.lua b/honey/image.lua new file mode 100644 index 0000000..f074272 --- /dev/null +++ b/honey/image.lua @@ -0,0 +1,50 @@ +local gl = honey.gl + +local module = {} +setmetatable(module, {__index=_G}) +setfenv(1, module) + +function Image(filename, params) + local params = params or {} + local data, width, height = honey.image.load(filename, 4) + local self = {} + self.width = width + self.height = height + + self.texture = gl.GenTextures() + gl.BindTexture(gl.TEXTURE_2D, self.texture) + for param, value in pairs(params) do + gl.TexParameteri(gl.TEXTURE_2D, gl[param], value) + end + 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) + + self.__gc = honey.util.gc_canary(function() + gl.DeleteTextures(self.texture) + end) + + return self +end + + +local cache = {} +function loadImage(filename, params) + if not cache[filename] then + local img = Image(filename, params) + cache[filename] = img + return img + end + + return cache[filename] +end + +function clearImageCache() + cache = {} +end + +return module diff --git a/honey/ode.lua b/honey/ode.lua new file mode 100644 index 0000000..4cd2e54 --- /dev/null +++ b/honey/ode.lua @@ -0,0 +1,55 @@ +local module = {} +setmetatable(module, {__index=_G} +setfenv(1, module) + + +--===== collision =====-- + +Geom = {} +Geom.__index = Geom + + +function Geom.new(_, type, params) + local self = {} + self.type = type + self.params = params + setmetatable(self, Geom) + return self +end +setmetatable(Geom, {__call=Geom.new}) + + +function Geom.renew(geom) + return ode.GeomGetData(geom) +end + + +local function instantiateSphere(space, params) + local geom = ode.CreateSphere(space, params.radius) + return geom +end + + +local function instantiatePlane(space, params) + local geom = ode.CreatePlane(space, params.a, params.b, params.c, params.d) + return geom +end + + +function Geom.instantiate(self, space) + if self.type == "sphere" then + self.geom = instantiateSphere(space, self.params) + elseif self.type == "plane" then + self.geom = instantiatePlane(space, self.params) + else + error(string.format("bad geom type: %s", self.type)) + end + ode.GeomSetData(self.geom, self) + return self +end + + +function Geom.setBody(self, body) + ode.GeomSetBody(self.geom, body.body) + return self +end diff --git a/honey/shader.lua b/honey/shader.lua index 083b260..6b281f7 100644 --- a/honey/shader.lua +++ b/honey/shader.lua @@ -52,6 +52,10 @@ function Shader.new(_, sources) gl.DeleteShader(shader) end + self.__gc = honey.util.gc_canary(function() + gl.DeleteProgram(self.program) + end) + setmetatable(self, Shader) return self end @@ -115,4 +119,18 @@ function Shader.configure(self, tbl) processKey("matrix", "setMatrix") end -return module.Shader + +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 diff --git a/honey/std.lua b/honey/std.lua index 2a5d2c2..98e942d 100644 --- a/honey/std.lua +++ b/honey/std.lua @@ -7,10 +7,17 @@ honey.terminate = init.terminate honey.ecs = require 'honey.ecs' --honey.standardSystems = require 'honey.ecs-systems' honey.mesh = require 'honey.mesh' -honey.Shader = require 'honey.shader' +honey.shader = require 'honey.shader' honey.Window = require 'honey.window' +-- image +local image = require 'honey.image' +for k, v in pairs(image) do + honey.image[k] = v +end + + local glm = require 'honey.glm' honey.Vec3 = glm.Vec3 honey.Mat4 = glm.Mat4 @@ -22,27 +22,12 @@ local vw, vh = 640, 480 -- create camera matrices local camera = { - view=Mat4():identity():translate(Vec3{0, 0, -30}), + view=Mat4():identity():translate(Vec3{0, 0, -3}), projection=Mat4():perspective(math.rad(45), 640/480, 0.1, 100), } --- create shader -local shader = honey.Shader{ - vertexFile = "vertex.glsl", - fragmentFile = "fragment.glsl", -} - --- load models -local plane = honey.mesh.loadFile("assets/plane.obj")[1] -local tetra = honey.mesh.loadFile("assets/tetrahedron.obj")[1] -local cube = honey.mesh.loadFile("assets/cube.obj")[1] -local octa = honey.mesh.loadFile("assets/octahedron.obj")[1] -local dodeca = honey.mesh.loadFile("assets/dodecahedron.obj")[1] -local icosa = honey.mesh.loadFile("assets/icosahedron.obj")[1] - - -- close window on ESCAPE key window:setKeyCallback(function(_, key, scancode, action) if action == glfw.PRESS then @@ -82,14 +67,39 @@ sdb:addSystem{ update = function(self, dt) local entities = self.db:queryComponent("renderMesh") for entity, tbl in pairs(entities) do - tbl.shader:use() - tbl.shader:configure{matrix={ - view=camera.view, - projection=camera.projection, - model=Mat4():identity(), - }} + -- get shader + local shader = honey.shader.loadShader(tbl.shader.vertex, tbl.shader.fragment) + shader:use() + + -- bind textures + local texOffset = 0 + for name, texTbl in pairs(tbl.textures) do + local texture = honey.image.loadImage(texTbl.filename, texTbl.params) + gl.BindTexture(gl.TEXTURE_2D + texOffset, texture.texture) + shader:setInt(name, texOffset) + texOffset = texOffset + 1 + end + + -- configure default uniforms + shader:configure{ + float={ + time=glfw.GetTime(), + }, + matrix={ + view=camera.view, + projection=camera.projection, + model=Mat4():identity(), + }, + } + + -- draw mesh local mesh = honey.mesh.loadMesh(tbl.mesh.filename, tbl.mesh.index) mesh:drawElements() + + -- unbind textures + for i=0,texOffset-1 do + gl.BindTexture(gl.TEXTURE_2D + i, 0) + end end end, db = edb, @@ -99,7 +109,10 @@ sdb:addSystem{ local id = edb:createEntity() edb:addComponent(id, "renderMesh", { - shader = shader, + textures = { + ourTexture={ filename="77155.png" }, + }, + shader = { vertex="vertex.glsl", fragment="fragment.glsl" }, mesh = { filename="assets/icosahedron.obj", index=1 }, }) |