History

Merge branch 'master' of https://github.com/highfidelity/hifi into applications_diet

Atlante45 committed 11 years ago

Commit 11a2eca2 parents 2039895 7632dbe92 files · +607 −340Browse files

Showing the changes to libraries/render-utils/src/GeometryCache.cpp (1 of 92 files). Show all

Unified · Split

libraries/render-utils/src/GeometryCache.cpp+1076−0
@@ -0,0 +1,1076 @@
1+//
2+// GeometryCache.cpp
3+// interface/src/renderer
4+//
5+// Created by Andrzej Kapolka on 6/21/13.
6+// Copyright 2013 High Fidelity, Inc.
7+//
8+// Distributed under the Apache License, Version 2.0.
9+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10+//
11+
12+// include this before QOpenGLBuffer, which includes an earlier version of OpenGL
13+#include <gpu/GPUConfig.h>
14+
15+#include <cmath>
16+
17+#include <QNetworkReply>
18+#include <QRunnable>
19+#include <QThreadPool>
20+
21+#include <SharedUtil.h>
22+
23+#include "TextureCache.h"
24+#include "GeometryCache.h"
25+
26+GeometryCache::GeometryCache() {
27+}
28+
29+GeometryCache::~GeometryCache() {
30+ foreach (const VerticesIndices& vbo, _hemisphereVBOs) {
31+ glDeleteBuffers(1, &vbo.first);
32+ glDeleteBuffers(1, &vbo.second);
33+ }
34+}
35+
36+void GeometryCache::renderHemisphere(int slices, int stacks) {
37+ VerticesIndices& vbo = _hemisphereVBOs[IntPair(slices, stacks)];
38+ int vertices = slices * (stacks - 1) + 1;
39+ int indices = slices * 2 * 3 * (stacks - 2) + slices * 3;
40+ if (vbo.first == 0) {
41+ GLfloat* vertexData = new GLfloat[vertices * 3];
42+ GLfloat* vertex = vertexData;
43+ for (int i = 0; i < stacks - 1; i++) {
44+ float phi = PI_OVER_TWO * (float)i / (float)(stacks - 1);
45+ float z = sinf(phi), radius = cosf(phi);
46+
47+ for (int j = 0; j < slices; j++) {
48+ float theta = TWO_PI * (float)j / (float)slices;
49+
50+ *(vertex++) = sinf(theta) * radius;
51+ *(vertex++) = cosf(theta) * radius;
52+ *(vertex++) = z;
53+ }
54+ }
55+ *(vertex++) = 0.0f;
56+ *(vertex++) = 0.0f;
57+ *(vertex++) = 1.0f;
58+
59+ glGenBuffers(1, &vbo.first);
60+ glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
61+ const int BYTES_PER_VERTEX = 3 * sizeof(GLfloat);
62+ glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);
63+ delete[] vertexData;
64+
65+ GLushort* indexData = new GLushort[indices];
66+ GLushort* index = indexData;
67+ for (int i = 0; i < stacks - 2; i++) {
68+ GLushort bottom = i * slices;
69+ GLushort top = bottom + slices;
70+ for (int j = 0; j < slices; j++) {
71+ int next = (j + 1) % slices;
72+
73+ *(index++) = bottom + j;
74+ *(index++) = top + next;
75+ *(index++) = top + j;
76+
77+ *(index++) = bottom + j;
78+ *(index++) = bottom + next;
79+ *(index++) = top + next;
80+ }
81+ }
82+ GLushort bottom = (stacks - 2) * slices;
83+ GLushort top = bottom + slices;
84+ for (int i = 0; i < slices; i++) {
85+ *(index++) = bottom + i;
86+ *(index++) = bottom + (i + 1) % slices;
87+ *(index++) = top;
88+ }
89+
90+ glGenBuffers(1, &vbo.second);
91+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
92+ const int BYTES_PER_INDEX = sizeof(GLushort);
93+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);
94+ delete[] indexData;
95+
96+ } else {
97+ glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
98+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
99+ }
100+ glEnableClientState(GL_VERTEX_ARRAY);
101+ glEnableClientState(GL_NORMAL_ARRAY);
102+
103+ glVertexPointer(3, GL_FLOAT, 0, 0);
104+ glNormalPointer(GL_FLOAT, 0, 0);
105+
106+ glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);
107+
108+ glDisableClientState(GL_VERTEX_ARRAY);
109+ glDisableClientState(GL_NORMAL_ARRAY);
110+
111+ glBindBuffer(GL_ARRAY_BUFFER, 0);
112+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
113+}
114+
115+const int NUM_VERTICES_PER_TRIANGLE = 3;
116+const int NUM_TRIANGLES_PER_QUAD = 2;
117+const int NUM_VERTICES_PER_TRIANGULATED_QUAD = NUM_VERTICES_PER_TRIANGLE * NUM_TRIANGLES_PER_QUAD;
118+const int NUM_COORDS_PER_VERTEX = 3;
119+const int NUM_BYTES_PER_VERTEX = NUM_COORDS_PER_VERTEX * sizeof(GLfloat);
120+const int NUM_BYTES_PER_INDEX = sizeof(GLushort);
121+
122+void GeometryCache::renderSphere(float radius, int slices, int stacks) {
123+ VerticesIndices& vbo = _sphereVBOs[IntPair(slices, stacks)];
124+ int vertices = slices * (stacks - 1) + 2;
125+ int indices = slices * stacks * NUM_VERTICES_PER_TRIANGULATED_QUAD;
126+ if (vbo.first == 0) {
127+ GLfloat* vertexData = new GLfloat[vertices * NUM_COORDS_PER_VERTEX];
128+ GLfloat* vertex = vertexData;
129+
130+ // south pole
131+ *(vertex++) = 0.0f;
132+ *(vertex++) = 0.0f;
133+ *(vertex++) = -1.0f;
134+
135+ //add stacks vertices climbing up Y axis
136+ for (int i = 1; i < stacks; i++) {
137+ float phi = PI * (float)i / (float)(stacks) - PI_OVER_TWO;
138+ float z = sinf(phi), radius = cosf(phi);
139+
140+ for (int j = 0; j < slices; j++) {
141+ float theta = TWO_PI * (float)j / (float)slices;
142+
143+ *(vertex++) = sinf(theta) * radius;
144+ *(vertex++) = cosf(theta) * radius;
145+ *(vertex++) = z;
146+ }
147+ }
148+
149+ // north pole
150+ *(vertex++) = 0.0f;
151+ *(vertex++) = 0.0f;
152+ *(vertex++) = 1.0f;
153+
154+ glGenBuffers(1, &vbo.first);
155+ glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
156+ glBufferData(GL_ARRAY_BUFFER, vertices * NUM_BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);
157+ delete[] vertexData;
158+
159+ GLushort* indexData = new GLushort[indices];
160+ GLushort* index = indexData;
161+
162+ // South cap
163+ GLushort bottom = 0;
164+ GLushort top = 1;
165+ for (int i = 0; i < slices; i++) {
166+ *(index++) = bottom;
167+ *(index++) = top + i;
168+ *(index++) = top + (i + 1) % slices;
169+ }
170+
171+ // (stacks - 2) ribbons
172+ for (int i = 0; i < stacks - 2; i++) {
173+ bottom = i * slices + 1;
174+ top = bottom + slices;
175+ for (int j = 0; j < slices; j++) {
176+ int next = (j + 1) % slices;
177+
178+ *(index++) = top + next;
179+ *(index++) = bottom + j;
180+ *(index++) = top + j;
181+
182+ *(index++) = bottom + next;
183+ *(index++) = bottom + j;
184+ *(index++) = top + next;
185+ }
186+ }
187+
188+ // north cap
189+ bottom = (stacks - 2) * slices + 1;
190+ top = bottom + slices;
191+ for (int i = 0; i < slices; i++) {
192+ *(index++) = bottom + (i + 1) % slices;
193+ *(index++) = bottom + i;
194+ *(index++) = top;
195+ }
196+
197+ glGenBuffers(1, &vbo.second);
198+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
199+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * NUM_BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);
200+ delete[] indexData;
201+
202+ } else {
203+ glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
204+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
205+ }
206+ glEnableClientState(GL_VERTEX_ARRAY);
207+ glEnableClientState(GL_NORMAL_ARRAY);
208+
209+ glVertexPointer(3, GL_FLOAT, 0, 0);
210+ glNormalPointer(GL_FLOAT, 0, 0);
211+
212+ glPushMatrix();
213+ glScalef(radius, radius, radius);
214+ glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);
215+ glPopMatrix();
216+
217+ glDisableClientState(GL_VERTEX_ARRAY);
218+ glDisableClientState(GL_NORMAL_ARRAY);
219+
220+ glBindBuffer(GL_ARRAY_BUFFER, 0);
221+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
222+}
223+
224+void GeometryCache::renderSquare(int xDivisions, int yDivisions) {
225+ VerticesIndices& vbo = _squareVBOs[IntPair(xDivisions, yDivisions)];
226+ int xVertices = xDivisions + 1;
227+ int yVertices = yDivisions + 1;
228+ int vertices = xVertices * yVertices;
229+ int indices = 2 * 3 * xDivisions * yDivisions;
230+ if (vbo.first == 0) {
231+ GLfloat* vertexData = new GLfloat[vertices * 3];
232+ GLfloat* vertex = vertexData;
233+ for (int i = 0; i <= yDivisions; i++) {
234+ float y = (float)i / yDivisions;
235+
236+ for (int j = 0; j <= xDivisions; j++) {
237+ *(vertex++) = (float)j / xDivisions;
238+ *(vertex++) = y;
239+ *(vertex++) = 0.0f;
240+ }
241+ }
242+
243+ glGenBuffers(1, &vbo.first);
244+ glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
245+ glBufferData(GL_ARRAY_BUFFER, vertices * NUM_BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);
246+ delete[] vertexData;
247+
248+ GLushort* indexData = new GLushort[indices];
249+ GLushort* index = indexData;
250+ for (int i = 0; i < yDivisions; i++) {
251+ GLushort bottom = i * xVertices;
252+ GLushort top = bottom + xVertices;
253+ for (int j = 0; j < xDivisions; j++) {
254+ int next = j + 1;
255+
256+ *(index++) = bottom + j;
257+ *(index++) = top + next;
258+ *(index++) = top + j;
259+
260+ *(index++) = bottom + j;
261+ *(index++) = bottom + next;
262+ *(index++) = top + next;
263+ }
264+ }
265+
266+ glGenBuffers(1, &vbo.second);
267+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
268+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * NUM_BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);
269+ delete[] indexData;
270+
271+ } else {
272+ glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
273+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
274+ }
275+ glEnableClientState(GL_VERTEX_ARRAY);
276+
277+ // all vertices have the same normal
278+ glNormal3f(0.0f, 0.0f, 1.0f);
279+
280+ glVertexPointer(3, GL_FLOAT, 0, 0);
281+
282+ glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);
283+
284+ glDisableClientState(GL_VERTEX_ARRAY);
285+
286+ glBindBuffer(GL_ARRAY_BUFFER, 0);
287+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
288+}
289+
290+void GeometryCache::renderHalfCylinder(int slices, int stacks) {
291+ VerticesIndices& vbo = _halfCylinderVBOs[IntPair(slices, stacks)];
292+ int vertices = (slices + 1) * stacks;
293+ int indices = 2 * 3 * slices * (stacks - 1);
294+ if (vbo.first == 0) {
295+ GLfloat* vertexData = new GLfloat[vertices * 2 * 3];
296+ GLfloat* vertex = vertexData;
297+ for (int i = 0; i <= (stacks - 1); i++) {
298+ float y = (float)i / (stacks - 1);
299+
300+ for (int j = 0; j <= slices; j++) {
301+ float theta = 3.0f * PI_OVER_TWO + PI * (float)j / (float)slices;
302+
303+ //normals
304+ *(vertex++) = sinf(theta);
305+ *(vertex++) = 0;
306+ *(vertex++) = cosf(theta);
307+
308+ // vertices
309+ *(vertex++) = sinf(theta);
310+ *(vertex++) = y;
311+ *(vertex++) = cosf(theta);
312+ }
313+ }
314+
315+ glGenBuffers(1, &vbo.first);
316+ glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
317+ glBufferData(GL_ARRAY_BUFFER, 2 * vertices * NUM_BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);
318+ delete[] vertexData;
319+
320+ GLushort* indexData = new GLushort[indices];
321+ GLushort* index = indexData;
322+ for (int i = 0; i < stacks - 1; i++) {
323+ GLushort bottom = i * (slices + 1);
324+ GLushort top = bottom + slices + 1;
325+ for (int j = 0; j < slices; j++) {
326+ int next = j + 1;
327+
328+ *(index++) = bottom + j;
329+ *(index++) = top + next;
330+ *(index++) = top + j;
331+
332+ *(index++) = bottom + j;
333+ *(index++) = bottom + next;
334+ *(index++) = top + next;
335+ }
336+ }
337+
338+ glGenBuffers(1, &vbo.second);
339+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
340+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * NUM_BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);
341+ delete[] indexData;
342+
343+ } else {
344+ glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
345+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
346+ }
347+ glEnableClientState(GL_VERTEX_ARRAY);
348+ glEnableClientState(GL_NORMAL_ARRAY);
349+
350+ glNormalPointer(GL_FLOAT, 6 * sizeof(float), 0);
351+ glVertexPointer(3, GL_FLOAT, (6 * sizeof(float)), (const void *)(3 * sizeof(float)));
352+
353+ glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);
354+
355+ glDisableClientState(GL_VERTEX_ARRAY);
356+ glDisableClientState(GL_NORMAL_ARRAY);
357+
358+ glBindBuffer(GL_ARRAY_BUFFER, 0);
359+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
360+}
361+
362+void GeometryCache::renderCone(float base, float height, int slices, int stacks) {
363+ VerticesIndices& vbo = _halfCylinderVBOs[IntPair(slices, stacks)];
364+ int vertices = (stacks + 2) * slices;
365+ int baseTriangles = slices - 2;
366+ int indices = NUM_VERTICES_PER_TRIANGULATED_QUAD * slices * stacks + NUM_VERTICES_PER_TRIANGLE * baseTriangles;
367+ if (vbo.first == 0) {
368+ GLfloat* vertexData = new GLfloat[vertices * NUM_COORDS_PER_VERTEX * 2];
369+ GLfloat* vertex = vertexData;
370+ // cap
371+ for (int i = 0; i < slices; i++) {
372+ float theta = TWO_PI * i / slices;
373+
374+ //normals
375+ *(vertex++) = 0.0f;
376+ *(vertex++) = 0.0f;
377+ *(vertex++) = -1.0f;
378+
379+ // vertices
380+ *(vertex++) = cosf(theta);
381+ *(vertex++) = sinf(theta);
382+ *(vertex++) = 0.0f;
383+ }
384+ // body
385+ for (int i = 0; i <= stacks; i++) {
386+ float z = (float)i / stacks;
387+ float radius = 1.0f - z;
388+
389+ for (int j = 0; j < slices; j++) {
390+ float theta = TWO_PI * j / slices;
391+
392+ //normals
393+ *(vertex++) = cosf(theta) / SQUARE_ROOT_OF_2;
394+ *(vertex++) = sinf(theta) / SQUARE_ROOT_OF_2;
395+ *(vertex++) = 1.0f / SQUARE_ROOT_OF_2;
396+
397+ // vertices
398+ *(vertex++) = radius * cosf(theta);
399+ *(vertex++) = radius * sinf(theta);
400+ *(vertex++) = z;
401+ }
402+ }
403+
404+ glGenBuffers(1, &vbo.first);
405+ glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
406+ glBufferData(GL_ARRAY_BUFFER, 2 * vertices * NUM_BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);
407+ delete[] vertexData;
408+
409+ GLushort* indexData = new GLushort[indices];
410+ GLushort* index = indexData;
411+ for (int i = 0; i < baseTriangles; i++) {
412+ *(index++) = 0;
413+ *(index++) = i + 2;
414+ *(index++) = i + 1;
415+ }
416+ for (int i = 1; i <= stacks; i++) {
417+ GLushort bottom = i * slices;
418+ GLushort top = bottom + slices;
419+ for (int j = 0; j < slices; j++) {
420+ int next = (j + 1) % slices;
421+
422+ *(index++) = bottom + j;
423+ *(index++) = top + next;
424+ *(index++) = top + j;
425+
426+ *(index++) = bottom + j;
427+ *(index++) = bottom + next;
428+ *(index++) = top + next;
429+ }
430+ }
431+
432+ glGenBuffers(1, &vbo.second);
433+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
434+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * NUM_BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);
435+ delete[] indexData;
436+
437+ } else {
438+ glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
439+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
440+ }
441+ glEnableClientState(GL_VERTEX_ARRAY);
442+ glEnableClientState(GL_NORMAL_ARRAY);
443+
444+ int stride = NUM_VERTICES_PER_TRIANGULATED_QUAD * sizeof(float);
445+ glNormalPointer(GL_FLOAT, stride, 0);
446+ glVertexPointer(NUM_COORDS_PER_VERTEX, GL_FLOAT, stride, (const void *)(NUM_COORDS_PER_VERTEX * sizeof(float)));
447+
448+ glPushMatrix();
449+ glScalef(base, base, height);
450+
451+ glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);
452+
453+ glPopMatrix();
454+
455+ glDisableClientState(GL_VERTEX_ARRAY);
456+ glDisableClientState(GL_NORMAL_ARRAY);
457+
458+ glBindBuffer(GL_ARRAY_BUFFER, 0);
459+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
460+}
461+
462+void GeometryCache::renderGrid(int xDivisions, int yDivisions) {
463+ QOpenGLBuffer& buffer = _gridBuffers[IntPair(xDivisions, yDivisions)];
464+ int vertices = (xDivisions + 1 + yDivisions + 1) * 2;
465+ if (!buffer.isCreated()) {
466+ GLfloat* vertexData = new GLfloat[vertices * 2];
467+ GLfloat* vertex = vertexData;
468+ for (int i = 0; i <= xDivisions; i++) {
469+ float x = (float)i / xDivisions;
470+
471+ *(vertex++) = x;
472+ *(vertex++) = 0.0f;
473+
474+ *(vertex++) = x;
475+ *(vertex++) = 1.0f;
476+ }
477+ for (int i = 0; i <= yDivisions; i++) {
478+ float y = (float)i / yDivisions;
479+
480+ *(vertex++) = 0.0f;
481+ *(vertex++) = y;
482+
483+ *(vertex++) = 1.0f;
484+ *(vertex++) = y;
485+ }
486+ buffer.create();
487+ buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
488+ buffer.bind();
489+ buffer.allocate(vertexData, vertices * 2 * sizeof(GLfloat));
490+ delete[] vertexData;
491+
492+ } else {
493+ buffer.bind();
494+ }
495+ glEnableClientState(GL_VERTEX_ARRAY);
496+
497+ glVertexPointer(2, GL_FLOAT, 0, 0);
498+
499+ glDrawArrays(GL_LINES, 0, vertices);
500+
501+ glDisableClientState(GL_VERTEX_ARRAY);
502+
503+ buffer.release();
504+}
505+
506+QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) {
507+ return getResource(url, fallback, delayLoad).staticCast<NetworkGeometry>();
508+}
509+
510+QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url,
511+ const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
512+ QSharedPointer<NetworkGeometry> geometry(new NetworkGeometry(url, fallback.staticCast<NetworkGeometry>(), delayLoad),
513+ &Resource::allReferencesCleared);
514+ geometry->setLODParent(geometry);
515+ return geometry.staticCast<Resource>();
516+}
517+
518+const float NetworkGeometry::NO_HYSTERESIS = -1.0f;
519+
520+NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad,
521+ const QVariantHash& mapping, const QUrl& textureBase) :
522+ Resource(url, delayLoad),
523+ _mapping(mapping),
524+ _textureBase(textureBase.isValid() ? textureBase : url),
525+ _fallback(fallback)
526+{
527+
528+ if (url.isEmpty()) {
529+ // make the minimal amount of dummy geometry to satisfy Model
530+ FBXJoint joint = { false, QVector<int>(), -1 };
531+ _geometry.joints.append(joint);
532+ _geometry.leftEyeJointIndex = -1;
533+ _geometry.rightEyeJointIndex = -1;
534+ _geometry.neckJointIndex = -1;
535+ _geometry.rootJointIndex = -1;
536+ _geometry.leanJointIndex = -1;
537+ _geometry.headJointIndex = -1;
538+ _geometry.leftHandJointIndex = -1;
539+ _geometry.rightHandJointIndex = -1;
540+ }
541+
542+ connect(this, &Resource::loaded, this, &NetworkGeometry::replaceTexturesWithPendingChanges);
543+}
544+
545+bool NetworkGeometry::isLoadedWithTextures() const {
546+ if (!isLoaded()) {
547+ return false;
548+ }
549+ foreach (const NetworkMesh& mesh, _meshes) {
550+ foreach (const NetworkMeshPart& part, mesh.parts) {
551+ if ((part.diffuseTexture && !part.diffuseTexture->isLoaded()) ||
552+ (part.normalTexture && !part.normalTexture->isLoaded()) ||
553+ (part.specularTexture && !part.specularTexture->isLoaded()) ||
554+ (part.emissiveTexture && !part.emissiveTexture->isLoaded())) {
555+ return false;
556+ }
557+ }
558+ }
559+ return true;
560+}
561+
562+QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance, float& hysteresis, bool delayLoad) const {
563+ if (_lodParent.data() != this) {
564+ return _lodParent.data()->getLODOrFallback(distance, hysteresis, delayLoad);
565+ }
566+ if (_failedToLoad && _fallback) {
567+ return _fallback;
568+ }
569+ QSharedPointer<NetworkGeometry> lod = _lodParent;
570+ float lodDistance = 0.0f;
571+ QMap<float, QSharedPointer<NetworkGeometry> >::const_iterator it = _lods.upperBound(distance);
572+ if (it != _lods.constBegin()) {
573+ it = it - 1;
574+ lod = it.value();
575+ lodDistance = it.key();
576+ }
577+ if (hysteresis != NO_HYSTERESIS && hysteresis != lodDistance) {
578+ // if we previously selected a different distance, make sure we've moved far enough to justify switching
579+ const float HYSTERESIS_PROPORTION = 0.1f;
580+ if (glm::abs(distance - qMax(hysteresis, lodDistance)) / fabsf(hysteresis - lodDistance) < HYSTERESIS_PROPORTION) {
581+ lod = _lodParent;
582+ lodDistance = 0.0f;
583+ it = _lods.upperBound(hysteresis);
584+ if (it != _lods.constBegin()) {
585+ it = it - 1;
586+ lod = it.value();
587+ lodDistance = it.key();
588+ }
589+ }
590+ }
591+ if (lod->isLoaded()) {
592+ hysteresis = lodDistance;
593+ return lod;
594+ }
595+ // if the ideal LOD isn't loaded, we need to make sure it's started to load, and possibly return the closest loaded one
596+ if (!delayLoad) {
597+ lod->ensureLoading();
598+ }
599+ float closestDistance = FLT_MAX;
600+ if (isLoaded()) {
601+ lod = _lodParent;
602+ closestDistance = distance;
603+ }
604+ for (it = _lods.constBegin(); it != _lods.constEnd(); it++) {
605+ float distanceToLOD = glm::abs(distance - it.key());
606+ if (it.value()->isLoaded() && distanceToLOD < closestDistance) {
607+ lod = it.value();
608+ closestDistance = distanceToLOD;
609+ }
610+ }
611+ hysteresis = NO_HYSTERESIS;
612+ return lod;
613+}
614+
615+uint qHash(const QWeakPointer<Animation>& animation, uint seed = 0) {
616+ return qHash(animation.data(), seed);
617+}
618+
619+QVector<int> NetworkGeometry::getJointMappings(const AnimationPointer& animation) {
620+ QVector<int> mappings = _jointMappings.value(animation);
621+ if (mappings.isEmpty() && isLoaded() && animation && animation->isLoaded()) {
622+ const FBXGeometry& animationGeometry = animation->getGeometry();
623+ for (int i = 0; i < animationGeometry.joints.size(); i++) {
624+ mappings.append(_geometry.jointIndices.value(animationGeometry.joints.at(i).name) - 1);
625+ }
626+ _jointMappings.insert(animation, mappings);
627+ }
628+ return mappings;
629+}
630+
631+void NetworkGeometry::setLoadPriority(const QPointer<QObject>& owner, float priority) {
632+ Resource::setLoadPriority(owner, priority);
633+
634+ for (int i = 0; i < _meshes.size(); i++) {
635+ NetworkMesh& mesh = _meshes[i];
636+ for (int j = 0; j < mesh.parts.size(); j++) {
637+ NetworkMeshPart& part = mesh.parts[j];
638+ if (part.diffuseTexture) {
639+ part.diffuseTexture->setLoadPriority(owner, priority);
640+ }
641+ if (part.normalTexture) {
642+ part.normalTexture->setLoadPriority(owner, priority);
643+ }
644+ if (part.specularTexture) {
645+ part.specularTexture->setLoadPriority(owner, priority);
646+ }
647+ if (part.emissiveTexture) {
648+ part.emissiveTexture->setLoadPriority(owner, priority);
649+ }
650+ }
651+ }
652+}
653+
654+void NetworkGeometry::setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities) {
655+ Resource::setLoadPriorities(priorities);
656+
657+ for (int i = 0; i < _meshes.size(); i++) {
658+ NetworkMesh& mesh = _meshes[i];
659+ for (int j = 0; j < mesh.parts.size(); j++) {
660+ NetworkMeshPart& part = mesh.parts[j];
661+ if (part.diffuseTexture) {
662+ part.diffuseTexture->setLoadPriorities(priorities);
663+ }
664+ if (part.normalTexture) {
665+ part.normalTexture->setLoadPriorities(priorities);
666+ }
667+ if (part.specularTexture) {
668+ part.specularTexture->setLoadPriorities(priorities);
669+ }
670+ if (part.emissiveTexture) {
671+ part.emissiveTexture->setLoadPriorities(priorities);
672+ }
673+ }
674+ }
675+}
676+
677+void NetworkGeometry::clearLoadPriority(const QPointer<QObject>& owner) {
678+ Resource::clearLoadPriority(owner);
679+
680+ for (int i = 0; i < _meshes.size(); i++) {
681+ NetworkMesh& mesh = _meshes[i];
682+ for (int j = 0; j < mesh.parts.size(); j++) {
683+ NetworkMeshPart& part = mesh.parts[j];
684+ if (part.diffuseTexture) {
685+ part.diffuseTexture->clearLoadPriority(owner);
686+ }
687+ if (part.normalTexture) {
688+ part.normalTexture->clearLoadPriority(owner);
689+ }
690+ if (part.specularTexture) {
691+ part.specularTexture->clearLoadPriority(owner);
692+ }
693+ if (part.emissiveTexture) {
694+ part.emissiveTexture->clearLoadPriority(owner);
695+ }
696+ }
697+ }
698+}
699+
700+void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) {
701+ if (_meshes.size() > 0) {
702+ TextureCache::SharedPointer textureCache = DependencyManager::get<TextureCache>();
703+ for (int i = 0; i < _meshes.size(); i++) {
704+ NetworkMesh& mesh = _meshes[i];
705+ for (int j = 0; j < mesh.parts.size(); j++) {
706+ NetworkMeshPart& part = mesh.parts[j];
707+
708+ QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();
709+ if (part.diffuseTextureName == name) {
710+ part.diffuseTexture =
711+ textureCache->getTexture(url, DEFAULT_TEXTURE,
712+ _geometry.meshes[i].isEye, QByteArray());
713+ part.diffuseTexture->setLoadPriorities(_loadPriorities);
714+ } else if (part.normalTextureName == name) {
715+ part.normalTexture = textureCache->getTexture(url, DEFAULT_TEXTURE,
716+ false, QByteArray());
717+ part.normalTexture->setLoadPriorities(_loadPriorities);
718+ } else if (part.specularTextureName == name) {
719+ part.specularTexture = textureCache->getTexture(url, DEFAULT_TEXTURE,
720+ false, QByteArray());
721+ part.specularTexture->setLoadPriorities(_loadPriorities);
722+ } else if (part.emissiveTextureName == name) {
723+ part.emissiveTexture = textureCache->getTexture(url, DEFAULT_TEXTURE,
724+ false, QByteArray());
725+ part.emissiveTexture->setLoadPriorities(_loadPriorities);
726+ }
727+ }
728+ }
729+ } else {
730+ qDebug() << "Adding a name url pair to pending" << name << url;
731+ // we don't have meshes downloaded yet, so hold this texture as pending
732+ _pendingTextureChanges.insert(name, url);
733+ }
734+}
735+
736+QStringList NetworkGeometry::getTextureNames() const {
737+ QStringList result;
738+ for (int i = 0; i < _meshes.size(); i++) {
739+ const NetworkMesh& mesh = _meshes[i];
740+ for (int j = 0; j < mesh.parts.size(); j++) {
741+ const NetworkMeshPart& part = mesh.parts[j];
742+
743+ if (!part.diffuseTextureName.isEmpty()) {
744+ QString textureURL = part.diffuseTexture->getURL().toString();
745+ result << part.diffuseTextureName + ":" + textureURL;
746+ }
747+
748+ if (!part.normalTextureName.isEmpty()) {
749+ QString textureURL = part.normalTexture->getURL().toString();
750+ result << part.normalTextureName + ":" + textureURL;
751+ }
752+
753+ if (!part.specularTextureName.isEmpty()) {
754+ QString textureURL = part.specularTexture->getURL().toString();
755+ result << part.specularTextureName + ":" + textureURL;
756+ }
757+
758+ if (!part.emissiveTextureName.isEmpty()) {
759+ QString textureURL = part.emissiveTexture->getURL().toString();
760+ result << part.emissiveTextureName + ":" + textureURL;
761+ }
762+ }
763+ }
764+ return result;
765+}
766+
767+void NetworkGeometry::replaceTexturesWithPendingChanges() {
768+ QHash<QString, QUrl>::Iterator it = _pendingTextureChanges.begin();
769+
770+ while (it != _pendingTextureChanges.end()) {
771+ setTextureWithNameToURL(it.key(), it.value());
772+ it = _pendingTextureChanges.erase(it);
773+ }
774+}
775+
776+/// Reads geometry in a worker thread.
777+class GeometryReader : public QRunnable {
778+public:
779+
780+ GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
781+ QNetworkReply* reply, const QVariantHash& mapping);
782+
783+ virtual void run();
784+
785+private:
786+
787+ QWeakPointer<Resource> _geometry;
788+ QUrl _url;
789+ QNetworkReply* _reply;
790+ QVariantHash _mapping;
791+};
792+
793+GeometryReader::GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
794+ QNetworkReply* reply, const QVariantHash& mapping) :
795+ _geometry(geometry),
796+ _url(url),
797+ _reply(reply),
798+ _mapping(mapping) {
799+}
800+
801+void GeometryReader::run() {
802+ QSharedPointer<Resource> geometry = _geometry.toStrongRef();
803+ if (geometry.isNull()) {
804+ _reply->deleteLater();
805+ return;
806+ }
807+ try {
808+ if (!_reply) {
809+ throw QString("Reply is NULL ?!");
810+ }
811+ std::string urlname = _url.path().toLower().toStdString();
812+ bool urlValid = true;
813+ urlValid &= !urlname.empty();
814+ urlValid &= !_url.path().isEmpty();
815+ urlValid &= _url.path().toLower().endsWith(".fbx")
816+ || _url.path().toLower().endsWith(".svo");
817+
818+ if (urlValid) {
819+ // Let's read the binaries from the network
820+ FBXGeometry fbxgeo;
821+ if (_url.path().toLower().endsWith(".svo")) {
822+ QByteArray fileBinary = _reply->readAll();
823+ if (fileBinary.isEmpty() || fileBinary.isNull()) {
824+ throw QString("Read File binary is empty?!");
825+ }
826+ fbxgeo = readSVO(fileBinary);
827+
828+ } else if (_url.path().toLower().endsWith(".fbx")) {
829+ bool grabLightmaps = true;
830+ float lightmapLevel = 1.0f;
831+ // HACK: For monday 12/01/2014 we need to kill lighmaps loading in starchamber...
832+ if (_url.path().toLower().endsWith("loungev4_11-18.fbx")) {
833+ grabLightmaps = false;
834+ } else if (_url.path().toLower().endsWith("apt8_reboot.fbx")) {
835+ lightmapLevel = 4.0f;
836+ } else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) {
837+ lightmapLevel = 3.5f;
838+ }
839+ fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel);
840+ }
841+ QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));
842+ } else {
843+ throw QString("url is invalid");
844+ }
845+
846+ } catch (const QString& error) {
847+ qDebug() << "Error reading " << _url << ": " << error;
848+ QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false));
849+ }
850+ _reply->deleteLater();
851+}
852+
853+void NetworkGeometry::init() {
854+ _mapping = QVariantHash();
855+ _geometry = FBXGeometry();
856+ _meshes.clear();
857+ _lods.clear();
858+ _pendingTextureChanges.clear();
859+ _request.setUrl(_url);
860+ Resource::init();
861+}
862+
863+void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
864+ QUrl url = reply->url();
865+ if (url.path().toLower().endsWith(".fst")) {
866+ // it's a mapping file; parse it and get the mesh filename
867+ _mapping = readMapping(reply->readAll());
868+ reply->deleteLater();
869+ QString filename = _mapping.value("filename").toString();
870+ if (filename.isNull()) {
871+ qDebug() << "Mapping file " << url << " has no filename.";
872+ finishedLoading(false);
873+
874+ } else {
875+ QString texdir = _mapping.value("texdir").toString();
876+ if (!texdir.isNull()) {
877+ if (!texdir.endsWith('/')) {
878+ texdir += '/';
879+ }
880+ _textureBase = url.resolved(texdir);
881+ }
882+ QVariantHash lods = _mapping.value("lod").toHash();
883+ for (QVariantHash::const_iterator it = lods.begin(); it != lods.end(); it++) {
884+ QSharedPointer<NetworkGeometry> geometry(new NetworkGeometry(url.resolved(it.key()),
885+ QSharedPointer<NetworkGeometry>(), true, _mapping, _textureBase));
886+ geometry->setSelf(geometry.staticCast<Resource>());
887+ geometry->setLODParent(_lodParent);
888+ _lods.insert(it.value().toFloat(), geometry);
889+ }
890+ _request.setUrl(url.resolved(filename));
891+
892+ // make the request immediately only if we have no LODs to switch between
893+ _startedLoading = false;
894+ if (_lods.isEmpty()) {
895+ attemptRequest();
896+ }
897+ }
898+ return;
899+ }
900+
901+ // send the reader off to the thread pool
902+ QThreadPool::globalInstance()->start(new GeometryReader(_self, url, reply, _mapping));
903+}
904+
905+void NetworkGeometry::reinsert() {
906+ Resource::reinsert();
907+
908+ _lodParent = qWeakPointerCast<NetworkGeometry, Resource>(_self);
909+ foreach (const QSharedPointer<NetworkGeometry>& lod, _lods) {
910+ lod->setLODParent(_lodParent);
911+ }
912+}
913+
914+void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
915+ _geometry = geometry;
916+
917+ TextureCache::SharedPointer textureCache = DependencyManager::get<TextureCache>();
918+
919+ foreach (const FBXMesh& mesh, _geometry.meshes) {
920+ NetworkMesh networkMesh;
921+
922+ int totalIndices = 0;
923+ foreach (const FBXMeshPart& part, mesh.parts) {
924+ NetworkMeshPart networkPart;
925+ if (!part.diffuseTexture.filename.isEmpty()) {
926+ networkPart.diffuseTexture = textureCache->getTexture(
927+ _textureBase.resolved(QUrl(part.diffuseTexture.filename)), DEFAULT_TEXTURE,
928+ mesh.isEye, part.diffuseTexture.content);
929+ networkPart.diffuseTextureName = part.diffuseTexture.name;
930+ networkPart.diffuseTexture->setLoadPriorities(_loadPriorities);
931+ }
932+ if (!part.normalTexture.filename.isEmpty()) {
933+ networkPart.normalTexture = textureCache->getTexture(
934+ _textureBase.resolved(QUrl(part.normalTexture.filename)), NORMAL_TEXTURE,
935+ false, part.normalTexture.content);
936+ networkPart.normalTextureName = part.normalTexture.name;
937+ networkPart.normalTexture->setLoadPriorities(_loadPriorities);
938+ }
939+ if (!part.specularTexture.filename.isEmpty()) {
940+ networkPart.specularTexture = textureCache->getTexture(
941+ _textureBase.resolved(QUrl(part.specularTexture.filename)), SPECULAR_TEXTURE,
942+ false, part.specularTexture.content);
943+ networkPart.specularTextureName = part.specularTexture.name;
944+ networkPart.specularTexture->setLoadPriorities(_loadPriorities);
945+ }
946+ if (!part.emissiveTexture.filename.isEmpty()) {
947+ networkPart.emissiveTexture = textureCache->getTexture(
948+ _textureBase.resolved(QUrl(part.emissiveTexture.filename)), EMISSIVE_TEXTURE,
949+ false, part.emissiveTexture.content);
950+ networkPart.emissiveTextureName = part.emissiveTexture.name;
951+ networkPart.emissiveTexture->setLoadPriorities(_loadPriorities);
952+ }
953+ networkMesh.parts.append(networkPart);
954+
955+ totalIndices += (part.quadIndices.size() + part.triangleIndices.size());
956+ }
957+
958+ {
959+ networkMesh._indexBuffer = gpu::BufferPointer(new gpu::Buffer());
960+ networkMesh._indexBuffer->resize(totalIndices * sizeof(int));
961+ int offset = 0;
962+ foreach(const FBXMeshPart& part, mesh.parts) {
963+ networkMesh._indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int),
964+ (gpu::Resource::Byte*) part.quadIndices.constData());
965+ offset += part.quadIndices.size() * sizeof(int);
966+ networkMesh._indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int),
967+ (gpu::Resource::Byte*) part.triangleIndices.constData());
968+ offset += part.triangleIndices.size() * sizeof(int);
969+ }
970+ }
971+
972+ {
973+ networkMesh._vertexBuffer = gpu::BufferPointer(new gpu::Buffer());
974+ // if we don't need to do any blending, the positions/normals can be static
975+ if (mesh.blendshapes.isEmpty()) {
976+ int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
977+ int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
978+ int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
979+ int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
980+ int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
981+ int clusterIndicesOffset = texCoords1Offset + mesh.texCoords1.size() * sizeof(glm::vec2);
982+ int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
983+
984+ networkMesh._vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
985+
986+ networkMesh._vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.vertices.constData());
987+ networkMesh._vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.normals.constData());
988+ networkMesh._vertexBuffer->setSubData(tangentsOffset,
989+ mesh.tangents.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.tangents.constData());
990+ networkMesh._vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.colors.constData());
991+ networkMesh._vertexBuffer->setSubData(texCoordsOffset,
992+ mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Resource::Byte*) mesh.texCoords.constData());
993+ networkMesh._vertexBuffer->setSubData(texCoords1Offset,
994+ mesh.texCoords1.size() * sizeof(glm::vec2), (gpu::Resource::Byte*) mesh.texCoords1.constData());
995+ networkMesh._vertexBuffer->setSubData(clusterIndicesOffset,
996+ mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Resource::Byte*) mesh.clusterIndices.constData());
997+ networkMesh._vertexBuffer->setSubData(clusterWeightsOffset,
998+ mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Resource::Byte*) mesh.clusterWeights.constData());
999+
1000+ // otherwise, at least the cluster indices/weights can be static
1001+ networkMesh._vertexStream = gpu::BufferStreamPointer(new gpu::BufferStream());
1002+ networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, 0, sizeof(glm::vec3));
1003+ if (mesh.normals.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, normalsOffset, sizeof(glm::vec3));
1004+ if (mesh.tangents.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, tangentsOffset, sizeof(glm::vec3));
1005+ if (mesh.colors.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, colorsOffset, sizeof(glm::vec3));
1006+ if (mesh.texCoords.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
1007+ if (mesh.texCoords1.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoords1Offset, sizeof(glm::vec2));
1008+ if (mesh.clusterIndices.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
1009+ if (mesh.clusterWeights.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
1010+
1011+ int channelNum = 0;
1012+ networkMesh._vertexFormat = gpu::Stream::FormatPointer(new gpu::Stream::Format());
1013+ networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ), 0);
1014+ if (mesh.normals.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
1015+ if (mesh.tangents.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
1016+ if (mesh.colors.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
1017+ if (mesh.texCoords.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
1018+ if (mesh.texCoords1.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
1019+ if (mesh.clusterIndices.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
1020+ if (mesh.clusterWeights.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
1021+ }
1022+ else {
1023+ int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
1024+ int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
1025+ int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
1026+ int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
1027+
1028+ networkMesh._vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
1029+ networkMesh._vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.tangents.constData());
1030+ networkMesh._vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.colors.constData());
1031+ networkMesh._vertexBuffer->setSubData(texCoordsOffset,
1032+ mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Resource::Byte*) mesh.texCoords.constData());
1033+ networkMesh._vertexBuffer->setSubData(clusterIndicesOffset,
1034+ mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Resource::Byte*) mesh.clusterIndices.constData());
1035+ networkMesh._vertexBuffer->setSubData(clusterWeightsOffset,
1036+ mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Resource::Byte*) mesh.clusterWeights.constData());
1037+
1038+ networkMesh._vertexStream = gpu::BufferStreamPointer(new gpu::BufferStream());
1039+ if (mesh.tangents.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, 0, sizeof(glm::vec3));
1040+ if (mesh.colors.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, colorsOffset, sizeof(glm::vec3));
1041+ if (mesh.texCoords.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
1042+ if (mesh.clusterIndices.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
1043+ if (mesh.clusterWeights.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
1044+
1045+ int channelNum = 0;
1046+ networkMesh._vertexFormat = gpu::Stream::FormatPointer(new gpu::Stream::Format());
1047+ networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ));
1048+ if (mesh.normals.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
1049+ if (mesh.tangents.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
1050+ if (mesh.colors.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
1051+ if (mesh.texCoords.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
1052+ if (mesh.clusterIndices.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
1053+ if (mesh.clusterWeights.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
1054+
1055+ }
1056+ }
1057+
1058+ _meshes.append(networkMesh);
1059+ }
1060+
1061+ finishedLoading(true);
1062+}
1063+
1064+bool NetworkMeshPart::isTranslucent() const {
1065+ return diffuseTexture && diffuseTexture->isTranslucent();
1066+}
1067+
1068+int NetworkMesh::getTranslucentPartCount(const FBXMesh& fbxMesh) const {
1069+ int count = 0;
1070+ for (int i = 0; i < parts.size(); i++) {
1071+ if (parts.at(i).isTranslucent() || fbxMesh.parts.at(i).opacity != 1.0f) {
1072+ count++;
1073+ }
1074+ }
1075+ return count;
1076+}