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