mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-07 04:53:28 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into team-teaching-scene-api
This commit is contained in:
commit
7c40b666e8
35 changed files with 898 additions and 164 deletions
|
@ -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");
|
||||
|
|
|
@ -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 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="poly-vox-section property">
|
||||
<div class="label">Voxel Volume Size</div>
|
||||
<div class="value">
|
||||
<div class="input-area">X <br><input class="coord" type='number' id="property-voxel-volume-size-x"></input></div>
|
||||
<div class="input-area">Y <br><input class="coord" type='number' id="property-voxel-volume-size-y"></input></div>
|
||||
<div class="input-area">Z <br><input class="coord" type='number' id="property-voxel-volume-size-z"></input></div>
|
||||
</div>
|
||||
|
||||
<div class="label">Surface Extractor</div>
|
||||
<div class="value">
|
||||
<select name="SelectVoxelSurfaceStyle" id="property-voxel-surface-style">
|
||||
<option value='0'>marching cubes</option>
|
||||
<option value='1'>cubic</option>
|
||||
<option value='2'>edged cubic</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="property">
|
||||
<div class="label">Rotation</div>
|
||||
<div class="value">
|
||||
|
@ -1107,19 +1143,19 @@
|
|||
<input type="text" id="property-web-source-url" class="url"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="particle-section property">
|
||||
<div class="label">Max Particles</div>
|
||||
<div class="value">
|
||||
<input type='number' id="property-particle-maxparticles" min="0" max="2048" step="1"></input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="particle-section property">
|
||||
<div class="label">Particle Life Span</div>
|
||||
<div class="value">
|
||||
<input type='number' id="property-particle-lifespan" min="0" step="0.1"></input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="particle-section property">
|
||||
<div class="label">Particle Emission Rate</div>
|
||||
<div class="value">
|
||||
|
@ -1152,7 +1188,7 @@
|
|||
<input class="coord" type='number' id="property-particle-radius" min="0" step="0.005"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="model-section property">
|
||||
<div class="label">Model URL</div>
|
||||
<div class="value">
|
||||
|
@ -1167,7 +1203,7 @@
|
|||
<option value='box'>box</option>
|
||||
<option value='sphere'>sphere</option>
|
||||
<option value='compound'>compound</option>
|
||||
</select>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="model-section zone-section property">
|
||||
|
@ -1346,7 +1382,7 @@
|
|||
<input type='checkbox' id="property-zone-stage-automatic-hour-day">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Day</div>
|
||||
<div class="value">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -82,7 +82,10 @@ void AvatarAppearanceDialog::setUseFullAvatar(bool useFullAvatar) {
|
|||
ui.useFullAvatar->setChecked(_useFullAvatar);
|
||||
ui.useSeparateBodyAndHead->setChecked(!_useFullAvatar);
|
||||
|
||||
DependencyManager::get<DialogsManager>()->getPreferencesDialog()->avatarDescriptionChanged();
|
||||
QPointer<PreferencesDialog> prefs = DependencyManager::get<DialogsManager>()->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<DialogsManager>()->getPreferencesDialog()->avatarDescriptionChanged();
|
||||
QPointer<PreferencesDialog> prefs = DependencyManager::get<DialogsManager>()->getPreferencesDialog();
|
||||
if (prefs) { // Preferences dialog may have been closed
|
||||
prefs->avatarDescriptionChanged();
|
||||
}
|
||||
|
||||
close();
|
||||
delete _marketplaceWindow;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <gpu/GPUConfig.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <PerfStat.h>
|
||||
|
@ -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<DeferredLightingEffect>()->renderLine(batch, p1, p2, lineColor, lineColor);
|
||||
|
||||
glLineWidth(getLineWidth());
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
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);
|
||||
};
|
||||
|
|
|
@ -15,17 +15,23 @@
|
|||
#include <LineEntityItem.h>
|
||||
#include "RenderableDebugableEntityItem.h"
|
||||
#include "RenderableEntityItem.h"
|
||||
#include <GeometryCache.h>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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<uint8_t>* 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<uint8_t>* 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<uint8_t>(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<uint8_t>(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<uint8_t>(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<PolyVox::PositionMaterialNormal> polyVoxMesh;
|
||||
|
||||
|
@ -134,6 +311,7 @@ void RenderablePolyVoxEntityItem::getModel() {
|
|||
surfaceExtractor.execute();
|
||||
break;
|
||||
}
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
||||
case PolyVoxEntityItem::SURFACE_CUBIC: {
|
||||
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> 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<uint32_t>& 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<PolyVox::PositionMaterialNormal>& 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<glm::vec3>(); normal != normalAttrib.end<glm::vec3>(); 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<uint8_t>* vol) :
|
||||
_result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)),
|
||||
_vol(vol) {
|
||||
}
|
||||
bool operator()(PolyVox::SimpleVolume<unsigned char>::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<uint8_t>* _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<glm::vec3> 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<glm::vec3> 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);
|
||||
}
|
||||
|
|
|
@ -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<uint8_t>* _volData = nullptr;
|
||||
model::Geometry _modelGeometry;
|
||||
bool _needsModelReload = true;
|
||||
|
||||
QVector<QVector<glm::vec3>> _points; // XXX
|
||||
|
||||
int _onCount = 0; // how many non-zero voxels are in _volData
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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<glm::vec3>()),
|
||||
|
||||
|
||||
_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<glm::vec3>, 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.
|
||||
|
|
|
@ -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<glm::vec3>);
|
||||
|
||||
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
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
#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<glm::vec3>& 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<glm::vec3> 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");
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<void(PolyVoxEntityItem&)> actor) {
|
||||
if (!_entityTree) {
|
||||
return false;
|
||||
}
|
||||
|
@ -415,7 +415,7 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c
|
|||
|
||||
PolyVoxEntityItem* polyVoxEntity = static_cast<PolyVoxEntityItem*>(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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <Octree.h>
|
||||
#include <OctreeScriptingInterface.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#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<void(PolyVoxEntityItem&)> 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;
|
||||
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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<glm::vec3>(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<glm::vec3>& 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<glm::vec3>, 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 {
|
||||
|
|
|
@ -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<glm::vec3>& points);
|
||||
|
||||
const QVector<glm::vec3>& 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<glm::vec3> _points;
|
||||
};
|
||||
|
||||
#endif // hifi_LineEntityItem_h
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<glm::vec3>& 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<glm::vec3>& 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));
|
||||
|
|
|
@ -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<glm::vec3>& 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<glm::vec3>& 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);
|
||||
|
|
|
@ -650,7 +650,6 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, con
|
|||
|
||||
void GeometryCache::updateVertices(int id, const QVector<glm::vec3>& points, const glm::vec4& color) {
|
||||
BatchItemDetails& details = _registeredVertices[id];
|
||||
|
||||
if (details.isCreated) {
|
||||
details.clear();
|
||||
#ifdef WANT_DEBUG
|
||||
|
|
|
@ -551,7 +551,6 @@ private:
|
|||
|
||||
Q_DECLARE_METATYPE(QPointer<Model>)
|
||||
Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>)
|
||||
Q_DECLARE_METATYPE(QVector<glm::vec3>)
|
||||
|
||||
/// Handle management of pending models that need blending
|
||||
class ModelBlender : public QObject, public Dependency {
|
||||
|
|
|
@ -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<QVector<QUuid>>(this);
|
||||
|
|
|
@ -27,6 +27,7 @@ static int pickRayMetaTypeId = qRegisterMetaType<PickRay>();
|
|||
static int collisionMetaTypeId = qRegisterMetaType<Collision>();
|
||||
|
||||
|
||||
|
||||
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<glm::vec3>& vector){
|
||||
QScriptValue array = engine->newArray();
|
||||
for (int i = 0; i < vector.size(); i++) {
|
||||
array.setProperty(i, vec3toScriptValue(engine, vector.at(i)));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
QVector<glm::vec3> qVectorVec3FromScriptValue(const QScriptValue& array){
|
||||
QVector<glm::vec3> 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);
|
||||
|
|
|
@ -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<glm::vec3>)
|
||||
|
||||
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<glm::vec3>& vector);
|
||||
QVector<glm::vec3> qVectorVec3FromScriptValue( const QScriptValue& array);
|
||||
|
||||
class PickRay {
|
||||
public:
|
||||
PickRay() : origin(0.0f), direction(0.0f) { }
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue