summaryrefslogtreecommitdiff
path: root/honey/asset/mesh.lua
blob: 5e0a26da6f1ba9416c0f1a824ec27c6756a4c3d7 (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
local gl = honey.gl

local module = {}
setmetatable(module, {__index=_G})
setfenv(1, module)


-- append the 8 floats per vertex to the vertices table
local function insertVertex(vertices, attrib, vertex)
	local pos = 3*vertex.v_idx
	for i=1,3 do
		table.insert(vertices, attrib.vertices[pos+i])
	end

	local normal = 3*vertex.vn_idx
	for i=1,3 do
		table.insert(vertices, attrib.normals[normal+i])
	end

	local tex = 2*vertex.vt_idx
	for i=1,2 do
		table.insert(vertices, attrib.texcoords[tex+i])
	end
end


-- creates a table of floats representing vertex data
-- and a table of ints representing face indices within the vertices
local function loadShape(shape, attrib, debug)
	local vertices = {}
	local indices = {}

	local start = shape.face_offset
	local finish = start + shape.length
	for i=start,finish-1 do
		assert(attrib.face_num_verts[i+1] == 3, "non-triangular face!")
		for j=0,2 do
			local vertex = attrib.faces[(3*i) + j + 1]
			insertVertex(vertices, attrib, vertex, debug)
			table.insert(indices, #indices)
		end
	end

	return vertices, indices
end


-- public helper function (used in some other places, like trimesh construction)
-- packages the vertices & indices tables from loadShape into a single array
loadFile = function(filename)
	local flags = honey.tinyobj.FLAG_TRIANGULATE
	local attrib, shapes, materials = honey.tinyobj.parse_obj(filename, flags)
	
	local meshes = {}
	for _, shape in ipairs(shapes) do
		local vertices, indices = loadShape(shape, attrib, debug)
		table.insert(meshes, {vertices=vertices, indices=indices})
	end
	return meshes
end


-- helper function to create a gl vertex array object from (vertices, indices) pair
local function createMesh(vertices, indices)
	vao = gl.GenVertexArrays()
	vbo = gl.GenBuffers()
	ebo = gl.GenBuffers()

	gl.BindVertexArray(vao)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.BufferData(gl.ARRAY_BUFFER, gl.FLOAT, vertices, gl.STATIC_DRAW)

	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo)
	gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_INT, indices, gl.STATIC_DRAW)

	local stride = 8
	local offset = 0
	
	-- position
	gl.VertexAttribPointer(0, 3, false, stride, offset)
	gl.EnableVertexAttribArray(0)
	offset = offset+3

	-- normal
	gl.VertexAttribPointer(1, 3, false, stride, offset)
	gl.EnableVertexAttribArray(1)
	offset = offset+3

	-- texture
	gl.VertexAttribPointer(2, 2, false, stride, offset)
	gl.EnableVertexAttribArray(2)
	offset = offset+2

	return vao, vbo, ebo, #vertices
end


local cache = {}


-- get a gl vertex array object + vertex count
get = function(filename, index)
	if not cache[filename] then
		local c = {}
		local meshes = loadFile(filename)
		for _, m in ipairs(meshes) do
			local vao, vbo, ebo, count = createMesh(m.vertices, m.indices)
			table.insert(c, { vao=vao, vbo=vbo, ebo=ebo, count=count })
		end
		cache[filename] = c
	end
	local m = cache[filename][index]
	return m.vao, m.count
end


-- forget a mesh
forget = function(filename)
	if not cache[filename] then return end
	for _, m in ipairs(cache[filename]) do
		gl.DeleteBuffers(m.vbo)
		gl.DeleteBuffers(m.ebo)
		gl.DeleteVertexArrays(m.vao)
	end
	cache[filename] = nil
end


-- clear the cache
clearCache = function()
	for key in pairs(cache) do
		forget(key)
	end
end


--===== builtin meshes =====--

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


return module