660 lines · 25.4 KB · C++
RawDownload
////  GeometryCache.cpp//  interface////  Created by Andrzej Kapolka on 6/21/13.//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include <cmath> #include <QNetworkReply>#include <QRunnable>#include <QThreadPool> #include "Application.h"#include "GeometryCache.h"#include "world.h" 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 = PIf * 0.5f * i / (stacks - 1);            float z = sinf(phi), radius = cosf(phi);                        for (int j = 0; j < slices; j++) {                float theta = PIf * 2.0f * j / 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::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 * PIf / 2 + PIf * j / 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>();} 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) {} 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())) {                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();    }    if (hysteresis != NO_HYSTERESIS && hysteresis != lodDistance) {        // if we previously selected a different distance, make sure we've moved far enough to justify switching        const float HYSTERESIS_PROPORTION = 0.1f;        if (glm::abs(distance - qMax(hysteresis, lodDistance)) / fabsf(hysteresis - lodDistance) < HYSTERESIS_PROPORTION) {            lod = _lodParent;            lodDistance = 0.0f;            it = _lods.upperBound(hysteresis);            if (it != _lods.constBegin()) {                it = it - 1;                lod = it.value();                lodDistance = it.key();            }        }    }    if (lod->isLoaded()) {        hysteresis = lodDistance;        return lod;    }    // if the ideal LOD isn't loaded, we need to make sure it's started to load, and possibly return the closest loaded one    if (!delayLoad) {        lod->ensureLoading();    }    float closestDistance = FLT_MAX;    if (isLoaded()) {        lod = _lodParent;        closestDistance = distance;    }    for (it = _lods.constBegin(); it != _lods.constEnd(); it++) {        float distanceToLOD = glm::abs(distance - it.key());        if (it.value()->isLoaded() && distanceToLOD < closestDistance) {            lod = it.value();            closestDistance = distanceToLOD;        }        }    hysteresis = NO_HYSTERESIS;    return lod;} glm::vec4 NetworkGeometry::computeAverageColor() const {    glm::vec4 totalColor;    int totalTriangles = 0;    for (int i = 0; i < _meshes.size(); i++) {        const FBXMesh& mesh = _geometry.meshes.at(i);        if (mesh.isEye) {            continue; // skip eyes        }        const NetworkMesh& networkMesh = _meshes.at(i);        for (int j = 0; j < mesh.parts.size(); j++) {            const FBXMeshPart& part = mesh.parts.at(j);            const NetworkMeshPart& networkPart = networkMesh.parts.at(j);            glm::vec4 color = glm::vec4(part.diffuseColor, 1.0f);            if (networkPart.diffuseTexture) {                color *= networkPart.diffuseTexture->getAverageColor();            }            int triangles = part.quadIndices.size() * 2 + part.triangleIndices.size();            totalColor += color * (float) triangles;            totalTriangles += triangles;        }    }    return (totalTriangles == 0) ? glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) : totalColor / (float) totalTriangles;} void NetworkGeometry::setLoadPriority(const QPointer<QObject>& owner, float priority) {    Resource::setLoadPriority(owner, priority);        for (int i = 0; i < _meshes.size(); i++) {        NetworkMesh& mesh = _meshes[i];        for (int j = 0; j < mesh.parts.size(); j++) {            NetworkMeshPart& part = mesh.parts[j];            if (part.diffuseTexture) {                part.diffuseTexture->setLoadPriority(owner, priority);            }            if (part.normalTexture) {                part.normalTexture->setLoadPriority(owner, priority);            }        }    }} void NetworkGeometry::setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities) {    Resource::setLoadPriorities(priorities);        for (int i = 0; i < _meshes.size(); i++) {        NetworkMesh& mesh = _meshes[i];        for (int j = 0; j < mesh.parts.size(); j++) {            NetworkMeshPart& part = mesh.parts[j];            if (part.diffuseTexture) {                part.diffuseTexture->setLoadPriorities(priorities);            }            if (part.normalTexture) {                part.normalTexture->setLoadPriorities(priorities);            }        }    }} void NetworkGeometry::clearLoadPriority(const QPointer<QObject>& owner) {    Resource::clearLoadPriority(owner);        for (int i = 0; i < _meshes.size(); i++) {        NetworkMesh& mesh = _meshes[i];        for (int j = 0; j < mesh.parts.size(); j++) {            NetworkMeshPart& part = mesh.parts[j];            if (part.diffuseTexture) {                part.diffuseTexture->clearLoadPriority(owner);            }            if (part.normalTexture) {                part.normalTexture->clearLoadPriority(owner);            }        }    }} /// Reads geometry in a worker thread.class GeometryReader : public QRunnable {public:     GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,        QNetworkReply* reply, const QVariantHash& mapping);     virtual void run(); private:         QWeakPointer<Resource> _geometry;    QUrl _url;    QNetworkReply* _reply;    QVariantHash _mapping;}; GeometryReader::GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,        QNetworkReply* reply, const QVariantHash& mapping) :    _geometry(geometry),    _url(url),    _reply(reply),    _mapping(mapping) {} void GeometryReader::run() {    QSharedPointer<Resource> geometry = _geometry.toStrongRef();    if (geometry.isNull()) {        _reply->deleteLater();        return;    }    try {        QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&,            _url.path().toLower().endsWith(".svo") ? readSVO(_reply->readAll()) : readFBX(_reply->readAll(), _mapping)));            } catch (const QString& error) {        qDebug() << "Error reading " << _url << ": " << error;        QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false));    }    _reply->deleteLater();} void NetworkGeometry::downloadFinished(QNetworkReply* reply) {    QUrl url = reply->url();    if (url.path().toLower().endsWith(".fst")) {

Lines 1–500 of 660.