1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Data Visualization module of the Qt Toolkit. |
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 "meshloader_p.h" |
31 | #include "vertexindexer_p.h" |
32 | #include "objecthelper_p.h" |
33 | |
34 | QT_BEGIN_NAMESPACE_DATAVISUALIZATION |
35 | |
36 | ObjectHelper::ObjectHelper(const QString &objectFile) |
37 | : m_objectFile(objectFile) |
38 | { |
39 | load(); |
40 | } |
41 | |
42 | struct ObjectHelperRef { |
43 | int refCount; |
44 | ObjectHelper *obj; |
45 | }; |
46 | |
47 | // The "Abstract3DRenderer *" key identifies the renderer |
48 | static QHash<const Abstract3DRenderer *, QHash<QString, ObjectHelperRef *> *> cacheTable; |
49 | |
50 | ObjectHelper::~ObjectHelper() |
51 | { |
52 | } |
53 | |
54 | void ObjectHelper::resetObjectHelper(const Abstract3DRenderer *cacheId, ObjectHelper *&obj, |
55 | const QString &meshFile) |
56 | { |
57 | Q_ASSERT(cacheId); |
58 | |
59 | if (obj) { |
60 | const QString &oldFile = obj->objectFile(); |
61 | if (meshFile == oldFile) |
62 | return; // same file, do nothing |
63 | releaseObjectHelper(cacheId, obj); |
64 | } |
65 | obj = getObjectHelper(cacheId, objectFile: meshFile); |
66 | } |
67 | |
68 | void ObjectHelper::releaseObjectHelper(const Abstract3DRenderer *cacheId, ObjectHelper *&obj) |
69 | { |
70 | Q_ASSERT(cacheId); |
71 | |
72 | if (obj) { |
73 | QHash<QString, ObjectHelperRef *> *objectTable = cacheTable.value(akey: cacheId, adefaultValue: 0); |
74 | if (objectTable) { |
75 | // Delete object if last reference is released |
76 | ObjectHelperRef *objRef = objectTable->value(akey: obj->m_objectFile, adefaultValue: 0); |
77 | if (objRef) { |
78 | objRef->refCount--; |
79 | if (objRef->refCount <= 0) { |
80 | objectTable->remove(akey: obj->m_objectFile); |
81 | delete objRef->obj; |
82 | delete objRef; |
83 | } |
84 | } |
85 | if (objectTable->isEmpty()) { |
86 | // Remove the entire cache if last object was removed |
87 | cacheTable.remove(akey: cacheId); |
88 | delete objectTable; |
89 | } |
90 | } else { |
91 | // Just delete the object if unknown cache |
92 | delete obj; |
93 | } |
94 | obj = 0; |
95 | } |
96 | } |
97 | |
98 | ObjectHelper *ObjectHelper::getObjectHelper(const Abstract3DRenderer *cacheId, |
99 | const QString &objectFile) |
100 | { |
101 | if (objectFile.isEmpty()) |
102 | return 0; |
103 | |
104 | QHash<QString, ObjectHelperRef *> *objectTable = cacheTable.value(akey: cacheId, adefaultValue: 0); |
105 | if (!objectTable) { |
106 | objectTable = new QHash<QString, ObjectHelperRef *>; |
107 | cacheTable.insert(akey: cacheId, avalue: objectTable); |
108 | } |
109 | |
110 | // Check if object helper for this mesh already exists |
111 | ObjectHelperRef *objRef = objectTable->value(akey: objectFile, adefaultValue: 0); |
112 | if (!objRef) { |
113 | objRef = new ObjectHelperRef; |
114 | objRef->refCount = 0; |
115 | objRef->obj = new ObjectHelper(objectFile); |
116 | objectTable->insert(akey: objectFile, avalue: objRef); |
117 | } |
118 | objRef->refCount++; |
119 | return objRef->obj; |
120 | } |
121 | |
122 | void ObjectHelper::load() |
123 | { |
124 | if (m_meshDataLoaded) { |
125 | // Delete old data |
126 | glDeleteBuffers(n: 1, buffers: &m_vertexbuffer); |
127 | glDeleteBuffers(n: 1, buffers: &m_uvbuffer); |
128 | glDeleteBuffers(n: 1, buffers: &m_normalbuffer); |
129 | glDeleteBuffers(n: 1, buffers: &m_elementbuffer); |
130 | m_indices.clear(); |
131 | m_indexedVertices.clear(); |
132 | m_indexedUVs.clear(); |
133 | m_indexedNormals.clear(); |
134 | m_vertexbuffer = 0; |
135 | m_uvbuffer = 0; |
136 | m_normalbuffer = 0; |
137 | m_elementbuffer = 0; |
138 | } |
139 | QVector<QVector3D> vertices; |
140 | QVector<QVector2D> uvs; |
141 | QVector<QVector3D> normals; |
142 | bool loadOk = MeshLoader::loadOBJ(path: m_objectFile, out_vertices&: vertices, out_uvs&: uvs, out_normals&: normals); |
143 | if (!loadOk) |
144 | qFatal(msg: "loading failed" ); |
145 | |
146 | // Index vertices |
147 | VertexIndexer::indexVBO(in_vertices: vertices, in_uvs: uvs, in_normals: normals, out_indices&: m_indices, out_vertices&: m_indexedVertices, out_uvs&: m_indexedUVs, |
148 | out_normals&: m_indexedNormals); |
149 | |
150 | m_indexCount = m_indices.size(); |
151 | |
152 | glGenBuffers(n: 1, buffers: &m_vertexbuffer); |
153 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_vertexbuffer); |
154 | glBufferData(GL_ARRAY_BUFFER, size: m_indexedVertices.size() * sizeof(QVector3D), |
155 | data: &m_indexedVertices.at(i: 0), |
156 | GL_STATIC_DRAW); |
157 | |
158 | glGenBuffers(n: 1, buffers: &m_normalbuffer); |
159 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_normalbuffer); |
160 | glBufferData(GL_ARRAY_BUFFER, size: m_indexedNormals.size() * sizeof(QVector3D), |
161 | data: &m_indexedNormals.at(i: 0), |
162 | GL_STATIC_DRAW); |
163 | |
164 | glGenBuffers(n: 1, buffers: &m_uvbuffer); |
165 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_uvbuffer); |
166 | glBufferData(GL_ARRAY_BUFFER, size: m_indexedUVs.size() * sizeof(QVector2D), |
167 | data: &m_indexedUVs.at(i: 0), GL_STATIC_DRAW); |
168 | |
169 | glGenBuffers(n: 1, buffers: &m_elementbuffer); |
170 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: m_elementbuffer); |
171 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size: m_indices.size() * sizeof(GLuint), |
172 | data: &m_indices.at(i: 0), GL_STATIC_DRAW); |
173 | |
174 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
175 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: 0); |
176 | |
177 | m_meshDataLoaded = true; |
178 | } |
179 | |
180 | QT_END_NAMESPACE_DATAVISUALIZATION |
181 | |