diff --git a/src/carcockpit/car_widget.cpp b/src/carcockpit/car_widget.cpp index 16adf1d..9247c57 100644 --- a/src/carcockpit/car_widget.cpp +++ b/src/carcockpit/car_widget.cpp @@ -268,7 +268,7 @@ car_widget::car_widget(utki::shared_ref context, all_parameters p ruis::render::gltf_loader l(*this->context.get().renderer.get().factory, true); demoscene = l.load(papki::fs_file("../res/samples_gltf/parent_and_children.glb")).to_shared_ptr(); - //demoscene = l.load(papki::fs_file("../res/samples_gltf/spray.glb")).to_shared_ptr(); + // demoscene = l.load(papki::fs_file("../res/samples_gltf/spray.glb")).to_shared_ptr(); sc_renderer = std::make_shared(this->context); sc_renderer->set_scene(demoscene); diff --git a/src/makefile b/src/makefile index 1327059..4c8ebe9 100644 --- a/src/makefile +++ b/src/makefile @@ -72,6 +72,7 @@ this_ldlibs += $(this__libmodel_obj) $(this__libruis_render) this_ldlibs += -lruisapp-opengles-xorg -lpapki -lclargs -ltml -lruis -lutki -lm -l ruis-render-opengles this_ldlibs += -l jsondom +this_ldlibs += -l rasterimage this_ldlibs += `pkg-config --libs glesv2` $(eval $(prorab-build-app)) diff --git a/src/ruis/render/scene/gltf_loader.cpp b/src/ruis/render/scene/gltf_loader.cpp index e658d7d..c1107e8 100644 --- a/src/ruis/render/scene/gltf_loader.cpp +++ b/src/ruis/render/scene/gltf_loader.cpp @@ -23,6 +23,7 @@ along with this program. If not, see . #include #include +#include #include #include #include @@ -67,6 +68,7 @@ inline bool gltf_loader::read_int_checked(const jsondom::value& json, const std: } inline bool gltf_loader::read_uint32_checked(const jsondom::value& json, const std::string& name, uint32_t& value) +// TODO: implement read_string_default instead, return value normally { auto it = json.object().find(name); if (it != json.object().end()) { @@ -350,25 +352,32 @@ utki::shared_ref gltf_loader::read_mesh(const jsondom::value& mesh_json) std::cout << accessors.size() << std::endl; // auto vbo_bitangents = render_factory_.create_vertex_buffer(utki::make_span(bitangents)); - //utki::shared_ref vao; - if(tangent_accessor > 0) - { + // utki::shared_ref vao; + if (tangent_accessor > 0) { + // auto vao = render_factory_.create_vertex_array( + // { + // utki::shared_ref(accessors[position_accessor].get().vbo), + // utki::shared_ref(accessors[texcoord_0_accessor].get().vbo), + // utki::shared_ref(accessors[normal_accessor].get().vbo), + // utki::shared_ref(accessors[tangent_accessor].get().vbo) + // // , vbo_bitangents + // }, + // utki::shared_ref(accessors[index_accessor].get().ibo), + // ruis::render::vertex_array::mode::triangles + // ); auto vao = render_factory_.create_vertex_array( - { - utki::shared_ref( - std::shared_ptr(accessors[position_accessor].get().vbo) - ), - utki::shared_ref( - std::shared_ptr(accessors[texcoord_0_accessor].get().vbo) - ), - utki::shared_ref( - std::shared_ptr(accessors[normal_accessor].get().vbo) - ), - utki::shared_ref( - std::shared_ptr(accessors[tangent_accessor].get().vbo) - ) - // , vbo_bitangents - }, + {utki::shared_ref( + std::shared_ptr(accessors[position_accessor].get().vbo) + ), + utki::shared_ref( + std::shared_ptr(accessors[texcoord_0_accessor].get().vbo) + ), + utki::shared_ref( + std::shared_ptr(accessors[normal_accessor].get().vbo) + ), + utki::shared_ref( + std::shared_ptr(accessors[tangent_accessor].get().vbo) + )}, utki::shared_ref( std::shared_ptr(accessors[index_accessor].get().ibo) ), @@ -376,29 +385,25 @@ utki::shared_ref gltf_loader::read_mesh(const jsondom::value& mesh_json) ); auto material_ = utki::make_shared(); primitives.push_back(utki::make_shared(vao, material_)); - } - else - { + } else { auto vao = render_factory_.create_vertex_array( - { - utki::shared_ref( - std::shared_ptr(accessors[position_accessor].get().vbo) - ), - utki::shared_ref( - std::shared_ptr(accessors[texcoord_0_accessor].get().vbo) - ), - utki::shared_ref( - std::shared_ptr(accessors[normal_accessor].get().vbo) - ) - }, + {utki::shared_ref( + std::shared_ptr(accessors[position_accessor].get().vbo) + ), + utki::shared_ref( + std::shared_ptr(accessors[texcoord_0_accessor].get().vbo) + ), + utki::shared_ref( + std::shared_ptr(accessors[normal_accessor].get().vbo) + )}, utki::shared_ref( std::shared_ptr(accessors[index_accessor].get().ibo) ), ruis::render::vertex_array::mode::triangles - ); + ); auto material_ = utki::make_shared(); primitives.push_back(utki::make_shared(vao, material_)); - } + } } auto new_mesh = utki::make_shared(primitives, name); @@ -447,6 +452,85 @@ utki::shared_ref gltf_loader::read_scene(const jsondom::value& scene_json return new_scene; } +utki::shared_ref gltf_loader::read_image(const jsondom::value& image_json) +{ + [[maybe_unused]] bool ok; + uint32_t buffer_view_index = 0; + [[maybe_unused]] uint32_t mime_type = 0; + std::string name; + std::string mime_type_string; + + ok = read_string_checked(image_json, "name", name); + ok = read_uint32_checked(image_json, "bufferView", buffer_view_index); + ok = read_string_checked(image_json, "mimeType", mime_type_string); // TODO: is a string + + auto new_image = + utki::make_shared(name, buffer_views[buffer_view_index], static_cast(0)); //// !!!! + return new_image; +} + +utki::shared_ref gltf_loader::read_sampler(const jsondom::value& sampler_json) +{ + [[maybe_unused]] bool ok; + uint32_t min_filter = 0; + uint32_t mag_filter = 0; + uint32_t wrap_s = 0; + uint32_t wrap_t = 0; + + ok = read_uint32_checked(sampler_json, "minFilter", min_filter); + ok = read_uint32_checked(sampler_json, "magFilter", mag_filter); + ok = read_uint32_checked(sampler_json, "wrapS", wrap_s); + ok = read_uint32_checked(sampler_json, "wrapT", wrap_t); + + auto new_sampler = utki::make_shared( + static_cast(min_filter), + static_cast(mag_filter), + static_cast(wrap_s), + static_cast(wrap_t) + ); + return new_sampler; +} + +utki::shared_ref gltf_loader::read_texture(const jsondom::value& texture_json) +{ + [[maybe_unused]] bool ok; + uint32_t image_index = 0; + uint32_t sampler_index = 0; + ok = read_uint32_checked(texture_json, "source", image_index); + ok = read_uint32_checked(texture_json, "sampler", sampler_index); + + auto image = images[image_index]; + auto sampler = samplers[sampler_index]; + + auto image_span = glb_binary_buffer.subspan(image.get().bv.get().byte_offset, image.get().bv.get().byte_length); + const papki::span_file fi(image_span); + + rasterimage::image_variant imvar; + if (image.get().mime_type_ == image_l::mime_type::image_png) { + imvar = rasterimage::read_png(fi); + } else if (image.get().mime_type_ == image_l::mime_type::image_jpeg) { + imvar = rasterimage::read_jpeg(fi); + } else { + throw std::invalid_argument("gltf: unknown texture image format"); + } + + ruis::render::render_factory::texture_2d_parameters tex_params; // TODO: fill texparams properly base on gltf file + tex_params.mag_filter = ruis::render::texture_2d::filter::linear; + tex_params.min_filter = ruis::render::texture_2d::filter::linear; + tex_params.mipmap = texture_2d::mipmap::linear; + + return render_factory_.create_texture_2d(std::move(imvar), tex_params); + + // auto new_texture = + // utki::make_shared(name, buffer_views[buffer_view_index], static_cast(mime_type)); + // return new_texture; +} + +utki::shared_ref gltf_loader::read_material(const jsondom::value& material_json) +{ + return utki::make_shared(); +} + utki::shared_ref gltf_loader::load(const papki::file& fi) { auto gltf = fi.load(); @@ -514,6 +598,56 @@ utki::shared_ref gltf_loader::load(const papki::file& fi) } } + ////////////////////////////////////////////////////////////////////// + + // std::cout << "loading images" << std::endl; + // { + // auto it = json.object().find("images"); + // if (it == json.object().end() || !it->second.is_array()) { + // throw std::invalid_argument("read_gltf(): glTF does not have any valid images"); + // } else { + // for (const auto& sub_json : it->second.array()) { + // images.push_back(read_image(sub_json)); + // } + // } + // } + + // std::cout << "loading samplers" << std::endl; + // { + // auto it = json.object().find("samplers"); + // if (it == json.object().end() || !it->second.is_array()) { + // throw std::invalid_argument("read_gltf(): glTF does not have any valid samplers"); + // } else { + // for (const auto& sub_json : it->second.array()) { + // samplers.push_back(read_sampler(sub_json)); + // } + // } + // } + + // std::cout << "loading textures" << std::endl; + // { + // auto it = json.object().find("textures"); + // if (it == json.object().end() || !it->second.is_array()) { + // throw std::invalid_argument("read_gltf(): glTF does not have any valid textures"); + // } else { + // for (const auto& sub_json : it->second.array()) { + // textures.push_back(read_texture(sub_json)); + // } + // } + // } + + // std::cout << "loading materials" << std::endl; + // { + // auto it = json.object().find("materials"); + // if (it == json.object().end() || !it->second.is_array()) { + // throw std::invalid_argument("read_gltf(): glTF does not have any valid materials"); + // } else { + // for (const auto& sub_json : it->second.array()) { + // materials.push_back(read_material(sub_json)); + // } + // } + // } + std::cout << "loading accessors" << std::endl; { auto it = json.object().find("accessors"); @@ -530,7 +664,7 @@ utki::shared_ref gltf_loader::load(const papki::file& fi) // load meshes auto meshes_it = json.object().find("meshes"); if (meshes_it == json.object().end() || !meshes_it->second.is_array()) { - throw std::invalid_argument("read_gltf(): glTF does not have any valid nodes"); + throw std::invalid_argument("read_gltf(): glTF does not have any valid meshes"); } else { // load all meshes into the scene object (actually, there should be an uber-object for mesh storage, but we // currenetly support only one scene) @@ -571,8 +705,6 @@ utki::shared_ref gltf_loader::load(const papki::file& fi) } } - // const papki::span_file fi(data); - // create scene auto active_scene = utki::make_shared(); int active_scene_index = -1; diff --git a/src/ruis/render/scene/gltf_loader.hpp b/src/ruis/render/scene/gltf_loader.hpp index 8eeb536..69bedfd 100644 --- a/src/ruis/render/scene/gltf_loader.hpp +++ b/src/ruis/render/scene/gltf_loader.hpp @@ -33,6 +33,9 @@ namespace ruis::render { struct buffer_view; struct accessor; +struct image_l; +struct sampler_l; +class material; class gltf_loader { @@ -48,6 +51,12 @@ class gltf_loader std::vector> accessors; // accessors. std::vector> buffer_views; // bv's + // std::vector> textures; + std::vector> materials; + std::vector> textures; + std::vector> samplers; + std::vector> images; + std::vector> child_indices; // storage for node child hierarchy (only during loading stage) inline int read_int(const jsondom::value& json, const std::string& name); @@ -79,6 +88,11 @@ class gltf_loader utki::shared_ref read_node(const jsondom::value& node_json); utki::shared_ref read_scene(const jsondom::value& scene_json); + utki::shared_ref read_image(const jsondom::value& image_json); + utki::shared_ref read_sampler(const jsondom::value& sampler_json); + utki::shared_ref read_texture(const jsondom::value& texture_json); + utki::shared_ref read_material(const jsondom::value& material_json); + public: utki::shared_ref load(const papki::file& fi); gltf_loader(ruis::render::render_factory& render_factory_, bool use_short_indices); @@ -145,4 +159,54 @@ struct accessor { ); }; +struct image_l { // TODO: put loader helper classes into separate namespace + std::string name; + utki::shared_ref bv; + enum class mime_type { + undefined = 0, + image_jpeg = 1, + image_png = 2 + } mime_type_; + + image_l(std::string name, utki::shared_ref bv, mime_type mime_type_) : + name(std::move(name)), + bv(std::move(bv)), + mime_type_(mime_type_) + {} +}; + +struct sampler_l { + enum class filter { + nearest = 9728, + linear = 9729, + nearest_mipmap_nearest = 9984, + linear_mipmap_nearest = 9985, + nearest_mipmap_linear = 9986, + linear_mipmap_linear = 9987 + }; + + enum class wrap { + clamp_to_edge = 33071, + mirrored_repeat = 33648, + repeat = 10497 + }; + + filter min; + filter mag; + wrap wrap_s; + wrap wrap_t; + + sampler_l(filter min, filter mag, wrap wrap_s, wrap wrap_t) : + min(min), + mag(mag), + wrap_s(wrap_s), + wrap_t(wrap_t) + {} +}; + +// struct texture_l { +// utki::shared_ref source; +// utki::shared_ref sampler; +// }; + } // namespace ruis::render \ No newline at end of file diff --git a/src/ruis/render/scene/mesh.hpp b/src/ruis/render/scene/mesh.hpp index 5e3836e..89fd313 100644 --- a/src/ruis/render/scene/mesh.hpp +++ b/src/ruis/render/scene/mesh.hpp @@ -22,15 +22,17 @@ along with this program. If not, see . #pragma once #include +#include #include namespace ruis::render { - class material { public: - std::shared_ptr shader; - // textures resources ? + std::string name; + std::shared_ptr tex_diffuse; + std::shared_ptr tex_normal; + std::shared_ptr tex_arm; // ambient occlusion, roughness, metalness }; class primitive diff --git a/src/ruis/render/scene/scene.hpp b/src/ruis/render/scene/scene.hpp index d324976..ef3cd51 100644 --- a/src/ruis/render/scene/scene.hpp +++ b/src/ruis/render/scene/scene.hpp @@ -49,7 +49,7 @@ class scene // void render(ruis::render::renderer& r); }; -class camera +class camera // TODO: derive from node { public: ruis::vec3 pos; @@ -66,7 +66,7 @@ class camera ruis::vec3 to_view_coords(ruis::vec3 vec); }; -class light +class light // TODO: derive from node { public: ruis::vec4 pos; // vec4, because w = 0 means light is at infinite distance diff --git a/src/ruis/render/scene/scene_renderer.cpp b/src/ruis/render/scene/scene_renderer.cpp index bcd411f..4d4dda3 100644 --- a/src/ruis/render/scene/scene_renderer.cpp +++ b/src/ruis/render/scene/scene_renderer.cpp @@ -86,7 +86,8 @@ void scene_renderer::render_node(utki::shared_ref n, ruis::mat4 parent_mod for (const auto& primitive : n.get().mesh_->primitives) { auto& phong = carcockpit::application::inst().shader_phong_v; - // TODO: primitive.get().material_ use later somehow, choose shader here + // TODO: primitive.get().material_ use later somehow, choose shader and textures here, set material-specific + // uniforms phong.render( primitive.get().vao.get(), diff --git a/tests/unit/makefile b/tests/unit/makefile index 5318e43..bb786c5 100644 --- a/tests/unit/makefile +++ b/tests/unit/makefile @@ -13,6 +13,8 @@ this_ldlibs += $(this__libruis_render) this_ldlibs += -l tst -l utki -l papki -l ruis-render-opengles this_ldlibs += -l jsondom +this_ldlibs += -l rasterimage +this_ldlibs += -l m this_ldlibs += -l ruisapp-opengles-xorg # TODO: remove when move gltf to ruis this_no_install := true