Merge pull request #5706 from sethalves/polyvox-again

Polyvox improvements
This commit is contained in:
Andrew Meadows 2015-09-04 10:32:36 -07:00
commit 5d40517edd
17 changed files with 832 additions and 256 deletions

View file

@ -3,6 +3,7 @@ var shiftHeld = false;
Script.include([
"libraries/toolBars.js",
"libraries/utils.js",
]);
var isActive = false;
@ -12,24 +13,25 @@ var toolWidth = 50;
var addingVoxels = false;
var deletingVoxels = false;
var addingSpheres = false;
var deletingSpheres = false;
offAlpha = 0.5;
onAlpha = 0.9;
var offAlpha = 0.5;
var onAlpha = 0.9;
var editSphereRadius = 4;
function floorVector(v) {
return {x: Math.floor(v.x), y: Math.floor(v.y), z: Math.floor(v.z)};
}
function vectorToString(v){
return "{" + v.x + ", " + v.x + ", " + v.x + "}";
}
var toolBar = (function () {
var that = {},
toolBar,
activeButton,
addVoxelButton,
deleteVoxelButton,
addSphereButton,
deleteSphereButton,
addTerrainButton;
function initialize() {
@ -66,6 +68,24 @@ var toolBar = (function () {
visible: false
});
addSphereButton = toolBar.addTool({
imageURL: toolIconUrl + "sphere-add.svg",
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
width: toolWidth,
height: toolHeight,
alpha: offAlpha,
visible: false
});
deleteSphereButton = toolBar.addTool({
imageURL: toolIconUrl + "sphere-delete.svg",
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
width: toolWidth,
height: toolHeight,
alpha: offAlpha,
visible: false
});
addTerrainButton = toolBar.addTool({
imageURL: toolIconUrl + "voxel-terrain.svg",
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
@ -78,6 +98,22 @@ var toolBar = (function () {
that.setActive(false);
}
function disableAllButtons() {
addingVoxels = false;
deletingVoxels = false;
addingSpheres = false;
deletingSpheres = false;
toolBar.setAlpha(offAlpha, addVoxelButton);
toolBar.setAlpha(offAlpha, deleteVoxelButton);
toolBar.setAlpha(offAlpha, addSphereButton);
toolBar.setAlpha(offAlpha, deleteSphereButton);
toolBar.selectTool(addVoxelButton, false);
toolBar.selectTool(deleteVoxelButton, false);
toolBar.selectTool(addSphereButton, false);
toolBar.selectTool(deleteSphereButton, false);
}
that.setActive = function(active) {
if (active != isActive) {
@ -91,6 +127,8 @@ var toolBar = (function () {
that.showTools = function(doShow) {
toolBar.showTool(addVoxelButton, doShow);
toolBar.showTool(deleteVoxelButton, doShow);
toolBar.showTool(addSphereButton, doShow);
toolBar.showTool(deleteSphereButton, doShow);
toolBar.showTool(addTerrainButton, doShow);
};
@ -103,37 +141,46 @@ var toolBar = (function () {
}
if (addVoxelButton === toolBar.clicked(clickedOverlay)) {
if (addingVoxels) {
addingVoxels = false;
deletingVoxels = false;
toolBar.setAlpha(offAlpha, addVoxelButton);
toolBar.setAlpha(offAlpha, deleteVoxelButton);
toolBar.selectTool(addVoxelButton, false);
toolBar.selectTool(deleteVoxelButton, false);
} else {
var wasAddingVoxels = addingVoxels;
disableAllButtons()
if (!wasAddingVoxels) {
addingVoxels = true;
deletingVoxels = false;
toolBar.setAlpha(onAlpha, addVoxelButton);
toolBar.setAlpha(offAlpha, deleteVoxelButton);
}
return true;
}
if (deleteVoxelButton === toolBar.clicked(clickedOverlay)) {
if (deletingVoxels) {
deletingVoxels = false;
addingVoxels = false;
toolBar.setAlpha(offAlpha, addVoxelButton);
toolBar.setAlpha(offAlpha, deleteVoxelButton);
} else {
var wasDeletingVoxels = deletingVoxels;
disableAllButtons()
if (!wasDeletingVoxels) {
deletingVoxels = true;
addingVoxels = false;
toolBar.setAlpha(offAlpha, addVoxelButton);
toolBar.setAlpha(onAlpha, deleteVoxelButton);
}
return true;
}
if (addSphereButton === toolBar.clicked(clickedOverlay)) {
var wasAddingSpheres = addingSpheres
disableAllButtons()
if (!wasAddingSpheres) {
addingSpheres = true;
toolBar.setAlpha(onAlpha, addSphereButton);
}
return true;
}
if (deleteSphereButton === toolBar.clicked(clickedOverlay)) {
var wasDeletingSpheres = deletingSpheres;
disableAllButtons()
if (!wasDeletingSpheres) {
deletingSpheres = true;
toolBar.setAlpha(onAlpha, deleteSphereButton);
}
return true;
}
if (addTerrainButton === toolBar.clicked(clickedOverlay)) {
addTerrainBlock();
return true;
@ -155,85 +202,212 @@ var toolBar = (function () {
}());
function getTerrainAlignedLocation(pos) {
var posDiv16 = Vec3.multiply(pos, 1.0 / 16.0);
var posDiv16Floored = floorVector(posDiv16);
return Vec3.multiply(posDiv16Floored, 16.0);
}
function lookupTerrainForLocation(pos) {
var baseLocation = getTerrainAlignedLocation(pos);
entitiesAtLoc = Entities.findEntities(baseLocation, 1.0);
for (var i = 0; i < entitiesAtLoc.length; i++) {
var id = entitiesAtLoc[i];
var properties = Entities.getEntityProperties(id);
if (properties.name == "terrain") {
return id;
}
}
return false;
}
function grabLowestJointY() {
var jointNames = MyAvatar.getJointNames();
var floorY = MyAvatar.position.y;
for (var jointName in jointNames) {
if (MyAvatar.getJointPosition(jointNames[jointName]).y < floorY) {
floorY = MyAvatar.getJointPosition(jointNames[jointName]).y;
}
}
return floorY;
}
function addTerrainBlock() {
var myPosDiv16 = Vec3.multiply(Vec3.sum(MyAvatar.position, {x:8, x:8, z:8}), 1.0 / 16.0);
var myPosDiv16Floored = floorVector(myPosDiv16);
var baseLocation = Vec3.multiply(myPosDiv16Floored, 16.0);
if (baseLocation.y + 8 > MyAvatar.position.y) {
var baseLocation = getTerrainAlignedLocation(Vec3.sum(MyAvatar.position, {x:8, y:8, z:8}));
if (baseLocation.y > MyAvatar.position.y) {
baseLocation.y -= 16;
}
print("myPosDiv16 is " + vectorToString(myPosDiv16));
print("MyPosDiv16Floored is " + vectorToString(myPosDiv16Floored));
print("baseLocation is " + vectorToString(baseLocation));
alreadyThere = Entities.findEntities(baseLocation, 1.0);
for (var i = 0; i < alreadyThere.length; i++) {
var id = alreadyThere[i];
var properties = Entities.getEntityProperties(id);
if (properties.name == "terrain") {
print("already terrain there");
var alreadyThere = lookupTerrainForLocation(baseLocation);
if (alreadyThere) {
// there is already a terrain block under MyAvatar.
// try in front of the avatar.
facingPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(8.0, Quat.getFront(Camera.getOrientation())));
facingPosition = Vec3.sum(facingPosition, {x:8, y:8, z:8});
baseLocation = getTerrainAlignedLocation(facingPosition);
alreadyThere = lookupTerrainForLocation(baseLocation);
if (alreadyThere) {
return;
}
}
var polyVoxId = Entities.addEntity({
var polyVoxID = Entities.addEntity({
type: "PolyVox",
name: "terrain",
position: baseLocation,
dimensions: { x: 16, y: 16, z: 16 },
voxelVolumeSize: {x:16, y:16, z:16},
voxelSurfaceStyle: 2
dimensions: { x:16, y:16, z:16 },
voxelVolumeSize: {x:16, y:64, z:16},
voxelSurfaceStyle: 0,
xTextureURL: "http://headache.hungry.com/~seth/hifi/dirt.jpeg",
yTextureURL: "http://headache.hungry.com/~seth/hifi/grass.png",
zTextureURL: "http://headache.hungry.com/~seth/hifi/dirt.jpeg"
});
Entities.setAllVoxels(polyVoxId, 255);
for (var y = 8; y < 16; y++) {
for (var x = 0; x < 16; x++) {
for (var z = 0; z < 16; z++) {
Entities.setVoxel(polyVoxId, {x: x, y: y, z: z}, 0);
}
}
var AvatarPositionInVoxelCoords = Entities.worldCoordsToVoxelCoords(polyVoxID, MyAvatar.position);
// TODO -- how to find the avatar's feet?
var topY = Math.round(AvatarPositionInVoxelCoords.y) - 4;
Entities.setVoxelsInCuboid(polyVoxID, {x:0, y:0, z:0}, {x:16, y:topY, z:16}, 255);
//////////
// stitch together the terrain with x/y/z NeighorID properties
//////////
// link neighbors to this plot
imXNNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:16, y:0, z:0}));
imYNNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:16, z:0}));
imZNNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:16}));
imXPNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:-16, y:0, z:0}));
imYPNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:-16, z:0}));
imZPNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:-16}));
if (imXNNeighborFor) {
var properties = Entities.getEntityProperties(imXNNeighborFor);
properties.xNNeighborID = polyVoxID;
Entities.editEntity(imXNNeighborFor, properties);
}
if (imYNNeighborFor) {
var properties = Entities.getEntityProperties(imYNNeighborFor);
properties.yNNeighborID = polyVoxID;
Entities.editEntity(imYNNeighborFor, properties);
}
if (imZNNeighborFor) {
var properties = Entities.getEntityProperties(imZNNeighborFor);
properties.zNNeighborID = polyVoxID;
Entities.editEntity(imZNNeighborFor, properties);
}
if (imXPNeighborFor) {
var properties = Entities.getEntityProperties(imXPNeighborFor);
properties.xPNeighborID = polyVoxID;
Entities.editEntity(imXPNeighborFor, properties);
}
if (imYPNeighborFor) {
var properties = Entities.getEntityProperties(imYPNeighborFor);
properties.yPNeighborID = polyVoxID;
Entities.editEntity(imYPNeighborFor, properties);
}
if (imZPNeighborFor) {
var properties = Entities.getEntityProperties(imZPNeighborFor);
properties.zPNeighborID = polyVoxID;
Entities.editEntity(imZPNeighborFor, properties);
}
// link this plot to its neighbors
var properties = Entities.getEntityProperties(polyVoxID);
properties.xNNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:-16, y:0, z:0}));
properties.yNNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:-16, z:0}));
properties.zNNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:-16}));
properties.xPNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:16, y:0, z:0}));
properties.yPNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:16, z:0}));
properties.zPNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:16}));
Entities.editEntity(polyVoxID, properties);
return true;
}
function attemptVoxelChange(pickRayDir, intersection) {
function attemptVoxelChangeForEntity(entityID, pickRayDir, intersectionLocation) {
var properties = Entities.getEntityProperties(intersection.entityID);
var properties = Entities.getEntityProperties(entityID);
if (properties.type != "PolyVox") {
return false;
}
if (addingVoxels == false && deletingVoxels == false) {
if (addingVoxels == false && deletingVoxels == false && addingSpheres == false && deletingSpheres == false) {
return false;
}
var voxelPosition = Entities.worldCoordsToVoxelCoords(intersection.entityID, intersection.intersection);
var pickRayDirInVoxelSpace = Entities.localCoordsToVoxelCoords(intersection.entityID, pickRayDir);
var voxelOrigin = Entities.worldCoordsToVoxelCoords(entityID, Vec3.subtract(intersectionLocation, pickRayDir));
var voxelPosition = Entities.worldCoordsToVoxelCoords(entityID, intersectionLocation);
var pickRayDirInVoxelSpace = Vec3.subtract(voxelPosition, voxelOrigin);
pickRayDirInVoxelSpace = Vec3.normalize(pickRayDirInVoxelSpace);
var doAdd = addingVoxels;
var doDelete = deletingVoxels;
var doAddSphere = addingSpheres;
var doDeleteSphere = deletingSpheres;
if (controlHeld) {
doAdd = deletingVoxels;
doDelete = addingVoxels;
if (doAdd) {
doAdd = false;
doDelete = true;
} else if (doDelete) {
doDelete = false;
doAdd = true;
} else if (doAddSphere) {
doAddSphere = false;
doDeleteSphere = true;
} else if (doDeleteSphere) {
doDeleteSphere = false;
doAddSphere = true;
}
}
if (doDelete) {
var toErasePosition = Vec3.sum(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1));
return Entities.setVoxel(intersection.entityID, floorVector(toErasePosition), 0);
return Entities.setVoxel(entityID, floorVector(toErasePosition), 0);
}
if (doAdd) {
var toDrawPosition = Vec3.subtract(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1));
return Entities.setVoxel(intersection.entityID, floorVector(toDrawPosition), 255);
return Entities.setVoxel(entityID, floorVector(toDrawPosition), 255);
}
if (doDeleteSphere) {
var toErasePosition = intersectionLocation;
return Entities.setVoxelSphere(entityID, floorVector(toErasePosition), editSphereRadius, 0);
}
if (doAddSphere) {
var toDrawPosition = intersectionLocation;
return Entities.setVoxelSphere(entityID, floorVector(toDrawPosition), editSphereRadius, 255);
}
}
function attemptVoxelChange(pickRayDir, intersection) {
var ids;
ids = Entities.findEntities(intersection.intersection, editSphereRadius + 1.0);
if (ids.indexOf(intersection.entityID) < 0) {
ids.push(intersection.entityID);
}
var success = false;
for (var i = 0; i < ids.length; i++) {
var entityID = ids[i];
success |= attemptVoxelChangeForEntity(entityID, pickRayDir, intersection.intersection)
}
return success;
}
function mousePressEvent(event) {
if (!event.isLeftButton) {
return;

View file

@ -78,7 +78,7 @@ void StereoDisplayPlugin::activate() {
}
void StereoDisplayPlugin::updateScreen() {
for (int i = 0; i < (int) _screenActions.size(); ++i) {
for (uint32_t i = 0; i < _screenActions.size(); ++i) {
if (_screenActions[i]->isChecked()) {
CONTAINER->setFullscreen(qApp->screens().at(i));
break;

View file

@ -68,6 +68,19 @@ RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() {
}
bool isEdged(PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle) {
switch (surfaceStyle) {
case PolyVoxEntityItem::SURFACE_CUBIC:
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
return false;
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
return true;
}
return false;
}
void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
_voxelDataLock.lockForWrite();
if (_voxelData == voxelData) {
@ -88,10 +101,8 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel
}
// if we are switching to or from "edged" we need to force a resize of _volData.
bool wasEdged = (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES);
bool willBeEdged = (voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES);
bool wasEdged = isEdged(_voxelSurfaceStyle);
bool willBeEdged = isEdged(voxelSurfaceStyle);
if (wasEdged != willBeEdged) {
_volDataLock.lockForWrite();
@ -113,15 +124,10 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
switch (_voxelSurfaceStyle) {
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
case PolyVoxEntityItem::SURFACE_CUBIC:
return scale / 2.0f;
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
return scale / -2.0f;
if (isEdged(_voxelSurfaceStyle)) {
return scale / -2.0f;
}
return glm::vec3(0.0f, 0.0f, 0.0f);
return scale / 2.0f;
}
@ -130,7 +136,7 @@ glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
glm::vec3 center = getCenterPosition();
glm::vec3 position = getPosition();
glm::vec3 positionToCenter = center - position;
positionToCenter -= getDimensions() * glm::vec3(0.5f, 0.5f, 0.5f) - getSurfacePositionAdjustment();
positionToCenter -= getDimensions() * Vectors::HALF - getSurfacePositionAdjustment();
glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
glm::mat4 scaled = glm::scale(centerToCorner, scale);
return scaled;
@ -195,6 +201,37 @@ bool RenderablePolyVoxEntityItem::setAll(uint8_t toValue) {
}
bool RenderablePolyVoxEntityItem::setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue) {
bool result = false;
if (_locked) {
return result;
}
int xLow = std::max(std::min((int)roundf(lowPosition.x), (int)roundf(_voxelVolumeSize.x) - 1), 0);
int yLow = std::max(std::min((int)roundf(lowPosition.y), (int)roundf(_voxelVolumeSize.y) - 1), 0);
int zLow = std::max(std::min((int)roundf(lowPosition.z), (int)roundf(_voxelVolumeSize.z) - 1), 0);
int xHigh = std::max(std::min(xLow + (int)roundf(cuboidSize.x), (int)roundf(_voxelVolumeSize.x)), xLow);
int yHigh = std::max(std::min(yLow + (int)roundf(cuboidSize.y), (int)roundf(_voxelVolumeSize.y)), yLow);
int zHigh = std::max(std::min(zLow + (int)roundf(cuboidSize.z), (int)roundf(_voxelVolumeSize.z)), zLow);
_volDataLock.lockForWrite();
_volDataDirty = true;
for (int x = xLow; x < xHigh; x++) {
for (int y = yLow; y < yHigh; y++) {
for (int z = zLow; z < zHigh; z++) {
result |= setVoxelInternal(x, y, z, toValue);
}
}
}
_volDataLock.unlock();
if (result) {
compressVolumeDataAndSendEditPacket();
}
return result;
}
bool RenderablePolyVoxEntityItem::setVoxelInVolume(glm::vec3 position, uint8_t toValue) {
if (_locked) {
@ -213,7 +250,6 @@ bool RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi
// This three-level for loop iterates over every voxel in the volume
_volDataLock.lockForWrite();
_volDataDirty = true;
for (int z = 0; z < _voxelVolumeSize.z; z++) {
for (int y = 0; y < _voxelVolumeSize.y; y++) {
for (int x = 0; x < _voxelVolumeSize.x; x++) {
@ -228,20 +264,52 @@ bool RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi
}
}
}
_volDataLock.unlock();
if (result) {
_volDataDirty = true;
_volDataLock.unlock();
compressVolumeDataAndSendEditPacket();
} else {
_volDataLock.unlock();
}
return result;
}
bool 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.y;
float radiusVoxelCoords = radiusWorldCoords / scaleY;
return setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue);
bool result = false;
if (_locked) {
return result;
}
glm::mat4 vtwMatrix = voxelToWorldMatrix();
// This three-level for loop iterates over every voxel in the volume
_volDataLock.lockForWrite();
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::vec4 pos(x + 0.5f, y + 0.5f, z + 0.5f, 1.0); // consider voxels cenetered on their coordinates
// convert to world coordinates
glm::vec3 worldPos = glm::vec3(vtwMatrix * pos);
// compute how far the current position is from the center of the volume
float fDistToCenter = glm::distance(worldPos, centerWorldCoords);
// If the current voxel is less than 'radius' units from the center then we set its value
if (fDistToCenter <= radiusWorldCoords) {
result |= setVoxelInternal(x, y, z, toValue);
}
}
}
}
if (result) {
_volDataDirty = true;
_volDataLock.unlock();
compressVolumeDataAndSendEditPacket();
} else {
_volDataLock.unlock();
}
return result;
}
class RaycastFunctor
@ -296,7 +364,6 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
glm::mat4 wtvMatrix = worldToVoxelMatrix();
glm::mat4 vtwMatrix = voxelToWorldMatrix();
glm::mat4 vtlMatrix = voxelToLocalMatrix();
glm::vec3 normDirection = glm::normalize(direction);
// the PolyVox ray intersection code requires a near and far point.
@ -304,67 +371,33 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
float distanceToEntity = glm::distance(origin, getPosition());
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);
glm::vec4 result;
glm::vec4 directionInVoxel = glm::normalize(farInVoxel - originInVoxel);
glm::vec4 result = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
PolyVox::RaycastResult raycastResult = doRayCast(originInVoxel, farInVoxel, result);
if (raycastResult == PolyVox::RaycastResults::Completed) {
// the ray completed its path -- nothing was hit.
return false;
}
// set up ray tests against each face of the voxel.
glm::vec3 minXPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.0f, 0.5f, 0.5f, 0.0f)));
glm::vec3 maxXPosition = glm::vec3(vtwMatrix * (result + glm::vec4(1.0f, 0.5f, 0.5f, 0.0f)));
glm::vec3 minYPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 0.0f, 0.5f, 0.0f)));
glm::vec3 maxYPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 1.0f, 0.5f, 0.0f)));
glm::vec3 minZPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 0.5f, 0.0f, 0.0f)));
glm::vec3 maxZPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 0.5f, 1.0f, 0.0f)));
glm::vec3 result3 = glm::vec3(result);
glm::vec4 baseDimensions = glm::vec4(1.0, 1.0, 1.0, 0.0);
glm::vec3 worldDimensions = glm::vec3(vtlMatrix * baseDimensions);
glm::vec2 xDimensions = glm::vec2(worldDimensions.z, worldDimensions.y);
glm::vec2 yDimensions = glm::vec2(worldDimensions.x, worldDimensions.z);
glm::vec2 zDimensions = glm::vec2(worldDimensions.x, worldDimensions.y);
AABox voxelBox;
voxelBox += result3 - Vectors::HALF;
voxelBox += result3 + Vectors::HALF;
glm::quat vtwRotation = extractRotation(vtwMatrix);
glm::quat minXRotation = vtwRotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f));
glm::quat maxXRotation = vtwRotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f));
glm::quat minYRotation = vtwRotation * glm::quat(glm::vec3(PI_OVER_TWO, 0.0f, 0.0f));
glm::quat maxYRotation = vtwRotation * glm::quat(glm::vec3(PI_OVER_TWO, 0.0f, 0.0f));
glm::quat minZRotation = vtwRotation * glm::quat(glm::vec3(0.0f, 0.0f, 0.0f));
glm::quat maxZRotation = vtwRotation * glm::quat(glm::vec3(0.0f, 0.0f, 0.0f));
float voxelDistance;
float bestDx = FLT_MAX;
bool hit[ 6 ];
float dx[ 6 ] = {FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX};
bool hit = voxelBox.findRayIntersection(glm::vec3(originInVoxel), glm::vec3(directionInVoxel), voxelDistance, face);
hit[0] = findRayRectangleIntersection(origin, direction, minXRotation, minXPosition, xDimensions, dx[0]);
hit[1] = findRayRectangleIntersection(origin, direction, maxXRotation, maxXPosition, xDimensions, dx[1]);
hit[2] = findRayRectangleIntersection(origin, direction, minYRotation, minYPosition, yDimensions, dx[2]);
hit[3] = findRayRectangleIntersection(origin, direction, maxYRotation, maxYPosition, yDimensions, dx[3]);
hit[4] = findRayRectangleIntersection(origin, direction, minZRotation, minZPosition, zDimensions, dx[4]);
hit[5] = findRayRectangleIntersection(origin, direction, maxZRotation, maxZPosition, zDimensions, dx[5]);
bool ok = false;
for (int i = 0; i < 6; i ++) {
if (hit[ i ] && dx[ i ] < bestDx) {
face = (BoxFace)i;
distance = dx[ i ];
ok = true;
bestDx = dx[ i ];
}
}
if (!ok) {
// if the attempt to put the ray against one of the voxel-faces fails, just return the center
glm::vec4 intersectedWorldPosition = vtwMatrix * (result + vec4(0.5f, 0.5f, 0.5f, 0.0f));
distance = glm::distance(glm::vec3(intersectedWorldPosition), origin);
face = BoxFace::MIN_X_FACE;
}
return true;
glm::vec4 voxelIntersectionPoint = glm::vec4(glm::vec3(originInVoxel) + glm::vec3(directionInVoxel) * voxelDistance, 1.0);
glm::vec4 intersectionPoint = vtwMatrix * voxelIntersectionPoint;
distance = glm::distance(origin, glm::vec3(intersectionPoint));
return hit;
}
@ -380,7 +413,7 @@ PolyVox::RaycastResult RenderablePolyVoxEntityItem::doRayCast(glm::vec4 originIn
_volDataLock.unlock();
// result is in voxel-space coordinates.
result = callback._result - glm::vec4(0.5f, 0.5f, 0.5f, 0.0f);
result = callback._result;
return raycastResult;
}
@ -402,21 +435,29 @@ bool RenderablePolyVoxEntityItem::isReadyToComputeShape() {
}
void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
_shapeInfoLock.lockForRead();
QReadLocker(&this->_shapeInfoLock);
info = _shapeInfo;
_shapeInfoLock.unlock();
}
void RenderablePolyVoxEntityItem::setXTextureURL(QString xTextureURL) {
PolyVoxEntityItem::setXTextureURL(xTextureURL);
if (xTextureURL != _xTextureURL) {
_xTexture.clear();
PolyVoxEntityItem::setXTextureURL(xTextureURL);
}
}
void RenderablePolyVoxEntityItem::setYTextureURL(QString yTextureURL) {
PolyVoxEntityItem::setYTextureURL(yTextureURL);
if (yTextureURL != _yTextureURL) {
_yTexture.clear();
PolyVoxEntityItem::setYTextureURL(yTextureURL);
}
}
void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) {
PolyVoxEntityItem::setZTextureURL(zTextureURL);
if (zTextureURL != _zTextureURL) {
_zTexture.clear();
PolyVoxEntityItem::setZTextureURL(zTextureURL);
}
}
void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
@ -426,9 +467,12 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
_volDataLock.lockForRead();
if (_volDataDirty) {
_volDataLock.unlock();
getMesh();
} else {
_volDataLock.unlock();
}
_volDataLock.unlock();
_meshLock.lockForRead();
model::MeshPointer mesh = _mesh;
@ -543,23 +587,21 @@ namespace render {
glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToWorldCoords(glm::vec3& voxelCoords) const {
return glm::vec3(voxelToWorldMatrix() * glm::vec4(voxelCoords, 1.0f));
glm::vec3 adjustedCoords;
if (isEdged(_voxelSurfaceStyle)) {
adjustedCoords = voxelCoords + Vectors::HALF;
} else {
adjustedCoords = voxelCoords - Vectors::HALF;
}
return glm::vec3(voxelToWorldMatrix() * glm::vec4(adjustedCoords, 1.0f));
}
glm::vec3 RenderablePolyVoxEntityItem::worldCoordsToVoxelCoords(glm::vec3& worldCoords) const {
glm::vec3 result = glm::vec3(worldToVoxelMatrix() * glm::vec4(worldCoords, 1.0f));
switch (_voxelSurfaceStyle) {
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
case PolyVoxEntityItem::SURFACE_CUBIC:
result += glm::vec3(0.5f, 0.5f, 0.5f);
break;
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
result -= glm::vec3(0.5f, 0.5f, 0.5f);
break;
if (isEdged(_voxelSurfaceStyle)) {
return result - Vectors::HALF;
}
return result;
return result + Vectors::HALF;
}
glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const {
@ -585,8 +627,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize)
}
_onCount = 0;
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
if (isEdged(_voxelSurfaceStyle)) {
// 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
@ -598,9 +639,11 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize)
_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);
// these should each have -1 after them, but if we leave layers on the upper-axis faces,
// they act more like I expect.
PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x,
_voxelVolumeSize.y,
_voxelVolumeSize.z);
_volData = new PolyVox::SimpleVolume<uint8_t>(PolyVox::Region(lowCorner, highCorner));
}
@ -613,35 +656,27 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize)
bool RenderablePolyVoxEntityItem::inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol,
PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
int x, int y, int z) {
int x, int y, int z) const {
// 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:
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
if (x < 0 || y < 0 || z < 0 ||
x >= vol->getWidth() - 2 || y >= vol->getHeight() - 2 || z >= vol->getDepth() - 2) {
return false;
}
return true;
if (isEdged(surfaceStyle)) {
if (x < 0 || y < 0 || z < 0 ||
x >= vol->getWidth() - 2 || y >= vol->getHeight() - 2 || z >= vol->getDepth() - 2) {
return false;
}
return true;
} else {
if (x < 0 || y < 0 || z < 0 ||
x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()) {
return false;
}
return true;
}
return false;
}
uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) {
_volDataLock.lockForRead();
auto result = getVoxelInternal(x, y, z);
_volDataLock.unlock();
return result;
QReadLocker(&this->_volDataLock);
return getVoxelInternal(x, y, z);
}
@ -650,19 +685,13 @@ uint8_t RenderablePolyVoxEntityItem::getVoxelInternal(int x, int y, int z) {
return 0;
}
// if _voxelSurfaceStyle is SURFACE_EDGED_CUBIC, we maintain an extra layer of
// if _voxelSurfaceStyle is *_EDGED_*, 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.
uint8_t result;
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
result = _volData->getVoxelAt(x + 1, y + 1, z + 1);
} else {
result = _volData->getVoxelAt(x, y, z);
if (isEdged(_voxelSurfaceStyle)) {
return _volData->getVoxelAt(x + 1, y + 1, z + 1);
}
return result;
return _volData->getVoxelAt(x, y, z);
}
@ -675,9 +704,7 @@ bool RenderablePolyVoxEntityItem::setVoxelInternal(int x, int y, int z, uint8_t
result = updateOnCount(x, y, z, toValue);
assert(_volData);
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
if (isEdged(_voxelSurfaceStyle)) {
_volData->setVoxelAt(x + 1, y + 1, z + 1, toValue);
} else {
_volData->setVoxelAt(x, y, z, toValue);
@ -710,13 +737,11 @@ bool RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toV
return false;
}
void RenderablePolyVoxEntityItem::decompressVolumeData() {
_threadRunning.acquire();
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::decompressVolumeDataAsync);
}
// take compressed data and expand it into _volData.
void RenderablePolyVoxEntityItem::decompressVolumeDataAsync() {
_voxelDataLock.lockForRead();
@ -777,7 +802,6 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() {
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacketAsync);
}
// 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::compressVolumeDataAndSendEditPacketAsync() {
@ -850,23 +874,157 @@ void RenderablePolyVoxEntityItem::getMesh() {
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::getMeshAsync);
}
void RenderablePolyVoxEntityItem::clearOutOfDateNeighbors() {
if (_xNNeighborID != UNKNOWN_ENTITY_ID) {
EntityItemPointer currentXNNeighbor = _xNNeighbor.lock();
if (currentXNNeighbor && currentXNNeighbor->getID() != _xNNeighborID) {
_xNNeighbor.reset();
}
}
if (_yNNeighborID != UNKNOWN_ENTITY_ID) {
EntityItemPointer currentYNNeighbor = _yNNeighbor.lock();
if (currentYNNeighbor && currentYNNeighbor->getID() != _yNNeighborID) {
_yNNeighbor.reset();
}
}
if (_zNNeighborID != UNKNOWN_ENTITY_ID) {
EntityItemPointer currentZNNeighbor = _zNNeighbor.lock();
if (currentZNNeighbor && currentZNNeighbor->getID() != _zNNeighborID) {
_zNNeighbor.reset();
}
}
if (_xPNeighborID != UNKNOWN_ENTITY_ID) {
EntityItemPointer currentXPNeighbor = _xPNeighbor.lock();
if (currentXPNeighbor && currentXPNeighbor->getID() != _xPNeighborID) {
_xPNeighbor.reset();
}
}
if (_yPNeighborID != UNKNOWN_ENTITY_ID) {
EntityItemPointer currentYPNeighbor = _yPNeighbor.lock();
if (currentYPNeighbor && currentYPNeighbor->getID() != _yPNeighborID) {
_yPNeighbor.reset();
}
}
if (_zPNeighborID != UNKNOWN_ENTITY_ID) {
EntityItemPointer currentZPNeighbor = _zPNeighbor.lock();
if (currentZPNeighbor && currentZPNeighbor->getID() != _zPNeighborID) {
_zPNeighbor.reset();
}
}
}
void RenderablePolyVoxEntityItem::cacheNeighbors() {
clearOutOfDateNeighbors();
EntityTreeElement* element = getElement();
EntityTree* tree = element ? element->getTree() : nullptr;
if (!tree) {
return;
}
if (_xNNeighborID != UNKNOWN_ENTITY_ID && _xNNeighbor.expired()) {
_xNNeighbor = tree->findEntityByID(_xNNeighborID);
}
if (_yNNeighborID != UNKNOWN_ENTITY_ID && _yNNeighbor.expired()) {
_yNNeighbor = tree->findEntityByID(_yNNeighborID);
}
if (_zNNeighborID != UNKNOWN_ENTITY_ID && _zNNeighbor.expired()) {
_zNNeighbor = tree->findEntityByID(_zNNeighborID);
}
if (_xPNeighborID != UNKNOWN_ENTITY_ID && _xPNeighbor.expired()) {
_xPNeighbor = tree->findEntityByID(_xPNeighborID);
}
if (_yPNeighborID != UNKNOWN_ENTITY_ID && _yPNeighbor.expired()) {
_yPNeighbor = tree->findEntityByID(_yPNeighborID);
}
if (_zPNeighborID != UNKNOWN_ENTITY_ID && _zPNeighbor.expired()) {
_zPNeighbor = tree->findEntityByID(_zPNeighborID);
}
}
void RenderablePolyVoxEntityItem::copyUpperEdgesFromNeighbors() {
if (_voxelSurfaceStyle != PolyVoxEntityItem::SURFACE_MARCHING_CUBES) {
return;
}
EntityItemPointer currentXPNeighbor = _xPNeighbor.lock();
EntityItemPointer currentYPNeighbor = _yPNeighbor.lock();
EntityItemPointer currentZPNeighbor = _zPNeighbor.lock();
if (currentXPNeighbor) {
auto polyVoxXPNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentXPNeighbor);
if (polyVoxXPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
for (int y = 0; y < _volData->getHeight(); y++) {
for (int z = 0; z < _volData->getDepth(); z++) {
uint8_t neighborValue = polyVoxXPNeighbor->getVoxel(0, y, z);
_volData->setVoxelAt(_volData->getWidth() - 1, y, z, neighborValue);
}
}
}
}
if (currentYPNeighbor) {
auto polyVoxYPNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentYPNeighbor);
if (polyVoxYPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
for (int x = 0; x < _volData->getWidth(); x++) {
for (int z = 0; z < _volData->getDepth(); z++) {
uint8_t neighborValue = polyVoxYPNeighbor->getVoxel(x, 0, z);
_volData->setVoxelAt(x, _volData->getWidth() - 1, z, neighborValue);
}
}
}
}
if (currentZPNeighbor) {
auto polyVoxZPNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentZPNeighbor);
if (polyVoxZPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
for (int x = 0; x < _volData->getWidth(); x++) {
for (int y = 0; y < _volData->getHeight(); y++) {
uint8_t neighborValue = polyVoxZPNeighbor->getVoxel(x, y, 0);
_volData->setVoxelAt(x, y, _volData->getDepth() - 1, neighborValue);
}
}
}
}
}
void RenderablePolyVoxEntityItem::getMeshAsync() {
model::MeshPointer mesh(new model::Mesh());
cacheNeighbors();
// A mesh object to hold the result of surface extraction
PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> polyVoxMesh;
_volDataLock.lockForRead();
if (!_volData) {
_volDataLock.unlock();
return;
}
copyUpperEdgesFromNeighbors();
switch (_voxelSurfaceStyle) {
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: {
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
surfaceExtractor.execute();
break;
}
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: {
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
surfaceExtractor.execute();
break;
}
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: {
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
surfaceExtractor.execute();
break;
}
case PolyVoxEntityItem::SURFACE_CUBIC: {
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
@ -908,7 +1066,7 @@ void RenderablePolyVoxEntityItem::getMeshAsync() {
_meshLock.unlock();
_volDataDirty = false;
_volDataLock.unlock();
bonkNeighbors();
_threadRunning.release();
}
@ -925,7 +1083,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_MARCHING_CUBES ||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
/* pull each triangle in the mesh into a polyhedron which can be collided with */
// pull each triangle in the mesh into a polyhedron which can be collided with
unsigned int i = 0;
_meshLock.lockForRead();
@ -972,10 +1130,16 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
} else {
unsigned int i = 0;
_volDataLock.lockForRead();
if (!_volData) {
_volDataLock.unlock();
return;
}
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) {
if (getVoxelInternal(x, y, z) > 0) {
if ((x > 0 && getVoxel(x - 1, y, z) > 0) &&
(y > 0 && getVoxel(x, y - 1, z) > 0) &&
@ -1033,6 +1197,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
}
}
}
_volDataLock.unlock();
}
if (points.isEmpty()) {
@ -1056,3 +1221,93 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
_threadRunning.release();
return;
}
void RenderablePolyVoxEntityItem::setXNNeighborID(const EntityItemID& xNNeighborID) {
if (xNNeighborID != _xNNeighborID) {
PolyVoxEntityItem::setXNNeighborID(xNNeighborID);
cacheNeighbors();
EntityItemPointer currentXNNeighbor = _xNNeighbor.lock();
if (currentXNNeighbor && currentXNNeighbor->getType() == EntityTypes::PolyVox) {
auto polyVoxXNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentXNNeighbor);
polyVoxXNNeighbor->setXPNeighborID(_id);
polyVoxXNNeighbor->rebakeMesh();
}
}
}
void RenderablePolyVoxEntityItem::setYNNeighborID(const EntityItemID& yNNeighborID) {
if (yNNeighborID != _yNNeighborID) {
PolyVoxEntityItem::setYNNeighborID(yNNeighborID);
cacheNeighbors();
EntityItemPointer currentYNNeighbor = _yNNeighbor.lock();
if (currentYNNeighbor && currentYNNeighbor->getType() == EntityTypes::PolyVox) {
auto polyVoxYNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentYNNeighbor);
polyVoxYNNeighbor->setYPNeighborID(_id);
polyVoxYNNeighbor->rebakeMesh();
}
}
}
void RenderablePolyVoxEntityItem::setZNNeighborID(const EntityItemID& zNNeighborID) {
if (zNNeighborID != _zNNeighborID) {
PolyVoxEntityItem::setZNNeighborID(zNNeighborID);
cacheNeighbors();
EntityItemPointer currentZNNeighbor = _yNNeighbor.lock();
if (currentZNNeighbor && currentZNNeighbor->getType() == EntityTypes::PolyVox) {
auto polyVoxZNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentZNNeighbor);
polyVoxZNNeighbor->setZPNeighborID(_id);
polyVoxZNNeighbor->rebakeMesh();
}
}
}
void RenderablePolyVoxEntityItem::setXPNeighborID(const EntityItemID& xPNeighborID) {
if (xPNeighborID != _xPNeighborID) {
PolyVoxEntityItem::setXPNeighborID(xPNeighborID);
rebakeMesh();
}
}
void RenderablePolyVoxEntityItem::setYPNeighborID(const EntityItemID& yPNeighborID) {
if (yPNeighborID != _yPNeighborID) {
PolyVoxEntityItem::setYPNeighborID(yPNeighborID);
rebakeMesh();
}
}
void RenderablePolyVoxEntityItem::setZPNeighborID(const EntityItemID& zPNeighborID) {
if (zPNeighborID != _zPNeighborID) {
PolyVoxEntityItem::setZPNeighborID(zPNeighborID);
rebakeMesh();
}
}
void RenderablePolyVoxEntityItem::rebakeMesh() {
QReadLocker(&this->_volDataLock);
_volDataDirty = true;
}
void RenderablePolyVoxEntityItem::bonkNeighbors() {
clearOutOfDateNeighbors();
cacheNeighbors();
EntityItemPointer currentXNNeighbor = _xNNeighbor.lock();
EntityItemPointer currentYNNeighbor = _yNNeighbor.lock();
EntityItemPointer currentZNNeighbor = _zNNeighbor.lock();
if (currentXNNeighbor && currentXNNeighbor->getType() == EntityTypes::PolyVox) {
auto polyVoxXNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentXNNeighbor);
polyVoxXNNeighbor->rebakeMesh();
}
if (currentYNNeighbor && currentYNNeighbor->getType() == EntityTypes::PolyVox) {
auto polyVoxYNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentYNNeighbor);
polyVoxYNNeighbor->rebakeMesh();
}
if (currentZNNeighbor && currentZNNeighbor->getType() == EntityTypes::PolyVox) {
auto polyVoxZNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentZNNeighbor);
polyVoxZNNeighbor->rebakeMesh();
}
}

