2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <dali-scene3d/public-api/loader/navigation-mesh-factory.h>
21 #include <dali/integration-api/debug.h>
24 #include <dali-scene3d/internal/algorithm/navigation-mesh-impl.h>
25 #include <dali/devel-api/adaptor-framework/file-stream.h>
29 namespace Dali::Scene3D::Loader
31 std::unique_ptr<Algorithm::NavigationMesh> NavigationMeshFactory::CreateFromFile(std::string filename)
33 std::vector<uint8_t> buffer;
35 Dali::FileStream fileStream(filename, Dali::FileStream::READ | Dali::FileStream::BINARY);
36 auto fin = fileStream.GetFile();
38 if(DALI_UNLIKELY(!fin))
40 const int bufferLength = 128;
41 char buffer[bufferLength];
43 // Return type of stderror_r is different between system type. We should not use return value.
44 [[maybe_unused]] auto ret = strerror_r(errno, buffer, bufferLength - 1);
46 DALI_LOG_ERROR("NavigationMesh: Can't open %s for reading: %s", filename.c_str(), buffer);
50 if(DALI_UNLIKELY(fseek(fin, 0, SEEK_END)))
52 DALI_LOG_ERROR("NavigationMesh: Error reading file: %s\n", filename.c_str());
56 auto size = ftell(fin);
57 if(DALI_UNLIKELY(size < 0))
59 DALI_LOG_ERROR("NavigationMesh: Error reading file: %s\n", filename.c_str());
63 auto fileSize = size_t(size);
64 if(DALI_UNLIKELY(fseek(fin, 0, SEEK_SET)))
66 DALI_LOG_ERROR("NavigationMesh: Error reading file: %s\n", filename.c_str());
71 auto count = fread(buffer.data(), 1, fileSize, fin);
72 if(DALI_UNLIKELY(count != fileSize))
74 DALI_LOG_ERROR("NavigationMesh: Error reading file: %s\n", filename.c_str());
77 return CreateFromBuffer(buffer);
80 std::unique_ptr<Algorithm::NavigationMesh> NavigationMeshFactory::CreateFromBuffer(const std::vector<uint8_t>& buffer)
82 auto impl = new Scene3D::Internal::Algorithm::NavigationMesh(buffer);
83 return std::make_unique<Algorithm::NavigationMesh>(impl);
86 std::unique_ptr<Algorithm::NavigationMesh> NavigationMeshFactory::CreateFromVertexFaceList(const Vector3* vertices, const Vector3* vertexNormals, uint32_t vertexCount, const uint32_t* faceIndices, uint32_t indexCount)
88 // The function takes the data and creates a binary buffer out of it
89 using namespace Dali::Scene3D::Algorithm;
90 auto header = Internal::Algorithm::NavigationMeshHeader_V10();
93 header.checksum = *reinterpret_cast<const uint32_t*>("NAVM");
94 header.version = 0; // latest version
96 // Copy given vertices
97 std::vector<NavigationMesh::Vertex> meshVertices;
98 meshVertices.reserve(vertexCount);
99 for(auto i = 0u; i < vertexCount; ++i)
101 meshVertices.emplace_back();
102 meshVertices.back().x = vertices[i].x;
103 meshVertices.back().y = vertices[i].y;
104 meshVertices.back().z = vertices[i].z;
107 // copy faces and edges
108 std::vector<NavigationMesh::Face> meshFaces;
109 meshFaces.resize(indexCount / 3);
111 bool computeNormals = (vertexNormals == nullptr);
112 for(auto& f : meshFaces)
114 f.vertex[0] = faceIndices[i];
115 f.vertex[1] = faceIndices[i + 1];
116 f.vertex[2] = faceIndices[i + 2];
118 // compute normals (if not supplied)
121 auto v01 = Vector3(meshVertices[f.vertex[1]].coordinates) - Vector3(meshVertices[f.vertex[0]].coordinates);
122 auto v02 = Vector3(meshVertices[f.vertex[2]].coordinates) - Vector3(meshVertices[f.vertex[0]].coordinates);
123 auto n = v01.Cross(v02);
131 auto& n0 = vertexNormals[faceIndices[i]];
132 auto& n1 = vertexNormals[faceIndices[i + 1]];
133 auto& n2 = vertexNormals[faceIndices[i + 2]];
135 auto faceNormal = (n0 + n1 + n2) / 3.0f;
136 faceNormal.Normalize();
137 f.normal[0] = faceNormal.x;
138 f.normal[1] = -faceNormal.y;
139 f.normal[2] = faceNormal.z;
144 // Create edges, in this case we don't care about duplicates
145 // This mesh cannot be used for navigation
146 std::vector<NavigationMesh::Edge> meshEdges;
147 meshEdges.reserve(meshFaces.size() * 3);
149 for(auto& f : meshFaces)
151 for(auto k = 0u; k < 3; ++k)
153 meshEdges.emplace_back();
154 auto& edge = meshEdges.back();
156 edge.face[1] = NavigationMesh::NULL_FACE;
157 edge.vertex[0] = f.vertex[k];
158 edge.vertex[1] = f.vertex[(k + 1) % 3];
163 std::vector<uint8_t> navigationMeshBinary;
165 // Build navigationMeshBinary binary
166 navigationMeshBinary.insert(navigationMeshBinary.end(),
167 reinterpret_cast<uint8_t*>(&header),
168 reinterpret_cast<uint8_t*>(&header) + sizeof(Internal::Algorithm::NavigationMeshHeader_V10));
170 auto& h = *reinterpret_cast<decltype(header)*>(navigationMeshBinary.data());
172 h.dataOffset = sizeof(header);
173 h.edgeCount = meshEdges.size();
174 h.polyCount = meshFaces.size();
175 h.vertexCount = meshVertices.size();
176 h.gravityVector[0] = 0.0f;
177 h.gravityVector[1] = -1.0f;
178 h.gravityVector[2] = 0.0f;
180 h.vertexDataOffset = 0;
181 h.edgeDataOffset = meshVertices.size() * sizeof(NavigationMesh::Vertex);
182 h.polyDataOffset = h.edgeDataOffset + meshEdges.size() * sizeof(NavigationMesh::Edge);
185 navigationMeshBinary.insert(navigationMeshBinary.end(),
186 reinterpret_cast<uint8_t*>(meshVertices.data()),
187 reinterpret_cast<uint8_t*>(meshVertices.data()) + (meshVertices.size() * sizeof(NavigationMesh::Vertex)));
188 navigationMeshBinary.insert(navigationMeshBinary.end(),
189 reinterpret_cast<uint8_t*>(meshEdges.data()),
190 reinterpret_cast<uint8_t*>(meshEdges.data()) + (meshEdges.size() * sizeof(NavigationMesh::Edge)));
191 navigationMeshBinary.insert(navigationMeshBinary.end(),
192 reinterpret_cast<uint8_t*>(meshFaces.data()),
193 reinterpret_cast<uint8_t*>(meshFaces.data()) + (meshFaces.size() * sizeof(NavigationMesh::Face)));
195 return NavigationMeshFactory::CreateFromBuffer(navigationMeshBinary);
198 std::unique_ptr<Algorithm::NavigationMesh> NavigationMeshFactory::CreateFromVertexFaceList(const std::vector<Vector3>& vertices, const std::vector<Vector3>& normals, const std::vector<uint32_t>& faceIndices)
200 return CreateFromVertexFaceList(vertices.data(), normals.data(), vertices.size(), faceIndices.data(), faceIndices.size());
203 std::vector<uint8_t> NavigationMeshFactory::GetMeshBinary(const Dali::Scene3D::Algorithm::NavigationMesh& navigationMesh)
205 auto& meshImpl = Internal::Algorithm::GetImplementation(navigationMesh);
207 // Return as mutable copy
208 return meshImpl.GetData();
211 } // namespace Dali::Scene3D::Loader