1// Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QT3DRENDER_BASEGEOMETRYLOADER_H
5#define QT3DRENDER_BASEGEOMETRYLOADER_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists for the convenience
12// of other Qt classes. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/QObject>
19
20#include <QtGui/QVector2D>
21#include <QtGui/QVector3D>
22#include <QtGui/QVector4D>
23
24#include <Qt3DRender/private/qgeometryloaderinterface_p.h>
25
26#include <vector>
27
28#include <private/qlocale_tools_p.h>
29
30QT_BEGIN_NAMESPACE
31
32class QIODevice;
33class QString;
34
35namespace Qt3DCore {
36class QGeometry;
37}
38
39namespace Qt3DRender {
40
41class BaseGeometryLoader : public QGeometryLoaderInterface
42{
43 Q_OBJECT
44public:
45 BaseGeometryLoader();
46
47 void setLoadTextureCoordinatesEnabled(bool b) { m_loadTextureCoords = b; }
48 bool isLoadTextureCoordinatesEnabled() const { return m_loadTextureCoords; }
49
50 void setTangentGenerationEnabled(bool b) { m_generateTangents = b; }
51 bool isTangentGenerationEnabled() const { return m_generateTangents; }
52
53 void setMeshCenteringEnabled(bool b) { m_centerMesh = b; }
54 bool isMeshCenteringEnabled() const { return m_centerMesh; }
55
56 bool hasNormals() const { return !m_normals.empty(); }
57 bool hasTextureCoordinates() const { return !m_texCoords.empty(); }
58 bool hasTangents() const { return !m_tangents.empty(); }
59
60 const std::vector<QVector3D> &vertices() const { return m_points; }
61 const std::vector<QVector3D> &normals() const { return m_normals; }
62 const std::vector<QVector2D> &textureCoordinates() const { return m_texCoords; }
63 const std::vector<QVector4D> &tangents() const { return m_tangents; }
64 const std::vector<unsigned int> &indices() const { return m_indices; }
65
66 Qt3DCore::QGeometry *geometry() const override;
67
68 bool load(QIODevice *ioDev, const QString &subMesh = QString()) override;
69
70protected:
71 virtual bool doLoad(QIODevice *ioDev, const QString &subMesh = QString()) = 0;
72
73 void generateAveragedNormals(const std::vector<QVector3D>& points,
74 std::vector<QVector3D>& normals,
75 const std::vector<unsigned int>& faces) const;
76 void generateGeometry();
77 void generateTangents(const std::vector<QVector3D>& points,
78 const std::vector<QVector3D>& normals,
79 const std::vector<unsigned int>& faces,
80 const std::vector<QVector2D>& texCoords,
81 std::vector<QVector4D>& tangents) const;
82 void center(std::vector<QVector3D>& points);
83
84 bool m_loadTextureCoords;
85 bool m_generateTangents;
86 bool m_centerMesh;
87
88 std::vector<QVector3D> m_points;
89 std::vector<QVector3D> m_normals;
90 std::vector<QVector2D> m_texCoords;
91 std::vector<QVector4D> m_tangents;
92 std::vector<unsigned int> m_indices;
93
94 Qt3DCore::QGeometry *m_geometry;
95};
96
97struct FaceIndices
98{
99 FaceIndices()
100 : positionIndex(std::numeric_limits<unsigned int>::max())
101 , texCoordIndex(std::numeric_limits<unsigned int>::max())
102 , normalIndex(std::numeric_limits<unsigned int>::max())
103 {}
104
105 FaceIndices(unsigned int posIndex, unsigned int tcIndex, unsigned int nIndex)
106 : positionIndex(posIndex)
107 , texCoordIndex(tcIndex)
108 , normalIndex(nIndex)
109 {}
110
111 bool operator == (const FaceIndices &other) const
112 {
113 return positionIndex == other.positionIndex &&
114 texCoordIndex == other.texCoordIndex &&
115 normalIndex == other.normalIndex;
116 }
117
118 unsigned int positionIndex;
119 unsigned int texCoordIndex;
120 unsigned int normalIndex;
121};
122QT3D_DECLARE_TYPEINFO(Qt3DRender, FaceIndices, Q_PRIMITIVE_TYPE)
123
124struct ByteArraySplitterEntry
125{
126 int start;
127 int size;
128};
129QT3D_DECLARE_TYPEINFO(Qt3DRender, ByteArraySplitterEntry, Q_PRIMITIVE_TYPE)
130
131/*
132 * A helper class to split a QByteArray and access its sections without
133 * additional memory allocations.
134 */
135class ByteArraySplitter
136{
137public:
138 explicit ByteArraySplitter(const char *begin, const char *end, char delimiter, Qt::SplitBehavior splitBehavior)
139 : m_input(begin)
140 {
141 int position = 0;
142 int lastPosition = 0;
143 for (auto it = begin; it != end; ++it) {
144 if (*it == delimiter) {
145 if (position > lastPosition || splitBehavior == Qt::KeepEmptyParts) { // skip multiple consecutive delimiters
146 const ByteArraySplitterEntry entry = { .start: lastPosition, .size: position - lastPosition };
147 m_entries.append(t: entry);
148 }
149 lastPosition = position + 1;
150 }
151
152 ++position;
153 }
154
155 const ByteArraySplitterEntry entry = { .start: lastPosition, .size: position - lastPosition };
156 m_entries.append(t: entry);
157 }
158
159 int size() const
160 {
161 return m_entries.size();
162 }
163
164 const char *charPtrAt(int index) const
165 {
166 return m_input + m_entries[index].start;
167 }
168
169 float floatAt(int index) const
170 {
171 return qstrntod(s00: m_input + m_entries[index].start, len: m_entries[index].size, se: nullptr, ok: nullptr);
172 }
173
174 int intAt(int index) const
175 {
176 return strtol(nptr: m_input + m_entries[index].start, endptr: nullptr, base: 10);
177 }
178
179 QString stringAt(int index) const
180 {
181 return QString::fromLatin1(str: m_input + m_entries[index].start, size: m_entries[index].size);
182 }
183
184 ByteArraySplitter splitterAt(int index, char delimiter, Qt::SplitBehavior splitBehavior) const
185 {
186 return ByteArraySplitter(m_input + m_entries[index].start, m_input + m_entries[index].start + m_entries[index].size, delimiter, splitBehavior);
187 }
188
189private:
190 QVarLengthArray<ByteArraySplitterEntry, 16> m_entries;
191 const char *m_input;
192};
193
194} // namespace Qt3DRender
195
196QT_END_NAMESPACE
197
198#endif // QT3DRENDER_BASEGEOMETRYLOADER_H
199

source code of qt3d/src/plugins/geometryloaders/default/basegeometryloader_p.h