// // GeometryCache.h // 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 // #ifndef hifi_GeometryCache_h #define hifi_GeometryCache_h #include "model-networking/ModelCache.h" #include #include #include #include #include #include #include #include #include #include class SimpleProgramKey; typedef QPair Vec2FloatPair; typedef QPair Vec2FloatPairPair; typedef QPair Vec2Pair; typedef QPair Vec2PairPair; typedef QPair Vec3Pair; typedef QPair Vec4Pair; typedef QPair Vec3PairVec2Pair; typedef QPair Vec3PairVec4; typedef QPair Vec3PairVec4Pair; typedef QPair Vec4PairVec4; typedef QPair Vec4PairVec4Pair; inline uint qHash(const Vec2FloatPairPair& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.first.x + 5009 * v.first.first.y + 5011 * v.first.second + 5021 * v.second.first.x + 5023 * v.second.first.y + 5039 * v.second.second); } inline uint qHash(const Vec2Pair& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.x + 5009 * v.first.y + 5011 * v.second.x + 5021 * v.second.y, seed); } inline uint qHash(const glm::vec4& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.x + 5009 * v.y + 5011 * v.z + 5021 * v.w, seed); } inline uint qHash(const Vec2PairPair& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.first.x + 5009 * v.first.first.y + 5011 * v.first.second.x + 5021 * v.first.second.y + 5023 * v.second.first.x + 5039 * v.second.first.y + 5051 * v.second.second.x + 5059 * v.second.second.y, seed); } inline uint qHash(const Vec3Pair& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.x + 5009 * v.first.y + 5011 * v.first.z + 5021 * v.second.x + 5023 * v.second.y + 5039 * v.second.z, seed); } inline uint qHash(const Vec4Pair& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.x + 5009 * v.first.y + 5011 * v.first.z + 5021 * v.first.w + 5023 * v.second.x + 5039 * v.second.y + 5051 * v.second.z + 5059 * v.second.w , seed); } inline uint qHash(const Vec3PairVec2Pair& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.first.x + 5009 * v.first.first.y + 5011 * v.first.first.z + 5021 * v.first.second.x + 5023 * v.first.second.y + 5039 * v.first.second.z + 5051 * v.second.first.x + 5059 * v.second.first.y + 5077 * v.second.second.x + 5081 * v.second.second.y, seed); } inline uint qHash(const Vec3PairVec4& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.first.x + 5009 * v.first.first.y + 5011 * v.first.first.z + 5021 * v.first.second.x + 5023 * v.first.second.y + 5039 * v.first.second.z + 5051 * v.second.x + 5059 * v.second.y + 5077 * v.second.z + 5081 * v.second.w, seed); } inline uint qHash(const Vec3PairVec4Pair& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.first.x + 5009 * v.first.first.y + 5011 * v.first.first.z + 5023 * v.first.second.x + 5039 * v.first.second.y + 5051 * v.first.second.z + 5077 * v.second.first.x + 5081 * v.second.first.y + 5087 * v.second.first.z + 5099 * v.second.first.w + 5101 * v.second.second.x + 5107 * v.second.second.y + 5113 * v.second.second.z + 5119 * v.second.second.w, seed); } inline uint qHash(const Vec4PairVec4& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.first.x + 5009 * v.first.first.y + 5011 * v.first.first.z + 5021 * v.first.first.w + 5023 * v.first.second.x + 5039 * v.first.second.y + 5051 * v.first.second.z + 5059 * v.first.second.w + 5077 * v.second.x + 5081 * v.second.y + 5087 * v.second.z + 5099 * v.second.w, seed); } inline uint qHash(const Vec4PairVec4Pair& v, uint seed) { // multiply by prime numbers greater than the possible size return qHash(v.first.first.x + 5009 * v.first.first.y + 5011 * v.first.first.z + 5021 * v.first.first.w + 5023 * v.first.second.x + 5039 * v.first.second.y + 5051 * v.first.second.z + 5059 * v.first.second.w + 5077 * v.second.first.x + 5081 * v.second.first.y + 5087 * v.second.first.z + 5099 * v.second.first.w + 5101 * v.second.second.x + 5107 * v.second.second.y + 5113 * v.second.second.z + 5119 * v.second.second.w, seed); } /// Stores cached geometry. class GeometryCache : public Dependency { SINGLETON_DEPENDENCY public: enum Shape { Line, Triangle, Quad, Hexagon, Octagon, Circle, Cube, Sphere, Tetrahedron, Octahedron, Dodecahedron, Icosahedron, Torus, // not yet implemented Cone, // not yet implemented Cylinder, // not yet implemented NUM_SHAPES, }; int allocateID() { return _nextID++; } void releaseID(int id); static const int UNKNOWN_ID; // Bind the pipeline and get the state to render static geometry void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool transparent = false, bool culled = true, bool unlit = false, bool depthBias = false); // Get the pipeline to render static geometry gpu::PipelinePointer getSimplePipeline(bool textured = false, bool transparent = false, bool culled = true, bool unlit = false, bool depthBias = false); void bindOpaqueWebBrowserProgram(gpu::Batch& batch); gpu::PipelinePointer getOpaqueWebBrowserProgram(); void bindTransparentWebBrowserProgram(gpu::Batch& batch); gpu::PipelinePointer getTransparentWebBrowserProgram(); render::ShapePipelinePointer getOpaqueShapePipeline() { return GeometryCache::_simpleOpaquePipeline; } render::ShapePipelinePointer getTransparentShapePipeline() { return GeometryCache::_simpleTransparentPipeline; } render::ShapePipelinePointer getWireShapePipeline() { return GeometryCache::_simpleWirePipeline; } // Static (instanced) geometry void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer); void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer); void renderSolidShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1), const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline); void renderSolidShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec3& color, const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) { renderSolidShapeInstance(batch, shape, glm::vec4(color, 1.0f), pipeline); } void renderWireShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1), const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline); void renderWireShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec3& color, const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) { renderWireShapeInstance(batch, shape, glm::vec4(color, 1.0f), pipeline); } void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline); void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec3& color, const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) { renderSolidSphereInstance(batch, glm::vec4(color, 1.0f), pipeline); } void renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline = _simpleWirePipeline); void renderWireSphereInstance(gpu::Batch& batch, const glm::vec3& color, const render::ShapePipelinePointer& pipeline = _simpleWirePipeline) { renderWireSphereInstance(batch, glm::vec4(color, 1.0f), pipeline); } void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline); void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec3& color, const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) { renderSolidCubeInstance(batch, glm::vec4(color, 1.0f), pipeline); } void renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline = _simpleWirePipeline); void renderWireCubeInstance(gpu::Batch& batch, const glm::vec3& color, const render::ShapePipelinePointer& pipeline = _simpleWirePipeline) { renderWireCubeInstance(batch, glm::vec4(color, 1.0f), pipeline); } // Dynamic geometry void renderShape(gpu::Batch& batch, Shape shape); void renderWireShape(gpu::Batch& batch, Shape shape); size_t getShapeTriangleCount(Shape shape); void renderCube(gpu::Batch& batch); void renderWireCube(gpu::Batch& batch); size_t getCubeTriangleCount(); void renderSphere(gpu::Batch& batch); void renderWireSphere(gpu::Batch& batch); size_t getSphereTriangleCount(); void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int majorRows, int majorCols, float majorEdge, int minorRows, int minorCols, float minorEdge, const glm::vec4& color, bool isLayered, int id); void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int rows, int cols, float edge, const glm::vec4& color, bool isLayered, int id) { renderGrid(batch, minCorner, maxCorner, rows, cols, edge, 0, 0, 0.0f, color, isLayered, id); } void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id); void renderUnitQuad(gpu::Batch& batch, const glm::vec4& color, int id); void renderUnitQuad(gpu::Batch& batch, int id) { renderUnitQuad(batch, glm::vec4(1), id); } void renderQuad(gpu::Batch& batch, int x, int y, int width, int height, const glm::vec4& color, int id) { renderQuad(batch, glm::vec2(x,y), glm::vec2(x + width, y + height), color, id); } // TODO: I think there's a bug in this version of the renderQuad() that's not correctly rebuilding the vbos // if the color changes by the corners are the same, as evidenced by the audio meter which should turn white // when it's clipping void renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec4& color, int id); void renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner, const glm::vec4& color, int id); void renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner, const glm::vec4& color, int id); void renderQuad(gpu::Batch& batch, const glm::vec3& topLeft, const glm::vec3& bottomLeft, const glm::vec3& bottomRight, const glm::vec3& topRight, const glm::vec2& texCoordTopLeft, const glm::vec2& texCoordBottomLeft, const glm::vec2& texCoordBottomRight, const glm::vec2& texCoordTopRight, const glm::vec4& color, int id); void renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& color, int id) { renderLine(batch, p1, p2, color, color, id); } void renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& color1, const glm::vec3& color2, int id) { renderLine(batch, p1, p2, glm::vec4(color1, 1.0f), glm::vec4(color2, 1.0f), id); } void renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec4& color, int id) { renderLine(batch, p1, p2, color, color, id); } void renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec4& color1, const glm::vec4& color2, int id); void renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec4& color, float glowIntensity, float glowWidth, int id); void renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec4& color, int id) { renderGlowLine(batch, p1, p2, color, 1.0f, 0.05f, id); } void renderDashedLine(gpu::Batch& batch, const glm::vec3& start, const glm::vec3& end, const glm::vec4& color, int id) { renderDashedLine(batch, start, end, color, 0.05f, 0.025f, id); } void renderDashedLine(gpu::Batch& batch, const glm::vec3& start, const glm::vec3& end, const glm::vec4& color, const float dash_length, const float gap_length, int id); void renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2, const glm::vec3& color, int id) { renderLine(batch, p1, p2, glm::vec4(color, 1.0f), id); } void renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2, const glm::vec4& color, int id) { renderLine(batch, p1, p2, color, color, id); } void renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2, const glm::vec3& color1, const glm::vec3& color2, int id) { renderLine(batch, p1, p2, glm::vec4(color1, 1.0f), glm::vec4(color2, 1.0f), id); } void renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2, const glm::vec4& color1, const glm::vec4& color2, int id); void updateVertices(int id, const QVector& points, const glm::vec4& color); void updateVertices(int id, const QVector& points, const QVector& colors); void updateVertices(int id, const QVector& points, const glm::vec4& color); void updateVertices(int id, const QVector& points, const QVector& colors); void updateVertices(int id, const QVector& points, const QVector& texCoords, const glm::vec4& color); void renderVertices(gpu::Batch& batch, gpu::Primitive primitiveType, int id); /// Set a batch to the simple pipeline, returning the previous pipeline void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false); struct ShapeData { size_t _indexOffset{ 0 }; size_t _indexCount{ 0 }; size_t _wireIndexOffset{ 0 }; size_t _wireIndexCount{ 0 }; gpu::BufferView _positionView; gpu::BufferView _normalView; gpu::BufferPointer _indices; void setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices); void setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices); void setupBatch(gpu::Batch& batch) const; void draw(gpu::Batch& batch) const; void drawWire(gpu::Batch& batch) const; void drawInstances(gpu::Batch& batch, size_t count) const; void drawWireInstances(gpu::Batch& batch, size_t count) const; }; using VShape = std::array; VShape _shapes; private: GeometryCache(); virtual ~GeometryCache(); void buildShapes(); typedef QPair IntPair; typedef QPair VerticesIndices; gpu::PipelinePointer _standardDrawPipeline; gpu::PipelinePointer _standardDrawPipelineNoBlend; gpu::BufferPointer _shapeVertices{ std::make_shared() }; gpu::BufferPointer _shapeIndices{ std::make_shared() }; class GridSchema { public: // data is arranged as majorRow, majorCol, minorRow, minorCol glm::vec4 period; glm::vec4 offset; glm::vec4 edge; }; using GridBuffer = gpu::BufferView; void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered); gpu::PipelinePointer _gridPipeline; gpu::PipelinePointer _gridPipelineLayered; int _gridSlot; class BatchItemDetails { public: static int population; gpu::BufferPointer verticesBuffer; gpu::BufferPointer colorBuffer; gpu::Stream::FormatPointer streamFormat; gpu::BufferStreamPointer stream; int vertices; int vertexSize; bool isCreated; BatchItemDetails(); BatchItemDetails(const GeometryCache::BatchItemDetails& other); ~BatchItemDetails(); void clear(); }; QHash _coneVBOs; int _nextID{ 1 }; QHash _lastRegisteredQuad3DTexture; QHash _registeredQuad3DTextures; QHash _lastRegisteredQuad2DTexture; QHash _registeredQuad2DTextures; QHash _lastRegisteredQuad3D; QHash _registeredQuad3D; QHash _lastRegisteredQuad2D; QHash _registeredQuad2D; QHash _lastRegisteredBevelRects; QHash _registeredBevelRects; QHash _lastRegisteredLine3D; QHash _registeredLine3DVBOs; QHash _lastRegisteredLine2D; QHash _registeredLine2DVBOs; QHash _registeredVertices; QHash _lastRegisteredDashedLines; QHash _registeredDashedLines; QHash _lastRegisteredGridBuffer; QHash _registeredGridBuffers; gpu::ShaderPointer _simpleShader; gpu::ShaderPointer _unlitShader; static render::ShapePipelinePointer _simpleOpaquePipeline; static render::ShapePipelinePointer _simpleTransparentPipeline; static render::ShapePipelinePointer _simpleWirePipeline; gpu::PipelinePointer _glowLinePipeline; QHash _simplePrograms; gpu::ShaderPointer _simpleOpaqueWebBrowserShader; gpu::PipelinePointer _simpleOpaqueWebBrowserPipeline; gpu::ShaderPointer _simpleTransparentWebBrowserShader; gpu::PipelinePointer _simpleTransparentWebBrowserPipeline; }; #endif // hifi_GeometryCache_h