View file

@ -93,6 +93,7 @@ public:
// coords are in world-space
virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue);
virtual bool setAll(uint8_t toValue);
virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue);
virtual void setXTextureURL(QString xTextureURL);
virtual void setYTextureURL(QString yTextureURL);
@ -105,6 +106,16 @@ public:
std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges);
virtual void setXNNeighborID(const EntityItemID& xNNeighborID);
virtual void setYNNeighborID(const EntityItemID& yNNeighborID);
virtual void setZNNeighborID(const EntityItemID& zNNeighborID);
virtual void setXPNeighborID(const EntityItemID& xPNeighborID);
virtual void setYPNeighborID(const EntityItemID& yPNeighborID);
virtual void setZPNeighborID(const EntityItemID& zPNeighborID);
virtual void rebakeMesh();
private:
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
// may not match _voxelVolumeSize.
@ -130,7 +141,7 @@ private:
int _onCount; // how many non-zero voxels are in _volData
bool inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
int x, int y, int z);
int x, int y, int z) const;
uint8_t getVoxelInternal(int x, int y, int z);
bool setVoxelInternal(int x, int y, int z, uint8_t toValue);
bool updateOnCount(int x, int y, int z, uint8_t toValue);
@ -147,6 +158,18 @@ private:
void computeShapeInfoWorkerAsync();
QSemaphore _threadRunning{1};
// these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID
EntityItemWeakPointer _xNNeighbor; // neighor found by going along negative X axis
EntityItemWeakPointer _yNNeighbor;
EntityItemWeakPointer _zNNeighbor;
EntityItemWeakPointer _xPNeighbor; // neighor found by going along positive X axis
EntityItemWeakPointer _yPNeighbor;
EntityItemWeakPointer _zPNeighbor;
void clearOutOfDateNeighbors();
void cacheNeighbors();
void copyUpperEdgesFromNeighbors();
void bonkNeighbors();
};

