local gl = honey.gl local glfw = honey.glfw local ode = honey.ode local ecs = require 'honey.ecs.ecs' local collision = require 'honey.ecs.collision' local node = require 'honey.ecs.node' local image = require 'honey.asset.image' local shader = require 'honey.asset.shader' local mesh = require 'honey.asset.mesh' local glm = require 'honey.glm' local Vec3 = glm.Vec3 local Mat4 = glm.Mat4 local module = {} setmetatable(module, {__index=_G}) setfenv(1, module) local function drawMesh(program, uniforms, matrices, vao, count) gl.UseProgram(program) -- bind matrices shader.configure(program, { matrix={ model = matrices.model, view = matrices.view, projection = matrices.projection, }, }) -- bind textures local offset = 0 for name, tbl in pairs(uniforms.textures or {}) do local tex = image.get(tbl.filename) gl.BindTexture(gl.TEXTURE_2D + offset, tex) shader.setInt(program, name, offset) offset = offset+1 end -- configure additional uniforms shader.configure(program, uniforms) -- render mesh gl.BindVertexArray(vao) gl.DrawElements(gl.TRIANGLES, count, gl.UNSIGNED_INT, 0) end local function drawMeshes(db, view, projection) local meshes = db:queryComponent("renderMesh") for id, tbl in pairs(meshes) do -- get model matrix local node = db:getComponent(id, "node") local model = (node and node._matrix) or Mat4():identity() -- get shader program local program = shader.get(tbl.shader) -- get mesh local vao, count = mesh.get(tbl.mesh.filename, tbl.mesh.index) -- draw c: drawMesh(program, tbl.uniforms or {}, {view=view, model=model, projection=projection}, vao, count) end end local function drawGeoms(db, view, projection) -- draw wireframes gl.Enable(gl.CULL_FACE) gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE) gl.LineWidth(1) -- shader program for all geoms local program = shader.get{ vertex="builtin.basic3d.vert", fragment="builtin.color.frag" } local uniforms = { vec3 = { color = Vec3{ 1, 0, 1 }, }, } local query = db:queryComponent("collision") for id, tbl in pairs(query) do -- compute model matrix local m = Mat4():identity() m[1][4], m[2][4], m[3][4] = ode.GeomGetPosition(tbl._geom) 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.GeomGetRotation(tbl._geom) local matrices = { view=view, projection=projection, model=m, } -- get the mesh if tbl.class == "sphere" then m:scale(Vec3{tbl.radius, tbl.radius, tbl.radius}) local vao, count = mesh.get("builtin.hemisphere", 1) drawMesh(program, uniforms, matrices, vao, count) m:rotateX(math.pi) drawMesh(program, uniforms, matrices, vao, count) elseif tbl.class == "box" then m:scale(Vec3{tbl.lx, tbl.ly, tbl.lz}) local vao, count = mesh.get("builtin.cube", 1) drawMesh(program, uniforms, matrices, vao, count) elseif tbl.class == "capsule" then m:scale(Vec3{tbl.radius, tbl.length/2, tbl.radius}) local vao, count = mesh.get("builtin.tube", 1) drawMesh(program, uniforms, matrices, vao, count) m:scale(Vec3{1, 2*tbl.radius/tbl.length, 1}) :translate(Vec3{0, tbl.length/2, 0}) vao, count = mesh.get("builtin.hemisphere", 1) drawMesh(program, uniforms, matrices, vao, count) m:translate(Vec3{0, -tbl.length, 0}) :rotateX(math.pi) drawMesh(program, uniforms, matrices, vao, count) elseif tbl.class == "ray" then m:scale(Vec3{0.001, 0.001, tbl.length}) :translate(Vec3{0, 0, 1/2}) local vao, count = mesh.get("builtin.cube", 1) drawMesh(program, uniforms, matrices, vao, count) end end -- switch out of wireframe mode gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL) end local render = ecs.System("render", function(db, dt, p) for id, camera in pairs(db:queryComponent("camera")) do -- get camera's view and projection matrices local projection = camera.projection local view = Mat4() local node = db:getComponent(id, "node") if node then honey.glm.mat4_inv(node._matrix.data, view.data) else view:identity() end -- optionally draw collision geoms if p.drawGeoms then drawGeoms(db, view, projection) end -- render all scene meshes drawMeshes(db, view, projection) end end) render:addDependencies(node.system) render:addDependencies(collision.system) system = {render} return module