local _math = require '_math' local mat4 = _math.mat4 local vec3 = _math.vec3 local vec4 = _math.vec4 local scalar = _math.scalar local collada_types = require 'collada_types' local pixel_data = love.filesystem.newFileData("pixel.glsl") local vertex_data = love.filesystem.newFileData("vertex.glsl") local shader = love.graphics.newShader(pixel_data, vertex_data) local images_textures = {} local node_instances = {} local collada_scene local index_buffer collada_scene = { load_buffers = function() ---------------------------------------------------------------------- -- index buffer ---------------------------------------------------------------------- local index_data = love.filesystem.newFileData("scene/test/test.idx") index_buffer = love.graphics.newBuffer("uint32", index_data, { index = true, usage = "static" }) ---------------------------------------------------------------------- -- vertex shader storage buffer ---------------------------------------------------------------------- local format = { { name = 'Position', format = 'floatvec4' }, { name = 'Normal', format = 'floatvec4' }, { name = 'Texture', format = 'floatvec4' }, } local vertex_data = love.filesystem.newFileData("scene/test/test.vtx") local shaderstorage_buffer = love.graphics.newBuffer(format, vertex_data, { shaderstorage = true, usage = "static" }) shader:send("VertexLayout", shaderstorage_buffer) end, load_images = function(base_path, images) local image_index = 0 for _, image in ipairs(images) do assert(string.sub(image.uri, 1, 1) == ".") path = base_path .. string.sub(image.uri, 2) print("load image", path) local image_data = love.image.newImageData(path) local texture = love.graphics.newTexture(image_data) images_textures[image_index] = texture image_index = image_index + 1 end end, node_world_transform = function(node) local world if node.parent_index >= 0 then world = node_instances[node.parent_index].world assert(world ~= nil) else world = mat4.identity() end for _, transform in ipairs(node.transforms) do local m if transform.type == collada_types.transform_type.LOOKAT then assert(false) elseif transform.type == collada_types.transform_type.MATRIX then m = mat4.load_table(transform.matrix) elseif transform.type == collada_types.transform_type.ROTATE then local rotate = vec4.load_table(transform.rotate) local w = rotate.f[3] m = mat4.rotation_axis(rotate, scalar.convert_to_radians(w)) elseif transform.type == collada_types.transform_type.SCALE then m = mat4.scaling_from_vector(vec3.load_table(transform.scale)) elseif transform.type == collada_types.transform_type.TRANSLATE then m = mat4.translation_from_vector(vec3.load_table(transform.translate)) else assert(false) end world = m * world end return world end, load_node_world_transforms = function(nodes) local node_index = 0 for _, node in ipairs(nodes) do world = collada_scene.node_world_transform(node) node_instances[node_index] = { world = world } node_index = node_index + 1 end end, set_color_or_texture = function(color_or_texture, color_uniform, sampler_uniform) if color_or_texture.type == collada_types.color_or_texture_type.COLOR then shader:send(color_uniform, color_or_texture.color) elseif color_or_texture.type == collada_types.color_or_texture_type.TEXTURE then shader:send(sampler_uniform, images_textures[color_or_texture.texture.image_index]) else assert(false) end end, set_instance_material = function(instance_material) local effect = instance_material.material.effect if effect.type == collada_types.effect_type.BLINN then collada_scene.set_color_or_texture(effect.blinn.emission, "emission_color", "emission_sampler"); collada_scene.set_color_or_texture(effect.blinn.ambient, "ambient_color", "ambient_sampler"); collada_scene.set_color_or_texture(effect.blinn.diffuse, "diffuse_color", "diffuse_sampler"); collada_scene.set_color_or_texture(effect.blinn.specular, "specular_color", "specular_sampler"); shader:send("shininess", effect.blinn.shininess); elseif effect.type == collada_types.effect_type.LAMBERT then collada_scene.set_color_or_texture(effect.lambert.emission, "emission_color", "emission_sampler"); collada_scene.set_color_or_texture(effect.lambert.ambient, "ambient_color", "ambient_sampler"); collada_scene.set_color_or_texture(effect.lambert.diffuse, "diffuse_color", "diffuse_sampler"); elseif effect.type == collada_types.effect_type.PHONG then collada_scene.set_color_or_texture(effect.phong.emission, "emission_color", "emission_sampler"); collada_scene.set_color_or_texture(effect.phong.ambient, "ambient_color", "ambient_sampler"); collada_scene.set_color_or_texture(effect.phong.diffuse, "diffuse_color", "diffuse_sampler"); collada_scene.set_color_or_texture(effect.phong.specular, "specular_color", "specular_sampler"); shader:send("shininess", effect.phong.shininess); elseif effect.type == collada_types.effect_type.CONSTANT then shader:send("emission_color", effect.constant.color) else assert(false) end local texture_channel = { instance_material.emission.input_set, instance_material.ambient.input_set, instance_material.diffuse.input_set, instance_material.specular.input_set, } shader:send("texture_channel", texture_channel) end, draw_geometry = function(geometry, instance_materials) local base_index_buffer_offset = geometry.mesh.index_buffer_offset / 4 for _, instance_material in ipairs(instance_materials) do collada_scene.set_instance_material(instance_material) local triangles = geometry.mesh.triangles[instance_material.element_index + 1] local index_offset = base_index_buffer_offset + triangles.index_offset local index_count = triangles.count * 3 local vertex_offset = geometry.mesh.vertex_buffer_offset / (4 * 4 * 3) shader:send("VertexOffset", vertex_offset) love.graphics.drawFromShader(index_buffer, index_count, 1, 1 + index_offset) end end, draw_node = function(node_index, node, transform) if node.type ~= collada_types.node_type.NODE then return end if node.instance_geometries_count == 0 and node.instance_controllers_count == 0 then return end local world = node_instances[node_index].world transform = world * transform shader:send("world_transform", "column", world.data) shader:send("transform", "column", transform.data) for _, instance_geometry in ipairs(node.instance_geometries) do collada_scene.draw_geometry(instance_geometry.geometry, instance_geometry.instance_materials) end end, draw_nodes = function(nodes, transform) love.graphics.setShader(shader) shader:send("view_position", {-88.57101, -71.71298, 104.5738, 1.0}) shader:send("light_position", {0.0, -56.804, 58.237, 1.0}) local node_index = 0 for _, node in ipairs(nodes) do collada_scene.draw_node(node_index, node, transform) node_index = node_index + 1 end end, } return { draw_nodes = collada_scene.draw_nodes, load_buffers = collada_scene.load_buffers, load_node_world_transforms = collada_scene.load_node_world_transforms, load_images = collada_scene.load_images, }