diff --git a/examples/edit.js b/examples/edit.js
index 7983a49575..6055400289 100644
--- a/examples/edit.js
+++ b/examples/edit.js
@@ -1,4 +1,3 @@
-
// newEditEntities.js
// examples
//
@@ -139,6 +138,7 @@ var toolBar = (function () {
newTextButton,
newWebButton,
newZoneButton,
+ newPolyVoxButton,
browseMarketplaceButton;
function initialize() {
@@ -224,6 +224,15 @@ var toolBar = (function () {
visible: false
});
+ newPolyVoxButton = toolBar.addTool({
+ imageURL: toolIconUrl + "polyvox.svg",
+ subImage: { x: 0, y: 0, width: 256, height: 256 },
+ width: toolWidth,
+ height: toolHeight,
+ alpha: 0.9,
+ visible: false
+ });
+
that.setActive(false);
}
@@ -266,6 +275,7 @@ var toolBar = (function () {
toolBar.showTool(newTextButton, doShow);
toolBar.showTool(newWebButton, doShow);
toolBar.showTool(newZoneButton, doShow);
+ toolBar.showTool(newPolyVoxButton, doShow);
};
var RESIZE_INTERVAL = 50;
@@ -468,6 +478,24 @@ var toolBar = (function () {
return true;
}
+ if (newPolyVoxButton === toolBar.clicked(clickedOverlay)) {
+ var position = getPositionToCreateEntity();
+
+ if (position.x > 0 && position.y > 0 && position.z > 0) {
+ placingEntityID = Entities.addEntity({
+ type: "PolyVox",
+ position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS),
+ DEFAULT_DIMENSIONS),
+ dimensions: { x: 10, y: 10, z: 10 },
+ voxelVolumeSize: {x:16, y:16, z:16},
+ voxelSurfaceStyle: 1
+ });
+ } else {
+ print("Can't create PolyVox: would be out of bounds.");
+ }
+ return true;
+ }
+
return false;
};
@@ -920,7 +948,7 @@ function selectAllEtitiesInCurrentSelectionBox(keepIfTouching) {
var boundingBoxCorner = Vec3.subtract(selectionManager.worldPosition,
Vec3.multiply(selectionManager.worldDimensions, 0.5));
var entities = Entities.findEntitiesInBox(boundingBoxCorner, selectionManager.worldDimensions);
-
+
if (!keepIfTouching) {
var isValid;
if (selectionManager.localPosition === null) {
@@ -992,7 +1020,7 @@ function handeMenuEvent(menuItem) {
}
}
} else if (menuItem == "Import Entities" || menuItem == "Import Entities from URL") {
-
+
var importURL;
if (menuItem == "Import Entities") {
importURL = Window.browse("Select models to import", "", "*.json");
diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html
index 7c214624c2..d9cad0feff 100644
--- a/examples/html/entityProperties.html
+++ b/examples/html/entityProperties.html
@@ -21,11 +21,11 @@
els[i].setAttribute('disabled', 'disabled');
}
}
-
+
function showElements(els, show) {
for (var i = 0; i < els.length; i++) {
els[i].style.display = (show) ? 'block' : 'none';
- }
+ }
}
function createEmitCheckedPropertyUpdateFunction(propertyName) {
@@ -344,7 +344,7 @@
var elZoneAtmosphereCenterY = document.getElementById("property-zone-atmosphere-center-y");
var elZoneAtmosphereCenterZ = document.getElementById("property-zone-atmosphere-center-z");
var elCenterAtmosphereToZone = document.getElementById("center-atmosphere-in-zone");
-
+
var elZoneAtmosphereInnerRadius = document.getElementById("property-zone-atmosphere-inner-radius");
var elZoneAtmosphereOuterRadius = document.getElementById("property-zone-atmosphere-outer-radius");
var elZoneAtmosphereMieScattering = document.getElementById("property-zone-atmosphere-mie-scattering");
@@ -354,6 +354,12 @@
var elZoneAtmosphereScatteringWavelengthsZ = document.getElementById("property-zone-atmosphere-scattering-wavelengths-z");
var elZoneAtmosphereHasStars = document.getElementById("property-zone-atmosphere-has-stars");
+ var elPolyVoxSelections = document.querySelectorAll(".poly-vox-section");
+ var elVoxelVolumeSizeX = document.getElementById("property-voxel-volume-size-x");
+ var elVoxelVolumeSizeY = document.getElementById("property-voxel-volume-size-y");
+ var elVoxelVolumeSizeZ = document.getElementById("property-voxel-volume-size-z");
+ var elVoxelSurfaceStyle = document.getElementById("property-voxel-surface-style");
+
if (window.EventBridge !== undefined) {
EventBridge.scriptEventReceived.connect(function(data) {
@@ -571,7 +577,7 @@
elZoneAtmosphereScatteringWavelengthsY.value = properties.atmosphere.scatteringWavelengths.y;
elZoneAtmosphereScatteringWavelengthsZ.value = properties.atmosphere.scatteringWavelengths.z;
elZoneAtmosphereHasStars.checked = properties.atmosphere.hasStars;
-
+
showElements(document.getElementsByClassName('skybox-section'), elZoneBackgroundMode.value == 'skybox');
showElements(document.getElementsByClassName('atmosphere-section'), elZoneBackgroundMode.value == 'atmosphere');
} else if (properties.type == "ParticleEffect") {
@@ -588,6 +594,11 @@
elParticleEmitStrength.value = properties.emitStrength.toFixed(2);
elParticleLocalGravity.value = properties.localGravity.toFixed(2);
elParticleRadius.value = properties.particleRadius.toFixed(3);
+ } else if (properties.type == "PolyVox") {
+ elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2);
+ elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2);
+ elVoxelVolumeSizeZ.value = properties.voxelVolumeSize.z.toFixed(2);
+ elVoxelSurfaceStyle.value = properties.voxelSurfaceStyle;
}
if (selected) {
@@ -704,7 +715,7 @@
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
elWebSourceURL.addEventListener('change', createEmitTextPropertyUpdateFunction('sourceUrl'));
-
+
elParticleMaxParticles.addEventListener('change', createEmitNumberPropertyUpdateFunction('maxParticles'));
elParticleLifeSpan.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifespan'));
elParticleEmitRate.addEventListener('change', createEmitNumberPropertyUpdateFunction('emitRate'));
@@ -810,7 +821,7 @@
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox');
}
});
-
+
elZoneSkyboxURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('skybox','url'));
var zoneAtmosphereCenterChangeFunction = createEmitGroupVec3PropertyUpdateFunction(
@@ -818,8 +829,8 @@
elZoneAtmosphereCenterX.addEventListener('change', zoneAtmosphereCenterChangeFunction);
elZoneAtmosphereCenterY.addEventListener('change', zoneAtmosphereCenterChangeFunction);
elZoneAtmosphereCenterZ.addEventListener('change', zoneAtmosphereCenterChangeFunction);
-
-
+
+
elZoneAtmosphereInnerRadius.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','innerRadius'));
elZoneAtmosphereOuterRadius.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','outerRadius'));
elZoneAtmosphereMieScattering.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','mieScattering'));
@@ -832,6 +843,13 @@
elZoneAtmosphereScatteringWavelengthsZ.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction);
elZoneAtmosphereHasStars.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('atmosphere','hasStars'));
+ var voxelVolumeSizeChangeFunction = createEmitVec3PropertyUpdateFunction(
+ 'voxelVolumeSize', elVoxelVolumeSizeX, elVoxelVolumeSizeY, elVoxelVolumeSizeZ);
+ elVoxelVolumeSizeX.addEventListener('change', voxelVolumeSizeChangeFunction);
+ elVoxelVolumeSizeY.addEventListener('change', voxelVolumeSizeChangeFunction);
+ elVoxelVolumeSizeZ.addEventListener('change', voxelVolumeSizeChangeFunction);
+ elVoxelSurfaceStyle.addEventListener('change', createEmitTextPropertyUpdateFunction('voxelSurfaceStyle'));
+
elMoveSelectionToGrid.addEventListener("click", function() {
EventBridge.emitWebEvent(JSON.stringify({
@@ -973,6 +991,24 @@
+
+
Voxel Volume Size
+
+
+
Surface Extractor
+
+
+
+
+
-
+
+
+
-
+
Model URL
@@ -1167,7 +1203,7 @@
-
+
@@ -1346,7 +1382,7 @@
-
+
Stage Day
diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js
index f9f8d57a51..1b1a6a9c12 100644
--- a/examples/libraries/entityPropertyDialogBox.js
+++ b/examples/libraries/entityPropertyDialogBox.js
@@ -98,6 +98,21 @@ EntityPropertyDialogBox = (function () {
index++;
}
+ if (properties.type == "PolyVox") {
+ array.push({ label: "Voxel Space Size:", type: "header" });
+ index++;
+
+ array.push({ label: "X:", value: properties.voxelVolumeSize.x.toFixed(decimals) });
+ index++;
+ array.push({ label: "Y:", value: properties.voxelVolumeSize.y.toFixed(decimals) });
+ index++;
+ array.push({ label: "Z:", value: properties.voxelVolumeSize.z.toFixed(decimals) });
+ index++;
+
+ array.push({ label: "Surface Extractor", value: properties.voxelSurfaceStyle });
+ index++;
+ }
+
array.push({ label: "Position:", type: "header" });
index++;
array.push({ label: "X:", value: properties.position.x.toFixed(decimals) });
@@ -333,6 +348,16 @@ EntityPropertyDialogBox = (function () {
properties.backgroundColor.blue = array[index++].value;
}
+ if (properties.type == "PolyVox") {
+ properties.shapeType = array[index++].value;
+
+ index++; // skip header
+ properties.voxelVolumeSize.x = array[index++].value;
+ properties.voxelVolumeSize.y = array[index++].value;
+ properties.voxelVolumeSize.z = array[index++].value;
+ properties.voxelSurfaceStyle = array[index++].value;
+ }
+
index++; // skip header
properties.position.x = array[index++].value;
properties.position.y = array[index++].value;
diff --git a/examples/voxels.js b/examples/voxels.js
index e274f1c4cc..799af04bef 100644
--- a/examples/voxels.js
+++ b/examples/voxels.js
@@ -1,5 +1,5 @@
-
var controlHeld = false;
+var shiftHeld = false;
function mousePressEvent(event) {
@@ -15,9 +15,11 @@ function mousePressEvent(event) {
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
if (controlHeld) {
- Entities.setVoxelSphere(id, intersection.intersection, 1.2, 0);
+ Entities.setVoxelSphere(id, intersection.intersection, 1.0, 0);
+ } else if (shiftHeld) {
+ Entities.setAllVoxels(id, 255);
} else {
- Entities.setVoxelSphere(id, intersection.intersection, 1.2, 255);
+ Entities.setVoxelSphere(id, intersection.intersection, 1.0, 255);
}
}
}
@@ -28,6 +30,9 @@ function keyPressEvent(event) {
if (event.text == "CONTROL") {
controlHeld = true;
}
+ if (event.text == "SHIFT") {
+ shiftHeld = true;
+ }
}
@@ -35,6 +40,9 @@ function keyReleaseEvent(event) {
if (event.text == "CONTROL") {
controlHeld = false;
}
+ if (event.text == "SHIFT") {
+ shiftHeld = false;
+ }
}
diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp
index d3f7a573b8..e51522bb7f 100644
--- a/interface/src/ui/ApplicationOverlay.cpp
+++ b/interface/src/ui/ApplicationOverlay.cpp
@@ -507,7 +507,6 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
QPoint rv;
auto canvasSize = qApp->getCanvasSize();
if (qApp->isHMDMode()) {
- float t;
glm::vec2 polar = getPolarCoordinates(*palm);
glm::vec2 point = sphericalToScreen(-polar);
rv.rx() = point.x;
diff --git a/interface/src/ui/AvatarAppearanceDialog.cpp b/interface/src/ui/AvatarAppearanceDialog.cpp
index ceaaf140c4..3ab99c141d 100644
--- a/interface/src/ui/AvatarAppearanceDialog.cpp
+++ b/interface/src/ui/AvatarAppearanceDialog.cpp
@@ -82,7 +82,10 @@ void AvatarAppearanceDialog::setUseFullAvatar(bool useFullAvatar) {
ui.useFullAvatar->setChecked(_useFullAvatar);
ui.useSeparateBodyAndHead->setChecked(!_useFullAvatar);
- DependencyManager::get
()->getPreferencesDialog()->avatarDescriptionChanged();
+ QPointer prefs = DependencyManager::get()->getPreferencesDialog();
+ if (prefs) { // Preferences dialog may have been closed
+ prefs->avatarDescriptionChanged();
+ }
}
void AvatarAppearanceDialog::headURLChanged(const QString& newValue, const QString& modelName) {
@@ -106,7 +109,10 @@ void AvatarAppearanceDialog::fullAvatarURLChanged(const QString& newValue, const
void AvatarAppearanceDialog::accept() {
saveAvatarAppearance();
- DependencyManager::get()->getPreferencesDialog()->avatarDescriptionChanged();
+ QPointer prefs = DependencyManager::get()->getPreferencesDialog();
+ if (prefs) { // Preferences dialog may have been closed
+ prefs->avatarDescriptionChanged();
+ }
close();
delete _marketplaceWindow;
diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp
index 8981d149ae..45abe36fdb 100644
--- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp
@@ -13,6 +13,7 @@
#include
#include
+#include
#include
#include
@@ -29,10 +30,26 @@ void RenderableLineEntityItem::render(RenderArgs* args) {
glm::vec3 p1 = ENTITY_ITEM_ZERO_VEC3;
glm::vec3 p2 = getDimensions();
glm::vec4 lineColor(toGlm(getXColor()), getLocalRenderAlpha());
+
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
batch.setModelTransform(getTransformToCenter());
- DependencyManager::get()->renderLine(batch, p1, p2, lineColor, lineColor);
+
+ glLineWidth(getLineWidth());
+ auto geometryCache = DependencyManager::get();
+ if (_lineVerticesID == GeometryCache::UNKNOWN_ID) {
+ _lineVerticesID = geometryCache ->allocateID();
+ }
+
+ //TODO: Figure out clean , efficient way to do relative line positioning. For now we'll just use absolute positioning.
+ //glTranslatef(position.x, position.y, position.z);
+ //glm::vec3 axis = glm::axis(rotation);
+ //glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
+ if (_pointsChanged) {
+ geometryCache->updateVertices(_lineVerticesID, getLinePoints(), lineColor);
+ _pointsChanged = false;
+ }
+ geometryCache->renderVertices(gpu::LINE_STRIP, _lineVerticesID);
RenderableDebugableEntityItem::render(this, args);
};
diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.h b/libraries/entities-renderer/src/RenderableLineEntityItem.h
index eb23b3ee48..8a25196ec5 100644
--- a/libraries/entities-renderer/src/RenderableLineEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableLineEntityItem.h
@@ -15,17 +15,23 @@
#include
#include "RenderableDebugableEntityItem.h"
#include "RenderableEntityItem.h"
+#include
class RenderableLineEntityItem : public LineEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
- LineEntityItem(entityItemID, properties) { }
+ LineEntityItem(entityItemID, properties),
+ _lineVerticesID(GeometryCache::UNKNOWN_ID)
+ { }
virtual void render(RenderArgs* args);
SIMPLE_RENDERABLE()
+
+protected:
+ int _lineVerticesID;
};
diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
index 014a9dd995..4d85e73bcc 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
@@ -33,22 +33,63 @@
#include "EntityTreeRenderer.h"
#include "RenderablePolyVoxEntityItem.h"
-
EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderablePolyVoxEntityItem(entityID, properties));
}
+RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID,
+ const EntityItemProperties& properties) :
+ PolyVoxEntityItem(entityItemID, properties) {
+
+ model::Mesh* mesh = new model::Mesh();
+ model::MeshPointer meshPtr(mesh);
+ _modelGeometry.setMesh(meshPtr);
+
+ setVoxelVolumeSize(_voxelVolumeSize);
+}
+
RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() {
delete _volData;
}
-void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
+bool inUserBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
+ int x, int y, int z) {
+ // x, y, z are in user voxel-coords, not adjusted-for-edge voxel-coords.
+ switch (surfaceStyle) {
+ case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
+ case PolyVoxEntityItem::SURFACE_CUBIC:
+ if (x < 0 || y < 0 || z < 0 ||
+ x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()) {
+ return false;
+ }
+ return true;
+ case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
+ if (x < 0 || y < 0 || z < 0 ||
+ x >= vol->getWidth() - 2 || y >= vol->getHeight() - 2 || z >= vol->getDepth() - 2) {
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+
+bool inBounds(const PolyVox::SimpleVolume* vol, int x, int y, int z) {
+ // x, y, z are in polyvox volume coords
+ return !(x < 0 || y < 0 || z < 0 || x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth());
+}
+
+
+void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
if (_volData && voxelVolumeSize == _voxelVolumeSize) {
return;
}
- qDebug() << "resetting voxel-space size";
+ #ifdef WANT_DEBUG
+ qDebug() << "resetting voxel-space size" << voxelVolumeSize.x << voxelVolumeSize.y << voxelVolumeSize.z;
+ #endif
PolyVoxEntityItem::setVoxelVolumeSize(voxelVolumeSize);
@@ -56,14 +97,69 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize)
delete _volData;
}
- PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
- PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize[0] - 1, // -1 because these corners are inclusive
- _voxelVolumeSize[1] - 1,
- _voxelVolumeSize[2] - 1);
+ _onCount = 0;
- _volData = new PolyVox::SimpleVolume(PolyVox::Region(lowCorner, highCorner));
+ if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
+ // with _EDGED_ we maintain an extra box of voxels around those that the user asked for. This
+ // changes how the surface extractor acts -- mainly it becomes impossible to have holes in the
+ // generated mesh. The non _EDGED_ modes will leave holes in the mesh at the edges of the
+ // voxel space.
+ PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
+ PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x + 1, // -1 + 2 because these corners are inclusive
+ _voxelVolumeSize.y + 1,
+ _voxelVolumeSize.z + 1);
+ _volData = new PolyVox::SimpleVolume(PolyVox::Region(lowCorner, highCorner));
+ } else {
+ PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
+ PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x - 1, // -1 because these corners are inclusive
+ _voxelVolumeSize.y - 1,
+ _voxelVolumeSize.z - 1);
+ _volData = new PolyVox::SimpleVolume(PolyVox::Region(lowCorner, highCorner));
+ }
+
+ // having the "outside of voxel-space" value be 255 has helped me notice some problems.
+ _volData->setBorderValue(255);
+
+ #ifdef WANT_DEBUG
+ qDebug() << " new size is" << _volData->getWidth() << _volData->getHeight() << _volData->getDepth();
+ #endif
+
+ // I'm not sure this is needed... the docs say that each element is initialized with its default
+ // constructor. I'll leave it here for now.
+ for (int z = 0; z < _volData->getDepth(); z++) {
+ for (int y = 0; y < _volData->getHeight(); y++) {
+ for (int x = 0; x < _volData->getWidth(); x++) {
+ _volData->setVoxelAt(x, y, z, 0);
+ }
+ }
+ }
+
+ // It's okay to decompress the old data here, because the data includes its original dimensions along
+ // with the voxel data, and writing voxels outside the bounds of the new space is harmless. This allows
+ // adjusting of the voxel-space size without overly mangling the shape. Shrinking the space and then
+ // restoring the previous size (without any edits in between) will put the original shape back.
+ decompressVolumeData();
}
+void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {
+ if (voxelSurfaceStyle == _voxelSurfaceStyle) {
+ return;
+ }
+
+ // if we are switching to or from "edged" we need to force a resize of _volData.
+ if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC ||
+ _voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
+ if (_volData) {
+ delete _volData;
+ }
+ _volData = nullptr;
+ PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle);
+ setVoxelVolumeSize(_voxelVolumeSize);
+ } else {
+ PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle);
+ }
+ _needsModelReload = true;
+}
void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
if (voxelData == _voxelData) {
@@ -73,57 +169,138 @@ void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
decompressVolumeData();
}
+glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
+ glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
+ switch (_voxelSurfaceStyle) {
+ case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
+ return scale / 2.0f;
+ case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
+ return scale / -2.0f;
+ case PolyVoxEntityItem::SURFACE_CUBIC:
+ return scale / 2.0f;
+ }
+ return glm::vec3(0.0f, 0.0f, 0.0f);
+}
+
+glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
+ glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
+ glm::vec3 center = getCenterPosition();
+ glm::vec3 position = getPosition();
+ glm::vec3 positionToCenter = center - position;
+ positionToCenter -= getDimensions() * glm::vec3(0.5f, 0.5f, 0.5f) - getSurfacePositionAdjustment();
+ glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
+ glm::mat4 scaled = glm::scale(centerToCorner, scale);
+ return scaled;
+}
glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const {
- glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
- glm::mat4 scaled = glm::scale(glm::mat4(), scale);
- glm::mat4 centerToCorner = glm::translate(scaled, _voxelVolumeSize / -2.0f);
glm::mat4 rotation = glm::mat4_cast(getRotation());
- glm::mat4 translation = glm::translate(getCenterPosition());
- return translation * rotation * centerToCorner;
+ glm::mat4 translation = glm::translate(getPosition());
+ return translation * rotation * voxelToLocalMatrix();
}
glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const {
glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix());
return worldToModelMatrix;
+}
+uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) {
+ assert(_volData);
+ if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) {
+ return 0;
+ }
+
+ // if _voxelSurfaceStyle is SURFACE_EDGED_CUBIC, we maintain an extra layer of
+ // voxels all around the requested voxel space. Having the empty voxels around
+ // the edges changes how the surface extractor behaves.
+
+ if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
+ return _volData->getVoxelAt(x + 1, y + 1, z + 1);
+ }
+ return _volData->getVoxelAt(x, y, z);
+}
+
+void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) {
+ assert(_volData);
+ if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) {
+ return;
+ }
+
+ if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
+ _volData->setVoxelAt(x + 1, y + 1, z + 1, toValue);
+ } else {
+ _volData->setVoxelAt(x, y, z, toValue);
+ }
+}
+
+
+void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toValue) {
+ // keep _onCount up to date
+ if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) {
+ return;
+ }
+
+ uint8_t uVoxelValue = getVoxel(x, y, z);
+ if (toValue != 0) {
+ if (uVoxelValue == 0) {
+ _onCount++;
+ }
+ } else {
+ // toValue == 0
+ if (uVoxelValue != 0) {
+ _onCount--;
+ assert(_onCount >= 0);
+ }
+ }
+}
+
+void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) {
+ for (int z = 0; z < _voxelVolumeSize.z; z++) {
+ for (int y = 0; y < _voxelVolumeSize.y; y++) {
+ for (int x = 0; x < _voxelVolumeSize.x; x++) {
+ updateOnCount(x, y, z, toValue);
+ setVoxel(x, y, z, toValue);
+ }
+ }
+ }
+ compressVolumeData();
+}
+
+void RenderablePolyVoxEntityItem::setVoxelInVolume(glm::vec3 position, uint8_t toValue) {
+ updateOnCount(position.x, position.y, position.z, toValue);
+ setVoxel(position.x, position.y, position.z, toValue);
}
void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) {
// This three-level for loop iterates over every voxel in the volume
- for (int z = 0; z < _volData->getDepth(); z++) {
- for (int y = 0; y < _volData->getHeight(); y++) {
- for (int x = 0; x < _volData->getWidth(); x++) {
+ for (int z = 0; z < _voxelVolumeSize.z; z++) {
+ for (int y = 0; y < _voxelVolumeSize.y; y++) {
+ for (int x = 0; x < _voxelVolumeSize.x; x++) {
// Store our current position as a vector...
- glm::vec3 pos(x, y, z);
+ glm::vec3 pos(x + 0.5f, y + 0.5f, z + 0.5f); // consider voxels cenetered on their coordinates
// And compute how far the current position is from the center of the volume
float fDistToCenter = glm::distance(pos, center);
// If the current voxel is less than 'radius' units from the center then we make it solid.
if (fDistToCenter <= radius) {
- _volData->setVoxelAt(x, y, z, toValue);
+ updateOnCount(x, y, z, toValue);
+ setVoxel(x, y, z, toValue);
}
}
}
}
compressVolumeData();
- _needsModelReload = true;
}
void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) {
// glm::vec3 centerVoxelCoords = worldToVoxelCoordinates(centerWorldCoords);
glm::vec4 centerVoxelCoords = worldToVoxelMatrix() * glm::vec4(centerWorldCoords, 1.0f);
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
- float scaleY = scale[0];
+ float scaleY = scale.y;
float radiusVoxelCoords = radiusWorldCoords / scaleY;
setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue);
}
void RenderablePolyVoxEntityItem::getModel() {
- if (!_volData) {
- // this will cause the allocation of _volData
- setVoxelVolumeSize(_voxelVolumeSize);
- }
-
// A mesh object to hold the result of surface extraction
PolyVox::SurfaceMesh polyVoxMesh;
@@ -134,6 +311,7 @@ void RenderablePolyVoxEntityItem::getModel() {
surfaceExtractor.execute();
break;
}
+ case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
case PolyVoxEntityItem::SURFACE_CUBIC: {
PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
@@ -143,24 +321,25 @@ void RenderablePolyVoxEntityItem::getModel() {
}
// convert PolyVox mesh to a Sam mesh
- model::Mesh* mesh = new model::Mesh();
- model::MeshPointer meshPtr(mesh);
+ auto mesh = _modelGeometry.getMesh();
const std::vector& vecIndices = polyVoxMesh.getIndices();
auto indexBuffer = new gpu::Buffer(vecIndices.size() * sizeof(uint32_t), (gpu::Byte*)vecIndices.data());
auto indexBufferPtr = gpu::BufferPointer(indexBuffer);
- mesh->setIndexBuffer(gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW)));
+ auto indexBufferView = new gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW));
+ mesh->setIndexBuffer(*indexBufferView);
const std::vector& vecVertices = polyVoxMesh.getVertices();
auto vertexBuffer = new gpu::Buffer(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal),
(gpu::Byte*)vecVertices.data());
auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer);
- mesh->setVertexBuffer(gpu::BufferView(vertexBufferPtr,
- 0,
- vertexBufferPtr->getSize() - sizeof(float) * 3,
- sizeof(PolyVox::PositionMaterialNormal),
- gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
+ auto vertexBufferView = new gpu::BufferView(vertexBufferPtr,
+ 0,
+ vertexBufferPtr->getSize() - sizeof(float) * 3,
+ sizeof(PolyVox::PositionMaterialNormal),
+ gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW));
+ mesh->setVertexBuffer(*vertexBufferView);
mesh->addAttribute(gpu::Stream::NORMAL,
gpu::BufferView(vertexBufferPtr,
sizeof(float) * 3,
@@ -168,15 +347,28 @@ void RenderablePolyVoxEntityItem::getModel() {
sizeof(PolyVox::PositionMaterialNormal),
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
+
+
// auto normalAttrib = mesh->getAttributeBuffer(gpu::Stream::NORMAL);
// for (auto normal = normalAttrib.begin(); normal != normalAttrib.end(); normal++) {
// (*normal) = -(*normal);
// }
+
+ // mesh->addAttribute(gpu::Stream::TEXCOORD,
+ // gpu::BufferView(vertexBufferPtr,
+ // sizeof(float) * 2,
+ // vertexBufferPtr->getSize() - sizeof(float) * 2,
+ // sizeof(PolyVox::PositionMaterialNormal),
+ // gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::RAW)));
+
+
+
+ #ifdef WANT_DEBUG
qDebug() << "---- vecIndices.size() =" << vecIndices.size();
qDebug() << "---- vecVertices.size() =" << vecVertices.size();
+ #endif
- _modelGeometry.setMesh(meshPtr);
_needsModelReload = false;
}
@@ -211,9 +403,20 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
class RaycastFunctor
{
public:
- RaycastFunctor() : _result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)) { }
+ RaycastFunctor(PolyVox::SimpleVolume* vol) :
+ _result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)),
+ _vol(vol) {
+ }
bool operator()(PolyVox::SimpleVolume::Sampler& sampler)
{
+ int x = sampler.getPosition().getX();
+ int y = sampler.getPosition().getY();
+ int z = sampler.getPosition().getZ();
+
+ if (!inBounds(_vol, x, y, z)) {
+ return true;
+ }
+
if (sampler.getVoxel() == 0) {
return true; // keep raycasting
}
@@ -222,6 +425,7 @@ public:
return false;
}
glm::vec4 _result;
+ const PolyVox::SimpleVolume* _vol = nullptr;
};
bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin,
@@ -237,33 +441,44 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
return true;
}
+ // the PolyVox ray intersection code requires a near and far point.
glm::mat4 wtvMatrix = worldToVoxelMatrix();
- glm::vec3 farPoint = origin + direction;
- glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
- glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 1.0f);
- glm::vec4 directionInVoxel = farInVoxel - originInVoxel;
-
- PolyVox::Vector3DFloat start(originInVoxel[0], originInVoxel[1], originInVoxel[2]);
- PolyVox::Vector3DFloat pvDirection(directionInVoxel[0], directionInVoxel[1], directionInVoxel[2]);
- pvDirection.normalise();
+ glm::vec3 normDirection = glm::normalize(direction);
// the PolyVox ray intersection code requires a near and far point.
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
+ // set ray cast length to long enough to cover all of the voxel space
float distanceToEntity = glm::distance(origin, getPosition());
- float largestDimension = glm::max(getDimensions()[0], getDimensions()[1], getDimensions()[2]);
- // set ray cast length to long enough to cover all of the voxel space
- pvDirection *= (distanceToEntity + largestDimension) / glm::min(scale[0], scale[1], scale[2]);
+ float largestDimension = glm::max(getDimensions().x, getDimensions().y, getDimensions().z) * 2.0f;
+ glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension);
+ glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
+ glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 1.0f);
+
+ PolyVox::Vector3DFloat startPoint(originInVoxel.x, originInVoxel.y, originInVoxel.z);
+ PolyVox::Vector3DFloat endPoint(farInVoxel.x, farInVoxel.y, farInVoxel.z);
PolyVox::RaycastResult raycastResult;
- RaycastFunctor callback;
- raycastResult = PolyVox::raycastWithDirection(_volData, start, pvDirection, callback);
+ RaycastFunctor callback(_volData);
+ raycastResult = PolyVox::raycastWithEndpoints(_volData, startPoint, endPoint, callback);
if (raycastResult == PolyVox::RaycastResults::Completed) {
// the ray completed its path -- nothing was hit.
return false;
}
- glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * callback._result;
+ glm::vec4 result = callback._result;
+ switch (_voxelSurfaceStyle) {
+ case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
+ result -= glm::vec4(1, 1, 1, 0); // compensate for the extra voxel border
+ break;
+ case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
+ case PolyVoxEntityItem::SURFACE_CUBIC:
+ break;
+ }
+
+ result -= glm::vec4(0.5f, 0.5f, 0.5f, 0.0f);
+
+ glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * result;
distance = glm::distance(glm::vec3(intersectedWorldPosition), origin);
@@ -276,51 +491,195 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
// compress the data in _volData and save the results. The compressed form is used during
// saves to disk and for transmission over the wire
void RenderablePolyVoxEntityItem::compressVolumeData() {
- int rawSize = _volData->getDepth() * _volData->getHeight() * _volData->getWidth();
+ quint16 voxelXSize = _voxelVolumeSize.x;
+ quint16 voxelYSize = _voxelVolumeSize.y;
+ quint16 voxelZSize = _voxelVolumeSize.z;
+ int rawSize = voxelXSize * voxelYSize * voxelZSize;
+
QByteArray uncompressedData = QByteArray(rawSize, '\0');
- for (int z = 0; z < _volData->getDepth(); z++) {
- for (int y = 0; y < _volData->getHeight(); y++) {
- for (int x = 0; x < _volData->getWidth(); x++) {
- uint8_t uVoxelValue = _volData->getVoxelAt(x, y, z);
- int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x;
+ for (int z = 0; z < voxelZSize; z++) {
+ for (int y = 0; y < voxelYSize; y++) {
+ for (int x = 0; x < voxelXSize; x++) {
+ uint8_t uVoxelValue = getVoxel(x, y, z);
+ int uncompressedIndex =
+ z * voxelYSize * voxelXSize +
+ y * voxelXSize +
+ x;
uncompressedData[uncompressedIndex] = uVoxelValue;
}
}
}
- QByteArray newVoxelData = qCompress(uncompressedData, 9);
- // HACK -- until we have a way to allow for properties larger than MTU, don't update.
- if (newVoxelData.length() < 1200) {
+ QByteArray newVoxelData;
+ QDataStream writer(&newVoxelData, QIODevice::WriteOnly | QIODevice::Truncate);
+ writer << voxelXSize << voxelYSize << voxelZSize;
+
+ QByteArray compressedData = qCompress(uncompressedData, 9);
+ writer << compressedData;
+
+ // make sure the compressed data can be sent over the wire-protocol
+ if (newVoxelData.size() < 1150) {
_voxelData = newVoxelData;
+ #ifdef WANT_DEBUG
qDebug() << "-------------- voxel compresss --------------";
qDebug() << "raw-size =" << rawSize << " compressed-size =" << newVoxelData.size();
+ #endif
} else {
+ // HACK -- until we have a way to allow for properties larger than MTU, don't update.
+ #ifdef WANT_DEBUG
qDebug() << "voxel data too large, reverting change.";
- // revert
+ #endif
+ // revert the active voxel-space to the last version that fit.
decompressVolumeData();
}
+
+ _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
+ _needsModelReload = true;
}
-// take compressed data and decompreess it into _volData.
+// take compressed data and expand it into _volData.
void RenderablePolyVoxEntityItem::decompressVolumeData() {
- int rawSize = _volData->getDepth() * _volData->getHeight() * _volData->getWidth();
- QByteArray uncompressedData = QByteArray(rawSize, '\0');
+ QDataStream reader(_voxelData);
+ quint16 voxelXSize, voxelYSize, voxelZSize;
+ reader >> voxelXSize;
+ reader >> voxelYSize;
+ reader >> voxelZSize;
- uncompressedData = qUncompress(_voxelData);
+ if (voxelXSize == 0 || voxelXSize > MAX_VOXEL_DIMENSION ||
+ voxelYSize == 0 || voxelYSize > MAX_VOXEL_DIMENSION ||
+ voxelZSize == 0 || voxelZSize > MAX_VOXEL_DIMENSION) {
+ qDebug() << "voxelSize is not reasonable, skipping decompressions."
+ << voxelXSize << voxelYSize << voxelZSize;
+ return;
+ }
+
+ int rawSize = voxelXSize * voxelYSize * voxelZSize;
+
+ QByteArray compressedData;
+ reader >> compressedData;
+ QByteArray uncompressedData = qUncompress(compressedData);
- for (int z = 0; z < _volData->getDepth(); z++) {
- for (int y = 0; y < _volData->getHeight(); y++) {
- for (int x = 0; x < _volData->getWidth(); x++) {
- int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x;
- _volData->setVoxelAt(x, y, z, uncompressedData[uncompressedIndex]);
+ if (uncompressedData.size() != rawSize) {
+ qDebug() << "PolyVox decompress -- size is (" << voxelXSize << voxelYSize << voxelZSize << ")" <<
+ "so expected uncompressed length of" << rawSize << "but length is" << uncompressedData.size();
+ return;
+ }
+
+ for (int z = 0; z < voxelZSize; z++) {
+ for (int y = 0; y < voxelYSize; y++) {
+ for (int x = 0; x < voxelXSize; x++) {
+ int uncompressedIndex = (z * voxelYSize * voxelXSize) + (y * voxelZSize) + x;
+ updateOnCount(x, y, z, uncompressedData[uncompressedIndex]);
+ setVoxel(x, y, z, uncompressedData[uncompressedIndex]);
}
}
}
- _needsModelReload = true;
-
+ #ifdef WANT_DEBUG
qDebug() << "--------------- voxel decompress ---------------";
qDebug() << "raw-size =" << rawSize << " compressed-size =" << _voxelData.size();
+ #endif
+
+ _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
+ _needsModelReload = true;
+ getModel();
+}
+
+// virtual
+ShapeType RenderablePolyVoxEntityItem::getShapeType() const {
+ if (_onCount > 0) {
+ return SHAPE_TYPE_COMPOUND;
+ }
+ return SHAPE_TYPE_NONE;
+}
+
+
+bool RenderablePolyVoxEntityItem::isReadyToComputeShape() {
+ if (_needsModelReload) {
+ return false;
+ }
+
+ #ifdef WANT_DEBUG
+ qDebug() << "RenderablePolyVoxEntityItem::isReadyToComputeShape" << (!_needsModelReload);
+ #endif
+ return true;
+}
+
+void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
+ #ifdef WANT_DEBUG
+ qDebug() << "RenderablePolyVoxEntityItem::computeShapeInfo";
+ #endif
+ ShapeType type = getShapeType();
+ if (type != SHAPE_TYPE_COMPOUND) {
+ EntityItem::computeShapeInfo(info);
+ return;
+ }
+
+ _points.clear();
+ unsigned int i = 0;
+
+ glm::mat4 wToM = voxelToLocalMatrix();
+
+ AABox box;
+
+ for (int z = 0; z < _voxelVolumeSize.z; z++) {
+ for (int y = 0; y < _voxelVolumeSize.y; y++) {
+ for (int x = 0; x < _voxelVolumeSize.x; x++) {
+ if (getVoxel(x, y, z) > 0) {
+ QVector pointsInPart;
+
+ float offL = -0.5f;
+ float offH = 0.5f;
+
+ // float offL = 0.0f;
+ // float offH = 1.0f;
+
+ glm::vec3 p000 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offL, 1.0f));
+ glm::vec3 p001 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offH, 1.0f));
+ glm::vec3 p010 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offL, 1.0f));
+ glm::vec3 p011 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offH, 1.0f));
+ glm::vec3 p100 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offL, 1.0f));
+ glm::vec3 p101 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offH, 1.0f));
+ glm::vec3 p110 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offL, 1.0f));
+ glm::vec3 p111 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offH, 1.0f));
+
+ box += p000;
+ box += p001;
+ box += p010;
+ box += p011;
+ box += p100;
+ box += p101;
+ box += p110;
+ box += p111;
+
+ pointsInPart << p000;
+ pointsInPart << p001;
+ pointsInPart << p010;
+ pointsInPart << p011;
+ pointsInPart << p100;
+ pointsInPart << p101;
+ pointsInPart << p110;
+ pointsInPart << p111;
+
+ // add next convex hull
+ QVector newMeshPoints;
+ _points << newMeshPoints;
+ // add points to the new convex hull
+ _points[i++] << pointsInPart;
+ }
+ }
+ }
+ }
+
+ if (_points.isEmpty()) {
+ EntityItem::computeShapeInfo(info);
+ return;
+ }
+
+ glm::vec3 collisionModelDimensions = box.getDimensions();
+ QByteArray b64 = _voxelData.toBase64();
+ info.setParams(type, collisionModelDimensions, QString(b64));
+ info.setConvexHulls(_points);
}
diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
index b04b32996b..c8f1b4a49d 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
@@ -21,8 +21,7 @@ class RenderablePolyVoxEntityItem : public PolyVoxEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
- RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
- PolyVoxEntityItem(entityItemID, properties) { }
+ RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual ~RenderablePolyVoxEntityItem();
@@ -34,6 +33,10 @@ public:
// _needsModelReload = true;
}
+ virtual uint8_t getVoxel(int x, int y, int z);
+ virtual void setVoxel(int x, int y, int z, uint8_t toValue);
+
+ void updateOnCount(int x, int y, int z, uint8_t new_value);
void render(RenderArgs* args);
virtual bool supportsDetailedRayIntersection() const { return true; }
@@ -41,27 +44,47 @@ public:
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject, bool precisionPicking) const;
+ virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle);
+
void getModel();
virtual void setVoxelData(QByteArray voxelData);
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
+ glm::vec3 getSurfacePositionAdjustment() const;
glm::mat4 voxelToWorldMatrix() const;
+ glm::mat4 voxelToLocalMatrix() const;
glm::mat4 worldToVoxelMatrix() const;
+ virtual ShapeType getShapeType() const;
+ virtual bool isReadyToComputeShape();
+ virtual void computeShapeInfo(ShapeInfo& info);
+
+
// coords are in voxel-volume space
virtual void setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue);
// coords are in world-space
virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue);
+ virtual void setAll(uint8_t toValue);
+
+ virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue);
+
private:
+ // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
+ // may not match _voxelVolumeSize.
+
void compressVolumeData();
void decompressVolumeData();
PolyVox::SimpleVolume* _volData = nullptr;
model::Geometry _modelGeometry;
bool _needsModelReload = true;
+
+ QVector> _points; // XXX
+
+ int _onCount = 0; // how many non-zero voxels are in _volData
};
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 6977f6ff04..1617131b8e 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -904,6 +904,7 @@ EntityItemProperties EntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(damping, getDamping);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(restitution, getRestitution);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(friction, getFriction);
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(created, getCreated);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifetime, getLifetime);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(script, getScript);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionSoundURL, getCollisionSoundURL);
@@ -954,6 +955,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, updateDamping);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, updateRestitution);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL);
@@ -1002,11 +1004,13 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
}
void EntityItem::recordCreationTime() {
- //assert(_created == UNKNOWN_CREATED_TIME);
- _created = usecTimestampNow();
+ if (_created == UNKNOWN_CREATED_TIME) {
+ _created = usecTimestampNow();
+ }
+ auto now = usecTimestampNow();
_lastEdited = _created;
- _lastUpdated = _created;
- _lastSimulated = _created;
+ _lastUpdated = now;
+ _lastSimulated = now;
}
void EntityItem::setCenterPosition(const glm::vec3& position) {
@@ -1341,6 +1345,13 @@ void EntityItem::updateLifetime(float value) {
}
}
+void EntityItem::updateCreated(uint64_t value) {
+ if (_created != value) {
+ _created = value;
+ _dirtyFlags |= EntityItem::DIRTY_LIFETIME;
+ }
+}
+
void EntityItem::setSimulatorID(const QUuid& value) {
_simulatorID = value;
_simulatorIDChangedTime = usecTimestampNow();
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index de34e89ea4..878d0bed7c 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -247,6 +247,9 @@ public:
float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity
void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity
+ quint64 getCreated() const { return _created; } /// get the created-time in useconds for the entity
+ void setCreated(quint64 value) { _created = value; } /// set the created-time in useconds for the entity
+
/// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted
bool isImmortal() const { return _lifetime == ENTITY_ITEM_IMMORTAL_LIFETIME; }
@@ -344,6 +347,7 @@ public:
void updateIgnoreForCollisions(bool value);
void updateCollisionsWillMove(bool value);
void updateLifetime(float value);
+ void updateCreated(uint64_t value);
virtual void updateShapeType(ShapeType type) { /* do nothing */ }
uint32_t getDirtyFlags() const { return _dirtyFlags; }
diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index 583cf15b9c..90f2b22698 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -27,6 +27,7 @@
#include "TextEntityItem.h"
#include "ZoneEntityItem.h"
#include "PolyVoxEntityItem.h"
+#include "LineEntityItem.h"
AtmospherePropertyGroup EntityItemProperties::_staticAtmosphere;
SkyboxPropertyGroup EntityItemProperties::_staticSkybox;
@@ -48,6 +49,7 @@ CONSTRUCT_PROPERTY(damping, ENTITY_ITEM_DEFAULT_DAMPING),
CONSTRUCT_PROPERTY(restitution, ENTITY_ITEM_DEFAULT_RESTITUTION),
CONSTRUCT_PROPERTY(friction, ENTITY_ITEM_DEFAULT_FRICTION),
CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME),
+CONSTRUCT_PROPERTY(created, UNKNOWN_CREATED_TIME),
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
CONSTRUCT_PROPERTY(color, ),
@@ -94,12 +96,13 @@ CONSTRUCT_PROPERTY(voxelSurfaceStyle, PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_S
CONSTRUCT_PROPERTY(name, ENTITY_ITEM_DEFAULT_NAME),
CONSTRUCT_PROPERTY(backgroundMode, BACKGROUND_MODE_INHERIT),
CONSTRUCT_PROPERTY(sourceUrl, ""),
+CONSTRUCT_PROPERTY(lineWidth, LineEntityItem::DEFAULT_LINE_WIDTH),
+CONSTRUCT_PROPERTY(linePoints, QVector()),
_id(UNKNOWN_ENTITY_ID),
_idSet(false),
_lastEdited(0),
-_created(UNKNOWN_CREATED_TIME),
_type(EntityTypes::Unknown),
_glowLevel(0.0f),
@@ -176,6 +179,11 @@ QString EntityItemProperties::getAnimationSettings() const {
return jsonByteString;
}
+void EntityItemProperties::setCreated(QDateTime &v) {
+ _created = v.toMSecsSinceEpoch() * 1000; // usec per msec
+ qDebug() << "EntityItemProperties::setCreated QDateTime" << v << _created;
+}
+
void EntityItemProperties::debugDump() const {
qCDebug(entities) << "EntityItemProperties...";
qCDebug(entities) << " _type=" << EntityTypes::getEntityTypeName(_type);
@@ -194,13 +202,6 @@ void EntityItemProperties::debugDump() const {
props.debugDumpBits();
}
-void EntityItemProperties::setCreated(quint64 usecTime) {
- _created = usecTime;
- if (_lastEdited < _created) {
- _lastEdited = _created;
- }
-}
-
void EntityItemProperties::setLastEdited(quint64 usecTime) {
_lastEdited = usecTime > _created ? usecTime : _created;
}
@@ -344,7 +345,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
CHECK_PROPERTY_CHANGE(PROP_VOXEL_DATA, voxelData);
CHECK_PROPERTY_CHANGE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle);
-
+ CHECK_PROPERTY_CHANGE(PROP_LINE_WIDTH, lineWidth);
+ CHECK_PROPERTY_CHANGE(PROP_LINE_POINTS, linePoints);
changedProperties += _stage.getChangedProperties();
changedProperties += _atmosphere.getChangedProperties();
changedProperties += _skybox.getChangedProperties();
@@ -375,10 +377,16 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(friction);
COPY_PROPERTY_TO_QSCRIPTVALUE(density);
COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime);
- if (!skipDefaults) {
+
+ if (!skipDefaults || _lifetime != defaultEntityProperties._lifetime) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable
}
+
+ auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec
+ created.setTimeSpec(Qt::OffsetFromUTC);
+ COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(created, created.toString(Qt::ISODate));
+
COPY_PROPERTY_TO_QSCRIPTVALUE(script);
COPY_PROPERTY_TO_QSCRIPTVALUE(registrationPoint);
COPY_PROPERTY_TO_QSCRIPTVALUE(angularVelocity);
@@ -426,10 +434,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl);
-
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelVolumeSize);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelData);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelSurfaceStyle);
+ COPY_PROPERTY_TO_QSCRIPTVALUE(lineWidth);
+ COPY_PROPERTY_TO_QSCRIPTVALUE(linePoints);
// Sitting properties support
if (!skipDefaults) {
@@ -471,7 +480,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
return properties;
}
-void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
+void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool honorReadOnly) {
QScriptValue typeScriptValue = object.property("type");
if (typeScriptValue.isValid()) {
setType(typeScriptValue.toVariant().toString());
@@ -512,7 +521,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE(locked, bool, setLocked);
COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures);
COPY_PROPERTY_FROM_QSCRIPTVALUE(userData, QString, setUserData);
- //COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID); DO NOT accept this info from QScriptValue
COPY_PROPERTY_FROM_QSCRIPTVALUE(text, QString, setText);
COPY_PROPERTY_FROM_QSCRIPTVALUE(lineHeight, float, setLineHeight);
COPY_PROPERTY_FROM_QSCRIPTVALUE(textColor, xColor, setTextColor);
@@ -535,10 +543,20 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightDirection, glmVec3, setKeyLightDirection);
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(backgroundMode, BackgroundMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
-
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelSurfaceStyle, uint16_t, setVoxelSurfaceStyle);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE(lineWidth, float, setLineWidth);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE(linePoints, qVectorVec3, setLinePoints);
+
+ 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]() {
+ auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec
+ return result;
+ });
+ COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID);
+ }
_stage.copyFromScriptValue(object, _defaultSettings);
_atmosphere.copyFromScriptValue(object, _defaultSettings);
@@ -554,10 +572,15 @@ QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine,
return properties.copyToScriptValue(engine, true);
}
-void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties) {
- properties.copyFromScriptValue(object);
+void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue &object, EntityItemProperties& properties) {
+ properties.copyFromScriptValue(object, false);
}
+void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object, EntityItemProperties& properties) {
+ properties.copyFromScriptValue(object, true);
+}
+
+
// TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the
// encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar
// to how we handle this in the Octree streaming case.
@@ -763,6 +786,11 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, properties.getVoxelSurfaceStyle());
}
+ if (properties.getType() == EntityTypes::Line) {
+ APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, properties.getLineWidth());
+ APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, properties.getLinePoints());
+ }
+
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
@@ -1003,6 +1031,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle);
}
+ if (properties.getType() == EntityTypes::Line) {
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_WIDTH, float, setLineWidth);
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_POINTS, QVector, setLinePoints);
+ }
+
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
@@ -1107,10 +1140,13 @@ void EntityItemProperties::markAllChanged() {
_skybox.markAllChanged();
_sourceUrlChanged = true;
-
_voxelVolumeSizeChanged = true;
_voxelDataChanged = true;
_voxelSurfaceStyleChanged = true;
+
+ _lineWidthChanged = true;
+ _linePointsChanged = true;
+
}
/// The maximum bounding cube for the entity, independent of it's rotation.
diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h
index dbe2e926c9..3c8133af8f 100644
--- a/libraries/entities/src/EntityItemProperties.h
+++ b/libraries/entities/src/EntityItemProperties.h
@@ -63,7 +63,7 @@ public:
void setType(EntityTypes::EntityType type) { _type = type; }
virtual QScriptValue copyToScriptValue(QScriptEngine* engine, bool skipDefaults) const;
- virtual void copyFromScriptValue(const QScriptValue& object);
+ virtual void copyFromScriptValue(const QScriptValue& object, bool honorReadOnly);
// editing related features supported by all entities
quint64 getLastEdited() const { return _lastEdited; }
@@ -96,6 +96,7 @@ public:
DEFINE_PROPERTY(PROP_RESTITUTION, Restitution, restitution, float);
DEFINE_PROPERTY(PROP_FRICTION, Friction, friction, float);
DEFINE_PROPERTY(PROP_LIFETIME, Lifetime, lifetime, float);
+ DEFINE_PROPERTY(PROP_CREATED, Created, created, quint64);
DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString);
DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString);
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
@@ -145,6 +146,8 @@ public:
DEFINE_PROPERTY_GROUP(Atmosphere, atmosphere, AtmospherePropertyGroup);
DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup);
DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString);
+ DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float);
+ DEFINE_PROPERTY_REF(LINE_POINTS, LinePoints, linePoints, QVector);
static QString getBackgroundModeString(BackgroundMode mode);
@@ -153,8 +156,6 @@ public:
float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); }
float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
- quint64 getCreated() const { return _created; }
- void setCreated(quint64 usecTime);
bool hasCreatedTime() const { return (_created != UNKNOWN_CREATED_TIME); }
bool containsBoundsProperties() const { return (_positionChanged || _dimensionsChanged); }
@@ -195,13 +196,14 @@ public:
void setVoxelDataDirty() { _voxelDataChanged = true; }
+ void setCreated(QDateTime& v);
+
bool hasTerseUpdateChanges() const;
private:
QUuid _id;
bool _idSet;
quint64 _lastEdited;
- quint64 _created;
EntityTypes::EntityType _type;
void setType(const QString& typeName) { _type = EntityTypes::getEntityTypeFromName(typeName); }
@@ -221,7 +223,8 @@ private:
Q_DECLARE_METATYPE(EntityItemProperties);
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
-void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties);
+void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue &object, EntityItemProperties& properties);
+void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object, EntityItemProperties& properties);
// define these inline here so the macros work
diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h
index 33abc59e4d..0f3459e5d2 100644
--- a/libraries/entities/src/EntityItemPropertiesMacros.h
+++ b/libraries/entities/src/EntityItemPropertiesMacros.h
@@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+#include
+
#ifndef hifi_EntityItemPropertiesMacros_h
#define hifi_EntityItemPropertiesMacros_h
@@ -95,14 +97,13 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { ret
inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { return xColorToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; }
+inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorVec3ToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
QByteArray b64 = v.toBase64();
return QScriptValue(QString(b64));
}
-
-
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
QScriptValue groupProperties = properties.property(#g); \
@@ -131,6 +132,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
typedef glm::vec3 glmVec3;
typedef glm::quat glmQuat;
+typedef QVector qVectorVec3;
inline float float_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); }
inline uint16_t uint16_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); }
@@ -138,6 +140,14 @@ inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); }
inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
+inline QDateTime QDateTime_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
+ isValid = true;
+ auto result = QDateTime::fromString(v.toVariant().toString().trimmed(), Qt::ISODate);
+ // result.setTimeSpec(Qt::OffsetFromUTC);
+ return result;
+}
+
+
inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true;
@@ -145,8 +155,6 @@ inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool&
return QByteArray::fromBase64(b64.toUtf8());
}
-
-
inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x");
@@ -167,6 +175,11 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal
return glm::vec3(0);
}
+inline qVectorVec3 qVectorVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
+ isValid = true;
+ return qVectorVec3FromScriptValue(v);
+}
+
inline glmQuat glmQuat_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x");
diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h
index bcb1ec0886..8eb09fece0 100644
--- a/libraries/entities/src/EntityPropertyFlags.h
+++ b/libraries/entities/src/EntityPropertyFlags.h
@@ -114,6 +114,10 @@ enum EntityPropertyList {
PROP_VOXEL_DATA,
PROP_VOXEL_SURFACE_STYLE,
+ //for lines
+ PROP_LINE_WIDTH,
+ PROP_LINE_POINTS,
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties ABOVE this line
PROP_AFTER_LAST_ITEM,
diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp
index d684fbf2fc..6866505d58 100644
--- a/libraries/entities/src/EntityScriptingInterface.cpp
+++ b/libraries/entities/src/EntityScriptingInterface.cpp
@@ -17,7 +17,6 @@
#include "ModelEntityItem.h"
#include "ZoneEntityItem.h"
#include "EntitiesLogging.h"
-#include "PolyVoxEntityItem.h"
EntityScriptingInterface::EntityScriptingInterface() :
@@ -370,7 +369,7 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra
quuidFromScriptValue(entityIDValue, value.entityID);
QScriptValue entityPropertiesValue = object.property("properties");
if (entityPropertiesValue.isValid()) {
- EntityItemPropertiesFromScriptValue(entityPropertiesValue, value.properties);
+ EntityItemPropertiesFromScriptValueHonorReadOnly(entityPropertiesValue, value.properties);
}
value.distance = object.property("distance").toVariant().toFloat();
@@ -395,7 +394,8 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra
}
-bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
+bool EntityScriptingInterface::setVoxels(QUuid entityID,
+ std::function actor) {
if (!_entityTree) {
return false;
}
@@ -415,7 +415,7 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c
PolyVoxEntityItem* polyVoxEntity = static_cast(entity.get());
_entityTree->lockForWrite();
- polyVoxEntity->setSphere(center, radius, value);
+ actor(*polyVoxEntity);
entity->setLastEdited(now);
entity->setLastBroadcast(now);
_entityTree->unlock();
@@ -430,3 +430,24 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c
queueEntityMessage(PacketTypeEntityEdit, entityID, properties);
return true;
}
+
+
+bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
+ return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {
+ polyVoxEntity.setSphere(center, radius, value);
+ });
+}
+
+
+bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) {
+ return setVoxels(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) {
+ polyVoxEntity.setVoxelInVolume(position, value);
+ });
+}
+
+
+bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) {
+ return setVoxels(entityID, [value](PolyVoxEntityItem& polyVoxEntity) {
+ polyVoxEntity.setAll(value);
+ });
+}
diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h
index 6c2dc06579..7761effe2f 100644
--- a/libraries/entities/src/EntityScriptingInterface.h
+++ b/libraries/entities/src/EntityScriptingInterface.h
@@ -21,6 +21,7 @@
#include
#include
#include
+#include "PolyVoxEntityItem.h"
#include "EntityEditPacketSender.h"
@@ -117,7 +118,10 @@ public slots:
Q_INVOKABLE void setSendPhysicsUpdates(bool value);
Q_INVOKABLE bool getSendPhysicsUpdates() const;
+ bool setVoxels(QUuid entityID, std::function actor);
Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value);
+ Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value);
+ Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value);
Q_INVOKABLE void dumpTree() const;
diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp
index 5eec93e8f5..937472820e 100644
--- a/libraries/entities/src/EntityTree.cpp
+++ b/libraries/entities/src/EntityTree.cpp
@@ -1055,7 +1055,7 @@ bool EntityTree::readFromMap(QVariantMap& map) {
QVariantMap entityMap = entityVariant.toMap();
QScriptValue entityScriptValue = variantMapToScriptValue(entityMap, scriptEngine);
EntityItemProperties properties;
- EntityItemPropertiesFromScriptValue(entityScriptValue, properties);
+ EntityItemPropertiesFromScriptValueIgnoreReadOnly(entityScriptValue, properties);
EntityItemID entityItemID;
if (entityMap.contains("id")) {
diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp
index 1aa79a4e6f..72f403a4e0 100644
--- a/libraries/entities/src/LineEntityItem.cpp
+++ b/libraries/entities/src/LineEntityItem.cpp
@@ -20,24 +20,41 @@
#include "EntityTreeElement.h"
+
+const float LineEntityItem::DEFAULT_LINE_WIDTH = 2.0f;
+
+
EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer result { new LineEntityItem(entityID, properties) };
return result;
}
LineEntityItem::LineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
- EntityItem(entityItemID)
+ EntityItem(entityItemID) ,
+ _lineWidth(DEFAULT_LINE_WIDTH),
+ _pointsChanged(true),
+ _points(QVector(0))
{
_type = EntityTypes::Line;
_created = properties.getCreated();
setProperties(properties);
+
+
}
EntityItemProperties LineEntityItem::getProperties() const {
+
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
+
properties._color = getXColor();
properties._colorChanged = false;
+
+
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineWidth, getLineWidth);
+
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints);
+
properties._glowLevel = getGlowLevel();
properties._glowLevelChanged = false;
@@ -48,8 +65,11 @@ EntityItemProperties LineEntityItem::getProperties() const {
bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
-
+
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineWidth, setLineWidth);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(linePoints, setLinePoints);
+
if (somethingChanged) {
bool wantDebug = false;
@@ -64,7 +84,12 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
return somethingChanged;
}
-int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
+void LineEntityItem::setLinePoints(const QVector& points) {
+ _points = points;
+ _pointsChanged = true;
+}
+
+int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
@@ -72,6 +97,9 @@ int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
+ READ_ENTITY_PROPERTY(PROP_LINE_WIDTH, float, setLineWidth);
+ READ_ENTITY_PROPERTY(PROP_LINE_POINTS, QVector, setLinePoints);
+
return bytesRead;
}
@@ -81,6 +109,8 @@ int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
EntityPropertyFlags LineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_COLOR;
+ requestedProperties += PROP_LINE_WIDTH;
+ requestedProperties += PROP_LINE_POINTS;
return requestedProperties;
}
@@ -95,6 +125,8 @@ void LineEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
+ APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, getLineWidth());
+ APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, getLinePoints());
}
void LineEntityItem::debugDump() const {
diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h
index 29b2c834ae..5151244b3c 100644
--- a/libraries/entities/src/LineEntityItem.h
+++ b/libraries/entities/src/LineEntityItem.h
@@ -51,6 +51,13 @@ class LineEntityItem : public EntityItem {
_color[BLUE_INDEX] = value.blue;
}
+ void setLineWidth(float lineWidth){ _lineWidth = lineWidth; }
+ float getLineWidth() const{ return _lineWidth; }
+
+ void setLinePoints(const QVector& points);
+
+ const QVector& getLinePoints() const{ return _points; }
+
virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; }
// never have a ray intersection pick a LineEntityItem.
@@ -60,9 +67,13 @@ class LineEntityItem : public EntityItem {
void** intersectedObject, bool precisionPicking) const { return false; }
virtual void debugDump() const;
+ static const float DEFAULT_LINE_WIDTH;
protected:
rgbColor _color;
+ float _lineWidth;
+ bool _pointsChanged;
+ QVector _points;
};
#endif // hifi_LineEntityItem_h
diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp
index c60b0f863a..95ab7d1035 100644
--- a/libraries/entities/src/PolyVoxEntityItem.cpp
+++ b/libraries/entities/src/PolyVoxEntityItem.cpp
@@ -22,7 +22,8 @@
const glm::vec3 PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE = glm::vec3(32, 32, 32);
-const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(qCompress(QByteArray(0), 9));
+const float PolyVoxEntityItem::MAX_VOXEL_DIMENSION = 32.0f;
+const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(qCompress(QByteArray(0), 9)); // XXX
const PolyVoxEntityItem::PolyVoxSurfaceStyle PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE =
PolyVoxEntityItem::SURFACE_MARCHING_CUBES;
@@ -41,6 +42,40 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const Ent
setProperties(properties);
}
+void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
+ assert((int)_voxelVolumeSize.x == _voxelVolumeSize.x);
+ assert((int)_voxelVolumeSize.y == _voxelVolumeSize.y);
+ assert((int)_voxelVolumeSize.z == _voxelVolumeSize.z);
+
+ _voxelVolumeSize = voxelVolumeSize;
+ if (_voxelVolumeSize.x < 1) {
+ qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to 1";
+ _voxelVolumeSize.x = 1;
+ }
+ if (_voxelVolumeSize.x > MAX_VOXEL_DIMENSION) {
+ qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to max";
+ _voxelVolumeSize.x = MAX_VOXEL_DIMENSION;
+ }
+
+ if (_voxelVolumeSize.y < 1) {
+ qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to 1";
+ _voxelVolumeSize.y = 1;
+ }
+ if (_voxelVolumeSize.y > MAX_VOXEL_DIMENSION) {
+ qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to max";
+ _voxelVolumeSize.y = MAX_VOXEL_DIMENSION;
+ }
+
+ if (_voxelVolumeSize.z < 1) {
+ qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to 1";
+ _voxelVolumeSize.z = 1;
+ }
+ if (_voxelVolumeSize.z > MAX_VOXEL_DIMENSION) {
+ qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to max";
+ _voxelVolumeSize.z = MAX_VOXEL_DIMENSION;
+ }
+}
+
EntityItemProperties PolyVoxEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize);
@@ -114,4 +149,3 @@ void PolyVoxEntityItem::debugDump() const {
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
}
-
diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h
index 53675e6efa..bf8214675b 100644
--- a/libraries/entities/src/PolyVoxEntityItem.h
+++ b/libraries/entities/src/PolyVoxEntityItem.h
@@ -40,19 +40,7 @@ class PolyVoxEntityItem : public EntityItem {
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
-
- const rgbColor& getColor() const { return _color; }
- xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
-
- void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
- void setXColor(const xColor& value) {
- _color[RED_INDEX] = value.red;
- _color[GREEN_INDEX] = value.green;
- _color[BLUE_INDEX] = value.blue;
- }
- virtual ShapeType getShapeType() const { return SHAPE_TYPE_POLYVOX; }
-
// never have a ray intersection pick a PolyVoxEntityItem.
virtual bool supportsDetailedRayIntersection() const { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@@ -61,7 +49,7 @@ class PolyVoxEntityItem : public EntityItem {
virtual void debugDump() const;
- virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { _voxelVolumeSize = voxelVolumeSize; }
+ virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
virtual const glm::vec3& getVoxelVolumeSize() const { return _voxelVolumeSize; }
virtual void setVoxelData(QByteArray voxelData) { _voxelData = voxelData; }
@@ -69,16 +57,19 @@ class PolyVoxEntityItem : public EntityItem {
enum PolyVoxSurfaceStyle {
SURFACE_MARCHING_CUBES,
- SURFACE_CUBIC
+ SURFACE_CUBIC,
+ SURFACE_EDGED_CUBIC
};
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; }
virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) {
- _voxelSurfaceStyle = (PolyVoxSurfaceStyle) voxelSurfaceStyle;
+ setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle);
}
virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; }
static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE;
+ static const float MAX_VOXEL_DIMENSION;
+
static const QByteArray DEFAULT_VOXEL_DATA;
static const PolyVoxSurfaceStyle DEFAULT_VOXEL_SURFACE_STYLE;
@@ -88,8 +79,15 @@ class PolyVoxEntityItem : public EntityItem {
// coords are in world-space
virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue) {}
+ virtual void setAll(uint8_t toValue) {}
+
+ virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue) {}
+
+ virtual uint8_t getVoxel(int x, int y, int z) { return 0; }
+ virtual void setVoxel(int x, int y, int z, uint8_t toValue) {}
+
+
protected:
- rgbColor _color;
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
QByteArray _voxelData;
PolyVoxSurfaceStyle _voxelSurfaceStyle;
diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp
index 4b02a32cad..78bb3f11e1 100644
--- a/libraries/networking/src/PacketHeaders.cpp
+++ b/libraries/networking/src/PacketHeaders.cpp
@@ -73,7 +73,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketTypeEntityAdd:
case PacketTypeEntityEdit:
case PacketTypeEntityData:
- return VERSION_NO_ENTITY_ID_SWAP;
+ return VERSION_ENTITIES_LINE_POINTS;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:
@@ -135,7 +135,6 @@ QString nameForPacketType(PacketType packetType) {
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAdd);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEdit);
- PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleEntitiesFix);
default:
return QString("Type: ") + QString::number((int)packetType);
}
diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h
index cf1a323741..228df1cdde 100644
--- a/libraries/networking/src/PacketHeaders.h
+++ b/libraries/networking/src/PacketHeaders.h
@@ -79,8 +79,7 @@ enum PacketType {
PacketTypeSignedTransactionPayment,
PacketTypeIceServerHeartbeat, // 50
PacketTypeUnverifiedPing,
- PacketTypeUnverifiedPingReply,
- PacketTypeParticleEntitiesFix
+ PacketTypeUnverifiedPingReply
};
typedef char PacketVersion;
@@ -183,5 +182,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25;
const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26;
const PacketVersion VERSION_NO_ENTITY_ID_SWAP = 27;
const PacketVersion VERSION_ENTITIES_PARTICLE_FIX = 28;
+const PacketVersion VERSION_ENTITIES_LINE_POINTS = 29;
#endif // hifi_PacketHeaders_h
diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp
index d53d29e444..adc2040b8a 100644
--- a/libraries/octree/src/Octree.cpp
+++ b/libraries/octree/src/Octree.cpp
@@ -2096,7 +2096,15 @@ void Octree::writeToJSONFile(const char* fileName, OctreeElement* element) {
top = _rootElement;
}
+ // include the "bitstream" version
+ PacketType expectedType = expectedDataPacketType();
+ PacketVersion expectedVersion = versionForPacketType(expectedType);
+ entityDescription["Version"] = (int) expectedVersion;
+
+ // store the entity data
bool entityDescriptionSuccess = writeToMap(entityDescription, top, true);
+
+ // convert the QVariantMap to JSON
if (entityDescriptionSuccess && persistFile.open(QIODevice::WriteOnly)) {
persistFile.write(QJsonDocument::fromVariant(entityDescription).toJson());
} else {
diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp
index 19fc278088..7c977210fc 100644
--- a/libraries/octree/src/OctreePacketData.cpp
+++ b/libraries/octree/src/OctreePacketData.cpp
@@ -325,6 +325,7 @@ bool OctreePacketData::appendValue(uint8_t value) {
bool OctreePacketData::appendValue(uint16_t value) {
const unsigned char* data = (const unsigned char*)&value;
+
int length = sizeof(value);
bool success = append(data, length);
if (success) {
@@ -358,6 +359,7 @@ bool OctreePacketData::appendValue(quint64 value) {
}
bool OctreePacketData::appendValue(float value) {
+
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
@@ -379,6 +381,17 @@ bool OctreePacketData::appendValue(const glm::vec3& value) {
return success;
}
+bool OctreePacketData::appendValue(const QVector& value) {
+ uint16_t qVecSize = value.size();
+ bool success = appendValue(qVecSize);
+ success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3));
+ if (success) {
+ _bytesOfValues += qVecSize * sizeof(glm::vec3);
+ _totalBytesOfValues += qVecSize * sizeof(glm::vec3);
+ }
+ return success;
+}
+
bool OctreePacketData::appendValue(const glm::quat& value) {
const size_t VALUES_PER_QUAT = 4;
const size_t PACKED_QUAT_SIZE = sizeof(uint16_t) * VALUES_PER_QUAT;
@@ -585,6 +598,15 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, xColor
return sizeof(rgbColor);
}
+
+int OctreePacketData::unpackDataFromBytes(const unsigned char *dataBytes, QVector& result) {
+ uint16_t length;
+ memcpy(&length, dataBytes, sizeof(uint16_t));
+ dataBytes += sizeof(length);
+ result.resize(length);
+ memcpy(result.data(), dataBytes, length * sizeof(glm::vec3));
+ return sizeof(uint16_t) + length * sizeof(glm::vec3);
+}
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(length));
diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h
index 5becb26ca2..9476fe024e 100644
--- a/libraries/octree/src/OctreePacketData.h
+++ b/libraries/octree/src/OctreePacketData.h
@@ -162,6 +162,9 @@ public:
/// appends a non-position vector to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const glm::vec3& value);
+
+ //appends a QVector of vec3's to the end of the stream, may fail if new data stream is too long to fit in packet
+ bool appendValue(const QVector& value);
/// appends a packed quat to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const glm::quat& value);
@@ -185,7 +188,7 @@ public:
bool appendRawData(const unsigned char* data, int length);
bool appendRawData(QByteArray data);
- /// returns a byte offset from beginning of the uncompressed stream based on offset from end.
+ /// returns a byte offset from beginning of the uncompressed stream based on offset from end.
/// Positive offsetFromEnd returns that many bytes before the end of uncompressed stream
int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; }
@@ -241,8 +244,10 @@ public:
static int unpackDataFromBytes(const unsigned char* dataBytes, QString& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result);
+ static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result);
+
private:
/// appends raw bytes, might fail if byte would cause packet to be too large
bool append(const unsigned char* data, int length);
diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp
index cf5a0d58da..303d63bef8 100644
--- a/libraries/render-utils/src/GeometryCache.cpp
+++ b/libraries/render-utils/src/GeometryCache.cpp
@@ -650,7 +650,6 @@ void GeometryCache::updateVertices(int id, const QVector& points, con
void GeometryCache::updateVertices(int id, const QVector& points, const glm::vec4& color) {
BatchItemDetails& details = _registeredVertices[id];
-
if (details.isCreated) {
details.clear();
#ifdef WANT_DEBUG
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index dcbdddcb0a..08385ffb61 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -551,7 +551,6 @@ private:
Q_DECLARE_METATYPE(QPointer)
Q_DECLARE_METATYPE(QWeakPointer)
-Q_DECLARE_METATYPE(QVector)
/// Handle management of pending models that need blending
class ModelBlender : public QObject, public Dependency {
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 91a4e3c397..30c3fbe8e4 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -318,7 +318,7 @@ void ScriptEngine::init() {
registerAvatarTypes(this);
registerAudioMetaTypes(this);
- qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue);
+ qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);
qScriptRegisterSequenceMetaType>(this);
diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp
index eb60e1c31d..241f835a46 100644
--- a/libraries/shared/src/RegisteredMetaTypes.cpp
+++ b/libraries/shared/src/RegisteredMetaTypes.cpp
@@ -27,6 +27,7 @@ static int pickRayMetaTypeId = qRegisterMetaType();
static int collisionMetaTypeId = qRegisterMetaType();
+
void registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);
qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
@@ -72,6 +73,26 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) {
vec3.z = object.property("z").toVariant().toFloat();
}
+QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector){
+ QScriptValue array = engine->newArray();
+ for (int i = 0; i < vector.size(); i++) {
+ array.setProperty(i, vec3toScriptValue(engine, vector.at(i)));
+ }
+ return array;
+}
+
+QVector qVectorVec3FromScriptValue(const QScriptValue& array){
+ QVector newVector;
+ int length = array.property("length").toInteger();
+
+ for (int i = 0; i < length; i++) {
+ glm::vec3 newVec3 = glm::vec3();
+ vec3FromScriptValue(array.property(i), newVec3);
+ newVector << newVec3;
+ }
+ return newVector;
+}
+
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) {
QScriptValue obj = engine->newObject();
obj.setProperty("x", vec2.x);
diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h
index 14f30c20fc..48eecba227 100644
--- a/libraries/shared/src/RegisteredMetaTypes.h
+++ b/libraries/shared/src/RegisteredMetaTypes.h
@@ -28,6 +28,7 @@ Q_DECLARE_METATYPE(glm::vec3)
Q_DECLARE_METATYPE(glm::vec2)
Q_DECLARE_METATYPE(glm::quat)
Q_DECLARE_METATYPE(xColor)
+Q_DECLARE_METATYPE(QVector)
void registerMetaTypes(QScriptEngine* engine);
@@ -55,6 +56,9 @@ void qColorFromScriptValue(const QScriptValue& object, QColor& color);
QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url);
void qURLFromScriptValue(const QScriptValue& object, QUrl& url);
+QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector);
+QVector qVectorVec3FromScriptValue( const QScriptValue& array);
+
class PickRay {
public:
PickRay() : origin(0.0f), direction(0.0f) { }
diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp
index 26cbe3ca13..c14fd33565 100644
--- a/libraries/shared/src/SettingInterface.cpp
+++ b/libraries/shared/src/SettingInterface.cpp
@@ -46,7 +46,7 @@ namespace Setting {
QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString());
QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
- // Let's set up the settings Private instance on it's own thread
+ // Let's set up the settings Private instance on its own thread
QThread* thread = new QThread();
Q_CHECK_PTR(thread);
thread->setObjectName("Settings Thread");
diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h
index e2a77fbba2..a3fbe55f36 100644
--- a/libraries/shared/src/ShapeInfo.h
+++ b/libraries/shared/src/ShapeInfo.h
@@ -35,8 +35,7 @@ enum ShapeType {
SHAPE_TYPE_CYLINDER_X,
SHAPE_TYPE_CYLINDER_Y,
SHAPE_TYPE_CYLINDER_Z,
- SHAPE_TYPE_LINE,
- SHAPE_TYPE_POLYVOX
+ SHAPE_TYPE_LINE
};
class ShapeInfo {