1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qssglightmapuvgenerator_p.h" |
5 | #include "xatlas.h" |
6 | |
7 | QT_BEGIN_NAMESPACE |
8 | |
9 | QSSGLightmapUVGeneratorResult QSSGLightmapUVGenerator::run(const QByteArray &positions, |
10 | const QByteArray &normals, |
11 | const QByteArray &uv0, |
12 | const QByteArray &index, |
13 | QSSGMesh::Mesh::ComponentType indexComponentType, |
14 | uint baseResolution) |
15 | { |
16 | QSSGLightmapUVGeneratorResult result; |
17 | |
18 | xatlas::MeshDecl meshInfo; |
19 | |
20 | if (indexComponentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16) { |
21 | meshInfo.indexFormat = xatlas::IndexFormat::UInt16; |
22 | } else if (indexComponentType == QSSGMesh::Mesh::ComponentType::UnsignedInt32) { |
23 | meshInfo.indexFormat = xatlas::IndexFormat::UInt32; |
24 | } else { |
25 | qWarning(msg: "Lightmap UV generator: Unknown index type %d; cannot generate" , |
26 | int(indexComponentType)); |
27 | return result; |
28 | } |
29 | |
30 | const quint32 indexComponentByteSize = QSSGMesh::MeshInternal::byteSizeForComponentType(componentType: indexComponentType); |
31 | const quint32 indexCount = index.size() / indexComponentByteSize; |
32 | |
33 | meshInfo.indexCount = indexCount; |
34 | meshInfo.indexData = index.constData(); |
35 | |
36 | const quint32 positionStride = 3 * sizeof(float); |
37 | const quint32 normalStride = 3 * sizeof(float); |
38 | const quint32 uvStride = 2 * sizeof(float); |
39 | |
40 | meshInfo.vertexCount = positions.size() / positionStride; |
41 | meshInfo.vertexPositionData = positions.data(); |
42 | meshInfo.vertexPositionStride = positionStride; |
43 | |
44 | if (!normals.isEmpty()) { |
45 | meshInfo.vertexNormalData = normals.constData(); |
46 | meshInfo.vertexNormalStride = normalStride; |
47 | } else { |
48 | meshInfo.vertexNormalData = nullptr; |
49 | meshInfo.vertexNormalStride = 0; |
50 | } |
51 | |
52 | if (!uv0.isEmpty()) { |
53 | meshInfo.vertexUvData = uv0.constData(); |
54 | meshInfo.vertexUvStride = uvStride; |
55 | } else { |
56 | meshInfo.vertexUvData = nullptr; |
57 | meshInfo.vertexUvStride = 0; |
58 | } |
59 | |
60 | xatlas::PackOptions packOptions; |
61 | packOptions.maxChartSize = 4096; |
62 | packOptions.padding = 1; |
63 | packOptions.resolution = baseResolution; |
64 | packOptions.blockAlign = true; |
65 | |
66 | xatlas::ChartOptions chartOptions; |
67 | |
68 | xatlas::Atlas *atlas = xatlas::Create(); |
69 | xatlas::AddMeshError err = xatlas::AddMesh(atlas, meshDecl: meshInfo, meshCountHint: 1); |
70 | if (err != xatlas::AddMeshError::Success) { |
71 | qWarning(msg: "Failed to register mesh for UV unwrapping (error %d)" , int(err)); |
72 | xatlas::Destroy(atlas); |
73 | return result; |
74 | } |
75 | xatlas::Generate(atlas, chartOptions, packOptions); |
76 | |
77 | const uint32_t textureWidth = atlas->width; |
78 | const uint32_t textureHeight = atlas->height; |
79 | if (textureWidth == 0 || textureHeight == 0) { |
80 | qWarning(msg: "Texture size is empty, UV unwrapping failed" ); |
81 | xatlas::Destroy(atlas); |
82 | return result; |
83 | } |
84 | result.lightmapWidth = textureWidth; |
85 | result.lightmapHeight = textureHeight; |
86 | |
87 | const xatlas::Mesh &output = atlas->meshes[0]; |
88 | result.lightmapUVChannel.resize(size: output.vertexCount * uvStride); |
89 | result.vertexMap.resize(size: output.vertexCount); |
90 | |
91 | float *uvPtr = reinterpret_cast<float *>(result.lightmapUVChannel.data()); |
92 | for (uint32_t i = 0; i < output.vertexCount; ++i) { |
93 | const float u = output.vertexArray[i].uv[0] / float(textureWidth); |
94 | const float v = output.vertexArray[i].uv[1] / float(textureHeight); |
95 | *uvPtr++ = u; |
96 | *uvPtr++ = v; |
97 | result.vertexMap[i] = output.vertexArray[i].xref; |
98 | } |
99 | |
100 | result.indexData.resize(size: output.indexCount * sizeof(quint32)); |
101 | quint32 *indexPtr = reinterpret_cast<quint32 *>(result.indexData.data()); |
102 | for (uint32_t i = 0; i < output.indexCount; ++i) |
103 | *indexPtr++ = output.indexArray[i]; |
104 | |
105 | xatlas::Destroy(atlas); |
106 | |
107 | return result; |
108 | } |
109 | |
110 | QT_END_NAMESPACE |
111 | |