View file

@ -12,16 +12,12 @@
//
<@include gpu/Inputs.slh@>
layout(location = 0) out vec4 _fragColor0;
layout(location = 1) out vec4 _fragColor1;
layout(location = 2) out vec4 _fragColor2;
<@include model/Material.slh@>
<@include DeferredBufferWrite.slh@>
in vec3 _normal;
in vec4 _position;
in vec4 _inPosition;
in vec4 _worldPosition;
uniform sampler2D xMap;
uniform sampler2D yMap;
@ -29,12 +25,12 @@ uniform sampler2D zMap;
uniform vec3 voxelVolumeSize;
void main(void) {
vec3 worldNormal = cross(dFdy(_inPosition.xyz), dFdx(_inPosition.xyz));
vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz));
worldNormal = normalize(worldNormal);
float inPositionX = (_inPosition.x - 0.5) / voxelVolumeSize.x;
float inPositionY = (_inPosition.y - 0.5) / voxelVolumeSize.y;
float inPositionZ = (_inPosition.z - 0.5) / voxelVolumeSize.z;
float inPositionX = (_worldPosition.x - 0.5) / voxelVolumeSize.x;
float inPositionY = (_worldPosition.y - 0.5) / voxelVolumeSize.y;
float inPositionZ = (_worldPosition.z - 0.5) / voxelVolumeSize.z;
vec4 xyDiffuse = texture(xMap, vec2(-inPositionX, -inPositionY));
vec4 xzDiffuse = texture(yMap, vec2(-inPositionX, inPositionZ));
@ -43,12 +39,7 @@ void main(void) {
vec3 xyDiffuseScaled = xyDiffuse.rgb * abs(worldNormal.z);
vec3 xzDiffuseScaled = xzDiffuse.rgb * abs(worldNormal.y);
vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x);
vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0);
Material mat = getMaterial();
_fragColor0 = vec4(diffuse.rgb, 0.0);
_fragColor1 = vec4(_normal, 1.0);
_fragColor2 = vec4(getMaterialSpecular(mat), getMaterialShininess(mat) / 128.0);
packDeferredFragment(_normal, 0.0, vec3(diffuse), vec3(0.01, 0.01, 0.01), 10.0);
}

