diff options
author | sanine-a <sanine.not@pm.me> | 2023-05-09 11:31:17 -0500 |
---|---|---|
committer | sanine-a <sanine.not@pm.me> | 2023-05-09 11:31:17 -0500 |
commit | a2ae7aae8357c8c2684d85fd58b0c5a0563ebab9 (patch) | |
tree | 5050161547408c80b521c9f4708bb9f7a9d0fa71 /honey/ecs-systems.lua | |
parent | 2a14abecaee073aef1f1966bb397d6086b2e4785 (diff) |
refactor: split ecs systems into multiple files
Diffstat (limited to 'honey/ecs-systems.lua')
-rw-r--r-- | honey/ecs-systems.lua | 375 |
1 files changed, 0 insertions, 375 deletions
diff --git a/honey/ecs-systems.lua b/honey/ecs-systems.lua deleted file mode 100644 index 1213763..0000000 --- a/honey/ecs-systems.lua +++ /dev/null @@ -1,375 +0,0 @@ -local ecs = require 'honey.ecs' -local glm = require 'honey.glm' -local Mat4 = glm.Mat4 -local Vec3 = glm.Vec3 -local Quaternion = glm.Quaternion -local gl = honey.gl -local glfw = honey.glfw -local ode = honey.ode - - -local module = {} -setmetatable(module, {__index=_G}) -setfenv(1, module) - - --- helper function for retrieving script functions -local function getFunction(script) - local f = require(script.script) - if script.func then - return f[script.func] - else - return f - end -end - - ---===== dispatch messages to handlers =====-- - -dispatch = function(entities, msg, data) - local query = entities:queryComponent(msg) - for id, handler in pairs(query) do - local f = getFunction(handler) - f(entities, id, data) - end -end - - - ---===== transform cascading =====-- - -node = function(params) - return { - db = params.db, - - priority = 2, - update = function(self, dt) - local nodes = self.db:queryComponent("node") - - -- prepare nodes - for id, node in pairs(nodes) do - node._visited = false - end - - -- helper function - local function recursiveTransform(node) - if node._visited then - return node._matrix - end - - if not node.parent then - node._matrix = node.matrix - else - local parentTransform = self.db:getComponent(node.parent, "node") - local parentMatrix = recursiveTransform(parentTransform) - node._matrix = parentMatrix * node.matrix - end - node._visited = true - return node._matrix - end - - -- compute nodes - for id, node in pairs(nodes) do - recursiveTransform(node) - end - end, - } -end - - - ---===== rendering =====-- - -function draw(model, view, projection, textures, shader, mesh) - shader:use() - - -- bind textures - local texOffset = 0 - for name, texTbl in pairs(textures or {}) 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=view, - projection=projection, - model=model, - }, - } - - -- draw mesh - mesh:drawElements() - - -- unbind textures - for i=0,texOffset-1 do - gl.BindTexture(gl.TEXTURE_2D + i, 0) - end -end - -function renderCamera(params) - return { - db = params.db, - priority = params.priority or 99, - update = function(self, dt) - for id, camera in pairs(self.db:queryComponent("camera")) do - local projection = camera.projection - local cameraTransform = self.db:getComponent(id, "node") - local view = Mat4() - if cameraTransform then - honey.glm.mat4_inv(cameraTransform._matrix.data, view.data) - else - view:identity() - end - - local entities = self.db:queryComponent("renderMesh") - for entity, tbl in pairs(entities) do - -- get model - local node = self.db:getComponent(entity, "node") - local model = - (node and node._matrix) or - Mat4():identity() - -- get shader - local shader = honey.shader.loadShader( - tbl.shader.vertex, tbl.shader.fragment - ) - -- get mesh - local mesh = honey.mesh.loadCached( - tbl.mesh.filename, tbl.mesh.index - ) - draw(model, view, projection, tbl.textures, shader, mesh) - end - - entities = self.db:queryComponent("renderQuad") - local quadmesh = honey.mesh.loadCached("builtin.quad", 1) - for entity, tbl in pairs(entities) do - -- get model - local model = Mat4():identity() - -- get shader - local shader = honey.shader.loadShader( - tbl.shader.vertex, tbl.shader.fragment - ) - draw(model, view, projection, tbl.textures, shader, quadmesh) - end - end - end, - } -end - - - ---===== script system =====-- - -script = function(params) - return { - db=params.db, - update=function(self, dt) - local entities = self.db:queryComponent("script") - for id, script in pairs(entities) do - local f = getFunction(script) - f(self.db, id, dt) - end - end - } -end - - ---===== physics =====-- - - -physics = function(params) - local interval = params.interval or 0.016 - local groupSize = params.groupSize or 20 - local refs = {} - return { - db=params.db, - space=params.space, - world=params.world, - contactGroup=ode.JointGroupCreate(groupSize), - time=interval, - - priority=1, - update=function(self, dt) - for i, ref in ipairs(refs) do - print(i, ref.tbl, ref.physics) - end - local query = self.db:queryComponent("physics") - - for id, physics in pairs(query) do - if not physics._body then - print("add physics body for "..id) - local body = ode.BodyCreate(self.world) - physics._gc = honey.util.gc_canary(function() - print("releasing physics body for " .. id) - ode.BodyDestroy(body) - body = nil - end) - - local collision = self.db:getComponent(id, "collision") - if collision then - print(id, collision.class) - ode.GeomSetBody(collision._geom, body) - end - - local mass = ode.MassCreate() - local class = physics.mass.class - if not class then - -- configure mass manually - elseif class == "sphere" then - ode.MassSetSphere( - mass, - physics.mass.density, - physics.mass.radius - ) - elseif class == "capsule" then - ode.MassSetCapsule( - mass, - physics.mass.density, - physics.mass.direction, - physics.mass.radius, - physics.mass.length - ) - end - ode.BodySetMass(body, mass) - local m = self.db:getComponent(id, "node").matrix - ode.BodySetPosition( - body, - m[1][4], m[2][4], m[3][4] - ) - ode.BodySetRotation( - body, - m[1][1], m[1][2], m[1][3], - m[2][1], m[2][2], m[2][3], - m[3][1], m[3][2], m[3][3] - ) - local vel = physics.velocity or Vec3{0,0,0} - ode.BodySetLinearVel( - body, vel[1], vel[2], vel[3] - ) - physics.velocity = vel - - local avel = physics.angularVelocity or Vec3{0,0,0} - ode.BodySetAngularVel( - body, avel[1], avel[2], avel[3] - ) - physics.angularVelocity = avel - - if physics.maxAngularSpeed then - ode.BodySetMaxAngularSpeed(body, physics.maxAngularSpeed) - end - - physics._body = body - end - end - - self.time = self.time + dt - -- only run the update every [interval] seconds - if self.time > interval then - self.time = self.time - interval - - -- check for near collisions between geoms - ode.SpaceCollide(self.space, function(a, b) - -- check for actual collisions - local collisions = ode.Collide(a, b, 1) - if #collisions > 0 then - -- set up the joint params - local contact = ode.CreateContact{ surface={ - mode = ode.ContactBounce + ode.ContactSoftCFM, - mu = ode.Infinity, - bounce = 0.90, - bounce_vel = 0.1, - soft_cfm = 0.001, - }} - ode.ContactSetGeom(contact, collisions[1]) - -- create the joint - local joint = ode.JointCreateContact( - self.world, - self.contactGroup, - contact - ) - -- attach the two bodies - local bodyA = ode.GeomGetBody(a) - local bodyB = ode.GeomGetBody(b) - ode.JointAttach(joint, bodyA, bodyB) - end - end) - -- update the world - ode.WorldQuickStep(self.world, interval) - -- remove all contact joints - ode.JointGroupEmpty(self.contactGroup) - - -- update entity nodes - for id, physics in pairs(query) do - local x,y,z = ode.BodyGetPosition(physics._body) - local d,a,b,c = ode.BodyGetQuaternion(physics._body) - local node = self.db:getComponent(id, "node") - local q = Quaternion{a,b,c,d} - node.matrix - :identity() - :translate(Vec3{x,y,z}) - :mul(Quaternion{a,b,c,d}:toMat4()) - - local vel = physics.velocity - vel[1], vel[2], vel[3] = ode.BodyGetLinearVel(physics._body) - local avel = physics.angularVelocity - avel[1], avel[2], avel[3] = ode.BodyGetAngularVel(physics._body) - end - end - end, - } -end - - ---===== collision space =====-- - - -local function createGeom(self, id, collision) - local geom - if collision.class == "sphere" then - geom = ode.CreateSphere(self.space, collision.radius) - elseif collision.class == "capsule" then - geom = ode.CreateCapsule(self.space, collision.radius, collision.length) - elseif collision.class == "plane" then - local node = self.db:getComponent(id, "node") - local m = node.matrix - local normal = node.matrix:mulv3(Vec3{0,1,0}):normalize() - local position = Vec3{m[1][4], m[2][4], m[3][4]} - print(position) - local d = normal:dot(position) - print(normal, d) - geom = ode.CreatePlane(self.space, normal[1], normal[2], normal[3], d) - end - collision._geom = geom - collision._gc = honey.util.gc_canary(function() - print("release geom for id"..id) - ode.GeomDestroy(geom) - end) -end - -function collision(params) - local db = params.db - local space = params.space - return { - db=db, - space=space, - priority=0, - update = function(self, dt) - local query = self.db:queryComponent("collision") - for id, collision in pairs(query) do - if not collision._geom then - createGeom(self, id, collision) - print(id, collision._geom) - end - end - end - } -end - - -return module |