summaryrefslogtreecommitdiff
path: root/honey/ecs/render.lua
blob: 1c38692b15a578683692258f1682a63d04b10207 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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})
			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