1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Quick 3D.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29
30 #include <QtCore/QCoreApplication>
31 #include <QtCore/QCommandLineParser>
32 #include <QtCore/QDebug>
33
34 #include <QtQuick3DAssetImport/private/qssgmeshutilities_p.h>
35
36 #include <QtGui/QMatrix4x4>
37
38 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
39 // QTextStream functions are moved to a namespace in Qt6
40 using Qt::hex;
41 #endif
42
43 using namespace QSSGMeshUtilities;
44
45 class MeshOffsetTracker
46 {
47 public:
MeshOffsetTracker(qint64 startOffset)48 MeshOffsetTracker(qint64 startOffset)
49 : m_startOffset(startOffset)
50 {
51 }
52
needsAlignment()53 bool needsAlignment() { return getAlignmentAmount() > 0; }
getAlignmentAmount()54 quint32 getAlignmentAmount() { return 4 - (m_byteCounter % 4); }
align()55 void align()
56 {
57 if (needsAlignment())
58 m_byteCounter += getAlignmentAmount();
59 }
60
advance(qint64 offset,bool forceAlign=true)61 void advance(qint64 offset, bool forceAlign = true) {
62 m_byteCounter += offset;
63 if (forceAlign)
64 align();
65 }
66
67 template <typename TDataType>
advance(OffsetDataRef<TDataType> & data,bool forceAlign=true)68 void advance(OffsetDataRef<TDataType> &data, bool forceAlign = true)
69 {
70 data.m_offset = m_byteCounter;
71 m_byteCounter += data.size() * sizeof(TDataType);
72 if (forceAlign)
73 align();
74 }
75
startOffset() const76 qint64 startOffset() const
77 {
78 return m_startOffset;
79 }
80
offset() const81 qint64 offset() const
82 {
83 return m_startOffset + m_byteCounter;
84 }
85
86 private:
87 qint64 m_startOffset = 0;
88 qint64 m_byteCounter = 0;
89 };
90
91
main(int argc,char * argv[])92 int main(int argc, char *argv[])
93 {
94 QCoreApplication app(argc, argv);
95
96 // Setup command line arguments
97 QCommandLineParser cmdLineParser;
98 cmdLineParser.process(app);
99 QStringList meshFileNames = cmdLineParser.positionalArguments();
100
101 // if there is nothing to do return early
102 if (meshFileNames.isEmpty())
103 return -1;
104
105 // Process Mesh files
106 for (const auto &meshFileName : meshFileNames) {
107 QFile meshFile(meshFileName);
108 if (!meshFile.open(QIODevice::ReadOnly)) {
109 qWarning() << "could not open " << meshFileName;
110 continue;
111 }
112
113 if (Mesh::isMulti(meshFile)) {
114 MeshMultiHeader* multiHeader = Mesh::loadMultiHeader(meshFile);
115 if (!multiHeader) {
116 qWarning() << "could not read MeshMultiHeader in " << meshFileName;
117 continue;
118 }
119
120 // Print Multiheader information
121 qDebug() << " -- Multiheader -- ";
122 qDebug() << "fileId: " << multiHeader->m_fileId;
123 qDebug() << "version: " << multiHeader->m_version;
124 qDebug() << "mesh entries: " << multiHeader->m_entries.m_size;
125
126 quint8 *theHeaderBaseAddr = reinterpret_cast<quint8 *>(multiHeader);
127 bool foundMesh = false;
128 for (quint32 idx = 0, end = multiHeader->m_entries.size(); idx < end && !foundMesh; ++idx) {
129 const MeshMultiEntry &entry(multiHeader->m_entries.index(theHeaderBaseAddr, idx));
130 qDebug() << "\t -- mesh entry" << idx << " -- ";
131 qDebug() << "\tid: " << entry.m_meshId;
132 qDebug() << "\toffset: " << Qt::hex << entry.m_meshOffset;
133 qDebug() << "\tpadding: " << entry.m_padding;
134
135 meshFile.seek(entry.m_meshOffset);
136
137 // Read mesh header
138 MeshDataHeader header;
139 meshFile.read(reinterpret_cast<char *>(&header), sizeof(MeshDataHeader));
140 qDebug() << "\t -- MeshDataHeader -- ";
141 qDebug() << "\tfileId: " << header.m_fileId;
142 qDebug() << "\tfileVersion: " << header.m_fileVersion;
143 qDebug() << "\tflags: " << header.m_headerFlags;
144 qDebug() << "\tsize(in bytes): " << header.m_sizeInBytes;
145
146 QByteArray meshMetadataData = meshFile.read(sizeof(Mesh));
147 Mesh *mesh = reinterpret_cast<Mesh *>(meshMetadataData.data());
148 MeshOffsetTracker offsetTracker(entry.m_meshOffset + sizeof(MeshDataHeader));
149 offsetTracker.advance(sizeof(Mesh), false);
150
151 // Vertex Buffer
152 qDebug() << "\t\t -- Vertex Buffer --";
153 meshFile.seek(offsetTracker.offset());
154 offsetTracker.advance(mesh->m_vertexBuffer.m_entries);
155 qDebug() << "\t\tentries offset: " << Qt::hex << mesh->m_vertexBuffer.m_entries.m_offset;
156 qDebug() << "\t\tentries size: " << mesh->m_vertexBuffer.m_entries.m_size * sizeof(MeshVertexBufferEntry);
157 QByteArray vertexBufferEntriesData = meshFile.read(mesh->m_vertexBuffer.m_entries.m_size * sizeof(MeshVertexBufferEntry));
158 for (quint32 idx = 0, end = mesh->m_vertexBuffer.m_entries.size(); idx < end; ++idx) {
159 // get name length
160 meshFile.seek(offsetTracker.offset());
161 QByteArray lenghtBuffer = meshFile.read(sizeof (quint32));
162 const quint32 &nameLenght = *reinterpret_cast<const quint32 *>(lenghtBuffer.constData());
163 offsetTracker.advance(sizeof(quint32), false);
164 QByteArray nameBuffer = meshFile.read(nameLenght);
165 offsetTracker.advance(nameLenght);
166 qDebug() << "\t\t\t -- Vertex Buffer Entry " << idx << "-- ";
167 const MeshVertexBufferEntry &entry = reinterpret_cast<const MeshVertexBufferEntry *>(vertexBufferEntriesData.constData())[idx];
168 qDebug() << "\t\t\tname: " << nameBuffer.constData();
169 qDebug() << "\t\t\ttype: " << toString(entry.m_componentType);
170 qDebug() << "\t\t\tnumComponents: " << entry.m_numComponents;
171 qDebug() << "\t\t\tfirstItemOffset: " << entry.m_firstItemOffset;
172 }
173 offsetTracker.advance(mesh->m_vertexBuffer.m_data);
174 qDebug() << "\t\tstride: " << mesh->m_vertexBuffer.m_stride;
175 qDebug() << "\t\tdata Offset: " << Qt::hex << mesh->m_vertexBuffer.m_data.m_offset;
176 qDebug() << "\t\tdata Size: " << mesh->m_vertexBuffer.m_data.m_size * sizeof(quint8);
177
178 // Index Buffer
179 qDebug() << "\t\t -- Index Buffer -- ";
180 offsetTracker.advance(mesh->m_indexBuffer.m_data);
181 qDebug() << "\t\tcomponentType: " << toString(mesh->m_indexBuffer.m_componentType);
182 qDebug() << "\t\tdata Offset: " << Qt::hex << mesh->m_indexBuffer.m_data.m_offset;
183 qDebug() << "\t\tdata Size: " << mesh->m_indexBuffer.m_data.m_size * sizeof(quint8);
184
185 // Subsets
186 qDebug() << "\t\t -- Subsets -- ";
187 meshFile.seek(offsetTracker.offset());
188 offsetTracker.advance(mesh->m_subsets);
189 qDebug() << "\t\toffset: " << Qt::hex << mesh->m_subsets.m_offset;
190 qDebug() << "\t\tsize: " << mesh->m_subsets.m_size * sizeof(MeshSubset);
191 QByteArray subsetEntriesData = meshFile.read(mesh->m_subsets.m_size * sizeof(MeshSubset));
192 for (quint32 idx = 0, end = mesh->m_subsets.size(); idx < end; ++idx) {
193 qDebug() << "\t\t -- Subset " << idx << "-- ";
194 MeshSubset &subset = reinterpret_cast<MeshSubset *>(subsetEntriesData.data())[idx];
195 qDebug() << "\t\thasCount: " << subset.hasCount();
196 qDebug() << "\t\tcount: " << subset.m_count;
197 qDebug() << "\t\toffset(size): " << subset.m_offset;
198 qDebug() << "\t\tbounds: (" << subset.m_bounds.minimum.x() << "," <<
199 subset.m_bounds.minimum.y() << "," <<
200 subset.m_bounds.minimum.z() << ") (" <<
201 subset.m_bounds.maximum.x() << "," <<
202 subset.m_bounds.maximum.y() << "," <<
203 subset.m_bounds.maximum.z() << ")";
204 meshFile.seek(offsetTracker.offset());
205 offsetTracker.advance(subset.m_name);
206 qDebug() << "\t\tname offset: " << Qt::hex << subset.m_name.m_offset;
207 qDebug() << "\t\tname size: " << subset.m_name.m_size * sizeof(char16_t);
208 QByteArray subsetNameBuffer = meshFile.read(subset.m_name.m_size * sizeof(char16_t));
209 const char16_t* name = reinterpret_cast<const char16_t*>(subsetNameBuffer.constData());
210 qDebug() << "\t\tname: " << QString::fromUtf16(name);
211 }
212
213 // Joints
214 qDebug() << "\t\t -- Joints -- ";
215 meshFile.seek(offsetTracker.offset());
216 offsetTracker.advance(mesh->m_joints);
217 qDebug() << "\t\toffset: " << Qt::hex << mesh->m_joints.m_offset;
218 qDebug() << "\t\tsize: " << mesh->m_joints.m_size * sizeof(Joint);
219 QByteArray jointsData = meshFile.read(mesh->m_joints.m_size * sizeof(Joint));
220 for (quint32 idx = 0, end = mesh->m_joints.size(); idx < end; ++idx) {
221 qDebug() << "\t\t -- Joint " << idx << "-- ";
222 const Joint &joint = reinterpret_cast<const Joint *>(jointsData.constData())[idx];
223 qDebug() << "\t\tid: " << joint.m_jointID;
224 qDebug() << "\t\tparentId: " << joint.m_parentID;
225 qDebug() << "\t\tinvBindPose: " << QMatrix4x4(joint.m_invBindPose);
226 qDebug() << "\t\tlocalToGlobalBoneSpace: " << QMatrix4x4(joint.m_localToGlobalBoneSpace);
227 }
228
229 // Draw Mode
230 qDebug() << "\t\tdraw Mode: " << static_cast<int>(mesh->m_drawMode);
231
232 // Winding
233 qDebug() << "\t\twinding: " << toString(mesh->m_winding);
234
235 }
236
237 }
238
239 meshFile.close();
240 qDebug() << "closed meshFile";
241 }
242
243 return 0;
244 }
245