From 64194866e9a1d6991efc9f44a0e3075905ab6470 Mon Sep 17 00:00:00 2001 From: sanine Date: Fri, 14 Apr 2023 00:55:50 -0500 Subject: begin physics reimplementation --- honey/ecs-systems.lua | 54 ++++++++++++++++++++++++++++++-- main.lua | 86 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 107 insertions(+), 33 deletions(-) diff --git a/honey/ecs-systems.lua b/honey/ecs-systems.lua index ed51e5d..cfd5675 100644 --- a/honey/ecs-systems.lua +++ b/honey/ecs-systems.lua @@ -1,6 +1,10 @@ local ecs = require 'honey.ecs' +local glm = require 'honey.glm' +local Vec3 = glm.Vec3 +local Quaternion = glm.Quaternion local gl = honey.gl local glfw = honey.glfw +local ode = honey.ode local module = {} @@ -36,6 +40,8 @@ end transform = function(params) return { db = params.db, + + priority = 1, update = function(self, dt) local entities = self.db:queryComponent("transform") @@ -66,7 +72,6 @@ transform = function(params) recursiveTransform(transform) end end, - priority = 0, } end @@ -160,9 +165,50 @@ physics = function(params) world=params.world, contactGroup=ode.JointGroupCreate(groupSize), time=interval, + + priority=0, update=function(self, dt) local query = self.db:queryComponent("physics") - -- TODO: create physics bodies + for id, physics in pairs(query) do + if not physics._body then + physics._body = ode.BodyCreate(self.world) + 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 + ) + end + ode.BodySetMass(physics._body, mass) + local m = self.db:getComponent(id, "transform").matrix + ode.BodySetPosition( + physics._body, + m[1][4], m[2][4], m[3][4] + ) + ode.BodySetRotation( + physics._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] + ) + ode.BodySetLinearVel( + physics._body, + physics.velocity[1], + physics.velocity[2], + physics.velocity[3] + ) + ode.BodySetAngularVel( + physics._body, + physics.angularVelocity[1], + physics.angularVelocity[2], + physics.angularVelocity[3] + ) + end + end self.time = self.time + dt -- only run the update every [interval] seconds @@ -204,7 +250,9 @@ physics = function(params) for id, physics in pairs(query) do local x,y,z = ode.BodyGetPosition(physics._body) local d,a,b,c = ode.BodyGetQuaternion(physics._body) - entity.transform + local transform = self.db:getComponent(id, "transform") + local q = Quaternion{a,b,c,d} + transform.matrix :identity() :translate(Vec3{x,y,z}) :mul(Quaternion{a,b,c,d}:toMat4()) diff --git a/main.lua b/main.lua index a686daa..16e27e6 100644 --- a/main.lua +++ b/main.lua @@ -7,6 +7,7 @@ local Mat4 = honey.Mat4 local Quaternion = honey.Quaternion local ecs = honey.ecs local sys = honey.standardSystems +local dispatch = sys.dispatch local ode = honey.ode local nvg = honey.nvg @@ -19,6 +20,16 @@ local vg = nvg.CreateContext() local november = nvg.CreateFont(vg, "November", "assets/november.regular.ttf") local vw, vh = 640, 480 +-- setup physics +local space = ode.HashSpaceCreate(ode.Space0) +local world = ode.WorldCreate() +ode.WorldSetGravity(world, 0, -10, 0) +ode.WorldSetCFM(world, 1e-5) +local physicsGc = honey.util.gc_canary(function() + ode.SpaceDestroy(space) + ode.WorldDestroy(world) +end) + -- setup ecs local entities = ecs.EntityDb() @@ -32,63 +43,78 @@ entities:addComponents(camera, { transform={ matrix=Mat4():identity():translate(Vec3{0, 0, -6}), }, + z = {value=-6}, script={ script="cameraRotationScript", }, + onKey = { + script="cameraKeyHandler", + }, }) ---entities:addComponent(camera, "camera", { --- projection=Mat4():perspective(math.rad(45), 640/480, 0.1, 100), ---}) ---entities:addComponent(camera, "transform", { --- matrix=Mat4():identity():translate(Vec3{0, 0, -6}), ---}) ---entities:addComponent(camera, "script", { --- name = "cameraRotationScript", ---}) --- systems:addSystem(sys.transform) systems:addSystem(sys.renderCamera, {camera=camera}) systems:addSystem(sys.script) +systems:addSystem(sys.physics, {space=space, world=world}) package.loaded['baseRotationScript'] = function(entities, id, dt) local transform = entities:getComponent(id, "transform") transform.matrix:rotateZ(math.pi * dt) end package.loaded['cameraRotationScript'] = function(entities, id, dt) local transform = entities:getComponent(id, "transform") - transform.matrix:identity():translate(Vec3{0, 0, -6 + math.sin(math.pi * glfw.GetTime())}) + local z = entities:getComponent(id, "z") + transform.matrix + :identity() + :translate(Vec3{0, 0, z.value + math.sin(math.pi * glfw.GetTime())}) +end +package.loaded['cameraKeyHandler'] = function(entities, id, data) + local z = entities:getComponent(id, "z") + if data.key == glfw.KEY_W then + z.value = z.value + 1 + elseif data.key == glfw.KEY_S then + z.value = z.value - 1 + end end local id = entities:createEntity() -entities:addComponent(id, "renderMesh", { - textures = { - ourTexture={ filename="77155.png" }, +entities:addComponents(id, { + renderMesh = { + textures = { ourTexture={ filename="77155.png" } }, + shader = { vertex="vertex.glsl", fragment="fragment.glsl" }, + mesh = { filename="assets/icosahedron.obj", index=1 }, + }, + transform = { + matrix = Mat4():identity():rotateZ(math.rad(45)), + }, + physics = { + mass = { + class = "sphere", + density = 1, + radius = 1, + }, + velocity = Vec3{ 0, 0, 0 }, + angularVelocity = Vec3{ 0, 0, 0 }, }, - shader = { vertex="vertex.glsl", fragment="fragment.glsl" }, - mesh = { filename="assets/icosahedron.obj", index=1 }, -}) -entities:addComponent(id, "transform", { - matrix = Mat4():identity():rotateZ(math.rad(45)), -}) -entities:addComponent(id, "script", { - script = "baseRotationScript", }) local id2 = entities:createEntity() -entities:addComponent(id2, "renderMesh", { - shader = { vertex="vertex.glsl", fragment="fragment.glsl" }, - mesh = { filename="assets/tetrahedron.obj", index=1 }, -}) -entities:addComponent(id2, "transform", { - parent=id, - matrix=Mat4():identity():translate(Vec3{0, 2, 0}), +entities:addComponents(id2, { + renderMesh = { + shader = { vertex="vertex.glsl", fragment="fragment.glsl" }, + mesh = { filename="assets/tetrahedron.obj", index=1 }, + }, + transform = { + parent=id, + matrix=Mat4():identity():translate(Vec3{0, 2, 0}), + }, }) -- close window on ESCAPE key window:setKeyCallback(function(_, key, scancode, action) + dispatch(entities, "onKey", {key=key, scancode=scancode, action=action}) if action == glfw.PRESS then if key == glfw.KEY_ESCAPE then window:setShouldClose(true) @@ -100,7 +126,7 @@ end) window:setFramebufferSizeCallback(function(_, width, height) gl.Viewport(0, 0, width, height) vw, vh = width, height - sys.dispatch(entities, "onWindowResize", { width=width, height=height }) + dispatch(entities, "onWindowResize", { width=width, height=height }) end) package.loaded["cameraHandleResize"] = function(entities, id, data) -- cgit v1.2.1