1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "gltf2.h"
16
17 #include <3d/gltf/gltf.h>
18 #include <3d/intf_graphics_context.h>
19 #include <core/ecs/intf_ecs.h>
20 #include <core/ecs/intf_entity_manager.h>
21 #include <core/intf_engine.h>
22 #include <core/io/intf_file_manager.h>
23 #include <core/log.h>
24 #include <core/plugin/intf_plugin_register.h>
25 #include <render/device/intf_gpu_resource_manager.h>
26 #include <render/intf_render_context.h>
27
28 #include "data.h"
29 #include "gltf2_exporter.h"
30 #include "gltf2_importer.h"
31 #include "gltf2_loader.h"
32
33 CORE3D_BEGIN_NAMESPACE()
34 using namespace BASE_NS;
35 using namespace CORE_NS;
36
Gltf2(IGraphicsContext & graphicsContext)37 Gltf2::Gltf2(IGraphicsContext& graphicsContext)
38 : engine_(&(graphicsContext.GetRenderContext().GetEngine())), renderContext_(&graphicsContext.GetRenderContext()),
39 fileManager_(engine_->GetFileManager())
40 {}
41
Gltf2(IFileManager & fileManager)42 Gltf2::Gltf2(IFileManager& fileManager) : fileManager_(fileManager) {}
43
44 // Internal helper.
LoadGLTF(IFileManager & fileManager,const string_view uri)45 GLTFLoadResult LoadGLTF(IFileManager& fileManager, const string_view uri)
46 {
47 auto loadResult = GLTF2::LoadGLTF(fileManager, uri);
48 GLTFLoadResult result;
49 result.error = move(loadResult.error);
50 result.success = loadResult.success;
51 result.data = IGLTFData::Ptr { loadResult.data.release() };
52
53 return result;
54 }
55
56 // Api loading function.
LoadGLTF(const string_view uri)57 GLTFLoadResult Gltf2::LoadGLTF(const string_view uri)
58 {
59 return CORE3D_NS::LoadGLTF(fileManager_, uri);
60 }
61
LoadGLTF(array_view<uint8_t const> data)62 GLTFLoadResult Gltf2::LoadGLTF(array_view<uint8_t const> data)
63 {
64 auto loadResult = GLTF2::LoadGLTF(fileManager_, data);
65 GLTFLoadResult result;
66 result.error = move(loadResult.error);
67 result.success = loadResult.success;
68 result.data = IGLTFData::Ptr { loadResult.data.release() };
69 return result;
70 }
71
72 // Api import functions
ImportGltfScene(size_t sceneIndex,const IGLTFData & gltfData,const GLTFResourceData & gltfResourceData,IEcs & ecs,Entity rootEntity,GltfSceneImportFlags flags)73 Entity Gltf2::ImportGltfScene(size_t sceneIndex, const IGLTFData& gltfData, const GLTFResourceData& gltfResourceData,
74 IEcs& ecs, Entity rootEntity, GltfSceneImportFlags flags)
75 {
76 CORE_ASSERT(renderContext_);
77 if (renderContext_) {
78 const GLTF2::Data& data = static_cast<const GLTF2::Data&>(gltfData);
79 return ImportScene(renderContext_->GetDevice(), sceneIndex, data, gltfResourceData, ecs, rootEntity, flags);
80 }
81 return {};
82 }
83
CreateGLTF2Importer(IEcs & ecs)84 IGLTF2Importer::Ptr Gltf2::CreateGLTF2Importer(IEcs& ecs)
85 {
86 CORE_ASSERT(engine_ && renderContext_);
87 if (engine_ && renderContext_) {
88 if (auto pool = ecs.GetThreadPool(); pool) {
89 return CreateGLTF2Importer(ecs, *pool);
90 }
91 auto ret = BASE_NS::make_unique<GLTF2::GLTF2Importer>(*engine_, *renderContext_, ecs);
92 if (ret->IsValid()) {
93 return IGLTF2Importer::Ptr { ret.release() };
94 }
95 }
96 return nullptr;
97 }
98
CreateGLTF2Importer(IEcs & ecs,IThreadPool & pool)99 IGLTF2Importer::Ptr Gltf2::CreateGLTF2Importer(IEcs& ecs, IThreadPool& pool)
100 {
101 CORE_ASSERT(engine_ && renderContext_);
102 if (engine_ && renderContext_) {
103 auto ret = BASE_NS::make_unique<GLTF2::GLTF2Importer>(*engine_, *renderContext_, ecs, pool);
104 if (ret->IsValid()) {
105 return IGLTF2Importer::Ptr { ret.release() };
106 }
107 }
108 return nullptr;
109 }
110
Load(string_view uri)111 ISceneLoader::Result Gltf2::Load(string_view uri)
112 {
113 ISceneLoader::Result sceneResult;
114 auto loadResult = GLTF2::LoadGLTF(fileManager_, uri);
115 sceneResult.error = loadResult.success ? 0 : 1;
116 sceneResult.message = BASE_NS::move(loadResult.error);
117 sceneResult.data.reset(new GLTF2::SceneData(BASE_NS::move(loadResult.data)));
118 return sceneResult;
119 }
120
CreateSceneImporter(IEcs & ecs)121 ISceneImporter::Ptr Gltf2::CreateSceneImporter(IEcs& ecs)
122 {
123 CORE_ASSERT(engine_ && renderContext_);
124 if (engine_ && renderContext_) {
125 return ISceneImporter::Ptr { new GLTF2::Gltf2SceneImporter(*engine_, *renderContext_, ecs) };
126 }
127 return nullptr;
128 }
129
CreateSceneImporter(IEcs & ecs,IThreadPool & pool)130 ISceneImporter::Ptr Gltf2::CreateSceneImporter(IEcs& ecs, IThreadPool& pool)
131 {
132 CORE_ASSERT(engine_ && renderContext_);
133 if (engine_ && renderContext_) {
134 return ISceneImporter::Ptr { new GLTF2::Gltf2SceneImporter(*engine_, *renderContext_, ecs, pool) };
135 }
136 return nullptr;
137 }
138
GetSupportedExtensions() const139 array_view<const string_view> Gltf2::GetSupportedExtensions() const
140 {
141 static constexpr string_view extensions[] = { "gltf", "glb" };
142 return extensions;
143 }
144
145 // IInterface
GetInterface(const Uid & uid) const146 const IInterface* Gltf2::GetInterface(const Uid& uid) const
147 {
148 if (uid == ISceneLoader::UID) {
149 return static_cast<const ISceneLoader*>(this);
150 }
151 if (uid == IInterface::UID) {
152 return static_cast<const IInterface*>(this);
153 }
154 return nullptr;
155 }
156
GetInterface(const Uid & uid)157 IInterface* Gltf2::GetInterface(const Uid& uid)
158 {
159 if (uid == ISceneLoader::UID) {
160 return static_cast<ISceneLoader*>(this);
161 }
162 if (uid == IInterface::UID) {
163 return static_cast<IInterface*>(this);
164 }
165 return nullptr;
166 }
167
Ref()168 void Gltf2::Ref() {}
169
Unref()170 void Gltf2::Unref() {}
171
172 // Api exporting function.
SaveGLTF(IEcs & ecs,const string_view uri)173 bool Gltf2::SaveGLTF(IEcs& ecs, const string_view uri)
174 {
175 CORE_ASSERT(engine_);
176 if (!engine_) {
177 return false;
178 }
179 auto file = fileManager_.CreateFile(uri);
180 if (!file) {
181 return false;
182 }
183 const auto result = GLTF2::ExportGLTF(*engine_, ecs);
184 if (!result.success) {
185 return false;
186 }
187
188 auto const ext = uri.rfind('.');
189 auto const extension = string_view(uri.data() + ext + 1);
190 if (extension == "gltf") {
191 for (auto const& buffer : result.data->buffers) {
192 string dataFileUri = uri.substr(0, ext) + ".bin";
193 auto dataFile = fileManager_.CreateFile(dataFileUri);
194 if (!dataFile) {
195 }
196 dataFile->Write(buffer->data.data(), buffer->data.size());
197 if (auto const path = dataFileUri.rfind('/'); path != string::npos) {
198 dataFileUri.erase(0, path + 1);
199 }
200 buffer->uri = dataFileUri;
201 }
202 GLTF2::SaveGLTF(*result.data, *file, engine_->GetVersion());
203 } else {
204 GLTF2::SaveGLB(*result.data, *file, engine_->GetVersion());
205 }
206
207 return true;
208 }
209 CORE3D_END_NAMESPACE()
210