View file

@ -17,7 +17,7 @@
<$declareStandardTransform()$>
out vec4 _position;
out vec4 _inPosition;
out vec4 _worldPosition;
out vec3 _normal;
void main(void) {
@ -26,5 +26,5 @@ void main(void) {
TransformObject obj = getTransformObject();
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
<$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
_inPosition = inPosition;
_worldPosition = inPosition;
}

View file

@ -32,26 +32,8 @@ public:
QScriptValue toScriptValue(QScriptEngine* engine) const;
bool isInvalidID() const { return *this == UNKNOWN_ENTITY_ID; }
// QUuid id;
};
// inline bool operator<(const EntityItemID& a, const EntityItemID& b) {
// return a.id < b.id;
// }
// inline bool operator==(const EntityItemID& a, const EntityItemID& b) {
// return a.id == b.id;
// }
// inline bool operator!=(const EntityItemID& a, const EntityItemID& b) {
// return !(a == b);
// }
// inline uint qHash(const EntityItemID& a, uint seed) {
// return qHash(a.id, seed);
// }
inline QDebug operator<<(QDebug debug, const EntityItemID& id) {
debug << "[entity-id:" << id.toString() << "]";
return debug;

View file

@ -109,6 +109,13 @@ CONSTRUCT_PROPERTY(strokeWidths, QVector<float>()),
CONSTRUCT_PROPERTY(xTextureURL, ""),
CONSTRUCT_PROPERTY(yTextureURL, ""),
CONSTRUCT_PROPERTY(zTextureURL, ""),
CONSTRUCT_PROPERTY(xNNeighborID, UNKNOWN_ENTITY_ID),
CONSTRUCT_PROPERTY(yNNeighborID, UNKNOWN_ENTITY_ID),
CONSTRUCT_PROPERTY(zNNeighborID, UNKNOWN_ENTITY_ID),
CONSTRUCT_PROPERTY(xPNeighborID, UNKNOWN_ENTITY_ID),
CONSTRUCT_PROPERTY(yPNeighborID, UNKNOWN_ENTITY_ID),
CONSTRUCT_PROPERTY(zPNeighborID, UNKNOWN_ENTITY_ID),
_id(UNKNOWN_ENTITY_ID),
_idSet(false),
@ -377,6 +384,12 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_X_TEXTURE_URL, xTextureURL);
CHECK_PROPERTY_CHANGE(PROP_Y_TEXTURE_URL, yTextureURL);
CHECK_PROPERTY_CHANGE(PROP_Z_TEXTURE_URL, zTextureURL);
CHECK_PROPERTY_CHANGE(PROP_X_N_NEIGHBOR_ID, xNNeighborID);
CHECK_PROPERTY_CHANGE(PROP_Y_N_NEIGHBOR_ID, yNNeighborID);
CHECK_PROPERTY_CHANGE(PROP_Z_N_NEIGHBOR_ID, zNNeighborID);
CHECK_PROPERTY_CHANGE(PROP_X_P_NEIGHBOR_ID, xPNeighborID);
CHECK_PROPERTY_CHANGE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID);
CHECK_PROPERTY_CHANGE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID);
changedProperties += _stage.getChangedProperties();
changedProperties += _atmosphere.getChangedProperties();
@ -521,6 +534,14 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(yTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(zTextureURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(xNNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(yNNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(zNNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(xPNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(yPNeighborID);
COPY_PROPERTY_TO_QSCRIPTVALUE(zPNeighborID);
return properties;
}
@ -620,6 +641,14 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(zTextureURL, QString, setZTextureURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(xNNeighborID, EntityItemID, setXNNeighborID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(yNNeighborID, EntityItemID, setYNNeighborID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(zNNeighborID, EntityItemID, setZNNeighborID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(xPNeighborID, EntityItemID, setXPNeighborID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(yPNeighborID, EntityItemID, setYPNeighborID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(zPNeighborID, EntityItemID, setZPNeighborID);
_lastEdited = usecTimestampNow();
}
@ -852,6 +881,12 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent
APPEND_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, properties.getXTextureURL());
APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, properties.getYTextureURL());
APPEND_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, properties.getZTextureURL());
APPEND_ENTITY_PROPERTY(PROP_X_N_NEIGHBOR_ID, properties.getXNNeighborID());
APPEND_ENTITY_PROPERTY(PROP_Y_N_NEIGHBOR_ID, properties.getYNNeighborID());
APPEND_ENTITY_PROPERTY(PROP_Z_N_NEIGHBOR_ID, properties.getZNNeighborID());
APPEND_ENTITY_PROPERTY(PROP_X_P_NEIGHBOR_ID, properties.getXPNeighborID());
APPEND_ENTITY_PROPERTY(PROP_Y_P_NEIGHBOR_ID, properties.getYPNeighborID());
APPEND_ENTITY_PROPERTY(PROP_Z_P_NEIGHBOR_ID, properties.getZPNeighborID());
}
if (properties.getType() == EntityTypes::Line) {
@ -1115,6 +1150,12 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_X_TEXTURE_URL, QString, setXTextureURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_TEXTURE_URL, QString, setYTextureURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Z_TEXTURE_URL, QString, setZTextureURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_X_N_NEIGHBOR_ID, EntityItemID, setXNNeighborID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_N_NEIGHBOR_ID, EntityItemID, setYNNeighborID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Z_N_NEIGHBOR_ID, EntityItemID, setZNNeighborID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_X_P_NEIGHBOR_ID, EntityItemID, setXPNeighborID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_P_NEIGHBOR_ID, EntityItemID, setYPNeighborID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Z_P_NEIGHBOR_ID, EntityItemID, setZPNeighborID);
}
if (properties.getType() == EntityTypes::Line) {
@ -1248,13 +1289,21 @@ void EntityItemProperties::markAllChanged() {
_descriptionChanged = true;
_faceCameraChanged = true;
_actionDataChanged = true;
_normalsChanged = true;
_strokeWidthsChanged = true;
_xTextureURLChanged = true;
_yTextureURLChanged = true;
_zTextureURLChanged = true;
_xNNeighborIDChanged = true;
_yNNeighborIDChanged = true;
_zNNeighborIDChanged = true;
_xPNeighborIDChanged = true;
_yPNeighborIDChanged = true;
_zPNeighborIDChanged = true;
}
/// The maximum bounding cube for the entity, independent of it's rotation.

View file

@ -161,6 +161,12 @@ public:
DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString);
DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString);
DEFINE_PROPERTY_REF(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString);
DEFINE_PROPERTY_REF(PROP_X_N_NEIGHBOR_ID, XNNeighborID, xNNeighborID, EntityItemID);
DEFINE_PROPERTY_REF(PROP_Y_N_NEIGHBOR_ID, YNNeighborID, yNNeighborID, EntityItemID);
DEFINE_PROPERTY_REF(PROP_Z_N_NEIGHBOR_ID, ZNNeighborID, zNNeighborID, EntityItemID);
DEFINE_PROPERTY_REF(PROP_X_P_NEIGHBOR_ID, XPNeighborID, xPNeighborID, EntityItemID);
DEFINE_PROPERTY_REF(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID);
DEFINE_PROPERTY_REF(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID);
static QString getBackgroundModeString(BackgroundMode mode);
@ -327,6 +333,12 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, XTextureURL, xTextureURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, YTextureURL, yTextureURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZTextureURL, zTextureURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, XNNeighborID, xNNeighborID, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, YNNeighborID, yNNeighborID, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZNNeighborID, zNNeighborID, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, XPNeighborID, xPNeighborID, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, YPNeighborID, yPNeighborID, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZPNeighborID, zPNeighborID, "");
properties.getStage().debugDump();
properties.getAtmosphere().debugDump();

View file

@ -14,6 +14,8 @@
#ifndef hifi_EntityItemPropertiesMacros_h
#define hifi_EntityItemPropertiesMacros_h
#include "EntityItemID.h"
#define APPEND_ENTITY_PROPERTY(P,V) \
if (requestedProperties.getHasProperty(P)) { \
LevelDetails propertyLevel = packetData->startLevel(); \
@ -106,6 +108,9 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
return QScriptValue(QString(b64));
}
inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v) { return QScriptValue(QUuid(v).toString()); }
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
QScriptValue groupProperties = properties.property(#g); \
@ -143,6 +148,9 @@ inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { re
inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }
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 EntityItemID EntityItemID_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
inline QDateTime QDateTime_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true;

View file

@ -124,21 +124,28 @@ enum EntityPropertyList {
PROP_FACE_CAMERA,
PROP_SCRIPT_TIMESTAMP,
PROP_ACTION_DATA,
PROP_X_TEXTURE_URL, // used by PolyVox
PROP_Y_TEXTURE_URL, // used by PolyVox
PROP_Z_TEXTURE_URL, // used by PolyVox
// Used by PolyLine entity
PROP_NORMALS,
PROP_STROKE_WIDTHS,
// used by particles
PROP_VELOCITY_SPREAD,
PROP_ACCELERATION_SPREAD,
PROP_X_N_NEIGHBOR_ID, // used by PolyVox
PROP_Y_N_NEIGHBOR_ID, // used by PolyVox
PROP_Z_N_NEIGHBOR_ID, // used by PolyVox
PROP_X_P_NEIGHBOR_ID, // used by PolyVox
PROP_Y_P_NEIGHBOR_ID, // used by PolyVox
PROP_Z_P_NEIGHBOR_ID, // used by PolyVox
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM,

View file

@ -493,6 +493,13 @@ bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) {
});
}
bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition,
const glm::vec3& cuboidSize, int value) {
return setVoxels(entityID, [lowPosition, cuboidSize, value](PolyVoxEntityItem& polyVoxEntity) {
return polyVoxEntity.setCuboid(lowPosition, cuboidSize, value);
});
}
bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
if (!entity) {

View file

@ -122,6 +122,8 @@ public slots:
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 bool setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition,
const glm::vec3& cuboidSize, int value);
Q_INVOKABLE bool setAllPoints(QUuid entityID, const QVector<glm::vec3>& points);
Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point);

