summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsanine-a <sanine.not@pm.me>2023-03-23 13:35:37 -0500
committersanine-a <sanine.not@pm.me>2023-03-23 13:35:37 -0500
commite5553bb81c93cd76456d07d3a1d7e8bb1b249b6e (patch)
treea92801deaba55c85dd4f52636ab4f616e8483796
parentf4346b8f06653dbc1e0c346d88f5f83ca8a7b876 (diff)
implement skeleton of physics system
-rw-r--r--assets/november.regular.ttfbin0 -> 11056 bytes
-rw-r--r--honey/ecs-systems.lua8
-rw-r--r--honey/ecs.lua19
-rw-r--r--honey/mat4.lua6
-rw-r--r--honey/quaternion.lua30
-rw-r--r--honey/std.lua1
-rw-r--r--main.lua139
7 files changed, 146 insertions, 57 deletions
diff --git a/assets/november.regular.ttf b/assets/november.regular.ttf
new file mode 100644
index 0000000..778df78
--- /dev/null
+++ b/assets/november.regular.ttf
Binary files differ
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'
diff --git a/main.lua b/main.lua
index 9f26eb3..2c92223 100644
--- a/main.lua
+++ b/main.lua
@@ -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