summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--honey/asset/mesh.lua12
-rw-r--r--honey/asset/shader.lua4
-rw-r--r--honey/ecs/ecs.lua6
-rw-r--r--honey/ecs/node.lua77
-rw-r--r--honey/ecs/render.lua144
-rw-r--r--honey/ecs/script.lua28
-rw-r--r--honey/init.lua26
-rw-r--r--honey/notes.md1
-rw-r--r--honey/std.lua10
-rw-r--r--main.lua231
10 files changed, 183 insertions, 356 deletions
diff --git a/honey/asset/mesh.lua b/honey/asset/mesh.lua
index 876c5e4..5e0a26d 100644
--- a/honey/asset/mesh.lua
+++ b/honey/asset/mesh.lua
@@ -136,14 +136,20 @@ end
--===== builtin meshes =====--
-function createBuiltins()
- cache["builtin.quad"] = {Mesh(
+local function builtin(name, vertices, indices)
+ local vao, vbo, ebo, count = createMesh(vertices, indices)
+ cache[name] = { {vao=vao, vbo=vbo, ebo=ebo, count=count } }
+end
+
+init = function()
+ builtin(
+ "builtin.quad",
{ 0, 0, 0, 0, 1, 0, 0, 0,
1, 0, 0, 0, 1, 0, 1, 0,
0, 1, 0, 0, 1, 0, 0, 1,
1, 1, 0, 0, 1, 0, 1, 1 },
{ 0, 1, 3, 0, 3, 2 }
- )}
+ )
end
diff --git a/honey/asset/shader.lua b/honey/asset/shader.lua
index 0e8c93a..a23c17b 100644
--- a/honey/asset/shader.lua
+++ b/honey/asset/shader.lua
@@ -35,8 +35,8 @@ local function buildProgram(sources)
local shader = compileShader(readFile(sources.vertex), gl.VERTEX_SHADER)
table.insert(shaders, shader)
end
- if sources.vertex then
- local shader = compileShader(readFile(sources.vertex), gl.VERTEX_SHADER)
+ if sources.fragment then
+ local shader = compileShader(readFile(sources.fragment), gl.FRAGMENT_SHADER)
table.insert(shaders, shader)
end
diff --git a/honey/ecs/ecs.lua b/honey/ecs/ecs.lua
index d7eb4ac..0c84041 100644
--- a/honey/ecs/ecs.lua
+++ b/honey/ecs/ecs.lua
@@ -77,11 +77,9 @@ end
-- load database from file
function EntityDb.load(self, filename)
- print(collectgarbage("count"))
self.entities = {}
self.components = {}
collectgarbage()
- print(collectgarbage("count"))
local env = {
Entity = function(id, components)
self:createEntity(id)
@@ -320,7 +318,6 @@ function SystemDb.update(self, dt)
-- check for dangling dependencies
local dangle = ""
for dependency in pairs(self.dangling) do
- print(dependency)
dangle = dangle .. string.format(
"unresolved dangling dependency: %s\n",
dependency
@@ -330,11 +327,10 @@ function SystemDb.update(self, dt)
error(dangle)
end
-
for _, name in ipairs(self.sort) do
local system = self.systems[name]
local params = self.params[name]
- system.f(self.db, dt, params)
+ system.f(self.entityDb, dt, params)
end
end
diff --git a/honey/ecs/node.lua b/honey/ecs/node.lua
index 4953af5..6a47a1f 100644
--- a/honey/ecs/node.lua
+++ b/honey/ecs/node.lua
@@ -1,52 +1,47 @@
+local ecs = require 'honey.ecs.ecs'
+
local module = {}
setmetatable(module, {__index=_G})
setfenv(1, module)
--===== transform cascading =====--
-system = function(params)
- return {
- db = params.db,
-
- priority = 2,
- update = function(self, dt)
- local nodes = self.db:queryComponent("node")
-
- -- prepare nodes
- for id, node in pairs(nodes) do
- node._visited = false
- node._child = nil
- end
-
- -- helper function
- local function recursiveTransform(id, node)
- if node._visited then
- return node._matrix
- end
-
- if not node.parent then
- node._matrix = node.matrix
- else
- local parentNode = self.db:getComponent(node.parent, "node")
- local parentMatrix = recursiveTransform(node.parent, parentNode)
- node._matrix = parentMatrix * node.matrix
- if node.name then
- if not parentNode._child then parentNode._child = {} end
- parentNode._child[node.name] = honey.ecs.Accessor(self.db, id)
- end
- end
- node._visited = true
- return node._matrix
- end
-
- -- compute nodes
- for id, node in pairs(nodes) do
- recursiveTransform(id, node)
- end
- end,
- }
+local function recursiveTransform(db, id, node)
+ if node._visited then
+ return node._matrix
+ end
+
+ if not node.parent then
+ node._matrix = node.matrix
+ else
+ local parentNode = db:getComponent(node.parent, "node")
+ local parentMatrix = recursiveTransform(db, node.parent, parentNode)
+ node._matrix = parentMatrix * node.matrix
+ if node.name then
+ if not parentNode._child then parentNode._child = {} end
+ parentNode._child[node.name] = ecs.Accessor(db, id)
+ end
+ end
+ node._visited = true
+ return node._matrix
end
+system = {ecs.System("node", function(db, dt, params)
+ local nodes = db:queryComponent("node")
+
+ -- prepare nodes
+ for id, node in pairs(nodes) do
+ node._visited = false
+ node._child = nil
+ end
+
+ -- compute nodes
+ for id, node in pairs(nodes) do
+ recursiveTransform(db, id, node)
+ end
+end)}
+
+
return module
diff --git a/honey/ecs/render.lua b/honey/ecs/render.lua
index 1e41e7a..8cca6cf 100644
--- a/honey/ecs/render.lua
+++ b/honey/ecs/render.lua
@@ -1,3 +1,9 @@
+local ecs = require 'honey.ecs.ecs'
+
+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
@@ -5,103 +11,77 @@ local Mat4 = glm.Mat4
local gl = honey.gl
local glfw = honey.glfw
+local node = require 'honey.ecs.node'
+
local module = {}
setmetatable(module, {__index=_G})
setfenv(1, module)
--===== rendering =====--
-function draw(model, view, projection, textures, shader, mesh)
- shader:use()
+local function drawMesh(program, uniforms, matrices, vao, count)
+ gl.UseProgram(program)
- -- bind textures
- local texOffset = 0
- for name, texTbl in pairs(textures or {}) do
- local texture = honey.image.loadImage(texTbl.filename, texTbl.params)
- gl.BindTexture(gl.TEXTURE_2D + texOffset, texture.texture)
- shader:setInt(name, texOffset)
- texOffset = texOffset + 1
- end
-
- -- configure default uniforms
- shader:configure{
- float={
- time=glfw.GetTime(),
- },
+ -- bind matrices
+ shader.configure(program, {
matrix={
- view=view,
- projection=projection,
- model=model,
+ model = matrices.model,
+ view = matrices.view,
+ projection = matrices.projection,
},
- }
+ })
- -- draw mesh
- mesh:drawElements()
-
- -- unbind textures
- for i=0,texOffset-1 do
- gl.BindTexture(gl.TEXTURE_2D + i, 0)
+ -- 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
-system = function(params)
- return {
- db = params.db,
- priority = params.priority or 99,
- update = function(self, dt)
- for id, camera in pairs(self.db:queryComponent("camera")) do
- local projection = camera.projection
- local cameraTransform = self.db:getComponent(id, "node")
- local view = Mat4()
- if cameraTransform then
- honey.glm.mat4_inv(cameraTransform._matrix.data, view.data)
- else
- view:identity()
- 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
- local entities = self.db:queryComponent("renderMesh")
- for entity, tbl in pairs(entities) do
- -- get model
- local node = self.db:getComponent(entity, "node")
- local model =
- (node and node._matrix) or
- Mat4():identity()
- -- get shader
- if not tbl.shader then
- print(node)
- print(node and node._matrix)
- print(node and node.name)
- print(node and node.parent)
- for k, v in pairs(tbl) do
- print(k, v)
- end
- end
- local shader = honey.shader.loadShader(
- tbl.shader.vertex, tbl.shader.fragment
- )
- -- get mesh
- local mesh = honey.mesh.loadCached(
- tbl.mesh.filename, tbl.mesh.index, tbl.mesh.debug
- )
- draw(model, view, projection, tbl.textures, shader, mesh)
- end
-
- entities = self.db:queryComponent("renderQuad")
- local quadmesh = honey.mesh.loadCached("builtin.quad", 1)
- for entity, tbl in pairs(entities) do
- -- get model
- local model = Mat4():identity()
- -- get shader
- local shader = honey.shader.loadShader(
- tbl.shader.vertex, tbl.shader.fragment
- )
- draw(model, view, projection, tbl.textures, shader, quadmesh)
- end
- end
- end,
- }
-end
+ -- iterate over all scene meshes
+ 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
+end)
+render:addDependencies(node.system)
+system = {render}
return module
diff --git a/honey/ecs/script.lua b/honey/ecs/script.lua
index 9ae7d72..46af4fa 100644
--- a/honey/ecs/script.lua
+++ b/honey/ecs/script.lua
@@ -1,3 +1,6 @@
+local ecs = require 'honey.ecs.ecs'
+local node = require 'honey.ecs.node'
+
local module = {}
setmetatable(module, {__index=_G})
setfenv(1, module)
@@ -16,8 +19,8 @@ end
--===== dispatch messages to handlers =====--
-dispatch = function(entities, msg, data)
- local query = entities:queryComponent(msg)
+dispatch = function(db, msg, data)
+ local query = db:queryComponent(msg)
for id, handler in pairs(query) do
local f = getFunction(handler)
f(entities, id, data)
@@ -26,19 +29,16 @@ end
--===== script system =====--
-system = function(params)
- return {
- db=params.db,
- update=function(self, dt)
- local entities = self.db:queryComponent("script")
- for id, script in pairs(entities) do
- local f = getFunction(script)
- f(self.db, id, dt)
- end
- end
- }
-end
+local script = ecs.System("script", function(db, dt, params)
+ local entities = db:queryComponent("script")
+ for id, script in pairs(entities) do
+ local f = getFunction(script)
+ f(db, id, dt)
+ end
+end)
+script:addDependencies(node.system)
+system = {script}
return module
diff --git a/honey/init.lua b/honey/init.lua
index d2f5279..7ceee2f 100644
--- a/honey/init.lua
+++ b/honey/init.lua
@@ -1,13 +1,10 @@
local glfw = honey.glfw
local gl = honey.gl
-local window = require 'honey.window'
-local module = {}
-setmetatable(module, {__index=_G})
-setfenv(1, module)
+local mesh = require 'honey.asset.mesh'
-function init(width, height, title)
+function honey.init(width, height, title)
local width = width or 640
local height = height or 480
local title = title or "honey3d"
@@ -16,34 +13,29 @@ function init(width, height, title)
glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 4)
glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 1)
- local window = honey.Window(width, height, title)
- glfw.MakeContextCurrent(window.win)
+ honey.window = glfw.CreateWindow(width, height, title, glfw.monitor_NULL, glfw.window_NULL)
+ glfw.MakeContextCurrent(honey.window)
gl.InitGlad()
gl.Enable(gl.DEPTH_TEST)
honey.ode.InitODE()
- honey.mesh.createBuiltins()
-
- return window
+ mesh.init()
end
-function loop(window, update)
+function honey.loop(update)
local prevTime = 0
- while not window:shouldClose() do
+ while glfw.WindowShouldClose(honey.window) == glfw.FALSE do
local time = glfw.GetTime()
local dt = time - prevTime
prevTime = time
update(dt)
- window:swapBuffers()
+ glfw.SwapBuffers(honey.window)
glfw.PollEvents()
end
end
-function terminate()
+function honey.terminate()
glfw.Terminate()
end
-
-
-return module
diff --git a/honey/notes.md b/honey/notes.md
index 16ccc49..863c019 100644
--- a/honey/notes.md
+++ b/honey/notes.md
@@ -9,6 +9,7 @@ assets are cached. each asset type has a module (e.g. `mesh`, `image`, `sound`,
* `get(filename)` - cached load of the given file. throws error if it cannot be found
* `forget(filename` - remove the cached copy, if any of the given file
* `clearCache()` - clear the full cache for that asset type
+ * `init()` - optional, initializes any builtins that must come after opengl or other things
individual assets may have additional functions.
diff --git a/honey/std.lua b/honey/std.lua
index 222798c..8b70699 100644
--- a/honey/std.lua
+++ b/honey/std.lua
@@ -1,15 +1,15 @@
local init = require 'honey.init'
-honey.init = init.init
-honey.loop = init.loop
-honey.terminate = init.terminate
-
honey.asset = {}
honey.asset.image = require 'honey.asset.image'
honey.asset.mesh = require 'honey.asset.mesh'
honey.asset.shader = require 'honey.asset.shader'
-honey.ecs = require 'honey.ecs'
+
+honey.ecs = require 'honey.ecs.ecs'
+honey.ecs.node = require 'honey.ecs.node'
+honey.ecs.render = require 'honey.ecs.render'
+honey.ecs.script = require 'honey.ecs.script'
-- glm is so frequently used that we load it globally, not locally
diff --git a/main.lua b/main.lua
index 10ffebe..c251071 100644
--- a/main.lua
+++ b/main.lua
@@ -1,197 +1,54 @@
require 'honey.std'
--- initialize honey
-window = honey.init()
-window:setInputMode(glfw.CURSOR, glfw.CURSOR_DISABLED)
-
--- setup vector graphics
-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 = honey.ecs.EntityDb()
-local systems = honey.ecs.SystemDb(entities)
-local script = honey.ecs.script
-systems:addSystem(honey.ecs.node.system)
-systems:addSystem(honey.ecs.render.system)
-systems:addSystem(honey.ecs.script.system)
-systems:addSystem(honey.ecs.collision.system, {space=space})
-systems:addSystem(honey.ecs.physics.system, {space=space, world=world})
-
-function setupEntities()
- local terrain = entities:createEntityWithComponents{
- node = {
- matrix = Mat4():identity():translate(Vec3{4,0,0}),
- },
- renderMesh = {
- textures = {
- ourTexture = {
- filename = "assets/green+grass-1024x1024.jpg",
- },
- },
- shader = {
- vertex = "vertex.glsl",
- fragment = "fragment.glsl",
- },
- mesh = { filename = "assets/terrain.obj", index=1 },
- },
- collision = {
- class = "trimesh",
- filename = "assets/terrain.obj",
- },
- }
-
--- local plane = entities:createEntity()
--- entities:addComponents(plane, {
--- node = {
--- matrix = Mat4()
--- :identity()
--- :rotateZ(math.rad(5))
--- },
--- collision = {
--- class = "plane",
--- },
--- })
---
--- local planeMesh = entities:createEntityWithComponents{
--- node = {
--- parent = plane,
--- matrix = Mat4():identity():rotateX(0.5*math.pi):scale(Vec3{20,20,20}),
--- },
--- renderMesh = {
--- textures = {
--- ourTexture={
--- filename="assets/green+grass-1024x1024.jpg"
--- }
--- },
--- shader = { vertex="vertex.glsl", fragment="fragment.glsl" },
--- mesh = { filename="builtin.quad", index=1 },
--- },
--- }
-
-
-
- local id = entities:createEntity()
- entities:addComponents(id, {
- renderMesh = {
- textures = {
- ourTexture={ filename="77155.png" }
- },
- shader = { vertex="vertex.glsl", fragment="fragment.glsl" },
- mesh = { filename="assets/icosahedron.obj", index=1 },
- },
- node = {
- matrix = Mat4()
- :identity()
- :translate(Vec3{0,1,0})
- :rotateZ(math.rad(45)),
- },
- collision = {
- class = "sphere",
- radius = 1,
- },
- physics = {
- mass = {
- class = "sphere",
- density = 1,
- radius = 1,
- },
- surface = true,
- velocity = Vec3{ 0, 0, 0 },
- angularVelocity = Vec3{ 0, 0, 0 },
- },
- })
-
- local id2 = entities:createEntity()
- entities:addComponents(id2, {
- renderMesh = {
- shader = { vertex="vertex.glsl", fragment="fragment.glsl" },
- --mesh = { filename="assets/tetrahedron.obj", index=1 },
- mesh = { filename="builtin.quad", index=1 },
- },
- node = {
- parent=id,
- matrix=Mat4():identity():translate(Vec3{0, 2, 0}),
- },
- })
-
- local quad = entities:createEntity()
- entities:addComponents(quad, {
- renderQuad = {
- shader = { vertex="vertex.glsl", fragment="fragment.glsl" },
- textures = { ourTexture = { filename = "44d9a0ec1c18e6126a5e9d9d9317f5ac.png" } },
- },
- })
-
- require('character')(entities)
-
- local skybox = entities:createEntityWithComponents{
- node = {
- matrix = Mat4():identity():scale(Vec3{2,2,2}):rotateX(math.rad(90))
- },
- renderMesh = {
- mesh = {
- filename="assets/skybox.obj",
- index=1,
- },
- shader = { vertex="vertex.glsl", fragment="fragment.glsl" },
- textures = {
- ourTexture = {
- filename = "assets/skyboxsun5deg2_tn.jpg"
- --filename = "assets/skybox.png"
- }
- },
- },
- }
-
- local misc = entities:createEntityWithComponents{
- onKey = { script = "scripts.loadSaveQuit" },
- onFramebufferSize = { script = "scripts.viewportResize" },
- }
-end
-setupEntities()
+local gl = honey.gl
-
--- connect event handler scripts
-window:bindEvents(entities)
-
---entities:load("save")
-
-
--- main loop
-local time = 0
-honey.loop(window, function(dt)
- time = time + dt
- if time > 1 then
- time = time-1
- print(collectgarbage("count"))
- end
+-- initialize honey
+honey.init()
+
+
+local db = honey.ecs.EntityDb()
+local systems = honey.ecs.SystemDb(db)
+
+systems:addSystems(honey.ecs.node.system)
+systems:addSystems(honey.ecs.render.system)
+systems:addSystems(honey.ecs.script.system)
+
+-- camera
+db:createEntityWithComponents{
+ node = {
+ matrix = Mat4()
+ :identity()
+ :translate(Vec3{0,0,10}),
+ },
+ camera = {
+ projection = Mat4()
+ :perspective(90, 640/480, 0.1, 1000)
+ },
+}
+
+-- mesh
+db:createEntityWithComponents{
+ node = {
+ matrix = Mat4()
+ :identity(),
+ },
+ renderMesh = {
+ mesh = {
+ filename = "assets/dodecahedron.obj",
+ index = 1,
+ },
+ textures = {
+ ourTexture = { filename = "assets/green-grass.jpg" },
+ },
+ shader = { vertex="vertex.glsl", fragment="fragment.glsl" },
+ },
+}
+
+honey.loop(function(dt)
gl.ClearColor(0.2, 0.4, 1.0, 1.0)
gl.Clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT + gl.STENCIL_BUFFER_BIT)
-
- gl.Enable(gl.DEPTH_TEST)
- gl.Disable(gl.CULL_FACE)
-
systems:update(dt)
- 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(1/dt)))
- nvg.EndFrame(vg)
end)
-
-- clean up
honey.terminate()