18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci#include "gltf2.h"
168bf80f4bSopenharmony_ci
178bf80f4bSopenharmony_ci#include <3d/gltf/gltf.h>
188bf80f4bSopenharmony_ci#include <3d/intf_graphics_context.h>
198bf80f4bSopenharmony_ci#include <core/ecs/intf_ecs.h>
208bf80f4bSopenharmony_ci#include <core/ecs/intf_entity_manager.h>
218bf80f4bSopenharmony_ci#include <core/intf_engine.h>
228bf80f4bSopenharmony_ci#include <core/io/intf_file_manager.h>
238bf80f4bSopenharmony_ci#include <core/log.h>
248bf80f4bSopenharmony_ci#include <core/plugin/intf_plugin_register.h>
258bf80f4bSopenharmony_ci#include <render/device/intf_gpu_resource_manager.h>
268bf80f4bSopenharmony_ci#include <render/intf_render_context.h>
278bf80f4bSopenharmony_ci
288bf80f4bSopenharmony_ci#include "data.h"
298bf80f4bSopenharmony_ci#include "gltf2_exporter.h"
308bf80f4bSopenharmony_ci#include "gltf2_importer.h"
318bf80f4bSopenharmony_ci#include "gltf2_loader.h"
328bf80f4bSopenharmony_ci
338bf80f4bSopenharmony_ciCORE3D_BEGIN_NAMESPACE()
348bf80f4bSopenharmony_ciusing namespace BASE_NS;
358bf80f4bSopenharmony_ciusing namespace CORE_NS;
368bf80f4bSopenharmony_ci
378bf80f4bSopenharmony_ciGltf2::Gltf2(IGraphicsContext& graphicsContext)
388bf80f4bSopenharmony_ci    : engine_(&(graphicsContext.GetRenderContext().GetEngine())), renderContext_(&graphicsContext.GetRenderContext()),
398bf80f4bSopenharmony_ci      fileManager_(engine_->GetFileManager())
408bf80f4bSopenharmony_ci{}
418bf80f4bSopenharmony_ci
428bf80f4bSopenharmony_ciGltf2::Gltf2(IFileManager& fileManager) : fileManager_(fileManager) {}
438bf80f4bSopenharmony_ci
448bf80f4bSopenharmony_ci// Internal helper.
458bf80f4bSopenharmony_ciGLTFLoadResult LoadGLTF(IFileManager& fileManager, const string_view uri)
468bf80f4bSopenharmony_ci{
478bf80f4bSopenharmony_ci    auto loadResult = GLTF2::LoadGLTF(fileManager, uri);
488bf80f4bSopenharmony_ci    GLTFLoadResult result;
498bf80f4bSopenharmony_ci    result.error = move(loadResult.error);
508bf80f4bSopenharmony_ci    result.success = loadResult.success;
518bf80f4bSopenharmony_ci    result.data = IGLTFData::Ptr { loadResult.data.release() };
528bf80f4bSopenharmony_ci
538bf80f4bSopenharmony_ci    return result;
548bf80f4bSopenharmony_ci}
558bf80f4bSopenharmony_ci
568bf80f4bSopenharmony_ci// Api loading function.
578bf80f4bSopenharmony_ciGLTFLoadResult Gltf2::LoadGLTF(const string_view uri)
588bf80f4bSopenharmony_ci{
598bf80f4bSopenharmony_ci    return CORE3D_NS::LoadGLTF(fileManager_, uri);
608bf80f4bSopenharmony_ci}
618bf80f4bSopenharmony_ci
628bf80f4bSopenharmony_ciGLTFLoadResult Gltf2::LoadGLTF(array_view<uint8_t const> data)
638bf80f4bSopenharmony_ci{
648bf80f4bSopenharmony_ci    auto loadResult = GLTF2::LoadGLTF(fileManager_, data);
658bf80f4bSopenharmony_ci    GLTFLoadResult result;
668bf80f4bSopenharmony_ci    result.error = move(loadResult.error);
678bf80f4bSopenharmony_ci    result.success = loadResult.success;
688bf80f4bSopenharmony_ci    result.data = IGLTFData::Ptr { loadResult.data.release() };
698bf80f4bSopenharmony_ci    return result;
708bf80f4bSopenharmony_ci}
718bf80f4bSopenharmony_ci
728bf80f4bSopenharmony_ci// Api import functions
738bf80f4bSopenharmony_ciEntity Gltf2::ImportGltfScene(size_t sceneIndex, const IGLTFData& gltfData, const GLTFResourceData& gltfResourceData,
748bf80f4bSopenharmony_ci    IEcs& ecs, Entity rootEntity, GltfSceneImportFlags flags)
758bf80f4bSopenharmony_ci{
768bf80f4bSopenharmony_ci    CORE_ASSERT(renderContext_);
778bf80f4bSopenharmony_ci    if (renderContext_) {
788bf80f4bSopenharmony_ci        const GLTF2::Data& data = static_cast<const GLTF2::Data&>(gltfData);
798bf80f4bSopenharmony_ci        return ImportScene(renderContext_->GetDevice(), sceneIndex, data, gltfResourceData, ecs, rootEntity, flags);
808bf80f4bSopenharmony_ci    }
818bf80f4bSopenharmony_ci    return {};
828bf80f4bSopenharmony_ci}
838bf80f4bSopenharmony_ci
848bf80f4bSopenharmony_ciIGLTF2Importer::Ptr Gltf2::CreateGLTF2Importer(IEcs& ecs)
858bf80f4bSopenharmony_ci{
868bf80f4bSopenharmony_ci    CORE_ASSERT(engine_ && renderContext_);
878bf80f4bSopenharmony_ci    if (engine_ && renderContext_) {
888bf80f4bSopenharmony_ci        if (auto pool = ecs.GetThreadPool(); pool) {
898bf80f4bSopenharmony_ci            return CreateGLTF2Importer(ecs, *pool);
908bf80f4bSopenharmony_ci        }
918bf80f4bSopenharmony_ci        return IGLTF2Importer::Ptr { new GLTF2::GLTF2Importer(*engine_, *renderContext_, ecs) };
928bf80f4bSopenharmony_ci    }
938bf80f4bSopenharmony_ci    return nullptr;
948bf80f4bSopenharmony_ci}
958bf80f4bSopenharmony_ci
968bf80f4bSopenharmony_ciIGLTF2Importer::Ptr Gltf2::CreateGLTF2Importer(IEcs& ecs, IThreadPool& pool)
978bf80f4bSopenharmony_ci{
988bf80f4bSopenharmony_ci    CORE_ASSERT(engine_ && renderContext_);
998bf80f4bSopenharmony_ci    if (engine_ && renderContext_) {
1008bf80f4bSopenharmony_ci        return IGLTF2Importer::Ptr { new GLTF2::GLTF2Importer(*engine_, *renderContext_, ecs, pool) };
1018bf80f4bSopenharmony_ci    }
1028bf80f4bSopenharmony_ci    return nullptr;
1038bf80f4bSopenharmony_ci}
1048bf80f4bSopenharmony_ci
1058bf80f4bSopenharmony_ciISceneLoader::Result Gltf2::Load(string_view uri)
1068bf80f4bSopenharmony_ci{
1078bf80f4bSopenharmony_ci    ISceneLoader::Result sceneResult;
1088bf80f4bSopenharmony_ci    auto loadResult = GLTF2::LoadGLTF(fileManager_, uri);
1098bf80f4bSopenharmony_ci    sceneResult.error = loadResult.success ? 0 : 1;
1108bf80f4bSopenharmony_ci    sceneResult.message = BASE_NS::move(loadResult.error);
1118bf80f4bSopenharmony_ci    sceneResult.data.reset(new GLTF2::SceneData(BASE_NS::move(loadResult.data)));
1128bf80f4bSopenharmony_ci    return sceneResult;
1138bf80f4bSopenharmony_ci}
1148bf80f4bSopenharmony_ci
1158bf80f4bSopenharmony_ciISceneImporter::Ptr Gltf2::CreateSceneImporter(IEcs& ecs)
1168bf80f4bSopenharmony_ci{
1178bf80f4bSopenharmony_ci    CORE_ASSERT(engine_ && renderContext_);
1188bf80f4bSopenharmony_ci    if (engine_ && renderContext_) {
1198bf80f4bSopenharmony_ci        return ISceneImporter::Ptr { new GLTF2::Gltf2SceneImporter(*engine_, *renderContext_, ecs) };
1208bf80f4bSopenharmony_ci    }
1218bf80f4bSopenharmony_ci    return nullptr;
1228bf80f4bSopenharmony_ci}
1238bf80f4bSopenharmony_ci
1248bf80f4bSopenharmony_ciISceneImporter::Ptr Gltf2::CreateSceneImporter(IEcs& ecs, IThreadPool& pool)
1258bf80f4bSopenharmony_ci{
1268bf80f4bSopenharmony_ci    CORE_ASSERT(engine_ && renderContext_);
1278bf80f4bSopenharmony_ci    if (engine_ && renderContext_) {
1288bf80f4bSopenharmony_ci        return ISceneImporter::Ptr { new GLTF2::Gltf2SceneImporter(*engine_, *renderContext_, ecs, pool) };
1298bf80f4bSopenharmony_ci    }
1308bf80f4bSopenharmony_ci    return nullptr;
1318bf80f4bSopenharmony_ci}
1328bf80f4bSopenharmony_ci
1338bf80f4bSopenharmony_ciarray_view<const string_view> Gltf2::GetSupportedExtensions() const
1348bf80f4bSopenharmony_ci{
1358bf80f4bSopenharmony_ci    static constexpr string_view extensions[] = { "gltf", "glb" };
1368bf80f4bSopenharmony_ci    return extensions;
1378bf80f4bSopenharmony_ci}
1388bf80f4bSopenharmony_ci
1398bf80f4bSopenharmony_ci// IInterface
1408bf80f4bSopenharmony_ciconst IInterface* Gltf2::GetInterface(const Uid& uid) const
1418bf80f4bSopenharmony_ci{
1428bf80f4bSopenharmony_ci    if (uid == ISceneLoader::UID) {
1438bf80f4bSopenharmony_ci        return static_cast<const ISceneLoader*>(this);
1448bf80f4bSopenharmony_ci    }
1458bf80f4bSopenharmony_ci    if (uid == IInterface::UID) {
1468bf80f4bSopenharmony_ci        return static_cast<const IInterface*>(this);
1478bf80f4bSopenharmony_ci    }
1488bf80f4bSopenharmony_ci    return nullptr;
1498bf80f4bSopenharmony_ci}
1508bf80f4bSopenharmony_ci
1518bf80f4bSopenharmony_ciIInterface* Gltf2::GetInterface(const Uid& uid)
1528bf80f4bSopenharmony_ci{
1538bf80f4bSopenharmony_ci    if (uid == ISceneLoader::UID) {
1548bf80f4bSopenharmony_ci        return static_cast<ISceneLoader*>(this);
1558bf80f4bSopenharmony_ci    }
1568bf80f4bSopenharmony_ci    if (uid == IInterface::UID) {
1578bf80f4bSopenharmony_ci        return static_cast<IInterface*>(this);
1588bf80f4bSopenharmony_ci    }
1598bf80f4bSopenharmony_ci    return nullptr;
1608bf80f4bSopenharmony_ci}
1618bf80f4bSopenharmony_ci
1628bf80f4bSopenharmony_civoid Gltf2::Ref() {}
1638bf80f4bSopenharmony_ci
1648bf80f4bSopenharmony_civoid Gltf2::Unref() {}
1658bf80f4bSopenharmony_ci
1668bf80f4bSopenharmony_ci// Api exporting function.
1678bf80f4bSopenharmony_cibool Gltf2::SaveGLTF(IEcs& ecs, const string_view uri)
1688bf80f4bSopenharmony_ci{
1698bf80f4bSopenharmony_ci    CORE_ASSERT(engine_);
1708bf80f4bSopenharmony_ci    if (engine_) {
1718bf80f4bSopenharmony_ci        if (auto result = GLTF2::ExportGLTF(*engine_, ecs); result.success) {
1728bf80f4bSopenharmony_ci            if (auto file = fileManager_.CreateFile(uri); file) {
1738bf80f4bSopenharmony_ci                auto const ext = uri.rfind('.');
1748bf80f4bSopenharmony_ci                auto const extension = string_view(uri.data() + ext + 1);
1758bf80f4bSopenharmony_ci                if (extension == "gltf") {
1768bf80f4bSopenharmony_ci                    for (auto const& buffer : result.data->buffers) {
1778bf80f4bSopenharmony_ci                        string dataFileUri = uri.substr(0, ext) + ".bin";
1788bf80f4bSopenharmony_ci                        if (auto dataFile = fileManager_.CreateFile(dataFileUri); dataFile) {
1798bf80f4bSopenharmony_ci                            dataFile->Write(buffer->data.data(), buffer->data.size());
1808bf80f4bSopenharmony_ci                            if (auto const path = dataFileUri.rfind('/'); path != string::npos) {
1818bf80f4bSopenharmony_ci                                dataFileUri.erase(0, path + 1);
1828bf80f4bSopenharmony_ci                            }
1838bf80f4bSopenharmony_ci                            buffer->uri = dataFileUri;
1848bf80f4bSopenharmony_ci                        }
1858bf80f4bSopenharmony_ci                    }
1868bf80f4bSopenharmony_ci                    GLTF2::SaveGLTF(*result.data, *file, engine_->GetVersion());
1878bf80f4bSopenharmony_ci                } else {
1888bf80f4bSopenharmony_ci                    GLTF2::SaveGLB(*result.data, *file, engine_->GetVersion());
1898bf80f4bSopenharmony_ci                }
1908bf80f4bSopenharmony_ci            } else {
1918bf80f4bSopenharmony_ci                result.error += "Failed to create file: " + uri;
1928bf80f4bSopenharmony_ci                result.success = false;
1938bf80f4bSopenharmony_ci            }
1948bf80f4bSopenharmony_ci            return result.success;
1958bf80f4bSopenharmony_ci        } else {
1968bf80f4bSopenharmony_ci            return result.success;
1978bf80f4bSopenharmony_ci        }
1988bf80f4bSopenharmony_ci    }
1998bf80f4bSopenharmony_ci    return false;
2008bf80f4bSopenharmony_ci}
2018bf80f4bSopenharmony_ciCORE3D_END_NAMESPACE()
202