891 lines · 38.1 KB · C++
RawDownload
////  GeometryCache.cpp//  interface/src/renderer////  Created by Andrzej Kapolka on 6/21/13.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include <cmath> #include <QNetworkReply>#include <QRunnable>#include <QThreadPool> #include "Application.h"#include "GeometryCache.h"#include "Model.h"#include "world.h" GeometryCache::GeometryCache() :    _pendingBlenders(0) {} GeometryCache::~GeometryCache() {    foreach (const VerticesIndices& vbo, _hemisphereVBOs) {        glDeleteBuffers(1, &vbo.first);        glDeleteBuffers(1, &vbo.second);    }} void GeometryCache::renderHemisphere(int slices, int stacks) {    VerticesIndices& vbo = _hemisphereVBOs[IntPair(slices, stacks)];    int vertices = slices * (stacks - 1) + 1;    int indices = slices * 2 * 3 * (stacks - 2) + slices * 3;    if (vbo.first == 0) {            GLfloat* vertexData = new GLfloat[vertices * 3];        GLfloat* vertex = vertexData;        for (int i = 0; i < stacks - 1; i++) {            float phi = PI_OVER_TWO * (float)i / (float)(stacks - 1);            float z = sinf(phi), radius = cosf(phi);                        for (int j = 0; j < slices; j++) {                float theta = TWO_PI * (float)j / (float)slices;                 *(vertex++) = sinf(theta) * radius;                *(vertex++) = cosf(theta) * radius;                *(vertex++) = z;            }        }        *(vertex++) = 0.0f;        *(vertex++) = 0.0f;        *(vertex++) = 1.0f;                glGenBuffers(1, &vbo.first);        glBindBuffer(GL_ARRAY_BUFFER, vbo.first);        const int BYTES_PER_VERTEX = 3 * sizeof(GLfloat);        glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);        delete[] vertexData;                GLushort* indexData = new GLushort[indices];        GLushort* index = indexData;        for (int i = 0; i < stacks - 2; i++) {            GLushort bottom = i * slices;            GLushort top = bottom + slices;            for (int j = 0; j < slices; j++) {                int next = (j + 1) % slices;                                *(index++) = bottom + j;                *(index++) = top + next;                *(index++) = top + j;                                *(index++) = bottom + j;                *(index++) = bottom + next;                *(index++) = top + next;            }        }        GLushort bottom = (stacks - 2) * slices;        GLushort top = bottom + slices;        for (int i = 0; i < slices; i++) {                *(index++) = bottom + i;            *(index++) = bottom + (i + 1) % slices;            *(index++) = top;        }                glGenBuffers(1, &vbo.second);        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);        const int BYTES_PER_INDEX = sizeof(GLushort);        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);        delete[] indexData;        } else {        glBindBuffer(GL_ARRAY_BUFFER, vbo.first);        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);    }    glEnableClientState(GL_VERTEX_ARRAY);    glEnableClientState(GL_NORMAL_ARRAY);     glVertexPointer(3, GL_FLOAT, 0, 0);    glNormalPointer(GL_FLOAT, 0, 0);            glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);            glDisableClientState(GL_VERTEX_ARRAY);    glDisableClientState(GL_NORMAL_ARRAY);        glBindBuffer(GL_ARRAY_BUFFER, 0);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);}  void GeometryCache::renderSphere(float radius, int slices, int stacks) {    VerticesIndices& vbo = _sphereVBOs[IntPair(slices, stacks)];    int vertices = slices * (stacks - 1) + 2;    const int NUM_VERTICES_PER_TRIANGLE = 3;    const int NUM_TRIANGLES_PER_QUAD = 2;    int indices = slices * NUM_TRIANGLES_PER_QUAD * NUM_VERTICES_PER_TRIANGLE * (stacks - 1) + slices * NUM_TRIANGLES_PER_QUAD * NUM_VERTICES_PER_TRIANGLE;    if (vbo.first == 0) {        const int NUM_COORDS_PER_VERTEX = 3;        GLfloat* vertexData = new GLfloat[vertices * NUM_COORDS_PER_VERTEX];        GLfloat* vertex = vertexData;         // south pole        *(vertex++) = 0.0f;        *(vertex++) = 0.0f;        *(vertex++) = -1.0f;         //add stacks vertices climbing up Y axis        for (int i = 1; i < stacks; i++) {            float phi = PI * (float)i / (float)(stacks) - PI_OVER_TWO;            float z = sinf(phi), radius = cosf(phi);                        for (int j = 0; j < slices; j++) {                float theta = TWO_PI * (float)j / (float)slices;                 *(vertex++) = sinf(theta) * radius;                *(vertex++) = cosf(theta) * radius;                *(vertex++) = z;            }        }         // north pole        *(vertex++) = 0.0f;        *(vertex++) = 0.0f;        *(vertex++) = 1.0f;                glGenBuffers(1, &vbo.first);        glBindBuffer(GL_ARRAY_BUFFER, vbo.first);        const int BYTES_PER_VERTEX = NUM_COORDS_PER_VERTEX * sizeof(GLfloat);        glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);        delete[] vertexData;                GLushort* indexData = new GLushort[indices];        GLushort* index = indexData;         // South cap        GLushort bottom = 0;        GLushort top = 1;        for (int i = 0; i < slices; i++) {                *(index++) = bottom;            *(index++) = top + i;            *(index++) = top + (i + 1) % slices;        }         // (stacks - 2) ribbons        for (int i = 0; i < stacks - 2; i++) {            bottom = i * slices + 1;            top = bottom + slices;            for (int j = 0; j < slices; j++) {                int next = (j + 1) % slices;                                *(index++) = bottom + j;                *(index++) = top + next;                *(index++) = top + j;                                *(index++) = bottom + j;                *(index++) = bottom + next;                *(index++) = top + next;            }        }                // north cap        bottom = (stacks - 2) * slices + 1;        top = bottom + slices;        for (int i = 0; i < slices; i++) {                *(index++) = bottom + i;            *(index++) = bottom + (i + 1) % slices;            *(index++) = top;        }                glGenBuffers(1, &vbo.second);        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);        const int BYTES_PER_INDEX = sizeof(GLushort);        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);        delete[] indexData;        } else {        glBindBuffer(GL_ARRAY_BUFFER, vbo.first);        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);    }    glEnableClientState(GL_VERTEX_ARRAY);    glEnableClientState(GL_NORMAL_ARRAY);     glVertexPointer(3, GL_FLOAT, 0, 0);    glNormalPointer(GL_FLOAT, 0, 0);     glPushMatrix();    glScalef(radius, radius, radius);    glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);    glPopMatrix();     glDisableClientState(GL_VERTEX_ARRAY);    glDisableClientState(GL_NORMAL_ARRAY);        glBindBuffer(GL_ARRAY_BUFFER, 0);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);} void GeometryCache::renderSquare(int xDivisions, int yDivisions) {    VerticesIndices& vbo = _squareVBOs[IntPair(xDivisions, yDivisions)];    int xVertices = xDivisions + 1;    int yVertices = yDivisions + 1;    int vertices = xVertices * yVertices;    int indices = 2 * 3 * xDivisions * yDivisions;    if (vbo.first == 0) {        GLfloat* vertexData = new GLfloat[vertices * 3];        GLfloat* vertex = vertexData;        for (int i = 0; i <= yDivisions; i++) {            float y = (float)i / yDivisions;                        for (int j = 0; j <= xDivisions; j++) {                *(vertex++) = (float)j / xDivisions;                *(vertex++) = y;                *(vertex++) = 0.0f;            }        }                glGenBuffers(1, &vbo.first);        glBindBuffer(GL_ARRAY_BUFFER, vbo.first);        const int BYTES_PER_VERTEX = 3 * sizeof(GLfloat);        glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);        delete[] vertexData;                GLushort* indexData = new GLushort[indices];        GLushort* index = indexData;        for (int i = 0; i < yDivisions; i++) {            GLushort bottom = i * xVertices;            GLushort top = bottom + xVertices;            for (int j = 0; j < xDivisions; j++) {                int next = j + 1;                                *(index++) = bottom + j;                *(index++) = top + next;                *(index++) = top + j;                                *(index++) = bottom + j;                *(index++) = bottom + next;                *(index++) = top + next;            }        }                glGenBuffers(1, &vbo.second);        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);        const int BYTES_PER_INDEX = sizeof(GLushort);        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);        delete[] indexData;            } else {        glBindBuffer(GL_ARRAY_BUFFER, vbo.first);        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);    }    glEnableClientState(GL_VERTEX_ARRAY);     // all vertices have the same normal    glNormal3f(0.0f, 0.0f, 1.0f);        glVertexPointer(3, GL_FLOAT, 0, 0);            glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);            glDisableClientState(GL_VERTEX_ARRAY);        glBindBuffer(GL_ARRAY_BUFFER, 0);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);} void GeometryCache::renderHalfCylinder(int slices, int stacks) {    VerticesIndices& vbo = _halfCylinderVBOs[IntPair(slices, stacks)];    int vertices = (slices + 1) * stacks;    int indices = 2 * 3 * slices * (stacks - 1);    if (vbo.first == 0) {            GLfloat* vertexData = new GLfloat[vertices * 2 * 3];        GLfloat* vertex = vertexData;        for (int i = 0; i <= (stacks - 1); i++) {            float y = (float)i / (stacks - 1);                        for (int j = 0; j <= slices; j++) {                float theta = 3.f * PI_OVER_TWO + PI * (float)j / (float)slices;                 //normals                *(vertex++) = sinf(theta);                *(vertex++) = 0;                *(vertex++) = cosf(theta);                 // vertices                *(vertex++) = sinf(theta);                *(vertex++) = y;                *(vertex++) = cosf(theta);            }        }                glGenBuffers(1, &vbo.first);        glBindBuffer(GL_ARRAY_BUFFER, vbo.first);        const int BYTES_PER_VERTEX = 3 * sizeof(GLfloat);        glBufferData(GL_ARRAY_BUFFER, 2 * vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);        delete[] vertexData;                GLushort* indexData = new GLushort[indices];        GLushort* index = indexData;        for (int i = 0; i < stacks - 1; i++) {            GLushort bottom = i * (slices + 1);            GLushort top = bottom + slices + 1;            for (int j = 0; j < slices; j++) {                int next = j + 1;                                *(index++) = bottom + j;                *(index++) = top + next;                *(index++) = top + j;                                *(index++) = bottom + j;                *(index++) = bottom + next;                *(index++) = top + next;            }        }                glGenBuffers(1, &vbo.second);        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);        const int BYTES_PER_INDEX = sizeof(GLushort);        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);        delete[] indexData;        } else {        glBindBuffer(GL_ARRAY_BUFFER, vbo.first);        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);    }    glEnableClientState(GL_VERTEX_ARRAY);    glEnableClientState(GL_NORMAL_ARRAY);     glNormalPointer(GL_FLOAT, 6 * sizeof(float), 0);    glVertexPointer(3, GL_FLOAT, (6 * sizeof(float)), (const void *)(3 * sizeof(float)));            glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);            glDisableClientState(GL_VERTEX_ARRAY);    glDisableClientState(GL_NORMAL_ARRAY);        glBindBuffer(GL_ARRAY_BUFFER, 0);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);} void GeometryCache::renderGrid(int xDivisions, int yDivisions) {    QOpenGLBuffer& buffer = _gridBuffers[IntPair(xDivisions, yDivisions)];    int vertices = (xDivisions + 1 + yDivisions + 1) * 2;    if (!buffer.isCreated()) {        GLfloat* vertexData = new GLfloat[vertices * 2];        GLfloat* vertex = vertexData;        for (int i = 0; i <= xDivisions; i++) {            float x = (float)i / xDivisions;                    *(vertex++) = x;            *(vertex++) = 0.0f;                        *(vertex++) = x;            *(vertex++) = 1.0f;        }        for (int i = 0; i <= yDivisions; i++) {            float y = (float)i / yDivisions;                        *(vertex++) = 0.0f;            *(vertex++) = y;                        *(vertex++) = 1.0f;            *(vertex++) = y;        }        buffer.create();        buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);        buffer.bind();        buffer.allocate(vertexData, vertices * 2 * sizeof(GLfloat));        delete[] vertexData;            } else {        buffer.bind();    }    glEnableClientState(GL_VERTEX_ARRAY);        glVertexPointer(2, GL_FLOAT, 0, 0);        glDrawArrays(GL_LINES, 0, vertices);        glDisableClientState(GL_VERTEX_ARRAY);        buffer.release();} QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) {    return getResource(url, fallback, delayLoad).staticCast<NetworkGeometry>();} void GeometryCache::noteRequiresBlend(Model* model) {    if (_pendingBlenders < QThread::idealThreadCount()) {        if (model->maybeStartBlender()) {            _pendingBlenders++;        }        return;    }    if (!_modelsRequiringBlends.contains(model)) {        _modelsRequiringBlends.append(model);    }} void GeometryCache::setBlendedVertices(const QPointer<Model>& model, int blendNumber,        const QWeakPointer<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {    if (!model.isNull()) {        model->setBlendedVertices(blendNumber, geometry, vertices, normals);    }    _pendingBlenders--;    while (!_modelsRequiringBlends.isEmpty()) {        Model* nextModel = _modelsRequiringBlends.takeFirst();        if (nextModel && nextModel->maybeStartBlender()) {            _pendingBlenders++;            return;        }    }} QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url,        const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {    QSharedPointer<NetworkGeometry> geometry(new NetworkGeometry(url, fallback.staticCast<NetworkGeometry>(), delayLoad),        &Resource::allReferencesCleared);    geometry->setLODParent(geometry);    return geometry.staticCast<Resource>();} const float NetworkGeometry::NO_HYSTERESIS = -1.0f; NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad,        const QVariantHash& mapping, const QUrl& textureBase) :    Resource(url, delayLoad),    _mapping(mapping),    _textureBase(textureBase.isValid() ? textureBase : url),    _fallback(fallback) {        if (url.isEmpty()) {        // make the minimal amount of dummy geometry to satisfy Model        FBXJoint joint = { false, QVector<int>(), -1 };        _geometry.joints.append(joint);        _geometry.leftEyeJointIndex = -1;        _geometry.rightEyeJointIndex = -1;        _geometry.neckJointIndex = -1;        _geometry.rootJointIndex = -1;        _geometry.leanJointIndex = -1;        _geometry.headJointIndex = -1;        _geometry.leftHandJointIndex = -1;        _geometry.rightHandJointIndex = -1;    }} bool NetworkGeometry::isLoadedWithTextures() const {    if (!isLoaded()) {        return false;    }    foreach (const NetworkMesh& mesh, _meshes) {        foreach (const NetworkMeshPart& part, mesh.parts) {            if ((part.diffuseTexture && !part.diffuseTexture->isLoaded()) ||                    (part.normalTexture && !part.normalTexture->isLoaded()) ||                    (part.specularTexture && !part.specularTexture->isLoaded())) {                return false;            }        }    }    return true;} QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance, float& hysteresis, bool delayLoad) const {    if (_lodParent.data() != this) {        return _lodParent.data()->getLODOrFallback(distance, hysteresis, delayLoad);    }    if (_failedToLoad && _fallback) {        return _fallback;    }    QSharedPointer<NetworkGeometry> lod = _lodParent;    float lodDistance = 0.0f;    QMap<float, QSharedPointer<NetworkGeometry> >::const_iterator it = _lods.upperBound(distance);    if (it != _lods.constBegin()) {        it = it - 1;        lod = it.value();        lodDistance = it.key();    }

Lines 1–500 of 891.