2283 lines · 96.0 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 this before QOpenGLBuffer, which includes an earlier version of OpenGL#include <gpu/GPUConfig.h> #include <cmath> #include <QNetworkReply>#include <QRunnable>#include <QThreadPool> #include <gpu/Batch.h>#include <gpu/GLBackend.h> #include <SharedUtil.h> #include "TextureCache.h"#include "GeometryCache.h" //#define WANT_DEBUG const int GeometryCache::UNKNOWN_ID = -1; GeometryCache::GeometryCache() :    _nextID(0){    const qint64 GEOMETRY_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE;    setUnusedResourceCacheSize(GEOMETRY_DEFAULT_UNUSED_MAX_SIZE);} GeometryCache::~GeometryCache() {    #ifdef WANT_DEBUG        qDebug() << "GeometryCache::~GeometryCache()... ";        qDebug() << "    _registeredLine3DVBOs.size():" << _registeredLine3DVBOs.size();        qDebug() << "    _line3DVBOs.size():" << _line3DVBOs.size();        qDebug() << "    BatchItemDetails... population:" << GeometryCache::BatchItemDetails::population;    #endif //def WANT_DEBUG} const int NUM_VERTICES_PER_TRIANGLE = 3;const int NUM_TRIANGLES_PER_QUAD = 2;const int NUM_VERTICES_PER_TRIANGULATED_QUAD = NUM_VERTICES_PER_TRIANGLE * NUM_TRIANGLES_PER_QUAD;const int NUM_COORDS_PER_VERTEX = 3;const int NUM_BYTES_PER_VERTEX = NUM_COORDS_PER_VERTEX * sizeof(GLfloat);const int NUM_BYTES_PER_INDEX = sizeof(GLushort); void GeometryCache::renderSphere(float radius, int slices, int stacks, const glm::vec4& color, bool solid) {     Vec2Pair radiusKey(glm::vec2(radius, slices), glm::vec2(stacks, 0));    IntPair slicesStacksKey(slices, stacks);    Vec3Pair colorKey(glm::vec3(color.x, color.y, slices), glm::vec3(color.z, color.y, stacks));     int vertices = slices * (stacks - 1) + 2;        int indices = slices * (stacks - 1) * NUM_VERTICES_PER_TRIANGULATED_QUAD;        if (!_sphereVertices.contains(radiusKey)) {        gpu::BufferPointer verticesBuffer(new gpu::Buffer());        _sphereVertices[radiusKey] = verticesBuffer;         GLfloat* vertexData = new GLfloat[vertices * NUM_COORDS_PER_VERTEX];        GLfloat* vertex = vertexData;         // south pole        *(vertex++) = 0.0f;        *(vertex++) = 0.0f;        *(vertex++) = -1.0f * radius;         //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;            float stackRadius = cosf(phi) * radius;                        for (int j = 0; j < slices; j++) {                float theta = TWO_PI * (float)j / (float)slices;                 *(vertex++) = sinf(theta) * stackRadius;                *(vertex++) = cosf(theta) * stackRadius;                *(vertex++) = z;            }        }         // north pole        *(vertex++) = 0.0f;        *(vertex++) = 0.0f;        *(vertex++) = 1.0f * radius;         verticesBuffer->append(sizeof(GLfloat) * vertices * NUM_COORDS_PER_VERTEX, (gpu::Buffer::Byte*) vertexData);        delete[] vertexData;         #ifdef WANT_DEBUG            qDebug() << "GeometryCache::renderSphere()... --- CREATING VERTICES BUFFER";            qDebug() << "    radius:" << radius;            qDebug() << "    slices:" << slices;            qDebug() << "    stacks:" << stacks;             qDebug() << "    _sphereVertices.size():" << _sphereVertices.size();        #endif    }        if (!_sphereIndices.contains(slicesStacksKey)) {        gpu::BufferPointer indicesBuffer(new gpu::Buffer());        _sphereIndices[slicesStacksKey] = indicesBuffer;         GLushort* indexData = new GLushort[indices];        GLushort* index = indexData;                int indexCount = 0;         // 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;                        indexCount += 3;        }         // (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++) = top + next;                *(index++) = bottom + j;                *(index++) = top + j;                 indexCount += 3;                                *(index++) = bottom + next;                *(index++) = bottom + j;                *(index++) = top + next;                 indexCount += 3;             }        }                // north cap        bottom = (stacks - 2) * slices + 1;        top = bottom + slices;        for (int i = 0; i < slices; i++) {                *(index++) = bottom + (i + 1) % slices;            *(index++) = bottom + i;            *(index++) = top;                indexCount += 3;         }        indicesBuffer->append(sizeof(GLushort) * indices, (gpu::Buffer::Byte*) indexData);        delete[] indexData;                #ifdef WANT_DEBUG            qDebug() << "GeometryCache::renderSphere()... --- CREATING INDEX BUFFER";            qDebug() << "    radius:" << radius;            qDebug() << "    slices:" << slices;            qDebug() << "    stacks:" << stacks;            qDebug() << "indexCount:" << indexCount;            qDebug() << "   indices:" << indices;            qDebug() << "    _sphereIndices.size():" << _sphereIndices.size();        #endif    }     if (!_sphereColors.contains(colorKey)) {        gpu::BufferPointer colorBuffer(new gpu::Buffer());        _sphereColors[colorKey] = colorBuffer;         int compactColor = ((int(color.x * 255.0f) & 0xFF)) |                            ((int(color.y * 255.0f) & 0xFF) << 8) |                            ((int(color.z * 255.0f) & 0xFF) << 16) |                            ((int(color.w * 255.0f) & 0xFF) << 24);         int* colorData = new int[vertices];        int* colorDataAt = colorData;         for(int v = 0; v < vertices; v++) {            *(colorDataAt++) = compactColor;        }         colorBuffer->append(sizeof(int) * vertices, (gpu::Buffer::Byte*) colorData);        delete[] colorData;         #ifdef WANT_DEBUG            qDebug() << "GeometryCache::renderSphere()... --- CREATING COLORS BUFFER";            qDebug() << "    vertices:" << vertices;            qDebug() << "    color:" << color;            qDebug() << "    slices:" << slices;            qDebug() << "    stacks:" << stacks;            qDebug() << "    _sphereColors.size():" << _sphereColors.size();        #endif     }    gpu::BufferPointer verticesBuffer = _sphereVertices[radiusKey];    gpu::BufferPointer indicesBuffer = _sphereIndices[slicesStacksKey];    gpu::BufferPointer colorBuffer = _sphereColors[colorKey];        const int VERTICES_SLOT = 0;    const int NORMALS_SLOT = 1;    const int COLOR_SLOT = 2;    gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone    streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);    streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));    streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));     gpu::BufferView verticesView(verticesBuffer, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);    gpu::BufferView normalsView(verticesBuffer, streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element);    gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);        gpu::Batch batch;     batch.setInputFormat(streamFormat);    batch.setInputBuffer(VERTICES_SLOT, verticesView);    batch.setInputBuffer(NORMALS_SLOT, normalsView);    batch.setInputBuffer(COLOR_SLOT, colorView);    batch.setIndexBuffer(gpu::UINT16, indicesBuffer, 0);     if (solid) {        batch.drawIndexed(gpu::TRIANGLES, indices);    } else {        batch.drawIndexed(gpu::LINES, indices);    }     gpu::GLBackend::renderBatch(batch);     glDisableClientState(GL_VERTEX_ARRAY);    glDisableClientState(GL_COLOR_ARRAY);     glBindBuffer(GL_ARRAY_BUFFER, 0);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);} void GeometryCache::renderCone(float base, float height, int slices, int stacks) {    VerticesIndices& vbo = _coneVBOs[IntPair(slices, stacks)];    int vertices = (stacks + 2) * slices;    int baseTriangles = slices - 2;    int indices = NUM_VERTICES_PER_TRIANGULATED_QUAD * slices * stacks + NUM_VERTICES_PER_TRIANGLE * baseTriangles;    if (vbo.first == 0) {        GLfloat* vertexData = new GLfloat[vertices * NUM_COORDS_PER_VERTEX * 2];        GLfloat* vertex = vertexData;        // cap        for (int i = 0; i < slices; i++) {            float theta = TWO_PI * i / slices;                        //normals            *(vertex++) = 0.0f;            *(vertex++) = 0.0f;            *(vertex++) = -1.0f;             // vertices            *(vertex++) = cosf(theta);            *(vertex++) = sinf(theta);            *(vertex++) = 0.0f;        }        // body        for (int i = 0; i <= stacks; i++) {            float z = (float)i / stacks;            float radius = 1.0f - z;                        for (int j = 0; j < slices; j++) {                float theta = TWO_PI * j / slices;                 //normals                *(vertex++) = cosf(theta) / SQUARE_ROOT_OF_2;                *(vertex++) = sinf(theta) / SQUARE_ROOT_OF_2;                *(vertex++) = 1.0f / SQUARE_ROOT_OF_2;                 // vertices                *(vertex++) = radius * cosf(theta);                *(vertex++) = radius * sinf(theta);                *(vertex++) = z;            }        }                glGenBuffers(1, &vbo.first);        glBindBuffer(GL_ARRAY_BUFFER, vbo.first);        glBufferData(GL_ARRAY_BUFFER, 2 * vertices * NUM_BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);        delete[] vertexData;                GLushort* indexData = new GLushort[indices];        GLushort* index = indexData;        for (int i = 0; i < baseTriangles; i++) {            *(index++) = 0;            *(index++) = i + 2;            *(index++) = i + 1;        }        for (int i = 1; i <= stacks; 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;            }        }                glGenBuffers(1, &vbo.second);        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * NUM_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);     int stride = NUM_VERTICES_PER_TRIANGULATED_QUAD * sizeof(float);    glNormalPointer(GL_FLOAT, stride, 0);    glVertexPointer(NUM_COORDS_PER_VERTEX, GL_FLOAT, stride, (const void *)(NUM_COORDS_PER_VERTEX * sizeof(float)));        glPushMatrix();    glScalef(base, base, height);        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::renderGrid(int xDivisions, int yDivisions, const glm::vec4& color) {    IntPair key(xDivisions, yDivisions);    Vec3Pair colorKey(glm::vec3(color.x, color.y, yDivisions), glm::vec3(color.z, color.y, xDivisions));     int vertices = (xDivisions + 1 + yDivisions + 1) * 2;    if (!_gridBuffers.contains(key)) {        gpu::BufferPointer verticesBuffer(new gpu::Buffer());         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;        }         verticesBuffer->append(sizeof(GLfloat) * vertices * 2, (gpu::Buffer::Byte*) vertexData);        delete[] vertexData;                _gridBuffers[key] = verticesBuffer;    }     if (!_gridColors.contains(colorKey)) {        gpu::BufferPointer colorBuffer(new gpu::Buffer());        _gridColors[colorKey] = colorBuffer;         int compactColor = ((int(color.x * 255.0f) & 0xFF)) |                            ((int(color.y * 255.0f) & 0xFF) << 8) |                            ((int(color.z * 255.0f) & 0xFF) << 16) |                            ((int(color.w * 255.0f) & 0xFF) << 24);         int* colorData = new int[vertices];        int* colorDataAt = colorData;                                    for(int v = 0; v < vertices; v++) {            *(colorDataAt++) = compactColor;        }         colorBuffer->append(sizeof(int) * vertices, (gpu::Buffer::Byte*) colorData);        delete[] colorData;    }    gpu::BufferPointer verticesBuffer = _gridBuffers[key];    gpu::BufferPointer colorBuffer = _gridColors[colorKey];     const int VERTICES_SLOT = 0;    const int COLOR_SLOT = 1;    gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone        streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);    streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));     gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);    gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);        gpu::Batch batch;     batch.setInputFormat(streamFormat);    batch.setInputBuffer(VERTICES_SLOT, verticesView);    batch.setInputBuffer(COLOR_SLOT, colorView);    batch.draw(gpu::LINES, vertices, 0);     gpu::GLBackend::renderBatch(batch);     glDisableClientState(GL_VERTEX_ARRAY);    glDisableClientState(GL_COLOR_ARRAY);     glBindBuffer(GL_ARRAY_BUFFER, 0); } // TODO: properly handle the x,y,w,h changing for an ID// TODO: why do we seem to create extra BatchItemDetails when we resize the window?? what's that??void GeometryCache::renderGrid(int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id) {    #ifdef WANT_DEBUG        qDebug() << "GeometryCache::renderGrid(x["<<x<<"], "            "y["<<y<<"],"            "w["<<width<<"],"            "h["<<height<<"],"            "rows["<<rows<<"],"            "cols["<<cols<<"],"            " id:"<<id<<")...";    #endif                bool registered = (id != UNKNOWN_ID);    Vec3Pair key(glm::vec3(x, y, width), glm::vec3(height, rows, cols));    Vec3Pair colorKey(glm::vec3(color.x, color.y, rows), glm::vec3(color.z, color.y, cols));     int vertices = (cols + 1 + rows + 1) * 2;    if ((registered && !_registeredAlternateGridBuffers.contains(id)) || (!registered && !_alternateGridBuffers.contains(key))) {        gpu::BufferPointer verticesBuffer(new gpu::Buffer());         GLfloat* vertexData = new GLfloat[vertices * 2];        GLfloat* vertex = vertexData;         int dx = width / cols;        int dy = height / rows;        int tx = x;        int ty = y;         // Draw horizontal grid lines        for (int i = rows + 1; --i >= 0; ) {            *(vertex++) = x;            *(vertex++) = ty;             *(vertex++) = x + width;            *(vertex++) = ty;             ty += dy;        }        // Draw vertical grid lines        for (int i = cols + 1; --i >= 0; ) {            //glVertex2i(tx, y);            //glVertex2i(tx, y + height);            *(vertex++) = tx;            *(vertex++) = y;             *(vertex++) = tx;            *(vertex++) = y + height;            tx += dx;        }         verticesBuffer->append(sizeof(GLfloat) * vertices * 2, (gpu::Buffer::Byte*) vertexData);        delete[] vertexData;                if (registered) {            _registeredAlternateGridBuffers[id] = verticesBuffer;        } else {            _alternateGridBuffers[key] = verticesBuffer;        }    }     if (!_gridColors.contains(colorKey)) {        gpu::BufferPointer colorBuffer(new gpu::Buffer());        _gridColors[colorKey] = colorBuffer;         int compactColor = ((int(color.x * 255.0f) & 0xFF)) |                            ((int(color.y * 255.0f) & 0xFF) << 8) |                            ((int(color.z * 255.0f) & 0xFF) << 16) |                            ((int(color.w * 255.0f) & 0xFF) << 24);         int* colorData = new int[vertices];        int* colorDataAt = colorData;

Lines 1–500 of 2283.