Merge pull request #14530 from SamGondelman/NOverlays4

Case 20134: Grid Entities
This commit is contained in:
Jeff Clinton 2019-01-02 09:12:34 -08:00 committed by GitHub
commit bb27acf934
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 696 additions and 94 deletions

View file

@ -85,7 +85,7 @@ void Grid3DOverlay::render(RenderArgs* args) {
DependencyManager::get<GeometryCache>()->renderGrid(*batch, minCorner, maxCorner,
_minorGridRowDivisions, _minorGridColDivisions, MINOR_GRID_EDGE,
_majorGridRowDivisions, _majorGridColDivisions, MAJOR_GRID_EDGE,
gridColor, _drawInFront, _geometryId);
gridColor, _geometryId);
}
}

View file

@ -26,6 +26,7 @@
#include "RenderableZoneEntityItem.h"
#include "RenderableMaterialEntityItem.h"
#include "RenderableImageEntityItem.h"
#include "RenderableGridEntityItem.h"
using namespace render;
@ -259,6 +260,10 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer,
result = make_renderer<PolyVoxEntityRenderer>(entity);
break;
case Type::Grid:
result = make_renderer<GridEntityRenderer>(entity);
break;
case Type::Light:
result = make_renderer<LightEntityRenderer>(entity);
break;

View file

@ -0,0 +1,148 @@
//
// Created by Sam Gondelman on 11/29/18
// Copyright 2018 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 "RenderableGridEntityItem.h"
#include <DependencyManager.h>
#include <GeometryCache.h>
using namespace render;
using namespace render::entities;
GridEntityRenderer::GridEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
GridEntityRenderer::~GridEntityRenderer() {
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
geometryCache->releaseID(_geometryId);
}
}
bool GridEntityRenderer::isTransparent() const {
return Parent::isTransparent() || _alpha < 1.0f;
}
bool GridEntityRenderer::needsRenderUpdate() const {
return Parent::needsRenderUpdate();
}
bool GridEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
bool needsUpdate = resultWithReadLock<bool>([&] {
if (_color != entity->getColor()) {
return true;
}
if (_alpha != entity->getAlpha()) {
return true;
}
if (_followCamera != entity->getFollowCamera()) {
return true;
}
if (_majorGridEvery != entity->getMajorGridEvery()) {
return true;
}
if (_minorGridEvery != entity->getMinorGridEvery()) {
return true;
}
return false;
});
return needsUpdate;
}
void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
withWriteLock([&] {
_color = entity->getColor();
_alpha = entity->getAlpha();
_followCamera = entity->getFollowCamera();
_majorGridEvery = entity->getMajorGridEvery();
_minorGridEvery = entity->getMinorGridEvery();
});
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity]() {
withWriteLock([&] {
_dimensions = entity->getScaledDimensions();
updateModelTransformAndBound();
_renderTransform = getModelTransform();
});
});
}
Item::Bound GridEntityRenderer::getBound() {
if (_followCamera) {
// This is a UI element that should always be in view, lie to the octree to avoid culling
const AABox DOMAIN_BOX = AABox(glm::vec3(-TREE_SCALE / 2), TREE_SCALE);
return DOMAIN_BOX;
}
return Parent::getBound();
}
ShapeKey GridEntityRenderer::getShapeKey() {
auto builder = render::ShapeKey::Builder().withOwnPipeline().withUnlit().withDepthBias();
if (isTransparent()) {
builder.withTranslucent();
}
return builder.build();
}
void GridEntityRenderer::doRender(RenderArgs* args) {
glm::u8vec3 color;
glm::vec3 dimensions;
Transform renderTransform;
withReadLock([&] {
color = _color;
dimensions = _dimensions;
renderTransform = _renderTransform;
});
if (!_visible) {
return;
}
auto batch = args->_batch;
Transform transform;
transform.setScale(dimensions);
transform.setRotation(renderTransform.getRotation());
if (_followCamera) {
// Get the camera position rounded to the nearest major grid line
// This grid is for UI and should lie on worldlines
glm::vec3 localCameraPosition = glm::inverse(transform.getRotation()) * (args->getViewFrustum().getPosition() - renderTransform.getTranslation());
localCameraPosition.z = 0;
localCameraPosition = (float)_majorGridEvery * glm::round(localCameraPosition / (float)_majorGridEvery);
transform.setTranslation(renderTransform.getTranslation() + transform.getRotation() * localCameraPosition);
} else {
transform.setTranslation(renderTransform.getTranslation());
}
batch->setModelTransform(transform);
auto minCorner = glm::vec2(-0.5f, -0.5f);
auto maxCorner = glm::vec2(0.5f, 0.5f);
float majorGridRowDivisions = dimensions.x / _majorGridEvery;
float majorGridColDivisions = dimensions.y / _majorGridEvery;
float minorGridRowDivisions = dimensions.x / _minorGridEvery;
float minorGridColDivisions = dimensions.y / _minorGridEvery;
glm::vec4 gridColor(toGlm(color), _alpha);
const float MINOR_GRID_EDGE = 0.0025f;
const float MAJOR_GRID_EDGE = 0.005f;
DependencyManager::get<GeometryCache>()->renderGrid(*batch, minCorner, maxCorner,
minorGridRowDivisions, minorGridColDivisions, MINOR_GRID_EDGE,
majorGridRowDivisions, majorGridColDivisions, MAJOR_GRID_EDGE,
gridColor, _geometryId);
}

