require 'honey.std' local glfw = honey.glfw local gl = honey.gl local Vec3 = honey.Vec3 local Mat4 = honey.Mat4 local ecs = honey.ecs local systems = honey.standardSystems local ode = honey.ode -- 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 -- create camera matrices local camera = { view=Mat4():identity():translate(Vec3{0, 0, -60}), projection=Mat4():perspective(math.rad(45), 640/480, 0.1, 100), } -- setup ecs local level = ecs.Level() level:addSystem(systems.transformCascade) level:addSystem(systems.renderCam(camera)) level:addSystem(systems.update) -- create shader local shader = honey.Shader{ vertexFile = "vertex.glsl", fragmentFile = "fragment.glsl", } -- load models local plane = honey.mesh.loadFile("assets/plane.obj")[1] local tetra = honey.mesh.loadFile("assets/tetrahedron.obj")[1] local cube = honey.mesh.loadFile("assets/cube.obj")[1] local octa = honey.mesh.loadFile("assets/octahedron.obj")[1] local dodeca = honey.mesh.loadFile("assets/dodecahedron.obj")[1] local icosa = honey.mesh.loadFile("assets/icosahedron.obj")[1] -- update function for each entity function updateTransform(self, dt) self.transform:rotateY(0.3 * math.pi * dt) self.transform:rotateX(0.1 * math.pi * dt) end -- create entities function growLine(prev, depth) if depth == 0 then return prev end local entity = { transform=Mat4():identity():translate(Vec3{2, 0, 0}), parent=false, mesh=octa, shader=shader, update=updateTransform, } prev.parent = entity level:addEntity(prev) return growLine(entity, depth-1) end local leaf = { transform=Mat4():identity():translate(Vec3{2, 0, 0}), parent=false, mesh=tetra, shader=shader, } local root = growLine(leaf, 24) root.update = function(self, dt) self.transform:rotateY(0.2 * math.pi * dt) end level:addEntity(root) local groundPlane = { transform=Mat4():identity():translate(Vec3{0, -2, 0}):scale(Vec3{10, 10, 10}), parent=false, mesh=plane, shader=shader, } level:addEntity(groundPlane) local ball = { transform=Mat4():identity(), 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, } level:addEntity(ball) -- close window on ESCAPE key window:setKeyCallback(function(_, key) if key == glfw.KEY_ESCAPE then window:setShouldClose(true) end end) -- resize window correctly window:setFramebufferSizeCallback(function(_, width, height) gl.Viewport(0, 0, width, height) camera.projection:perspectiveResize(width/height) end) -- 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() end) -- clean up honey.terminate()