From 03cb6175ab79d143eecc015e3dee21375e70326d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 12 Jul 2016 09:10:21 -0700 Subject: [PATCH] Support triangle and hexagon shapes, add shape support to overlays. --- interface/src/ui/overlays/Overlays.cpp | 3 + interface/src/ui/overlays/Shape3DOverlay.cpp | 130 ++++++++++++++++++ interface/src/ui/overlays/Shape3DOverlay.h | 46 +++++++ .../src/RenderableShapeEntityItem.cpp | 6 +- libraries/entities/src/ShapeEntityItem.cpp | 8 +- libraries/entities/src/ShapeEntityItem.h | 2 + libraries/networking/src/udt/PacketHeaders.h | 3 +- libraries/render-utils/src/GeometryCache.cpp | 93 ++++++++++++- libraries/render-utils/src/GeometryCache.h | 16 ++- scripts/system/html/entityProperties.html | 3 + 10 files changed, 298 insertions(+), 12 deletions(-) create mode 100644 interface/src/ui/overlays/Shape3DOverlay.cpp create mode 100644 interface/src/ui/overlays/Shape3DOverlay.h diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 9ff7f6268f..e99ca3a9e0 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -22,6 +22,7 @@ #include "Image3DOverlay.h" #include "Circle3DOverlay.h" #include "Cube3DOverlay.h" +#include "Shape3DOverlay.h" #include "ImageOverlay.h" #include "Line3DOverlay.h" #include "LocalModelsOverlay.h" @@ -157,6 +158,8 @@ unsigned int Overlays::addOverlay(const QString& type, const QVariant& propertie thisOverlay = std::make_shared(); } else if (type == Text3DOverlay::TYPE) { thisOverlay = std::make_shared(); + } else if (type == Shape3DOverlay::TYPE) { + thisOverlay = std::make_shared(); } else if (type == Cube3DOverlay::TYPE) { thisOverlay = std::make_shared(); } else if (type == Sphere3DOverlay::TYPE) { diff --git a/interface/src/ui/overlays/Shape3DOverlay.cpp b/interface/src/ui/overlays/Shape3DOverlay.cpp new file mode 100644 index 0000000000..cd07385aab --- /dev/null +++ b/interface/src/ui/overlays/Shape3DOverlay.cpp @@ -0,0 +1,130 @@ +// +// Shape3DOverlay.cpp +// interface/src/ui/overlays +// +// Copyright 2014 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 QGLWidget, which includes an earlier version of OpenGL +#include "Shape3DOverlay.h" + +#include +#include +#include +#include + +QString const Shape3DOverlay::TYPE = "shape"; + +Shape3DOverlay::Shape3DOverlay(const Shape3DOverlay* Shape3DOverlay) : + Volume3DOverlay(Shape3DOverlay) +{ +} + +void Shape3DOverlay::render(RenderArgs* args) { + if (!_visible) { + return; // do nothing if we're not visible + } + + float alpha = getAlpha(); + xColor color = getColor(); + const float MAX_COLOR = 255.0f; + glm::vec4 cubeColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); + + // TODO: handle registration point?? + glm::vec3 position = getPosition(); + glm::vec3 dimensions = getDimensions(); + glm::quat rotation = getRotation(); + + auto batch = args->_batch; + + if (batch) { + Transform transform; + transform.setTranslation(position); + transform.setRotation(rotation); + auto geometryCache = DependencyManager::get(); + auto pipeline = args->_pipeline; + if (!pipeline) { + pipeline = _isSolid ? geometryCache->getShapePipeline() : geometryCache->getWireShapePipeline(); + } + + transform.setScale(dimensions); + batch->setModelTransform(transform); + if (_isSolid) { + geometryCache->renderSolidShapeInstance(*batch, _shape, cubeColor, pipeline); + } else { + geometryCache->renderWireShapeInstance(*batch, _shape, cubeColor, pipeline); + } + } +} + +const render::ShapeKey Shape3DOverlay::getShapeKey() { + auto builder = render::ShapeKey::Builder(); + if (getAlpha() != 1.0f) { + builder.withTranslucent(); + } + if (!getIsSolid()) { + builder.withUnlit().withDepthBias(); + } + return builder.build(); +} + +Shape3DOverlay* Shape3DOverlay::createClone() const { + return new Shape3DOverlay(this); +} + + +static const std::array shapeStrings { { + "Line", + "Triangle", + "Quad", + "Hexagon", + "Octagon", + "Circle", + "Cube", + "Sphere", + "Tetrahedron", + "Octahedron", + "Dodecahedron", + "Icosahedron", + "Torus", + "Cone", + "Cylinder" +} }; + + +void Shape3DOverlay::setProperties(const QVariantMap& properties) { + Volume3DOverlay::setProperties(properties); + + auto shape = properties["shape"]; + if (shape.isValid()) { + const QString shapeStr = shape.toString(); + for (size_t i = 0; i < shapeStrings.size(); ++i) { + if (shapeStr == shapeStrings[i]) { + this->_shape = static_cast(i); + break; + } + } + } + + auto borderSize = properties["borderSize"]; + + if (borderSize.isValid()) { + float value = borderSize.toFloat(); + setBorderSize(value); + } +} + +QVariant Shape3DOverlay::getProperty(const QString& property) { + if (property == "borderSize") { + return _borderSize; + } + + if (property == "shape") { + return shapeStrings[_shape]; + } + + return Volume3DOverlay::getProperty(property); +} diff --git a/interface/src/ui/overlays/Shape3DOverlay.h b/interface/src/ui/overlays/Shape3DOverlay.h new file mode 100644 index 0000000000..2361001721 --- /dev/null +++ b/interface/src/ui/overlays/Shape3DOverlay.h @@ -0,0 +1,46 @@ +// +// Shape3DOverlay.h +// interface/src/ui/overlays +// +// Copyright 2014 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_Shape3DOverlay_h +#define hifi_Shape3DOverlay_h + +#include "Volume3DOverlay.h" + +#include + +class Shape3DOverlay : public Volume3DOverlay { + Q_OBJECT + +public: + static QString const TYPE; + virtual QString getType() const override { return TYPE; } + + Shape3DOverlay() {} + Shape3DOverlay(const Shape3DOverlay* Shape3DOverlay); + + virtual void render(RenderArgs* args) override; + virtual const render::ShapeKey getShapeKey() override; + + virtual Shape3DOverlay* createClone() const override; + + float getBorderSize() const { return _borderSize; } + + void setBorderSize(float value) { _borderSize = value; } + + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; + +private: + float _borderSize; + GeometryCache::Shape _shape { GeometryCache::Hexagon }; +}; + + +#endif // hifi_Shape3DOverlay_h diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index ec07e10ccf..48ad05a714 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -23,9 +23,11 @@ // is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down. static const float SPHERE_ENTITY_SCALE = 0.5f; -static GeometryCache::Shape MAPPING[entity::NUM_SHAPES] = { +static std::array MAPPING { { GeometryCache::Triangle, GeometryCache::Quad, + GeometryCache::Hexagon, + GeometryCache::Octagon, GeometryCache::Circle, GeometryCache::Cube, GeometryCache::Sphere, @@ -36,7 +38,7 @@ static GeometryCache::Shape MAPPING[entity::NUM_SHAPES] = { GeometryCache::Torus, GeometryCache::Cone, GeometryCache::Cylinder, -}; +} }; RenderableShapeEntityItem::Pointer RenderableShapeEntityItem::baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 84208cc6f1..141526643c 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -20,17 +20,19 @@ #include "ShapeEntityItem.h" namespace entity { - static const std::vector shapeStrings { { + static const std::array shapeStrings { { "Triangle", "Quad", - "Circle", + "Hexagon", + "Octagon", + "Circle", "Cube", "Sphere", "Tetrahedron", "Octahedron", "Dodecahedron", "Icosahedron", - "Torus", + "Torus", "Cone", "Cylinder" } }; diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 2ae4ae2ca1..122fc98dc0 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -15,6 +15,8 @@ namespace entity { enum Shape { Triangle, Quad, + Hexagon, + Octagon, Circle, Cube, Sphere, diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 9581f3ca20..85030135a1 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -97,7 +97,8 @@ public: ICEServerHeartbeatACK, NegotiateAudioFormat, SelectedAudioFormat, - LAST_PACKET_TYPE = SelectedAudioFormat + MoreEntityShapes, + LAST_PACKET_TYPE = MoreEntityShapes }; }; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 4558b68af9..50a93d2200 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -60,6 +60,18 @@ static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3); static const gpu::Type SHAPE_INDEX_TYPE = gpu::UINT32; static const uint SHAPE_INDEX_SIZE = sizeof(gpu::uint32); +template +std::vector polygon() { + std::vector result; + result.reserve(SIDES); + double angleIncrement = 2.0 * M_PI / SIDES; + for (size_t i = 0; i < SIDES; ++i) { + double angle = (double)i * angleIncrement; + result.push_back(vec3{ cos(angle) * 0.5, 0.0, sin(angle) * 0.5 }); + } + return result; +} + void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices) { vertexBuffer->append(vertices); @@ -239,6 +251,75 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid shapeData.setupIndices(indexBuffer, solidIndices, wireIndices); } +template +void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { + using namespace geometry; + Index baseVertex = (Index)(vertexBuffer->getSize() / SHAPE_VERTEX_STRIDE); + VertexVector vertices; + IndexVector solidIndices, wireIndices; + + // Top and bottom faces + std::vector shape = polygon(); + for (const vec3& v : shape) { + vertices.push_back(vec3(v.x, 0.5f, v.z)); + vertices.push_back(vec3(0, 1, 0)); + } + for (const vec3& v : shape) { + vertices.push_back(vec3(v.x, -0.5f, v.z)); + vertices.push_back(vec3(0, -1, 0)); + } + for (uint32_t i = 2; i < N; ++i) { + solidIndices.push_back(baseVertex + 0); + solidIndices.push_back(baseVertex + i); + solidIndices.push_back(baseVertex + i - 1); + solidIndices.push_back(baseVertex + N); + solidIndices.push_back(baseVertex + i + N - 1); + solidIndices.push_back(baseVertex + i + N); + } + for (uint32_t i = 1; i <= N; ++i) { + wireIndices.push_back(baseVertex + (i % N)); + wireIndices.push_back(baseVertex + i - 1); + wireIndices.push_back(baseVertex + (i % N) + N); + wireIndices.push_back(baseVertex + (i - 1) + N); + } + + // Now do the sides + baseVertex += 2 * N; + + for (uint32_t i = 0; i < N; ++i) { + vec3 left = shape[i]; + vec3 right = shape[(i + 1) % N]; + vec3 normal = glm::normalize(left + right); + vec3 topLeft = vec3(left.x, 0.5f, left.z); + vec3 topRight = vec3(right.x, 0.5f, right.z); + vec3 bottomLeft = vec3(left.x, -0.5f, left.z); + vec3 bottomRight = vec3(right.x, -0.5f, right.z); + + vertices.push_back(topLeft); + vertices.push_back(normal); + vertices.push_back(bottomLeft); + vertices.push_back(normal); + vertices.push_back(topRight); + vertices.push_back(normal); + vertices.push_back(bottomRight); + vertices.push_back(normal); + + solidIndices.push_back(baseVertex + 0); + solidIndices.push_back(baseVertex + 2); + solidIndices.push_back(baseVertex + 1); + solidIndices.push_back(baseVertex + 1); + solidIndices.push_back(baseVertex + 2); + solidIndices.push_back(baseVertex + 3); + wireIndices.push_back(baseVertex + 0); + wireIndices.push_back(baseVertex + 1); + wireIndices.push_back(baseVertex + 3); + wireIndices.push_back(baseVertex + 2); + baseVertex += 4; + } + + shapeData.setupVertices(vertexBuffer, vertices); + shapeData.setupIndices(indexBuffer, solidIndices, wireIndices); +} // FIXME solids need per-face vertices, but smooth shaded // components do not. Find a way to support using draw elements @@ -285,10 +366,13 @@ void GeometryCache::buildShapes() { // Not implememented yet: //Triangle, + extrudePolygon<3>(_shapes[Triangle], _shapeVertices, _shapeIndices); + //Hexagon, + extrudePolygon<6>(_shapes[Hexagon], _shapeVertices, _shapeIndices); + //Octagon, + extrudePolygon<8>(_shapes[Octagon], _shapeVertices, _shapeIndices); //Quad, //Circle, - //Octahetron, - //Dodecahedron, //Torus, //Cone, //Cylinder, @@ -1757,6 +1841,11 @@ void GeometryCache::renderSolidShapeInstance(gpu::Batch& batch, GeometryCache::S renderInstances(batch, color, false, pipeline, shape); } +void GeometryCache::renderWireShapeInstance(gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { + renderInstances(batch, color, true, pipeline, shape); +} + + void GeometryCache::renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { renderInstances(batch, color, false, pipeline, GeometryCache::Sphere); } diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 385f2c6fa4..bab0942672 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -132,6 +132,8 @@ public: Line, Triangle, Quad, + Hexagon, + Octagon, Circle, Cube, Sphere, @@ -139,10 +141,9 @@ public: Octahedron, Dodecahedron, Icosahedron, - Torus, - Cone, - Cylinder, - + Torus, // not yet implemented + Cone, // not yet implemented + Cylinder, // not yet implemented NUM_SHAPES, }; @@ -170,6 +171,13 @@ public: 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 = _simplePipeline); + void renderWireShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec3& color, + const render::ShapePipelinePointer& pipeline = _simplePipeline) { + renderWireShapeInstance(batch, shape, glm::vec4(color, 1.0f), pipeline); + } + void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline = _simplePipeline); void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec3& color, diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 54c79b1d9f..f2ade39144 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -1354,6 +1354,9 @@ + + +