View file

@ -12,6 +12,7 @@
#include <QByteArray>
#include <QDebug>
#include <QWriteLocker>
#include <ByteCountCoding.h>
@ -56,13 +57,14 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const Ent
_voxelSurfaceStyle(PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE),
_xTextureURL(PolyVoxEntityItem::DEFAULT_X_TEXTURE_URL),
_yTextureURL(PolyVoxEntityItem::DEFAULT_Y_TEXTURE_URL),
_zTextureURL(PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL)
{
_zTextureURL(PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL) {
_type = EntityTypes::PolyVox;
setProperties(properties);
}
void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
QWriteLocker(&this->_voxelDataLock);
assert((int)_voxelVolumeSize.x == _voxelVolumeSize.x);
assert((int)_voxelVolumeSize.y == _voxelVolumeSize.y);
assert((int)_voxelVolumeSize.z == _voxelVolumeSize.z);
@ -96,6 +98,12 @@ void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
}
}
const glm::vec3& PolyVoxEntityItem::getVoxelVolumeSize() const {
QWriteLocker locker(&this->_voxelDataLock);
return _voxelVolumeSize;
}
EntityItemProperties PolyVoxEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize);
@ -104,6 +112,12 @@ EntityItemProperties PolyVoxEntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(xTextureURL, getXTextureURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(yTextureURL, getYTextureURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(zTextureURL, getZTextureURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(xNNeighborID, getXNNeighborID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(yNNeighborID, getYNNeighborID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(zNNeighborID, getZNNeighborID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(xPNeighborID, getXPNeighborID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(yPNeighborID, getYPNeighborID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(zPNeighborID, getZPNeighborID);
return properties;
}
@ -116,6 +130,12 @@ bool PolyVoxEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(xTextureURL, setXTextureURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(yTextureURL, setYTextureURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(zTextureURL, setZTextureURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(xNNeighborID, setXNNeighborID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(yNNeighborID, setYNNeighborID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(zNNeighborID, setZNNeighborID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(xPNeighborID, setXPNeighborID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(yPNeighborID, setYPNeighborID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(zPNeighborID, setZPNeighborID);
if (somethingChanged) {
bool wantDebug = false;
@ -143,6 +163,12 @@ int PolyVoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* dat
READ_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, QString, setXTextureURL);
READ_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, QString, setYTextureURL);
READ_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, QString, setZTextureURL);
READ_ENTITY_PROPERTY(PROP_X_N_NEIGHBOR_ID, EntityItemID, setXNNeighborID);
READ_ENTITY_PROPERTY(PROP_Y_N_NEIGHBOR_ID, EntityItemID, setYNNeighborID);
READ_ENTITY_PROPERTY(PROP_Z_N_NEIGHBOR_ID, EntityItemID, setZNNeighborID);
READ_ENTITY_PROPERTY(PROP_X_P_NEIGHBOR_ID, EntityItemID, setXPNeighborID);
READ_ENTITY_PROPERTY(PROP_Y_P_NEIGHBOR_ID, EntityItemID, setYPNeighborID);
READ_ENTITY_PROPERTY(PROP_Z_P_NEIGHBOR_ID, EntityItemID, setZPNeighborID);
return bytesRead;
}
@ -157,16 +183,22 @@ EntityPropertyFlags PolyVoxEntityItem::getEntityProperties(EncodeBitstreamParams
requestedProperties += PROP_X_TEXTURE_URL;
requestedProperties += PROP_Y_TEXTURE_URL;
requestedProperties += PROP_Z_TEXTURE_URL;
requestedProperties += PROP_X_N_NEIGHBOR_ID;
requestedProperties += PROP_Y_N_NEIGHBOR_ID;
requestedProperties += PROP_Z_N_NEIGHBOR_ID;
requestedProperties += PROP_X_P_NEIGHBOR_ID;
requestedProperties += PROP_Y_P_NEIGHBOR_ID;
requestedProperties += PROP_Z_P_NEIGHBOR_ID;
return requestedProperties;
}
void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, getVoxelVolumeSize());
@ -175,7 +207,12 @@ void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeB
APPEND_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, getXTextureURL());
APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, getYTextureURL());
APPEND_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, getZTextureURL());
APPEND_ENTITY_PROPERTY(PROP_X_N_NEIGHBOR_ID, getXNNeighborID());
APPEND_ENTITY_PROPERTY(PROP_Y_N_NEIGHBOR_ID, getYNNeighborID());
APPEND_ENTITY_PROPERTY(PROP_Z_N_NEIGHBOR_ID, getZNNeighborID());
APPEND_ENTITY_PROPERTY(PROP_X_P_NEIGHBOR_ID, getXPNeighborID());
APPEND_ENTITY_PROPERTY(PROP_Y_P_NEIGHBOR_ID, getYPNeighborID());
APPEND_ENTITY_PROPERTY(PROP_Z_P_NEIGHBOR_ID, getZPNeighborID());
}
void PolyVoxEntityItem::debugDump() const {
@ -187,15 +224,12 @@ void PolyVoxEntityItem::debugDump() const {
}
void PolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
_voxelDataLock.lockForWrite();
QWriteLocker(&this->_voxelDataLock);
_voxelData = voxelData;
_voxelDataDirty = true;
_voxelDataLock.unlock();
}
const QByteArray PolyVoxEntityItem::getVoxelData() const {
_voxelDataLock.lockForRead();
auto result = _voxelData;
_voxelDataLock.unlock();
return result;
QReadLocker(&this->_voxelDataLock);
return _voxelData;
}

View file

@ -50,7 +50,7 @@ class PolyVoxEntityItem : public EntityItem {
virtual void debugDump() const;
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
virtual const glm::vec3& getVoxelVolumeSize() const { return _voxelVolumeSize; }
virtual const glm::vec3& getVoxelVolumeSize() const;
virtual void setVoxelData(QByteArray voxelData);
virtual const QByteArray getVoxelData() const;
@ -85,6 +85,7 @@ class PolyVoxEntityItem : public EntityItem {
// coords are in world-space
virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) { return false; }
virtual bool setAll(uint8_t toValue) { return false; }
virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int value) { return false; }
virtual uint8_t getVoxel(int x, int y, int z) { return 0; }
virtual bool setVoxel(int x, int y, int z, uint8_t toValue) { return false; }
@ -103,6 +104,28 @@ class PolyVoxEntityItem : public EntityItem {
virtual void setZTextureURL(QString zTextureURL) { _zTextureURL = zTextureURL; }
virtual const QString& getZTextureURL() const { return _zTextureURL; }
virtual void setXNNeighborID(const EntityItemID& xNNeighborID) { _xNNeighborID = xNNeighborID; }
void setXNNeighborID(const QString& xNNeighborID) { setXNNeighborID(QUuid(xNNeighborID)); }
virtual const EntityItemID& getXNNeighborID() const { return _xNNeighborID; }
virtual void setYNNeighborID(const EntityItemID& yNNeighborID) { _yNNeighborID = yNNeighborID; }
void setYNNeighborID(const QString& yNNeighborID) { setYNNeighborID(QUuid(yNNeighborID)); }
virtual const EntityItemID& getYNNeighborID() const { return _yNNeighborID; }
virtual void setZNNeighborID(const EntityItemID& zNNeighborID) { _zNNeighborID = zNNeighborID; }
void setZNNeighborID(const QString& zNNeighborID) { setZNNeighborID(QUuid(zNNeighborID)); }
virtual const EntityItemID& getZNNeighborID() const { return _zNNeighborID; }
virtual void setXPNeighborID(const EntityItemID& xPNeighborID) { _xPNeighborID = xPNeighborID; }
void setXPNeighborID(const QString& xPNeighborID) { setXPNeighborID(QUuid(xPNeighborID)); }
virtual const EntityItemID& getXPNeighborID() const { return _xPNeighborID; }
virtual void setYPNeighborID(const EntityItemID& yPNeighborID) { _yPNeighborID = yPNeighborID; }
void setYPNeighborID(const QString& yPNeighborID) { setYPNeighborID(QUuid(yPNeighborID)); }
virtual const EntityItemID& getYPNeighborID() const { return _yPNeighborID; }
virtual void setZPNeighborID(const EntityItemID& zPNeighborID) { _zPNeighborID = zPNeighborID; }
void setZPNeighborID(const QString& zPNeighborID) { setZPNeighborID(QUuid(zPNeighborID)); }
virtual const EntityItemID& getZPNeighborID() const { return _zPNeighborID; }
virtual void rebakeMesh() {};
protected:
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
@ -116,6 +139,14 @@ class PolyVoxEntityItem : public EntityItem {
QString _yTextureURL;
QString _zTextureURL;
// for non-edged surface styles, these are used to compute the high-axis edges
EntityItemID _xNNeighborID{UNKNOWN_ENTITY_ID};
EntityItemID _yNNeighborID{UNKNOWN_ENTITY_ID};
EntityItemID _zNNeighborID{UNKNOWN_ENTITY_ID};
EntityItemID _xPNeighborID{UNKNOWN_ENTITY_ID};
EntityItemID _yPNeighborID{UNKNOWN_ENTITY_ID};
EntityItemID _zPNeighborID{UNKNOWN_ENTITY_ID};
};
#endif // hifi_PolyVoxEntityItem_h

View file

@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) {
case EntityAdd:
case EntityEdit:
case EntityData:
return VERSION_ENTITIES_PARTICLE_MODIFICATIONS;
return VERSION_ENTITIES_POLYVOX_NEIGHBORS;
case AvatarData:
return 13;
default:

View file

@ -144,5 +144,6 @@ const PacketVersion VERSION_POLYVOX_TEXTURES = 36;
const PacketVersion VERSION_ENTITIES_POLYLINE = 37;
const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38;
const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39;
const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40;
#endif // hifi_PacketHeaders_h
#endif // hifi_PacketHeaders_h