History

move back into interface for now

ZappoMan committed 11 years ago

Commit 3de35401 parent 4ac673f10 files · +7 −8Browse files

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

Unified · Split

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