diff options
author | sanine-a <sanine.not@pm.me> | 2023-03-23 13:35:37 -0500 |
---|---|---|
committer | sanine-a <sanine.not@pm.me> | 2023-03-23 13:35:37 -0500 |
commit | e5553bb81c93cd76456d07d3a1d7e8bb1b249b6e (patch) | |
tree | a92801deaba55c85dd4f52636ab4f616e8483796 | |
parent | f4346b8f06653dbc1e0c346d88f5f83ca8a7b876 (diff) |
implement skeleton of physics system
-rw-r--r-- | assets/november.regular.ttf | bin | 0 -> 11056 bytes | |||
-rw-r--r-- | honey/ecs-systems.lua | 8 | ||||
-rw-r--r-- | honey/ecs.lua | 19 | ||||
-rw-r--r-- | honey/mat4.lua | 6 | ||||
-rw-r--r-- | honey/quaternion.lua | 30 | ||||
-rw-r--r-- | honey/std.lua | 1 | ||||
-rw-r--r-- | main.lua | 139 |
7 files changed, 146 insertions, 57 deletions
diff --git a/assets/november.regular.ttf b/assets/november.regular.ttf Binary files differnew file mode 100644 index 0000000..778df78 --- /dev/null +++ b/assets/november.regular.ttf diff --git a/honey/ecs-systems.lua b/honey/ecs-systems.lua index a511b3d..237aa78 100644 --- a/honey/ecs-systems.lua +++ b/honey/ecs-systems.lua @@ -28,11 +28,11 @@ end -- update transforms
transformCascade = {
filter=ecs.Filter.AND{"transform", "parent"},
- preUpdate=function(entity)
+ prepareEntity=function(self, entity)
entity._transform = nil
entity._transformComputed = false
end,
- update=function(entity, dt)
+ update=function(self, entity, dt)
recursiveComputeTransform(entity)
end,
priority=98,
@@ -45,7 +45,7 @@ function renderCam(camera, priority) local priority = priority or 99
return {
filter=ecs.Filter.AND{"mesh", "shader", "transform"},
- update=function(entity, dt)
+ update=function(self, entity, dt)
entity.shader:use()
entity.shader:configure{
matrix={
@@ -64,7 +64,7 @@ end update = {
filter=ecs.Filter.AND{"update"},
- update=function(entity, dt)
+ update=function(self, entity, dt)
entity.update(entity, dt)
end,
priority=50,
diff --git a/honey/ecs.lua b/honey/ecs.lua index 23bb0ba..d611b37 100644 --- a/honey/ecs.lua +++ b/honey/ecs.lua @@ -123,6 +123,9 @@ function Level.addSystem(self, system) system.entities = {} table.insert(self.systems, system) table.sort(self.systems, systemLt) + if system.setup then + system.setup(system) + end end @@ -131,7 +134,7 @@ local function addEntityToSystem(system, id, entity) if system.entities[id] then return end if system.onAddEntity then - system.onAddEntity(id, entity) + system:onAddEntity(id, entity) end system.entities[id] = true end @@ -142,7 +145,7 @@ local function removeEntityFromSystem(system, id, entity) if not system.entities[id] then return end if system.onRemoveEntity then - system.onRemoveEntity(id, entity) + system:onRemoveEntity(id, entity) end system.entities[id] = nil end @@ -195,20 +198,20 @@ end function Level.update(self, dt) for _, system in ipairs(self.systems) do if system.preUpdate then + system:preUpdate() + end + if system.prepareEntity then for id in pairs(system.entities) do local entity = self.entities[id] - system.preUpdate(entity) + system:prepareEntity(entity) end end for id in pairs(system.entities) do local entity = self.entities[id] - system.update(entity, dt) + system:update(entity, dt) end if system.postUpdate then - for id in pairs(system.entities) do - local entity = self.entities[id] - system.postUpdate(entity) - end + system:postUpdate() end end end diff --git a/honey/mat4.lua b/honey/mat4.lua index 6ea17fd..cdc5e7d 100644 --- a/honey/mat4.lua +++ b/honey/mat4.lua @@ -114,6 +114,12 @@ function Mat4.zero(self) end +function Mat4.mul(self, other) + glm.mat4_mul(self.data, other.data, self.data) + return self +end + + function Mat4.translate(self, vec) glm.translate(self.data, vec.data) return self diff --git a/honey/quaternion.lua b/honey/quaternion.lua new file mode 100644 index 0000000..6fbfdd5 --- /dev/null +++ b/honey/quaternion.lua @@ -0,0 +1,30 @@ +local glm = honey.glm
+local Mat4 = require "honey.mat4"
+
+local module = {}
+setmetatable(module, {__index=_G})
+setfenv(1, module)
+
+Quaternion = {}
+Quaternion.__index = Quaternion
+
+
+function Quaternion.new(_, tbl)
+ local tbl = tbl or { 0, 0, 0, 0 }
+ local self = {}
+ self.data = glm.quat_create()
+ glm.quat_init(self.data, unpack(tbl))
+ setmetatable(self, Quaternion)
+ return self
+end
+setmetatable(Quaternion, {__call=Quaternion.new})
+
+
+function Quaternion.toMat4(self)
+ local m = Mat4()
+ glm.quat_mat4(self.data, m.data)
+ return m
+end
+
+
+return module.Quaternion
diff --git a/honey/std.lua b/honey/std.lua index 7cb7695..80b071e 100644 --- a/honey/std.lua +++ b/honey/std.lua @@ -11,3 +11,4 @@ honey.mesh = require 'honey.mesh' honey.Shader = require 'honey.shader' honey.Vec3 = require 'honey.vec3' honey.Window = require 'honey.window' +honey.Quaternion = require 'honey.quaternion' @@ -4,54 +4,20 @@ local glfw = honey.glfw local gl = honey.gl local Vec3 = honey.Vec3 local Mat4 = honey.Mat4 +local Quaternion = honey.Quaternion local ecs = honey.ecs local systems = honey.standardSystems local ode = honey.ode +local nvg = honey.nvg -- initialize honey local window = honey.init() --- setup physics -local world = ode.WorldCreate() -local space = ode.HashSpaceCreate(ode.Space0) -ode.WorldSetGravity(world, 0, -10, 0) -ode.WorldSetCFM(world, 1e-5) -ode.CreatePlane(space, 0, 1, 0, 0) -local contactgroup = ode.JointGroupCreate(16) -local body = ode.BodyCreate(world) -local geom = ode.CreateSphere(space, 0.5) -local mass = ode.MassCreate() -ode.MassSetSphere(mass, 1, 0.5) -ode.BodySetMass(body, mass) -ode.GeomSetBody(geom, body) -ode.BodySetPosition(body, 0, 3, 0) - -function physicsStep() - ode.SpaceCollide(space, function(o1, o2) - local b1 = ode.GeomGetBody(o1) - local b2 = ode.GeomGetBody(o2) - local contact = ode.CreateContact{ - surface = { - mode = ode.ContactBounce + ode.ContactSoftCFM, - mu = ode.Infinity, - bounce = 1.0, - bounce_vel = 0.1, - soft_cfm = 0.001, - }, - } - local collisions = ode.Collide(o1, o2, 1) - if #collisions > 0 then - print("collision detected!") - ode.ContactSetGeom(contact, collisions[1]) - local joint = ode.JointCreateContact(world, contactgroup, contact) - ode.JointAttach(joint, b1, b2) - end - end) - ode.WorldQuickStep(world, 0.01) - ode.JointGroupEmpty(contactgroup) -end - +-- setup vector graphics +local vg = nvg.CreateContext() +local november = nvg.CreateFont(vg, "November", "assets/november.regular.ttf") +local vw, vh = 640, 480 -- create camera matrices local camera = { @@ -65,6 +31,63 @@ level:addSystem(systems.transformCascade) level:addSystem(systems.renderCam(camera)) level:addSystem(systems.update) +-- physics system +local world = ode.WorldCreate() +local space = ode.HashSpaceCreate(ode.Space0) +level:addSystem{ + setup=function(self) + self.time = 0 + self.world=world + self.space=space + ode.WorldSetGravity(self.world, 0, -10, 0) + ode.WorldSetCFM(self.world, 1e-5) + self.contactgroup = ode.JointGroupCreate(32) + self.__gc = honey.util.gc_canary(function() + ode.WorldDestroy(self.world) + ode.SpaceDestroy(self.space) + end) + end, + filter = ecs.Filter.AND{"transform", "collisionShape", "physicsBody"}, + preUpdate = function(self) + self.dt = nil + if self.time > 0.01 then + self.time = self.time - 0.01 + ode.SpaceCollide(self.space, function(o1, o2) + local b1 = ode.GeomGetBody(o1) + local b2 = ode.GeomGetBody(o2) + local contact = ode.CreateContact{ + surface = { + mode = ode.ContactBounce + ode.ContactSoftCFM, + mu = ode.Infinity, + bounce = 0.99, + bounce_vel = 0.1, + soft_cfm = 0.001, + }, + } + local collisions = ode.Collide(o1, o2, 1) + if #collisions > 0 then + print("collision detected!") + ode.ContactSetGeom(contact, collisions[1]) + local joint = ode.JointCreateContact(self.world, self.contactgroup, contact) + ode.JointAttach(joint, b1, b2) + end + end) + ode.WorldQuickStep(self.world, 0.01) + ode.JointGroupEmpty(self.contactgroup) + end + end, + update = function(self, entity, dt) + if not self.dt then + self.dt = dt + self.time = self.time + dt + end + + local x, y, z = ode.BodyGetPosition(entity.physicsBody) + local a, b, c, d = ode.BodyGetQuaternion(entity.physicsBody) + entity.transform:identity():translate(Vec3{x, y, z}):mul(Quaternion{a, b, c, d}:toMat4()) + end, +} + -- create shader local shader = honey.Shader{ vertexFile = "vertex.glsl", @@ -127,13 +150,20 @@ local ball = { parent=false, mesh=icosa, shader=shader, - update=function(self, dt) - local x, y, z = ode.BodyGetPosition(body) - self.transform:identity():translate(Vec3{x, y, z}) - end, + collisionShape=ode.CreateSphere(space, 0.5), + physicsBody=ode.BodyCreate(world), } level:addEntity(ball) +local mass = ode.MassCreate() +ode.MassSetSphere(mass, 1, 0.5) +ode.BodySetMass(ball.physicsBody, mass) +ode.GeomSetBody(ball.collisionShape, ball.physicsBody) +ode.BodySetPosition(ball.physicsBody, 0, 3, 0) +ode.BodySetLinearVel(ball.physicsBody, 1, 0, 0) + +ode.CreatePlane(space, 0, 1, 0, -2) + -- close window on ESCAPE key window:setKeyCallback(function(_, key) if key == glfw.KEY_ESCAPE then @@ -145,14 +175,33 @@ end) window:setFramebufferSizeCallback(function(_, width, height) gl.Viewport(0, 0, width, height) camera.projection:perspectiveResize(width/height) + vw, vh = width, height end) +-- averager (for fps) +function averager(memory) + local buf = {} + local avg = 0 + for i=1,memory do table.insert(buf, 0) end + return function(value) + table.insert(buf, value) + local val = table.remove(buf, 1) + avg = avg + value - val + return avg / memory + end +end +local fpsAverage = averager(200) + -- main loop honey.loop(window, function(dt) gl.ClearColor(0.2, 0.4, 1.0, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT) level:update(dt) - physicsStep() + nvg.BeginFrame(vg, vw, vh, 1.0) + nvg.StrokeColor(vg, nvg.RGBf(1, 1, 1)) + nvg.FontFace(vg, "November") + nvg.Text(vg, 50, 50, "fps: "..tostring(math.floor(fpsAverage(1/dt)))) + nvg.EndFrame(vg) end) -- clean up |