View file

@ -0,0 +1,51 @@
//
// Created by Sam Gondelman on 11/29/18
// Copyright 2018 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_RenderableGridEntityItem_h
#define hifi_RenderableGridEntityItem_h
#include "RenderableEntityItem.h"
#include <GridEntityItem.h>
namespace render { namespace entities {
class GridEntityRenderer : public TypedEntityRenderer<GridEntityItem> {
using Parent = TypedEntityRenderer<GridEntityItem>;
using Pointer = std::shared_ptr<GridEntityRenderer>;
public:
GridEntityRenderer(const EntityItemPointer& entity);
~GridEntityRenderer();
protected:
Item::Bound getBound() override;
ShapeKey getShapeKey() override;
bool isTransparent() const override;
private:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
glm::u8vec3 _color;
float _alpha;
bool _followCamera;
uint32_t _majorGridEvery;
float _minorGridEvery;
glm::vec3 _dimensions;
int _geometryId { 0 };
};
} }
#endif // hifi_RenderableGridEntityItem_h

View file

@ -13,44 +13,42 @@
#include <ImageEntityItem.h>
namespace render {
namespace entities {
namespace render { namespace entities {
class ImageEntityRenderer : public TypedEntityRenderer<ImageEntityItem> {
using Parent = TypedEntityRenderer<ImageEntityItem>;
using Pointer = std::shared_ptr<ImageEntityRenderer>;
public:
ImageEntityRenderer(const EntityItemPointer& entity);
~ImageEntityRenderer();
class ImageEntityRenderer : public TypedEntityRenderer<ImageEntityItem> {
using Parent = TypedEntityRenderer<ImageEntityItem>;
using Pointer = std::shared_ptr<ImageEntityRenderer>;
public:
ImageEntityRenderer(const EntityItemPointer& entity);
~ImageEntityRenderer();
protected:
ShapeKey getShapeKey() override;
protected:
ShapeKey getShapeKey() override;
bool isTransparent() const override;
bool isTransparent() const override;
private:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
private:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
QString _imageURL;
NetworkTexturePointer _texture;
bool _textureIsLoaded { false };
QString _imageURL;
NetworkTexturePointer _texture;
bool _textureIsLoaded { false };
bool _emissive;
bool _keepAspectRatio;
BillboardMode _billboardMode;
QRect _subImage;
bool _emissive;
bool _keepAspectRatio;
BillboardMode _billboardMode;
QRect _subImage;
glm::u8vec3 _color;
float _alpha;
glm::u8vec3 _color;
float _alpha;
glm::vec3 _dimensions;
glm::vec3 _dimensions;
int _geometryId { 0 };
};
int _geometryId { 0 };
};
}
}
} }
#endif // hifi_RenderableImageEntityItem_h

View file

