summaryrefslogtreecommitdiff
path: root/honey/ecs-systems.lua
diff options
context:
space:
mode:
authorsanine-a <sanine.not@pm.me>2023-05-09 11:31:17 -0500
committersanine-a <sanine.not@pm.me>2023-05-09 11:31:17 -0500
commita2ae7aae8357c8c2684d85fd58b0c5a0563ebab9 (patch)
tree5050161547408c80b521c9f4708bb9f7a9d0fa71 /honey/ecs-systems.lua
parent2a14abecaee073aef1f1966bb397d6086b2e4785 (diff)
refactor: split ecs systems into multiple files
Diffstat (limited to 'honey/ecs-systems.lua')
-rw-r--r--honey/ecs-systems.lua375
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