1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "meshloader_p.h" |
5 | #include "vertexindexer_p.h" |
6 | #include "objecthelper_p.h" |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | ObjectHelper::ObjectHelper(const QString &objectFile) |
11 | : m_objectFile(objectFile) |
12 | { |
13 | load(); |
14 | } |
15 | |
16 | struct ObjectHelperRef { |
17 | int refCount; |
18 | ObjectHelper *obj; |
19 | }; |
20 | |
21 | // The "Abstract3DRenderer *" key identifies the renderer |
22 | static QHash<const Abstract3DRenderer *, QHash<QString, ObjectHelperRef *> *> cacheTable; |
23 | |
24 | ObjectHelper::~ObjectHelper() |
25 | { |
26 | } |
27 | |
28 | void ObjectHelper::resetObjectHelper(const Abstract3DRenderer *cacheId, ObjectHelper *&obj, |
29 | const QString &meshFile) |
30 | { |
31 | Q_ASSERT(cacheId); |
32 | |
33 | if (obj) { |
34 | const QString &oldFile = obj->objectFile(); |
35 | if (meshFile == oldFile) |
36 | return; // same file, do nothing |
37 | releaseObjectHelper(cacheId, obj); |
38 | } |
39 | obj = getObjectHelper(cacheId, objectFile: meshFile); |
40 | } |
41 | |
42 | void ObjectHelper::releaseObjectHelper(const Abstract3DRenderer *cacheId, ObjectHelper *&obj) |
43 | { |
44 | Q_ASSERT(cacheId); |
45 | |
46 | if (obj) { |
47 | QHash<QString, ObjectHelperRef *> *objectTable = cacheTable.value(key: cacheId, defaultValue: 0); |
48 | if (objectTable) { |
49 | // Delete object if last reference is released |
50 | ObjectHelperRef *objRef = objectTable->value(key: obj->m_objectFile, defaultValue: 0); |
51 | if (objRef) { |
52 | objRef->refCount--; |
53 | if (objRef->refCount <= 0) { |
54 | objectTable->remove(key: obj->m_objectFile); |
55 | delete objRef->obj; |
56 | delete objRef; |
57 | } |
58 | } |
59 | if (objectTable->isEmpty()) { |
60 | // Remove the entire cache if last object was removed |
61 | cacheTable.remove(key: cacheId); |
62 | delete objectTable; |
63 | } |
64 | } else { |
65 | // Just delete the object if unknown cache |
66 | delete obj; |
67 | } |
68 | obj = 0; |
69 | } |
70 | } |
71 | |
72 | ObjectHelper *ObjectHelper::getObjectHelper(const Abstract3DRenderer *cacheId, |
73 | const QString &objectFile) |
74 | { |
75 | if (objectFile.isEmpty()) |
76 | return 0; |
77 | |
78 | QHash<QString, ObjectHelperRef *> *objectTable = cacheTable.value(key: cacheId, defaultValue: 0); |
79 | if (!objectTable) { |
80 | objectTable = new QHash<QString, ObjectHelperRef *>; |
81 | cacheTable.insert(key: cacheId, value: objectTable); |
82 | } |
83 | |
84 | // Check if object helper for this mesh already exists |
85 | ObjectHelperRef *objRef = objectTable->value(key: objectFile, defaultValue: 0); |
86 | if (!objRef) { |
87 | objRef = new ObjectHelperRef; |
88 | objRef->refCount = 0; |
89 | objRef->obj = new ObjectHelper(objectFile); |
90 | if (objRef->obj->m_meshDataLoaded) { |
91 | objectTable->insert(key: objectFile, value: objRef); |
92 | } else { |
93 | delete objRef->obj; |
94 | delete objRef; |
95 | objRef = nullptr; |
96 | } |
97 | } |
98 | if (objRef) { |
99 | objRef->refCount++; |
100 | return objRef->obj; |
101 | } |
102 | return nullptr; |
103 | } |
104 | |
105 | void ObjectHelper::load() |
106 | { |
107 | if (m_meshDataLoaded) { |
108 | // Delete old data |
109 | glDeleteBuffers(n: 1, buffers: &m_vertexbuffer); |
110 | glDeleteBuffers(n: 1, buffers: &m_uvbuffer); |
111 | glDeleteBuffers(n: 1, buffers: &m_normalbuffer); |
112 | glDeleteBuffers(n: 1, buffers: &m_elementbuffer); |
113 | m_indices.clear(); |
114 | m_indexedVertices.clear(); |
115 | m_indexedUVs.clear(); |
116 | m_indexedNormals.clear(); |
117 | m_vertexbuffer = 0; |
118 | m_uvbuffer = 0; |
119 | m_normalbuffer = 0; |
120 | m_elementbuffer = 0; |
121 | } |
122 | QList<QVector3D> vertices; |
123 | QList<QVector2D> uvs; |
124 | QList<QVector3D> normals; |
125 | bool loadOk = MeshLoader::loadOBJ(path: m_objectFile, out_vertices&: vertices, out_uvs&: uvs, out_normals&: normals); |
126 | |
127 | if (!loadOk) { |
128 | qCritical() << "Loading" << m_objectFile << "failed" ; |
129 | m_meshDataLoaded = false; |
130 | } else { |
131 | // Index vertices |
132 | VertexIndexer::indexVBO(in_vertices: vertices, in_uvs: uvs, in_normals: normals, out_indices&: m_indices, out_vertices&: m_indexedVertices, out_uvs&: m_indexedUVs, |
133 | out_normals&: m_indexedNormals); |
134 | |
135 | m_indexCount = m_indices.size(); |
136 | |
137 | glGenBuffers(n: 1, buffers: &m_vertexbuffer); |
138 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_vertexbuffer); |
139 | glBufferData(GL_ARRAY_BUFFER, size: m_indexedVertices.size() * sizeof(QVector3D), |
140 | data: &m_indexedVertices.at(i: 0), |
141 | GL_STATIC_DRAW); |
142 | |
143 | glGenBuffers(n: 1, buffers: &m_normalbuffer); |
144 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_normalbuffer); |
145 | glBufferData(GL_ARRAY_BUFFER, size: m_indexedNormals.size() * sizeof(QVector3D), |
146 | data: &m_indexedNormals.at(i: 0), |
147 | GL_STATIC_DRAW); |
148 | |
149 | glGenBuffers(n: 1, buffers: &m_uvbuffer); |
150 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_uvbuffer); |
151 | glBufferData(GL_ARRAY_BUFFER, size: m_indexedUVs.size() * sizeof(QVector2D), |
152 | data: &m_indexedUVs.at(i: 0), GL_STATIC_DRAW); |
153 | |
154 | glGenBuffers(n: 1, buffers: &m_elementbuffer); |
155 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: m_elementbuffer); |
156 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size: m_indices.size() * sizeof(GLuint), |
157 | data: &m_indices.at(i: 0), GL_STATIC_DRAW); |
158 | |
159 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
160 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: 0); |
161 | |
162 | m_meshDataLoaded = true; |
163 | } |
164 | } |
165 | |
166 | QT_END_NAMESPACE |
167 | |