@ -439,6 +439,10 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_KEEP_ASPECT_RATIO, keepAspectRatio);
CHECK_PROPERTY_CHANGE(PROP_SUB_IMAGE, subImage);
CHECK_PROPERTY_CHANGE(PROP_GRID_FOLLOW_CAMERA, followCamera);
CHECK_PROPERTY_CHANGE(PROP_MAJOR_GRID_EVERY, majorGridEvery);
CHECK_PROPERTY_CHANGE(PROP_MINOR_GRID_EVERY, minorGridEvery);
// Certifiable Properties
CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName);
CHECK_PROPERTY_CHANGE(PROP_ITEM_DESCRIPTION, itemDescription);
@ -714,6 +718,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @see {@link Entities.EntityProperties-Line|EntityProperties-Line}
* @see {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine}
* @see {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox}
* @see {@link Entities.EntityProperties-Grid|EntityProperties-Grid}
* @see {@link Entities.EntityProperties-Light|EntityProperties-Light}
* @see {@link Entities.EntityProperties-Zone|EntityProperties-Zone}
* @see {@link Entities.EntityProperties-Material|EntityProperties-Material}
@ -1272,7 +1277,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* <code>"isFacingAvatar"</code> to <code>true</code> to set <code>billboardMode</code> to "full". Setting either to <code>false</code> sets the mode to "none"
* @property {Rect} subImage={ x: 0, y: 0, width: -1, height: -1 } - The portion of the image to display. If width or height are -1, defaults to
* the full image in that dimension.
* @property {Color} color=255,255,255 - The color of image.
* @property {Color} color=255,255,255 - The color of the image.
* @property {number} alpha=1 - The alpha of the image.
* @example <caption>Create a image entity.</caption>
* var image = Entities.addEntity({
@ -1285,6 +1290,30 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* });
*/
/**jsdoc
* The <code>"Grid"</code> {@link Entities.EntityType|EntityType} displays a grid on a 2D plane.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* @typedef {object} Entities.EntityProperties-Grid
* @property {Color} color=255,255,255 - The color of the grid.
* @property {number} alpha=1 - The alpha of the grid.
* @property {boolean} followCamera=true - If <code>true</code>, the grid is always visible even as the camera moves to another
* position.
* @property {number} majorGridEvery=5 - Integer number of <code>minorGridEvery</code> intervals at which to draw a thick grid
* line. Minimum value = <code>1</code>.
* @property {number} minorGridEvery=1 - Real number of meters at which to draw thin grid lines. Minimum value =
* <code>0.001</code>.
* @example <caption>Create a grid entity.</caption>
* var grid = Entities.addEntity({
* type: "Grid",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* dimensions: { x: 100.0, y: 100.0, z: 0.01 },
* followCamera: false,
* majorGridEvery: 4,
* minorGridEvery: 0.5,
* lifetime: 300 // Delete after 5 minutes.
* });
*/
QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime,
bool strictSemantics, EntityPsuedoPropertyFlags psueudoPropertyFlags) const {
@ -1577,6 +1606,16 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
}
}
// Grid only
if (_type == EntityTypes::Grid) {
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GRID_FOLLOW_CAMERA, followCamera);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MAJOR_GRID_EVERY, majorGridEvery);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MINOR_GRID_EVERY, minorGridEvery);
}
/**jsdoc
* The axis-aligned bounding box of an entity.
* @typedef {object} Entities.BoundingBox
@ -1815,6 +1854,10 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(keepAspectRatio, bool, setKeepAspectRatio);
COPY_PROPERTY_FROM_QSCRIPTVALUE(subImage, QRect, setSubImage);
COPY_PROPERTY_FROM_QSCRIPTVALUE(followCamera, bool, setFollowCamera);
COPY_PROPERTY_FROM_QSCRIPTVALUE(majorGridEvery, uint32_t, setMajorGridEvery);
COPY_PROPERTY_FROM_QSCRIPTVALUE(minorGridEvery, float, setMinorGridEvery);
if (!honorReadOnly) {
// this is used by the json reader to set things that we don't want javascript to able to affect.
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(created, QDateTime, setCreated, [this]() {
@ -1999,6 +2042,10 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(keepAspectRatio);
COPY_PROPERTY_IF_CHANGED(subImage);
COPY_PROPERTY_IF_CHANGED(followCamera);
COPY_PROPERTY_IF_CHANGED(majorGridEvery);
COPY_PROPERTY_IF_CHANGED(minorGridEvery);
// Certifiable Properties
COPY_PROPERTY_IF_CHANGED(itemName);
COPY_PROPERTY_IF_CHANGED(itemDescription);
@ -2359,6 +2406,10 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_KEEP_ASPECT_RATIO, KeepAspectRatio, keepAspectRatio, bool);
ADD_PROPERTY_TO_MAP(PROP_SUB_IMAGE, SubImage, subImage, QRect);
ADD_PROPERTY_TO_MAP(PROP_GRID_FOLLOW_CAMERA, FollowCamera, followCamera, bool);
ADD_PROPERTY_TO_MAP(PROP_MAJOR_GRID_EVERY, MajorGridEvery, majorGridEvery, uint32_t);
ADD_PROPERTY_TO_MAP(PROP_MINOR_GRID_EVERY, MinorGridEvery, minorGridEvery, float);
// FIXME - these are not yet handled
//ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64);
@ -2693,6 +2744,16 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha());
}
// Grid
if (properties.getType() == EntityTypes::Grid) {
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha());
APPEND_ENTITY_PROPERTY(PROP_GRID_FOLLOW_CAMERA, properties.getFollowCamera());
APPEND_ENTITY_PROPERTY(PROP_MAJOR_GRID_EVERY, properties.getMajorGridEvery());
APPEND_ENTITY_PROPERTY(PROP_MINOR_GRID_EVERY, properties.getMinorGridEvery());
}
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
@ -3101,6 +3162,16 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
}
// Grid
if (properties.getType() == EntityTypes::Grid) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GRID_FOLLOW_CAMERA, bool, setFollowCamera);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAJOR_GRID_EVERY, uint32_t, setMajorGridEvery);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MINOR_GRID_EVERY, float, setMinorGridEvery);
}
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData);
@ -3433,6 +3504,10 @@ void EntityItemProperties::markAllChanged() {
_emissiveChanged = true;
_keepAspectRatioChanged = true;
_subImageChanged = true;
_followCameraChanged = true;
_majorGridEveryChanged = true;
_minorGridEveryChanged = true;
}
// The minimum bounding box for the entity.
@ -3989,6 +4064,16 @@ QList<QString> EntityItemProperties::listChangedProperties() {
out += "billboardMode";
}
if (followCameraChanged()) {
out += "followCamera";
}
if (majorGridEveryChanged()) {
out += "majorGridEvery";
}
if (minorGridEveryChanged()) {
out += "minorGridEvery";
}
getAnimation().listChangedProperties(out);
getKeyLight().listChangedProperties(out);
getAmbientLight().listChangedProperties(out);

View file

@ -46,6 +46,7 @@
#include "BloomPropertyGroup.h"
#include "TextEntityItem.h"
#include "ZoneEntityItem.h"
#include "GridEntityItem.h"
#include "MaterialMappingMode.h"
#include "BillboardMode.h"
@ -80,6 +81,7 @@ class EntityItemProperties {
friend class LineEntityItem;
friend class PolyLineEntityItem;
friend class PolyVoxEntityItem;
friend class GridEntityItem;
friend class LightEntityItem;
friend class ZoneEntityItem;
friend class MaterialEntityItem;
@ -258,6 +260,10 @@ public:
DEFINE_PROPERTY_REF(PROP_KEEP_ASPECT_RATIO, KeepAspectRatio, keepAspectRatio, bool, true);
DEFINE_PROPERTY_REF(PROP_SUB_IMAGE, SubImage, subImage, QRect, QRect());
DEFINE_PROPERTY_REF(PROP_GRID_FOLLOW_CAMERA, FollowCamera, followCamera, bool, true);
DEFINE_PROPERTY(PROP_MAJOR_GRID_EVERY, MajorGridEvery, majorGridEvery, uint32_t, GridEntityItem::DEFAULT_MAJOR_GRID_EVERY);
DEFINE_PROPERTY(PROP_MINOR_GRID_EVERY, MinorGridEvery, minorGridEvery, float, GridEntityItem::DEFAULT_MINOR_GRID_EVERY);
// Certifiable Properties - related to Proof of Purchase certificates
DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME);
DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION);

View file

@ -226,6 +226,7 @@ inline quint32 quint32_convertFromScriptValue(const QScriptValue& v, bool& isVal
}
inline quint16 quint16_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline uint32_t uint32_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }
inline uint8_t uint8_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return (uint8_t)(0xff & v.toVariant().toInt(&isValid)); }

View file

@ -318,6 +318,12 @@ enum EntityPropertyList {
PROP_IMAGE_URL = PROP_MODEL_URL,
PROP_KEEP_ASPECT_RATIO = PROP_ANIMATION_PLAYING,
// Aliases/Piggyback properties for Grid. These properties intentionally reuse the enum values for
// other properties which will never overlap with each other.
PROP_GRID_FOLLOW_CAMERA = PROP_ANIMATION_PLAYING,
PROP_MAJOR_GRID_EVERY = PROP_ANIMATION_URL,
PROP_MINOR_GRID_EVERY = PROP_ANIMATION_FPS,
// WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above
};

View file

@ -29,6 +29,7 @@
#include "LineEntityItem.h"
#include "PolyLineEntityItem.h"
#include "PolyVoxEntityItem.h"
#include "GridEntityItem.h"
#include "LightEntityItem.h"
#include "ZoneEntityItem.h"
#include "MaterialEntityItem.h"
@ -52,6 +53,7 @@ REGISTER_ENTITY_TYPE(ParticleEffect)
REGISTER_ENTITY_TYPE(Line)
REGISTER_ENTITY_TYPE(PolyLine)
REGISTER_ENTITY_TYPE(PolyVox)
REGISTER_ENTITY_TYPE(Grid)
REGISTER_ENTITY_TYPE(Light)
REGISTER_ENTITY_TYPE(Zone)
REGISTER_ENTITY_TYPE(Material)

View file

@ -76,6 +76,8 @@ public:
* <td>{@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine}</td></tr>
* <tr><td><code>"PolyVox"</code></td><td>A set of textured voxels.</td>
* <td>{@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox}</td></tr>
* <tr><td><code>"Grid"</code></td><td>A grid of lines in a plane.</td>
* <td>{@link Entities.EntityProperties-Grid|EntityProperties-Grid}</td></tr>
* <tr><td><code>"Light"</code></td><td>A local lighting effect.</td>
* <td>{@link Entities.EntityProperties-Light|EntityProperties-Light}</td></tr>
* <tr><td><code>"Zone"</code></td><td>A volume of lighting effects and avatar permissions.</td>
@ -100,6 +102,7 @@ public:
Line,
PolyLine,
PolyVox,
Grid,
Light,
Zone,
Material,

View file

@ -0,0 +1,178 @@
//
// Created by Sam Gondelman on 11/29/18
// Copyright 2018 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 "GridEntityItem.h"
#include "EntityItemProperties.h"
const uint32_t GridEntityItem::DEFAULT_MAJOR_GRID_EVERY = 5;
const float GridEntityItem::DEFAULT_MINOR_GRID_EVERY = 1.0f;
EntityItemPointer GridEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
Pointer entity(new GridEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); });
entity->setProperties(properties);
return entity;
}
// our non-pure virtual subclass for now...
GridEntityItem::GridEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) {
_type = EntityTypes::Grid;
}
void GridEntityItem::setUnscaledDimensions(const glm::vec3& value) {
const float GRID_ENTITY_ITEM_FIXED_DEPTH = 0.01f;
// NOTE: Grid Entities always have a "depth" of 1cm.
EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, GRID_ENTITY_ITEM_FIXED_DEPTH));
}
EntityItemProperties GridEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(followCamera, getFollowCamera);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(majorGridEvery, getMajorGridEvery);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(minorGridEvery, getMinorGridEvery);
return properties;
}
bool GridEntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(followCamera, setFollowCamera);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(majorGridEvery, setMajorGridEvery);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(minorGridEvery, setMinorGridEvery);
if (somethingChanged) {
bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();
int elapsed = now - getLastEdited();
qCDebug(entities) << "GridEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " getLastEdited()=" << getLastEdited();
}
setLastEdited(properties.getLastEdited());
}
return somethingChanged;
}
int GridEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) {
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_COLOR, u8vec3Color, setColor);
READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha);
READ_ENTITY_PROPERTY(PROP_GRID_FOLLOW_CAMERA, bool, setFollowCamera);
READ_ENTITY_PROPERTY(PROP_MAJOR_GRID_EVERY, uint32_t, setMajorGridEvery);
READ_ENTITY_PROPERTY(PROP_MINOR_GRID_EVERY, float, setMinorGridEvery);
return bytesRead;
}
EntityPropertyFlags GridEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_COLOR;
requestedProperties += PROP_ALPHA;
requestedProperties += PROP_GRID_FOLLOW_CAMERA;
requestedProperties += PROP_MAJOR_GRID_EVERY;
requestedProperties += PROP_MINOR_GRID_EVERY;
return requestedProperties;
}
void GridEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha());
APPEND_ENTITY_PROPERTY(PROP_GRID_FOLLOW_CAMERA, getFollowCamera());
APPEND_ENTITY_PROPERTY(PROP_MAJOR_GRID_EVERY, getMajorGridEvery());
APPEND_ENTITY_PROPERTY(PROP_MINOR_GRID_EVERY, getMinorGridEvery());
}
void GridEntityItem::setColor(const glm::u8vec3& color) {
withWriteLock([&] {
_color = color;
});
}
glm::u8vec3 GridEntityItem::getColor() const {
return resultWithReadLock<glm::u8vec3>([&] {
return _color;
});
}
void GridEntityItem::setAlpha(float alpha) {
withWriteLock([&] {
_alpha = alpha;
});
}
float GridEntityItem::getAlpha() const {
return resultWithReadLock<float>([&] {
return _alpha;
});
}
void GridEntityItem::setFollowCamera(bool followCamera) {
withWriteLock([&] {
_followCamera = followCamera;
});
}
bool GridEntityItem::getFollowCamera() const {
return resultWithReadLock<bool>([&] {
return _followCamera;
});
}
void GridEntityItem::setMajorGridEvery(uint32_t majorGridEvery) {
withWriteLock([&] {
const uint32_t MAJOR_GRID_EVERY_MIN = 1;
_majorGridEvery = std::max(majorGridEvery, MAJOR_GRID_EVERY_MIN);
});
}
uint32_t GridEntityItem::getMajorGridEvery() const {
return resultWithReadLock<uint32_t>([&] {
return _majorGridEvery;
});
}
void GridEntityItem::setMinorGridEvery(float minorGridEvery) {
withWriteLock([&] {
const float MINOR_GRID_EVERY_MIN = 0.01f;
_minorGridEvery = std::max(minorGridEvery, MINOR_GRID_EVERY_MIN);
});
}
float GridEntityItem::getMinorGridEvery() const {
return resultWithReadLock<float>([&] {
return _minorGridEvery;
});
}

View file

@ -0,0 +1,71 @@
//
// Created by Sam Gondelman on 11/29/18
// Copyright 2018 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_GridEntityItem_h
#define hifi_GridEntityItem_h
#include "EntityItem.h"
class GridEntityItem : public EntityItem {
using Pointer = std::shared_ptr<GridEntityItem>;
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
GridEntityItem(const EntityItemID& entityItemID);
ALLOW_INSTANTIATION // This class can be instantiated
virtual void setUnscaledDimensions(const glm::vec3& value) override;
// methods for getting/setting all properties of an entity
EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
bool setProperties(const EntityItemProperties& properties) override;
EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
static const uint32_t DEFAULT_MAJOR_GRID_EVERY;
static const float DEFAULT_MINOR_GRID_EVERY;
void setColor(const glm::u8vec3& color);
glm::u8vec3 getColor() const;
void setAlpha(float alpha);
float getAlpha() const;
void setFollowCamera(bool followCamera);
bool getFollowCamera() const;
void setMajorGridEvery(uint32_t majorGridEvery);
uint32_t getMajorGridEvery() const;
void setMinorGridEvery(float minorGridEvery);
float getMinorGridEvery() const;
protected:
glm::u8vec3 _color;
float _alpha;
bool _followCamera { true };
uint32_t _majorGridEvery { DEFAULT_MAJOR_GRID_EVERY };
float _minorGridEvery { DEFAULT_MINOR_GRID_EVERY };
};
#endif // hifi_GridEntityItem_h

View file

@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit:
case PacketType::EntityData:
case PacketType::EntityPhysics:
return static_cast<PacketVersion>(EntityVersion::ImageEntities);
return static_cast<PacketVersion>(EntityVersion::GridEntities);
case PacketType::EntityQuery:
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
case PacketType::AvatarIdentity:

View file

@ -248,7 +248,8 @@ enum class EntityVersion : PacketVersion {
MaterialRepeat,
EntityHostTypes,
CleanupProperties,
ImageEntities
ImageEntities,
GridEntities
};
enum class EntityScriptCallMethodVersion : PacketVersion {

View file

@ -944,42 +944,44 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch, const glm::vec4& color)
}
void GeometryCache::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) {
static const glm::vec2 MIN_TEX_COORD(0.0f, 0.0f);
static const glm::vec2 MAX_TEX_COORD(1.0f, 1.0f);
bool registered = (id != UNKNOWN_ID);
int majorRows, int majorCols, float majorEdge, int minorRows, int minorCols, float minorEdge,
const glm::vec4& color, int id) {
Vec2FloatPair majorKey(glm::vec2(majorRows, majorCols), majorEdge);
Vec2FloatPair minorKey(glm::vec2(minorRows, minorCols), minorEdge);
Vec2FloatPairPair key(majorKey, minorKey);
// Make the gridbuffer
if (registered && (!_registeredGridBuffers.contains(id) || _lastRegisteredGridBuffer[id] != key)) {
GridSchema gridSchema;
GridBuffer gridBuffer = std::make_shared<gpu::Buffer>(sizeof(GridSchema), (const gpu::Byte*) &gridSchema);
if (registered && _registeredGridBuffers.contains(id)) {
gridBuffer = _registeredGridBuffers[id];
GridBuffer gridBuffer;
if (id != UNKNOWN_ID) {
auto gridBufferIter = _registeredGridBuffers.find(id);
bool hadGridBuffer = gridBufferIter != _registeredGridBuffers.end();
if (hadGridBuffer) {
gridBuffer = gridBufferIter.value();
} else {
GridSchema gridSchema;
gridBuffer = std::make_shared<gpu::Buffer>(sizeof(GridSchema), (const gpu::Byte*)&gridSchema);
}
_registeredGridBuffers[id] = gridBuffer;
_lastRegisteredGridBuffer[id] = key;
if (!hadGridBuffer || _lastRegisteredGridBuffer[id] != key) {
_registeredGridBuffers[id] = gridBuffer;
_lastRegisteredGridBuffer[id] = key;
gridBuffer.edit<GridSchema>().period = glm::vec4(majorRows, majorCols, minorRows, minorCols);
gridBuffer.edit<GridSchema>().offset.x = -(majorEdge / majorRows) / 2;
gridBuffer.edit<GridSchema>().offset.y = -(majorEdge / majorCols) / 2;
gridBuffer.edit<GridSchema>().offset.z = -(minorEdge / minorRows) / 2;
gridBuffer.edit<GridSchema>().offset.w = -(minorEdge / minorCols) / 2;
gridBuffer.edit<GridSchema>().edge = glm::vec4(glm::vec2(majorEdge),
// If rows or columns are not set, do not draw minor gridlines
glm::vec2((minorRows != 0 && minorCols != 0) ? minorEdge : 0.0f));
gridBuffer.edit<GridSchema>().period = glm::vec4(majorRows, majorCols, minorRows, minorCols);
gridBuffer.edit<GridSchema>().offset.x = -(majorEdge / majorRows) / 2;
gridBuffer.edit<GridSchema>().offset.y = -(majorEdge / majorCols) / 2;
gridBuffer.edit<GridSchema>().offset.z = -(minorEdge / minorRows) / 2;
gridBuffer.edit<GridSchema>().offset.w = -(minorEdge / minorCols) / 2;
gridBuffer.edit<GridSchema>().edge = glm::vec4(glm::vec2(majorEdge),
// If rows or columns are not set, do not draw minor gridlines
glm::vec2((minorRows != 0 && minorCols != 0) ? minorEdge : 0.0f));
}
}
// Set the grid pipeline
useGridPipeline(batch, _registeredGridBuffers[id], isLayered);
useGridPipeline(batch, gridBuffer, color.a < 1.0f);
static const glm::vec2 MIN_TEX_COORD(0.0f, 0.0f);
static const glm::vec2 MAX_TEX_COORD(1.0f, 1.0f);
renderQuad(batch, minCorner, maxCorner, MIN_TEX_COORD, MAX_TEX_COORD, color, id);
}
@ -2115,26 +2117,40 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
}
}
void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered) {
if (!_gridPipeline) {
auto program = gpu::Shader::createProgram(shader::render_utils::program::grid);
_gridSlot = 0;
auto stateLayered = std::make_shared<gpu::State>();
stateLayered->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
PrepareStencil::testMask(*stateLayered);
_gridPipelineLayered = gpu::Pipeline::create(program, stateLayered);
auto state = std::make_shared<gpu::State>(stateLayered->getValues());
void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool transparent) {
if (!_gridPipelineOpaque || !_gridPipelineTransparent) {
const float DEPTH_BIAS = 0.001f;
state->setDepthBias(DEPTH_BIAS);
state->setDepthTest(true, false, gpu::LESS_EQUAL);
PrepareStencil::testMaskDrawShape(*state);
_gridPipeline = gpu::Pipeline::create(program, state);
// FIXME: need forward pipelines
{
auto program = gpu::Shader::createProgram(shader::render_utils::program::grid);
auto state = std::make_shared<gpu::State>();
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(false,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMaskDrawShape(*state);
state->setCullMode(gpu::State::CULL_NONE);
state->setDepthBias(DEPTH_BIAS);
_gridPipelineOpaque = gpu::Pipeline::create(program, state);
}
{
auto program = gpu::Shader::createProgram(shader::render_utils::program::grid_translucent);
auto state = std::make_shared<gpu::State>();
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMask(*state);
state->setCullMode(gpu::State::CULL_NONE);
state->setDepthBias(DEPTH_BIAS);
_gridPipelineTransparent = gpu::Pipeline::create(program, state);
}
}
gpu::PipelinePointer pipeline = isLayered ? _gridPipelineLayered : _gridPipeline;
batch.setPipeline(pipeline);
batch.setUniformBuffer(_gridSlot, gridBuffer);
batch.setPipeline(transparent ? _gridPipelineTransparent : _gridPipelineOpaque);
batch.setUniformBuffer(0, gridBuffer);
}

View file

@ -270,11 +270,7 @@ public:
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);
}
const glm::vec4& color, int id);
void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id);
@ -414,9 +410,8 @@ private:
};
using GridBuffer = gpu::BufferView;
void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered);
gpu::PipelinePointer _gridPipeline;
gpu::PipelinePointer _gridPipelineLayered;
int _gridSlot;
gpu::PipelinePointer _gridPipelineOpaque;
gpu::PipelinePointer _gridPipelineTransparent;
class BatchItemDetails {
public:

View file

@ -1,8 +1,6 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// grid.frag
// fragment shader
//
// Created by Zach Pomerantz on 2/16/2016.
// Copyright 2016 High Fidelity, Inc.
@ -11,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include gpu/ShaderConstants.h@>
<@include gpu/Paint.slh@>
@ -21,26 +21,20 @@ struct Grid {
};
LAYOUT(binding=0) uniform gridBuffer {
Grid grid;
Grid grid;
};
Grid getGrid() { return grid; }
layout(location=GPU_ATTR_TEXCOORD0) in vec2 varTexCoord0;
layout(location=GPU_ATTR_COLOR) in vec4 varColor;
layout(location=0) out vec4 outFragColor;
void main(void) {
Grid grid = getGrid();
float alpha = mix(paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge),
paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy),
float(grid.edge.z == 0.0));
if (alpha == 0.0) {
if (alpha < 0.0001) {
discard;
}
outFragColor = vec4(varColor.xyz, varColor.w * alpha);
packDeferredFragmentUnlit(vec3(1.0, 0.0, 0.0), 1.0, varColor.xyz);
}

View file

@ -0,0 +1,41 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// Created by Sam Gondelman on 12/22/18
// Copyright 2018 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 DeferredBufferWrite.slh@>
<@include gpu/ShaderConstants.h@>
<@include gpu/Paint.slh@>
struct Grid {
vec4 period;
vec4 offset;
vec4 edge;
};
LAYOUT(binding=0) uniform gridBuffer {
Grid grid;
};
layout(location=GPU_ATTR_TEXCOORD0) in vec2 varTexCoord0;
layout(location=GPU_ATTR_COLOR) in vec4 varColor;
void main(void) {
float alpha = mix(paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge),
paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy),
float(grid.edge.z == 0.0));
alpha *= varColor.w;
if (alpha < 0.0001) {
discard;
}
packDeferredFragmentTranslucent(vec3(1.0, 0.0, 0.0), alpha, varColor.xyz, DEFAULT_ROUGHNESS);
}

View file

@ -0,0 +1 @@
VERTEX standardTransformPNTC