mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 02:13:09 +02:00
Merge branch 'master' into ajt/new-anim-system
This commit is contained in:
commit
5882ec02d0
25 changed files with 1027 additions and 300 deletions
88
examples/entityScripts/breakdanceEntity.js
Normal file
88
examples/entityScripts/breakdanceEntity.js
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
//
|
||||||
|
// breakdanceEntity.js
|
||||||
|
// examples/entityScripts
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 9/3/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This is an example of an entity script which when assigned to an entity, will start the breakdance game if you grab and hold the entity
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
Script.include("../toys/breakdanceCore.js");
|
||||||
|
Script.include("../libraries/utils.js");
|
||||||
|
|
||||||
|
var _this;
|
||||||
|
|
||||||
|
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
|
||||||
|
// our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
|
||||||
|
BreakdanceEntity = function() {
|
||||||
|
_this = this;
|
||||||
|
print("BreakdanceEntity constructor");
|
||||||
|
};
|
||||||
|
|
||||||
|
BreakdanceEntity.prototype = {
|
||||||
|
|
||||||
|
// update() will be called regulary, because we've hooked the update signal in our preload() function
|
||||||
|
// we will check out userData for the grabData. In the case of the hydraGrab script, it will tell us
|
||||||
|
// if we're currently being grabbed and if the person grabbing us is the current interfaces avatar.
|
||||||
|
// we will watch this for state changes and print out if we're being grabbed or released when it changes.
|
||||||
|
update: function() {
|
||||||
|
var GRAB_USER_DATA_KEY = "grabKey";
|
||||||
|
|
||||||
|
// because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID
|
||||||
|
var entityID = _this.entityID;
|
||||||
|
|
||||||
|
// we want to assume that if there is no grab data, then we are not being grabbed
|
||||||
|
var defaultGrabData = { activated: false, avatarId: null };
|
||||||
|
|
||||||
|
// this handy function getEntityCustomData() is available in utils.js and it will return just the specific section
|
||||||
|
// of user data we asked for. If it's not available it returns our default data.
|
||||||
|
var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, defaultGrabData);
|
||||||
|
|
||||||
|
// if the grabData says we're being grabbed, and the owner ID is our session, then we are being grabbed by this interface
|
||||||
|
if (grabData.activated && grabData.avatarId == MyAvatar.sessionUUID) {
|
||||||
|
|
||||||
|
if (!_this.beingGrabbed) {
|
||||||
|
// remember we're being grabbed so we can detect being released
|
||||||
|
_this.beingGrabbed = true;
|
||||||
|
breakdanceStart();
|
||||||
|
print("I'm was grabbed...");
|
||||||
|
} else {
|
||||||
|
breakdanceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (_this.beingGrabbed) {
|
||||||
|
|
||||||
|
// if we are not being grabbed, and we previously were, then we were just released, remember that
|
||||||
|
// and print out a message
|
||||||
|
_this.beingGrabbed = false;
|
||||||
|
print("I'm was released...");
|
||||||
|
breakdanceEnd();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// preload() will be called when the entity has become visible (or known) to the interface
|
||||||
|
// it gives us a chance to set our local JavaScript object up. In this case it means:
|
||||||
|
// * remembering our entityID, so we can access it in cases where we're called without an entityID
|
||||||
|
// * connecting to the update signal so we can check our grabbed state
|
||||||
|
preload: function(entityID) {
|
||||||
|
this.entityID = entityID;
|
||||||
|
Script.update.connect(this.update);
|
||||||
|
},
|
||||||
|
|
||||||
|
// unload() will be called when our entity is no longer available. It may be because we were deleted,
|
||||||
|
// or because we've left the domain or quit the application. In all cases we want to unhook our connection
|
||||||
|
// to the update signal
|
||||||
|
unload: function(entityID) {
|
||||||
|
Script.update.disconnect(this.update);
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// entity scripts always need to return a newly constructed object of our type
|
||||||
|
return new BreakdanceEntity();
|
||||||
|
})
|
81
examples/entityScripts/detectGrabExample.js
Normal file
81
examples/entityScripts/detectGrabExample.js
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
//
|
||||||
|
// detectGrabExample.js
|
||||||
|
// examples/entityScripts
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 9/3/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This is an example of an entity script which when assigned to an entity, will detect when the entity is being grabbed by the hydraGrab script
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
Script.include("../libraries/utils.js");
|
||||||
|
|
||||||
|
var _this;
|
||||||
|
|
||||||
|
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
|
||||||
|
// our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
|
||||||
|
DetectGrabbed = function() {
|
||||||
|
_this = this;
|
||||||
|
};
|
||||||
|
|
||||||
|
DetectGrabbed.prototype = {
|
||||||
|
|
||||||
|
// update() will be called regulary, because we've hooked the update signal in our preload() function
|
||||||
|
// we will check out userData for the grabData. In the case of the hydraGrab script, it will tell us
|
||||||
|
// if we're currently being grabbed and if the person grabbing us is the current interfaces avatar.
|
||||||
|
// we will watch this for state changes and print out if we're being grabbed or released when it changes.
|
||||||
|
update: function() {
|
||||||
|
var GRAB_USER_DATA_KEY = "grabKey";
|
||||||
|
|
||||||
|
// because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID
|
||||||
|
var entityID = _this.entityID;
|
||||||
|
|
||||||
|
// we want to assume that if there is no grab data, then we are not being grabbed
|
||||||
|
var defaultGrabData = { activated: false, avatarId: null };
|
||||||
|
|
||||||
|
// this handy function getEntityCustomData() is available in utils.js and it will return just the specific section
|
||||||
|
// of user data we asked for. If it's not available it returns our default data.
|
||||||
|
var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, defaultGrabData);
|
||||||
|
|
||||||
|
// if the grabData says we're being grabbed, and the owner ID is our session, then we are being grabbed by this interface
|
||||||
|
if (grabData.activated && grabData.avatarId == MyAvatar.sessionUUID) {
|
||||||
|
|
||||||
|
// remember we're being grabbed so we can detect being released
|
||||||
|
_this.beingGrabbed = true;
|
||||||
|
|
||||||
|
// print out that we're being grabbed
|
||||||
|
print("I'm being grabbed...");
|
||||||
|
|
||||||
|
} else if (_this.beingGrabbed) {
|
||||||
|
|
||||||
|
// if we are not being grabbed, and we previously were, then we were just released, remember that
|
||||||
|
// and print out a message
|
||||||
|
_this.beingGrabbed = false;
|
||||||
|
print("I'm was released...");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// preload() will be called when the entity has become visible (or known) to the interface
|
||||||
|
// it gives us a chance to set our local JavaScript object up. In this case it means:
|
||||||
|
// * remembering our entityID, so we can access it in cases where we're called without an entityID
|
||||||
|
// * connecting to the update signal so we can check our grabbed state
|
||||||
|
preload: function(entityID) {
|
||||||
|
this.entityID = entityID;
|
||||||
|
Script.update.connect(this.update);
|
||||||
|
},
|
||||||
|
|
||||||
|
// unload() will be called when our entity is no longer available. It may be because we were deleted,
|
||||||
|
// or because we've left the domain or quit the application. In all cases we want to unhook our connection
|
||||||
|
// to the update signal
|
||||||
|
unload: function(entityID) {
|
||||||
|
Script.update.disconnect(this.update);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// entity scripts always need to return a newly constructed object of our type
|
||||||
|
return new DetectGrabbed();
|
||||||
|
})
|
|
@ -91,10 +91,7 @@ Wand.prototype.setTipColors = function(color1, color2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Wand.prototype.onUpdate = function(deltaTime) {
|
Wand.prototype.onUpdate = function(deltaTime) {
|
||||||
logDebug("Z4");
|
|
||||||
|
|
||||||
if (this.visible) {
|
if (this.visible) {
|
||||||
logDebug("5");
|
|
||||||
var time = new Date().getTime() / 250;
|
var time = new Date().getTime() / 250;
|
||||||
var scale1 = Math.abs(Math.sin(time));
|
var scale1 = Math.abs(Math.sin(time));
|
||||||
var scale2 = Math.abs(Math.cos(time));
|
var scale2 = Math.abs(Math.cos(time));
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
Script.include("../libraries/utils.js");
|
|
||||||
|
|
||||||
function getPositionPuppet() {
|
function getPositionPuppet() {
|
||||||
var DISTANCE_IN_FRONT = 2;
|
var DISTANCE_IN_FRONT = 2;
|
||||||
var DISTANCE_UP = 0.4;
|
var DISTANCE_UP = 0.4;
|
||||||
|
@ -513,7 +511,7 @@ breakdanceUpdate = function(deltaTime) {
|
||||||
} else {
|
} else {
|
||||||
Overlays.editOverlay(textOverlay, { text: "pose:" + poses[poseValue].name + "\n" + "animation:" + poses[poseValue].animation });
|
Overlays.editOverlay(textOverlay, { text: "pose:" + poses[poseValue].name + "\n" + "animation:" + poses[poseValue].animation });
|
||||||
var props = Entities.getEntityProperties(puppetEntityID);
|
var props = Entities.getEntityProperties(puppetEntityID);
|
||||||
print("puppetEntityID:" + puppetEntityID + "age:"+props.age);
|
//print("puppetEntityID:" + puppetEntityID + "age:"+props.age);
|
||||||
Entities.editEntity(puppetEntityID, {
|
Entities.editEntity(puppetEntityID, {
|
||||||
animationURL: poses[poseValue].animation,
|
animationURL: poses[poseValue].animation,
|
||||||
lifetime: TEMPORARY_LIFETIME + props.age // renew lifetime
|
lifetime: TEMPORARY_LIFETIME + props.age // renew lifetime
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
Script.include("../libraries/utils.js");
|
||||||
Script.include("breakdanceCore.js");
|
Script.include("breakdanceCore.js");
|
||||||
breakdanceStart();
|
breakdanceStart();
|
||||||
Script.update.connect(breakdanceUpdate);
|
Script.update.connect(breakdanceUpdate);
|
||||||
|
|
|
@ -34,7 +34,7 @@ MODE_INFO[BALL_EDIT_MODE_ADD] = {
|
||||||
},
|
},
|
||||||
colors: [ COLORS.GREEN, COLORS.BLUE ],
|
colors: [ COLORS.GREEN, COLORS.BLUE ],
|
||||||
// FIXME use an http path or find a way to get the relative path to the file
|
// FIXME use an http path or find a way to get the relative path to the file
|
||||||
url: "file:///" + Script.resolvePath('../html/magBalls/addMode.html').replace("c:", "C:"),
|
url: Script.resolvePath('../html/magBalls/addMode.html'),
|
||||||
};
|
};
|
||||||
|
|
||||||
MODE_INFO[BALL_EDIT_MODE_DELETE] = {
|
MODE_INFO[BALL_EDIT_MODE_DELETE] = {
|
||||||
|
@ -45,10 +45,9 @@ MODE_INFO[BALL_EDIT_MODE_DELETE] = {
|
||||||
},
|
},
|
||||||
colors: [ COLORS.RED, COLORS.BLUE ],
|
colors: [ COLORS.RED, COLORS.BLUE ],
|
||||||
// FIXME use an http path or find a way to get the relative path to the file
|
// FIXME use an http path or find a way to get the relative path to the file
|
||||||
url: "file:///" + Script.resolvePath('../html/magBalls/deleteMode.html').replace("c:", "C:"),
|
url: Script.resolvePath('../html/magBalls/deleteMode.html'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var UI_POSITION_MODE_LABEL = Vec3.multiply(0.5,
|
var UI_POSITION_MODE_LABEL = Vec3.multiply(0.5,
|
||||||
Vec3.sum(MODE_INFO[BALL_EDIT_MODE_ADD].uiPosition,
|
Vec3.sum(MODE_INFO[BALL_EDIT_MODE_ADD].uiPosition,
|
||||||
MODE_INFO[BALL_EDIT_MODE_DELETE].uiPosition));
|
MODE_INFO[BALL_EDIT_MODE_DELETE].uiPosition));
|
||||||
|
|
|
@ -3,6 +3,7 @@ var shiftHeld = false;
|
||||||
|
|
||||||
Script.include([
|
Script.include([
|
||||||
"libraries/toolBars.js",
|
"libraries/toolBars.js",
|
||||||
|
"libraries/utils.js",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var isActive = false;
|
var isActive = false;
|
||||||
|
@ -12,24 +13,25 @@ var toolWidth = 50;
|
||||||
|
|
||||||
var addingVoxels = false;
|
var addingVoxels = false;
|
||||||
var deletingVoxels = false;
|
var deletingVoxels = false;
|
||||||
|
var addingSpheres = false;
|
||||||
|
var deletingSpheres = false;
|
||||||
|
|
||||||
offAlpha = 0.5;
|
var offAlpha = 0.5;
|
||||||
onAlpha = 0.9;
|
var onAlpha = 0.9;
|
||||||
|
var editSphereRadius = 4;
|
||||||
|
|
||||||
function floorVector(v) {
|
function floorVector(v) {
|
||||||
return {x: Math.floor(v.x), y: Math.floor(v.y), z: Math.floor(v.z)};
|
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 toolBar = (function () {
|
||||||
var that = {},
|
var that = {},
|
||||||
toolBar,
|
toolBar,
|
||||||
activeButton,
|
activeButton,
|
||||||
addVoxelButton,
|
addVoxelButton,
|
||||||
deleteVoxelButton,
|
deleteVoxelButton,
|
||||||
|
addSphereButton,
|
||||||
|
deleteSphereButton,
|
||||||
addTerrainButton;
|
addTerrainButton;
|
||||||
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
|
@ -66,6 +68,24 @@ var toolBar = (function () {
|
||||||
visible: false
|
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({
|
addTerrainButton = toolBar.addTool({
|
||||||
imageURL: toolIconUrl + "voxel-terrain.svg",
|
imageURL: toolIconUrl + "voxel-terrain.svg",
|
||||||
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
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);
|
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) {
|
that.setActive = function(active) {
|
||||||
if (active != isActive) {
|
if (active != isActive) {
|
||||||
|
@ -91,6 +127,8 @@ var toolBar = (function () {
|
||||||
that.showTools = function(doShow) {
|
that.showTools = function(doShow) {
|
||||||
toolBar.showTool(addVoxelButton, doShow);
|
toolBar.showTool(addVoxelButton, doShow);
|
||||||
toolBar.showTool(deleteVoxelButton, doShow);
|
toolBar.showTool(deleteVoxelButton, doShow);
|
||||||
|
toolBar.showTool(addSphereButton, doShow);
|
||||||
|
toolBar.showTool(deleteSphereButton, doShow);
|
||||||
toolBar.showTool(addTerrainButton, doShow);
|
toolBar.showTool(addTerrainButton, doShow);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -103,37 +141,46 @@ var toolBar = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addVoxelButton === toolBar.clicked(clickedOverlay)) {
|
if (addVoxelButton === toolBar.clicked(clickedOverlay)) {
|
||||||
if (addingVoxels) {
|
var wasAddingVoxels = addingVoxels;
|
||||||
addingVoxels = false;
|
disableAllButtons()
|
||||||
deletingVoxels = false;
|
if (!wasAddingVoxels) {
|
||||||
toolBar.setAlpha(offAlpha, addVoxelButton);
|
|
||||||
toolBar.setAlpha(offAlpha, deleteVoxelButton);
|
|
||||||
toolBar.selectTool(addVoxelButton, false);
|
|
||||||
toolBar.selectTool(deleteVoxelButton, false);
|
|
||||||
} else {
|
|
||||||
addingVoxels = true;
|
addingVoxels = true;
|
||||||
deletingVoxels = false;
|
|
||||||
toolBar.setAlpha(onAlpha, addVoxelButton);
|
toolBar.setAlpha(onAlpha, addVoxelButton);
|
||||||
toolBar.setAlpha(offAlpha, deleteVoxelButton);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteVoxelButton === toolBar.clicked(clickedOverlay)) {
|
if (deleteVoxelButton === toolBar.clicked(clickedOverlay)) {
|
||||||
if (deletingVoxels) {
|
var wasDeletingVoxels = deletingVoxels;
|
||||||
deletingVoxels = false;
|
disableAllButtons()
|
||||||
addingVoxels = false;
|
if (!wasDeletingVoxels) {
|
||||||
toolBar.setAlpha(offAlpha, addVoxelButton);
|
|
||||||
toolBar.setAlpha(offAlpha, deleteVoxelButton);
|
|
||||||
} else {
|
|
||||||
deletingVoxels = true;
|
deletingVoxels = true;
|
||||||
addingVoxels = false;
|
|
||||||
toolBar.setAlpha(offAlpha, addVoxelButton);
|
|
||||||
toolBar.setAlpha(onAlpha, deleteVoxelButton);
|
toolBar.setAlpha(onAlpha, deleteVoxelButton);
|
||||||
}
|
}
|
||||||
return true;
|
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)) {
|
if (addTerrainButton === toolBar.clicked(clickedOverlay)) {
|
||||||
addTerrainBlock();
|
addTerrainBlock();
|
||||||
return true;
|
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() {
|
function addTerrainBlock() {
|
||||||
|
var baseLocation = getTerrainAlignedLocation(Vec3.sum(MyAvatar.position, {x:8, y:8, z:8}));
|
||||||
var myPosDiv16 = Vec3.multiply(Vec3.sum(MyAvatar.position, {x:8, x:8, z:8}), 1.0 / 16.0);
|
if (baseLocation.y > MyAvatar.position.y) {
|
||||||
var myPosDiv16Floored = floorVector(myPosDiv16);
|
|
||||||
var baseLocation = Vec3.multiply(myPosDiv16Floored, 16.0);
|
|
||||||
|
|
||||||
if (baseLocation.y + 8 > MyAvatar.position.y) {
|
|
||||||
baseLocation.y -= 16;
|
baseLocation.y -= 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
print("myPosDiv16 is " + vectorToString(myPosDiv16));
|
var alreadyThere = lookupTerrainForLocation(baseLocation);
|
||||||
print("MyPosDiv16Floored is " + vectorToString(myPosDiv16Floored));
|
if (alreadyThere) {
|
||||||
print("baseLocation is " + vectorToString(baseLocation));
|
// there is already a terrain block under MyAvatar.
|
||||||
|
// try in front of the avatar.
|
||||||
alreadyThere = Entities.findEntities(baseLocation, 1.0);
|
facingPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(8.0, Quat.getFront(Camera.getOrientation())));
|
||||||
for (var i = 0; i < alreadyThere.length; i++) {
|
facingPosition = Vec3.sum(facingPosition, {x:8, y:8, z:8});
|
||||||
var id = alreadyThere[i];
|
baseLocation = getTerrainAlignedLocation(facingPosition);
|
||||||
var properties = Entities.getEntityProperties(id);
|
alreadyThere = lookupTerrainForLocation(baseLocation);
|
||||||
if (properties.name == "terrain") {
|
if (alreadyThere) {
|
||||||
print("already terrain there");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var polyVoxId = Entities.addEntity({
|
var polyVoxID = Entities.addEntity({
|
||||||
type: "PolyVox",
|
type: "PolyVox",
|
||||||
name: "terrain",
|
name: "terrain",
|
||||||
position: baseLocation,
|
position: baseLocation,
|
||||||
dimensions: { x: 16, y: 16, z: 16 },
|
dimensions: { x:16, y:16, z:16 },
|
||||||
voxelVolumeSize: {x:16, y:16, z:16},
|
voxelVolumeSize: {x:16, y:64, z:16},
|
||||||
voxelSurfaceStyle: 2
|
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++) {
|
var AvatarPositionInVoxelCoords = Entities.worldCoordsToVoxelCoords(polyVoxID, MyAvatar.position);
|
||||||
for (var x = 0; x < 16; x++) {
|
// TODO -- how to find the avatar's feet?
|
||||||
for (var z = 0; z < 16; z++) {
|
var topY = Math.round(AvatarPositionInVoxelCoords.y) - 4;
|
||||||
Entities.setVoxel(polyVoxId, {x: x, y: y, z: z}, 0);
|
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;
|
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") {
|
if (properties.type != "PolyVox") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addingVoxels == false && deletingVoxels == false) {
|
if (addingVoxels == false && deletingVoxels == false && addingSpheres == false && deletingSpheres == false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var voxelPosition = Entities.worldCoordsToVoxelCoords(intersection.entityID, intersection.intersection);
|
var voxelOrigin = Entities.worldCoordsToVoxelCoords(entityID, Vec3.subtract(intersectionLocation, pickRayDir));
|
||||||
var pickRayDirInVoxelSpace = Entities.localCoordsToVoxelCoords(intersection.entityID, pickRayDir);
|
var voxelPosition = Entities.worldCoordsToVoxelCoords(entityID, intersectionLocation);
|
||||||
|
var pickRayDirInVoxelSpace = Vec3.subtract(voxelPosition, voxelOrigin);
|
||||||
pickRayDirInVoxelSpace = Vec3.normalize(pickRayDirInVoxelSpace);
|
pickRayDirInVoxelSpace = Vec3.normalize(pickRayDirInVoxelSpace);
|
||||||
|
|
||||||
var doAdd = addingVoxels;
|
var doAdd = addingVoxels;
|
||||||
var doDelete = deletingVoxels;
|
var doDelete = deletingVoxels;
|
||||||
|
var doAddSphere = addingSpheres;
|
||||||
|
var doDeleteSphere = deletingSpheres;
|
||||||
|
|
||||||
if (controlHeld) {
|
if (controlHeld) {
|
||||||
doAdd = deletingVoxels;
|
if (doAdd) {
|
||||||
doDelete = addingVoxels;
|
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) {
|
if (doDelete) {
|
||||||
var toErasePosition = Vec3.sum(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1));
|
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) {
|
if (doAdd) {
|
||||||
var toDrawPosition = Vec3.subtract(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1));
|
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) {
|
function mousePressEvent(event) {
|
||||||
if (!event.isLeftButton) {
|
if (!event.isLeftButton) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -547,14 +547,11 @@ void SkeletonModel::computeBoundingShape() {
|
||||||
// compute the default transform of this joint
|
// compute the default transform of this joint
|
||||||
const JointState& state = _rig->getJointState(i);
|
const JointState& state = _rig->getJointState(i);
|
||||||
|
|
||||||
// HACK WORKAROUND: ignore joints that may have bad translation (e.g. have been flagged as such with zero radius)
|
// Each joint contributes a sphere at its position
|
||||||
if (state.getBoneRadius() > 0.0f) {
|
glm::vec3 axis(state.getBoneRadius());
|
||||||
// Each joint contributes a sphere at its position
|
glm::vec3 jointPosition = state.getPosition();
|
||||||
glm::vec3 axis(state.getBoneRadius());
|
totalExtents.addPoint(jointPosition + axis);
|
||||||
glm::vec3 jointPosition = state.getPosition();
|
totalExtents.addPoint(jointPosition - axis);
|
||||||
totalExtents.addPoint(jointPosition + axis);
|
|
||||||
totalExtents.addPoint(jointPosition - axis);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute bounding shape parameters
|
// compute bounding shape parameters
|
||||||
|
|
|
@ -78,7 +78,7 @@ void StereoDisplayPlugin::activate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void StereoDisplayPlugin::updateScreen() {
|
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()) {
|
if (_screenActions[i]->isChecked()) {
|
||||||
CONTAINER->setFullscreen(qApp->screens().at(i));
|
CONTAINER->setFullscreen(qApp->screens().at(i));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -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) {
|
void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
|
||||||
_voxelDataLock.lockForWrite();
|
_voxelDataLock.lockForWrite();
|
||||||
if (_voxelData == voxelData) {
|
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.
|
// if we are switching to or from "edged" we need to force a resize of _volData.
|
||||||
bool wasEdged = (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
|
bool wasEdged = isEdged(_voxelSurfaceStyle);
|
||||||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES);
|
bool willBeEdged = isEdged(voxelSurfaceStyle);
|
||||||
bool willBeEdged = (voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
|
|
||||||
voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES);
|
|
||||||
|
|
||||||
if (wasEdged != willBeEdged) {
|
if (wasEdged != willBeEdged) {
|
||||||
_volDataLock.lockForWrite();
|
_volDataLock.lockForWrite();
|
||||||
|
@ -113,15 +124,10 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel
|
||||||
|
|
||||||
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
|
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
|
||||||
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
|
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
|
||||||
switch (_voxelSurfaceStyle) {
|
if (isEdged(_voxelSurfaceStyle)) {
|
||||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
|
return scale / -2.0f;
|
||||||
case PolyVoxEntityItem::SURFACE_CUBIC:
|
|
||||||
return scale / 2.0f;
|
|
||||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
|
||||||
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
|
|
||||||
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 center = getCenterPosition();
|
||||||
glm::vec3 position = getPosition();
|
glm::vec3 position = getPosition();
|
||||||
glm::vec3 positionToCenter = center - position;
|
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 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
|
||||||
glm::mat4 scaled = glm::scale(centerToCorner, scale);
|
glm::mat4 scaled = glm::scale(centerToCorner, scale);
|
||||||
return scaled;
|
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) {
|
bool RenderablePolyVoxEntityItem::setVoxelInVolume(glm::vec3 position, uint8_t toValue) {
|
||||||
if (_locked) {
|
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
|
// This three-level for loop iterates over every voxel in the volume
|
||||||
_volDataLock.lockForWrite();
|
_volDataLock.lockForWrite();
|
||||||
_volDataDirty = true;
|
|
||||||
for (int z = 0; z < _voxelVolumeSize.z; z++) {
|
for (int z = 0; z < _voxelVolumeSize.z; z++) {
|
||||||
for (int y = 0; y < _voxelVolumeSize.y; y++) {
|
for (int y = 0; y < _voxelVolumeSize.y; y++) {
|
||||||
for (int x = 0; x < _voxelVolumeSize.x; x++) {
|
for (int x = 0; x < _voxelVolumeSize.x; x++) {
|
||||||
|
@ -228,20 +264,52 @@ bool RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_volDataLock.unlock();
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
_volDataDirty = true;
|
||||||
|
_volDataLock.unlock();
|
||||||
compressVolumeDataAndSendEditPacket();
|
compressVolumeDataAndSendEditPacket();
|
||||||
|
} else {
|
||||||
|
_volDataLock.unlock();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) {
|
bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) {
|
||||||
// glm::vec3 centerVoxelCoords = worldToVoxelCoordinates(centerWorldCoords);
|
bool result = false;
|
||||||
glm::vec4 centerVoxelCoords = worldToVoxelMatrix() * glm::vec4(centerWorldCoords, 1.0f);
|
if (_locked) {
|
||||||
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
|
return result;
|
||||||
float scaleY = scale.y;
|
}
|
||||||
float radiusVoxelCoords = radiusWorldCoords / scaleY;
|
|
||||||
return setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue);
|
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
|
class RaycastFunctor
|
||||||
|
@ -296,7 +364,6 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
|
||||||
|
|
||||||
glm::mat4 wtvMatrix = worldToVoxelMatrix();
|
glm::mat4 wtvMatrix = worldToVoxelMatrix();
|
||||||
glm::mat4 vtwMatrix = voxelToWorldMatrix();
|
glm::mat4 vtwMatrix = voxelToWorldMatrix();
|
||||||
glm::mat4 vtlMatrix = voxelToLocalMatrix();
|
|
||||||
glm::vec3 normDirection = glm::normalize(direction);
|
glm::vec3 normDirection = glm::normalize(direction);
|
||||||
|
|
||||||
// the PolyVox ray intersection code requires a near and far point.
|
// 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 distanceToEntity = glm::distance(origin, getPosition());
|
||||||
float largestDimension = glm::max(getDimensions().x, getDimensions().y, getDimensions().z) * 2.0f;
|
float largestDimension = glm::max(getDimensions().x, getDimensions().y, getDimensions().z) * 2.0f;
|
||||||
glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension);
|
glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension);
|
||||||
|
|
||||||
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
|
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
|
||||||
glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 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);
|
PolyVox::RaycastResult raycastResult = doRayCast(originInVoxel, farInVoxel, result);
|
||||||
if (raycastResult == PolyVox::RaycastResults::Completed) {
|
if (raycastResult == PolyVox::RaycastResults::Completed) {
|
||||||
// the ray completed its path -- nothing was hit.
|
// the ray completed its path -- nothing was hit.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up ray tests against each face of the voxel.
|
glm::vec3 result3 = glm::vec3(result);
|
||||||
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::vec4 baseDimensions = glm::vec4(1.0, 1.0, 1.0, 0.0);
|
AABox voxelBox;
|
||||||
glm::vec3 worldDimensions = glm::vec3(vtlMatrix * baseDimensions);
|
voxelBox += result3 - Vectors::HALF;
|
||||||
glm::vec2 xDimensions = glm::vec2(worldDimensions.z, worldDimensions.y);
|
voxelBox += result3 + Vectors::HALF;
|
||||||
glm::vec2 yDimensions = glm::vec2(worldDimensions.x, worldDimensions.z);
|
|
||||||
glm::vec2 zDimensions = glm::vec2(worldDimensions.x, worldDimensions.y);
|
|
||||||
|
|
||||||
glm::quat vtwRotation = extractRotation(vtwMatrix);
|
float voxelDistance;
|
||||||
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 bestDx = FLT_MAX;
|
bool hit = voxelBox.findRayIntersection(glm::vec3(originInVoxel), glm::vec3(directionInVoxel), voxelDistance, face);
|
||||||
bool hit[ 6 ];
|
|
||||||
float dx[ 6 ] = {FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX};
|
|
||||||
|
|
||||||
hit[0] = findRayRectangleIntersection(origin, direction, minXRotation, minXPosition, xDimensions, dx[0]);
|
glm::vec4 voxelIntersectionPoint = glm::vec4(glm::vec3(originInVoxel) + glm::vec3(directionInVoxel) * voxelDistance, 1.0);
|
||||||
hit[1] = findRayRectangleIntersection(origin, direction, maxXRotation, maxXPosition, xDimensions, dx[1]);
|
glm::vec4 intersectionPoint = vtwMatrix * voxelIntersectionPoint;
|
||||||
hit[2] = findRayRectangleIntersection(origin, direction, minYRotation, minYPosition, yDimensions, dx[2]);
|
distance = glm::distance(origin, glm::vec3(intersectionPoint));
|
||||||
hit[3] = findRayRectangleIntersection(origin, direction, maxYRotation, maxYPosition, yDimensions, dx[3]);
|
return hit;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -380,7 +413,7 @@ PolyVox::RaycastResult RenderablePolyVoxEntityItem::doRayCast(glm::vec4 originIn
|
||||||
_volDataLock.unlock();
|
_volDataLock.unlock();
|
||||||
|
|
||||||
// result is in voxel-space coordinates.
|
// result is in voxel-space coordinates.
|
||||||
result = callback._result - glm::vec4(0.5f, 0.5f, 0.5f, 0.0f);
|
result = callback._result;
|
||||||
return raycastResult;
|
return raycastResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,21 +435,29 @@ bool RenderablePolyVoxEntityItem::isReadyToComputeShape() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
|
void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
_shapeInfoLock.lockForRead();
|
QReadLocker(&this->_shapeInfoLock);
|
||||||
info = _shapeInfo;
|
info = _shapeInfo;
|
||||||
_shapeInfoLock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::setXTextureURL(QString xTextureURL) {
|
void RenderablePolyVoxEntityItem::setXTextureURL(QString xTextureURL) {
|
||||||
PolyVoxEntityItem::setXTextureURL(xTextureURL);
|
if (xTextureURL != _xTextureURL) {
|
||||||
|
_xTexture.clear();
|
||||||
|
PolyVoxEntityItem::setXTextureURL(xTextureURL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::setYTextureURL(QString yTextureURL) {
|
void RenderablePolyVoxEntityItem::setYTextureURL(QString yTextureURL) {
|
||||||
PolyVoxEntityItem::setYTextureURL(yTextureURL);
|
if (yTextureURL != _yTextureURL) {
|
||||||
|
_yTexture.clear();
|
||||||
|
PolyVoxEntityItem::setYTextureURL(yTextureURL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) {
|
void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) {
|
||||||
PolyVoxEntityItem::setZTextureURL(zTextureURL);
|
if (zTextureURL != _zTextureURL) {
|
||||||
|
_zTexture.clear();
|
||||||
|
PolyVoxEntityItem::setZTextureURL(zTextureURL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||||
|
@ -426,9 +467,12 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||||
|
|
||||||
_volDataLock.lockForRead();
|
_volDataLock.lockForRead();
|
||||||
if (_volDataDirty) {
|
if (_volDataDirty) {
|
||||||
|
_volDataLock.unlock();
|
||||||
getMesh();
|
getMesh();
|
||||||
|
} else {
|
||||||
|
_volDataLock.unlock();
|
||||||
}
|
}
|
||||||
_volDataLock.unlock();
|
|
||||||
|
|
||||||
_meshLock.lockForRead();
|
_meshLock.lockForRead();
|
||||||
model::MeshPointer mesh = _mesh;
|
model::MeshPointer mesh = _mesh;
|
||||||
|
@ -543,23 +587,21 @@ namespace render {
|
||||||
|
|
||||||
|
|
||||||
glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToWorldCoords(glm::vec3& voxelCoords) const {
|
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 RenderablePolyVoxEntityItem::worldCoordsToVoxelCoords(glm::vec3& worldCoords) const {
|
||||||
glm::vec3 result = glm::vec3(worldToVoxelMatrix() * glm::vec4(worldCoords, 1.0f));
|
glm::vec3 result = glm::vec3(worldToVoxelMatrix() * glm::vec4(worldCoords, 1.0f));
|
||||||
switch (_voxelSurfaceStyle) {
|
if (isEdged(_voxelSurfaceStyle)) {
|
||||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
|
return result - Vectors::HALF;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
return result + Vectors::HALF;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const {
|
glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const {
|
||||||
|
@ -585,8 +627,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize)
|
||||||
}
|
}
|
||||||
_onCount = 0;
|
_onCount = 0;
|
||||||
|
|
||||||
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
|
if (isEdged(_voxelSurfaceStyle)) {
|
||||||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
|
|
||||||
// with _EDGED_ we maintain an extra box of voxels around those that the user asked for. This
|
// 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
|
// 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
|
// 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));
|
_volData = new PolyVox::SimpleVolume<uint8_t>(PolyVox::Region(lowCorner, highCorner));
|
||||||
} else {
|
} else {
|
||||||
PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
|
PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
|
||||||
PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x - 1, // -1 because these corners are inclusive
|
// these should each have -1 after them, but if we leave layers on the upper-axis faces,
|
||||||
_voxelVolumeSize.y - 1,
|
// they act more like I expect.
|
||||||
_voxelVolumeSize.z - 1);
|
PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x,
|
||||||
|
_voxelVolumeSize.y,
|
||||||
|
_voxelVolumeSize.z);
|
||||||
_volData = new PolyVox::SimpleVolume<uint8_t>(PolyVox::Region(lowCorner, highCorner));
|
_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,
|
bool RenderablePolyVoxEntityItem::inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol,
|
||||||
PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
|
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.
|
// x, y, z are in user voxel-coords, not adjusted-for-edge voxel-coords.
|
||||||
switch (surfaceStyle) {
|
if (isEdged(surfaceStyle)) {
|
||||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
|
if (x < 0 || y < 0 || z < 0 ||
|
||||||
case PolyVoxEntityItem::SURFACE_CUBIC:
|
x >= vol->getWidth() - 2 || y >= vol->getHeight() - 2 || z >= vol->getDepth() - 2) {
|
||||||
if (x < 0 || y < 0 || z < 0 ||
|
return false;
|
||||||
x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()) {
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
} else {
|
||||||
return true;
|
if (x < 0 || y < 0 || z < 0 ||
|
||||||
|
x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()) {
|
||||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
return false;
|
||||||
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
|
}
|
||||||
if (x < 0 || y < 0 || z < 0 ||
|
return true;
|
||||||
x >= vol->getWidth() - 2 || y >= vol->getHeight() - 2 || z >= vol->getDepth() - 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) {
|
uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) {
|
||||||
_volDataLock.lockForRead();
|
QReadLocker(&this->_volDataLock);
|
||||||
auto result = getVoxelInternal(x, y, z);
|
return getVoxelInternal(x, y, z);
|
||||||
_volDataLock.unlock();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -650,19 +685,13 @@ uint8_t RenderablePolyVoxEntityItem::getVoxelInternal(int x, int y, int z) {
|
||||||
return 0;
|
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
|
// voxels all around the requested voxel space. Having the empty voxels around
|
||||||
// the edges changes how the surface extractor behaves.
|
// the edges changes how the surface extractor behaves.
|
||||||
|
if (isEdged(_voxelSurfaceStyle)) {
|
||||||
uint8_t result;
|
return _volData->getVoxelAt(x + 1, y + 1, z + 1);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
return _volData->getVoxelAt(x, y, z);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -675,9 +704,7 @@ bool RenderablePolyVoxEntityItem::setVoxelInternal(int x, int y, int z, uint8_t
|
||||||
|
|
||||||
result = updateOnCount(x, y, z, toValue);
|
result = updateOnCount(x, y, z, toValue);
|
||||||
|
|
||||||
assert(_volData);
|
if (isEdged(_voxelSurfaceStyle)) {
|
||||||
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
|
|
||||||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
|
|
||||||
_volData->setVoxelAt(x + 1, y + 1, z + 1, toValue);
|
_volData->setVoxelAt(x + 1, y + 1, z + 1, toValue);
|
||||||
} else {
|
} else {
|
||||||
_volData->setVoxelAt(x, y, z, toValue);
|
_volData->setVoxelAt(x, y, z, toValue);
|
||||||
|
@ -710,13 +737,11 @@ bool RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toV
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::decompressVolumeData() {
|
void RenderablePolyVoxEntityItem::decompressVolumeData() {
|
||||||
_threadRunning.acquire();
|
_threadRunning.acquire();
|
||||||
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::decompressVolumeDataAsync);
|
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::decompressVolumeDataAsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// take compressed data and expand it into _volData.
|
// take compressed data and expand it into _volData.
|
||||||
void RenderablePolyVoxEntityItem::decompressVolumeDataAsync() {
|
void RenderablePolyVoxEntityItem::decompressVolumeDataAsync() {
|
||||||
_voxelDataLock.lockForRead();
|
_voxelDataLock.lockForRead();
|
||||||
|
@ -777,7 +802,6 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() {
|
||||||
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacketAsync);
|
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacketAsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// compress the data in _volData and save the results. The compressed form is used during
|
// compress the data in _volData and save the results. The compressed form is used during
|
||||||
// saves to disk and for transmission over the wire
|
// saves to disk and for transmission over the wire
|
||||||
void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacketAsync() {
|
void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacketAsync() {
|
||||||
|
@ -850,23 +874,157 @@ void RenderablePolyVoxEntityItem::getMesh() {
|
||||||
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::getMeshAsync);
|
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() {
|
void RenderablePolyVoxEntityItem::getMeshAsync() {
|
||||||
model::MeshPointer mesh(new model::Mesh());
|
model::MeshPointer mesh(new model::Mesh());
|
||||||
|
|
||||||
|
cacheNeighbors();
|
||||||
|
|
||||||
// A mesh object to hold the result of surface extraction
|
// A mesh object to hold the result of surface extraction
|
||||||
PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> polyVoxMesh;
|
PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> polyVoxMesh;
|
||||||
|
|
||||||
_volDataLock.lockForRead();
|
_volDataLock.lockForRead();
|
||||||
|
if (!_volData) {
|
||||||
|
_volDataLock.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
copyUpperEdgesFromNeighbors();
|
||||||
|
|
||||||
switch (_voxelSurfaceStyle) {
|
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: {
|
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: {
|
||||||
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||||
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||||
surfaceExtractor.execute();
|
surfaceExtractor.execute();
|
||||||
break;
|
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: {
|
case PolyVoxEntityItem::SURFACE_CUBIC: {
|
||||||
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||||
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||||
|
@ -908,7 +1066,7 @@ void RenderablePolyVoxEntityItem::getMeshAsync() {
|
||||||
_meshLock.unlock();
|
_meshLock.unlock();
|
||||||
_volDataDirty = false;
|
_volDataDirty = false;
|
||||||
_volDataLock.unlock();
|
_volDataLock.unlock();
|
||||||
|
bonkNeighbors();
|
||||||
_threadRunning.release();
|
_threadRunning.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -925,7 +1083,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
|
||||||
|
|
||||||
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_MARCHING_CUBES ||
|
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_MARCHING_CUBES ||
|
||||||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_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;
|
unsigned int i = 0;
|
||||||
|
|
||||||
_meshLock.lockForRead();
|
_meshLock.lockForRead();
|
||||||
|
@ -972,10 +1130,16 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
|
||||||
} else {
|
} else {
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
_volDataLock.lockForRead();
|
||||||
|
if (!_volData) {
|
||||||
|
_volDataLock.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int z = 0; z < _voxelVolumeSize.z; z++) {
|
for (int z = 0; z < _voxelVolumeSize.z; z++) {
|
||||||
for (int y = 0; y < _voxelVolumeSize.y; y++) {
|
for (int y = 0; y < _voxelVolumeSize.y; y++) {
|
||||||
for (int x = 0; x < _voxelVolumeSize.x; x++) {
|
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) &&
|
if ((x > 0 && getVoxel(x - 1, y, z) > 0) &&
|
||||||
(y > 0 && getVoxel(x, y - 1, z) > 0) &&
|
(y > 0 && getVoxel(x, y - 1, z) > 0) &&
|
||||||
|
@ -1033,6 +1197,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_volDataLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (points.isEmpty()) {
|
if (points.isEmpty()) {
|
||||||
|
@ -1056,3 +1221,93 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
|
||||||
_threadRunning.release();
|
_threadRunning.release();
|
||||||
return;
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ public:
|
||||||
// coords are in world-space
|
// coords are in world-space
|
||||||
virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue);
|
virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue);
|
||||||
virtual bool setAll(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 setXTextureURL(QString xTextureURL);
|
||||||
virtual void setYTextureURL(QString yTextureURL);
|
virtual void setYTextureURL(QString yTextureURL);
|
||||||
|
@ -105,6 +106,16 @@ public:
|
||||||
std::shared_ptr<render::Scene> scene,
|
std::shared_ptr<render::Scene> scene,
|
||||||
render::PendingChanges& pendingChanges);
|
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:
|
private:
|
||||||
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
|
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
|
||||||
// may not match _voxelVolumeSize.
|
// may not match _voxelVolumeSize.
|
||||||
|
@ -130,7 +141,7 @@ private:
|
||||||
int _onCount; // how many non-zero voxels are in _volData
|
int _onCount; // how many non-zero voxels are in _volData
|
||||||
|
|
||||||
bool inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
|
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);
|
uint8_t getVoxelInternal(int x, int y, int z);
|
||||||
bool setVoxelInternal(int x, int y, int z, uint8_t toValue);
|
bool setVoxelInternal(int x, int y, int z, uint8_t toValue);
|
||||||
bool updateOnCount(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();
|
void computeShapeInfoWorkerAsync();
|
||||||
|
|
||||||
QSemaphore _threadRunning{1};
|
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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,16 +12,12 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
<@include gpu/Inputs.slh@>
|
<@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 model/Material.slh@>
|
||||||
|
<@include DeferredBufferWrite.slh@>
|
||||||
|
|
||||||
in vec3 _normal;
|
in vec3 _normal;
|
||||||
in vec4 _position;
|
in vec4 _position;
|
||||||
in vec4 _inPosition;
|
in vec4 _worldPosition;
|
||||||
|
|
||||||
uniform sampler2D xMap;
|
uniform sampler2D xMap;
|
||||||
uniform sampler2D yMap;
|
uniform sampler2D yMap;
|
||||||
|
@ -29,12 +25,12 @@ uniform sampler2D zMap;
|
||||||
uniform vec3 voxelVolumeSize;
|
uniform vec3 voxelVolumeSize;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec3 worldNormal = cross(dFdy(_inPosition.xyz), dFdx(_inPosition.xyz));
|
vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz));
|
||||||
worldNormal = normalize(worldNormal);
|
worldNormal = normalize(worldNormal);
|
||||||
|
|
||||||
float inPositionX = (_inPosition.x - 0.5) / voxelVolumeSize.x;
|
float inPositionX = (_worldPosition.x - 0.5) / voxelVolumeSize.x;
|
||||||
float inPositionY = (_inPosition.y - 0.5) / voxelVolumeSize.y;
|
float inPositionY = (_worldPosition.y - 0.5) / voxelVolumeSize.y;
|
||||||
float inPositionZ = (_inPosition.z - 0.5) / voxelVolumeSize.z;
|
float inPositionZ = (_worldPosition.z - 0.5) / voxelVolumeSize.z;
|
||||||
|
|
||||||
vec4 xyDiffuse = texture(xMap, vec2(-inPositionX, -inPositionY));
|
vec4 xyDiffuse = texture(xMap, vec2(-inPositionX, -inPositionY));
|
||||||
vec4 xzDiffuse = texture(yMap, vec2(-inPositionX, inPositionZ));
|
vec4 xzDiffuse = texture(yMap, vec2(-inPositionX, inPositionZ));
|
||||||
|
@ -43,12 +39,7 @@ void main(void) {
|
||||||
vec3 xyDiffuseScaled = xyDiffuse.rgb * abs(worldNormal.z);
|
vec3 xyDiffuseScaled = xyDiffuse.rgb * abs(worldNormal.z);
|
||||||
vec3 xzDiffuseScaled = xzDiffuse.rgb * abs(worldNormal.y);
|
vec3 xzDiffuseScaled = xzDiffuse.rgb * abs(worldNormal.y);
|
||||||
vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x);
|
vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x);
|
||||||
|
|
||||||
vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0);
|
vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0);
|
||||||
|
|
||||||
Material mat = getMaterial();
|
packDeferredFragment(_normal, 0.0, vec3(diffuse), vec3(0.01, 0.01, 0.01), 10.0);
|
||||||
|
|
||||||
_fragColor0 = vec4(diffuse.rgb, 0.0);
|
|
||||||
_fragColor1 = vec4(_normal, 1.0);
|
|
||||||
_fragColor2 = vec4(getMaterialSpecular(mat), getMaterialShininess(mat) / 128.0);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
out vec4 _position;
|
out vec4 _position;
|
||||||
out vec4 _inPosition;
|
out vec4 _worldPosition;
|
||||||
out vec3 _normal;
|
out vec3 _normal;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
|
@ -26,5 +26,5 @@ void main(void) {
|
||||||
TransformObject obj = getTransformObject();
|
TransformObject obj = getTransformObject();
|
||||||
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
|
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
|
||||||
<$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
|
<$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
|
||||||
_inPosition = inPosition;
|
_worldPosition = inPosition;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,26 +32,8 @@ public:
|
||||||
QScriptValue toScriptValue(QScriptEngine* engine) const;
|
QScriptValue toScriptValue(QScriptEngine* engine) const;
|
||||||
|
|
||||||
bool isInvalidID() const { return *this == UNKNOWN_ENTITY_ID; }
|
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) {
|
inline QDebug operator<<(QDebug debug, const EntityItemID& id) {
|
||||||
debug << "[entity-id:" << id.toString() << "]";
|
debug << "[entity-id:" << id.toString() << "]";
|
||||||
return debug;
|
return debug;
|
||||||
|
|
|
@ -109,6 +109,13 @@ CONSTRUCT_PROPERTY(strokeWidths, QVector<float>()),
|
||||||
CONSTRUCT_PROPERTY(xTextureURL, ""),
|
CONSTRUCT_PROPERTY(xTextureURL, ""),
|
||||||
CONSTRUCT_PROPERTY(yTextureURL, ""),
|
CONSTRUCT_PROPERTY(yTextureURL, ""),
|
||||||
CONSTRUCT_PROPERTY(zTextureURL, ""),
|
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),
|
_id(UNKNOWN_ENTITY_ID),
|
||||||
_idSet(false),
|
_idSet(false),
|
||||||
|
@ -377,6 +384,12 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||||
CHECK_PROPERTY_CHANGE(PROP_X_TEXTURE_URL, xTextureURL);
|
CHECK_PROPERTY_CHANGE(PROP_X_TEXTURE_URL, xTextureURL);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_Y_TEXTURE_URL, yTextureURL);
|
CHECK_PROPERTY_CHANGE(PROP_Y_TEXTURE_URL, yTextureURL);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_Z_TEXTURE_URL, zTextureURL);
|
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 += _stage.getChangedProperties();
|
||||||
changedProperties += _atmosphere.getChangedProperties();
|
changedProperties += _atmosphere.getChangedProperties();
|
||||||
|
@ -521,6 +534,14 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(yTextureURL);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(yTextureURL);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(zTextureURL);
|
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;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,6 +641,14 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(zTextureURL, QString, setZTextureURL);
|
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();
|
_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_X_TEXTURE_URL, properties.getXTextureURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, properties.getYTextureURL());
|
APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, properties.getYTextureURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, properties.getZTextureURL());
|
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) {
|
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_X_TEXTURE_URL, QString, setXTextureURL);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_TEXTURE_URL, QString, setYTextureURL);
|
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_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) {
|
if (properties.getType() == EntityTypes::Line) {
|
||||||
|
@ -1248,13 +1289,21 @@ void EntityItemProperties::markAllChanged() {
|
||||||
_descriptionChanged = true;
|
_descriptionChanged = true;
|
||||||
_faceCameraChanged = true;
|
_faceCameraChanged = true;
|
||||||
_actionDataChanged = true;
|
_actionDataChanged = true;
|
||||||
|
|
||||||
_normalsChanged = true;
|
_normalsChanged = true;
|
||||||
_strokeWidthsChanged = true;
|
_strokeWidthsChanged = true;
|
||||||
|
|
||||||
_xTextureURLChanged = true;
|
_xTextureURLChanged = true;
|
||||||
_yTextureURLChanged = true;
|
_yTextureURLChanged = true;
|
||||||
_zTextureURLChanged = 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.
|
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||||
|
|
|
@ -161,6 +161,12 @@ public:
|
||||||
DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString);
|
DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString);
|
||||||
DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, 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_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);
|
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, XTextureURL, xTextureURL, "");
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, YTextureURL, yTextureURL, "");
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, YTextureURL, yTextureURL, "");
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZTextureURL, zTextureURL, "");
|
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.getStage().debugDump();
|
||||||
properties.getAtmosphere().debugDump();
|
properties.getAtmosphere().debugDump();
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#ifndef hifi_EntityItemPropertiesMacros_h
|
#ifndef hifi_EntityItemPropertiesMacros_h
|
||||||
#define hifi_EntityItemPropertiesMacros_h
|
#define hifi_EntityItemPropertiesMacros_h
|
||||||
|
|
||||||
|
#include "EntityItemID.h"
|
||||||
|
|
||||||
#define APPEND_ENTITY_PROPERTY(P,V) \
|
#define APPEND_ENTITY_PROPERTY(P,V) \
|
||||||
if (requestedProperties.getHasProperty(P)) { \
|
if (requestedProperties.getHasProperty(P)) { \
|
||||||
LevelDetails propertyLevel = packetData->startLevel(); \
|
LevelDetails propertyLevel = packetData->startLevel(); \
|
||||||
|
@ -106,6 +108,9 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
|
||||||
return QScriptValue(QString(b64));
|
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) \
|
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
|
||||||
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
|
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
|
||||||
QScriptValue groupProperties = properties.property(#g); \
|
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 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 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 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) {
|
inline QDateTime QDateTime_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||||
isValid = true;
|
isValid = true;
|
||||||
|
|
|
@ -124,21 +124,28 @@ enum EntityPropertyList {
|
||||||
|
|
||||||
PROP_FACE_CAMERA,
|
PROP_FACE_CAMERA,
|
||||||
PROP_SCRIPT_TIMESTAMP,
|
PROP_SCRIPT_TIMESTAMP,
|
||||||
|
|
||||||
PROP_ACTION_DATA,
|
PROP_ACTION_DATA,
|
||||||
|
|
||||||
PROP_X_TEXTURE_URL, // used by PolyVox
|
PROP_X_TEXTURE_URL, // used by PolyVox
|
||||||
PROP_Y_TEXTURE_URL, // used by PolyVox
|
PROP_Y_TEXTURE_URL, // used by PolyVox
|
||||||
PROP_Z_TEXTURE_URL, // used by PolyVox
|
PROP_Z_TEXTURE_URL, // used by PolyVox
|
||||||
|
|
||||||
// Used by PolyLine entity
|
// Used by PolyLine entity
|
||||||
PROP_NORMALS,
|
PROP_NORMALS,
|
||||||
PROP_STROKE_WIDTHS,
|
PROP_STROKE_WIDTHS,
|
||||||
|
|
||||||
// used by particles
|
// used by particles
|
||||||
PROP_VELOCITY_SPREAD,
|
PROP_VELOCITY_SPREAD,
|
||||||
PROP_ACCELERATION_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
|
// ATTENTION: add new properties to end of list just ABOVE this line
|
||||||
PROP_AFTER_LAST_ITEM,
|
PROP_AFTER_LAST_ITEM,
|
||||||
|
|
|
@ -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) {
|
bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {
|
||||||
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
|
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
|
|
|
@ -122,6 +122,8 @@ public slots:
|
||||||
Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value);
|
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 setVoxel(QUuid entityID, const glm::vec3& position, int value);
|
||||||
Q_INVOKABLE bool setAllVoxels(QUuid entityID, 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 setAllPoints(QUuid entityID, const QVector<glm::vec3>& points);
|
||||||
Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point);
|
Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QWriteLocker>
|
||||||
|
|
||||||
#include <ByteCountCoding.h>
|
#include <ByteCountCoding.h>
|
||||||
|
|
||||||
|
@ -56,13 +57,14 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const Ent
|
||||||
_voxelSurfaceStyle(PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE),
|
_voxelSurfaceStyle(PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE),
|
||||||
_xTextureURL(PolyVoxEntityItem::DEFAULT_X_TEXTURE_URL),
|
_xTextureURL(PolyVoxEntityItem::DEFAULT_X_TEXTURE_URL),
|
||||||
_yTextureURL(PolyVoxEntityItem::DEFAULT_Y_TEXTURE_URL),
|
_yTextureURL(PolyVoxEntityItem::DEFAULT_Y_TEXTURE_URL),
|
||||||
_zTextureURL(PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL)
|
_zTextureURL(PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL) {
|
||||||
{
|
|
||||||
_type = EntityTypes::PolyVox;
|
_type = EntityTypes::PolyVox;
|
||||||
setProperties(properties);
|
setProperties(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
|
void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
|
||||||
|
QWriteLocker(&this->_voxelDataLock);
|
||||||
|
|
||||||
assert((int)_voxelVolumeSize.x == _voxelVolumeSize.x);
|
assert((int)_voxelVolumeSize.x == _voxelVolumeSize.x);
|
||||||
assert((int)_voxelVolumeSize.y == _voxelVolumeSize.y);
|
assert((int)_voxelVolumeSize.y == _voxelVolumeSize.y);
|
||||||
assert((int)_voxelVolumeSize.z == _voxelVolumeSize.z);
|
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 PolyVoxEntityItem::getProperties() const {
|
||||||
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize);
|
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(xTextureURL, getXTextureURL);
|
||||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(yTextureURL, getYTextureURL);
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(yTextureURL, getYTextureURL);
|
||||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(zTextureURL, getZTextureURL);
|
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;
|
return properties;
|
||||||
}
|
}
|
||||||
|
@ -116,6 +130,12 @@ bool PolyVoxEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(xTextureURL, setXTextureURL);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(xTextureURL, setXTextureURL);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(yTextureURL, setYTextureURL);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(yTextureURL, setYTextureURL);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(zTextureURL, setZTextureURL);
|
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) {
|
if (somethingChanged) {
|
||||||
bool wantDebug = false;
|
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_X_TEXTURE_URL, QString, setXTextureURL);
|
||||||
READ_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, QString, setYTextureURL);
|
READ_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, QString, setYTextureURL);
|
||||||
READ_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, QString, setZTextureURL);
|
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;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
|
@ -157,16 +183,22 @@ EntityPropertyFlags PolyVoxEntityItem::getEntityProperties(EncodeBitstreamParams
|
||||||
requestedProperties += PROP_X_TEXTURE_URL;
|
requestedProperties += PROP_X_TEXTURE_URL;
|
||||||
requestedProperties += PROP_Y_TEXTURE_URL;
|
requestedProperties += PROP_Y_TEXTURE_URL;
|
||||||
requestedProperties += PROP_Z_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;
|
return requestedProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||||
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
|
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
|
||||||
EntityPropertyFlags& requestedProperties,
|
EntityPropertyFlags& requestedProperties,
|
||||||
EntityPropertyFlags& propertyFlags,
|
EntityPropertyFlags& propertyFlags,
|
||||||
EntityPropertyFlags& propertiesDidntFit,
|
EntityPropertyFlags& propertiesDidntFit,
|
||||||
int& propertyCount,
|
int& propertyCount,
|
||||||
OctreeElement::AppendState& appendState) const {
|
OctreeElement::AppendState& appendState) const {
|
||||||
bool successPropertyFits = true;
|
bool successPropertyFits = true;
|
||||||
|
|
||||||
APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, getVoxelVolumeSize());
|
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_X_TEXTURE_URL, getXTextureURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, getYTextureURL());
|
APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, getYTextureURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, getZTextureURL());
|
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 {
|
void PolyVoxEntityItem::debugDump() const {
|
||||||
|
@ -187,15 +224,12 @@ void PolyVoxEntityItem::debugDump() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
|
void PolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
|
||||||
_voxelDataLock.lockForWrite();
|
QWriteLocker(&this->_voxelDataLock);
|
||||||
_voxelData = voxelData;
|
_voxelData = voxelData;
|
||||||
_voxelDataDirty = true;
|
_voxelDataDirty = true;
|
||||||
_voxelDataLock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray PolyVoxEntityItem::getVoxelData() const {
|
const QByteArray PolyVoxEntityItem::getVoxelData() const {
|
||||||
_voxelDataLock.lockForRead();
|
QReadLocker(&this->_voxelDataLock);
|
||||||
auto result = _voxelData;
|
return _voxelData;
|
||||||
_voxelDataLock.unlock();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ class PolyVoxEntityItem : public EntityItem {
|
||||||
virtual void debugDump() const;
|
virtual void debugDump() const;
|
||||||
|
|
||||||
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
|
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 void setVoxelData(QByteArray voxelData);
|
||||||
virtual const QByteArray getVoxelData() const;
|
virtual const QByteArray getVoxelData() const;
|
||||||
|
@ -85,6 +85,7 @@ class PolyVoxEntityItem : public EntityItem {
|
||||||
// coords are in world-space
|
// coords are in world-space
|
||||||
virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) { return false; }
|
virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) { return false; }
|
||||||
virtual bool setAll(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 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; }
|
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 void setZTextureURL(QString zTextureURL) { _zTextureURL = zTextureURL; }
|
||||||
virtual const QString& getZTextureURL() const { return _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:
|
protected:
|
||||||
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
|
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
|
||||||
|
|
||||||
|
@ -116,6 +139,14 @@ class PolyVoxEntityItem : public EntityItem {
|
||||||
QString _yTextureURL;
|
QString _yTextureURL;
|
||||||
QString _zTextureURL;
|
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
|
#endif // hifi_PolyVoxEntityItem_h
|
||||||
|
|
|
@ -2562,6 +2562,7 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
||||||
int maxJointIndex = firstFBXCluster.jointIndex;
|
int maxJointIndex = firstFBXCluster.jointIndex;
|
||||||
glm::mat4 inverseModelTransform = glm::inverse(modelTransform);
|
glm::mat4 inverseModelTransform = glm::inverse(modelTransform);
|
||||||
if (clusterIDs.size() > 1) {
|
if (clusterIDs.size() > 1) {
|
||||||
|
// this is a multi-mesh joint
|
||||||
extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size());
|
extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size());
|
||||||
extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size());
|
extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size());
|
||||||
float maxWeight = 0.0f;
|
float maxWeight = 0.0f;
|
||||||
|
@ -2645,6 +2646,7 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// this is a single-mesh joint
|
||||||
int jointIndex = maxJointIndex;
|
int jointIndex = maxJointIndex;
|
||||||
FBXJoint& joint = geometry.joints[jointIndex];
|
FBXJoint& joint = geometry.joints[jointIndex];
|
||||||
JointShapeInfo& jointShapeInfo = jointShapeInfos[jointIndex];
|
JointShapeInfo& jointShapeInfo = jointShapeInfos[jointIndex];
|
||||||
|
@ -2665,6 +2667,7 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
||||||
}
|
}
|
||||||
float radiusScale = extractUniformScale(joint.transform * firstFBXCluster.inverseBindMatrix);
|
float radiusScale = extractUniformScale(joint.transform * firstFBXCluster.inverseBindMatrix);
|
||||||
|
|
||||||
|
// compute average vertex
|
||||||
glm::vec3 averageVertex(0.0f);
|
glm::vec3 averageVertex(0.0f);
|
||||||
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
||||||
float proj = glm::dot(boneDirection, boneEnd - vertex);
|
float proj = glm::dot(boneDirection, boneEnd - vertex);
|
||||||
|
@ -2674,29 +2677,26 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
||||||
++jointShapeInfo.numVertexWeights;
|
++jointShapeInfo.numVertexWeights;
|
||||||
averageVertex += vertex;
|
averageVertex += vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compute joint's radius
|
||||||
int numVertices = extracted.mesh.vertices.size();
|
int numVertices = extracted.mesh.vertices.size();
|
||||||
jointShapeInfo.numVertices = numVertices;
|
jointShapeInfo.numVertices = numVertices;
|
||||||
if (numVertices > 0) {
|
if (numVertices > 0) {
|
||||||
|
// compute average radius
|
||||||
averageVertex /= (float)jointShapeInfo.numVertices;
|
averageVertex /= (float)jointShapeInfo.numVertices;
|
||||||
float averageRadius = 0.0f;
|
float averageRadius = 0.0f;
|
||||||
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
||||||
averageRadius += glm::distance(vertex, averageVertex);
|
averageRadius += glm::distance(vertex, averageVertex);
|
||||||
}
|
}
|
||||||
jointShapeInfo.averageRadius = averageRadius * radiusScale / (float)jointShapeInfo.numVertices;
|
averageRadius *= radiusScale / (float)jointShapeInfo.numVertices;
|
||||||
|
|
||||||
|
// final radius is minimum of average and weighted
|
||||||
|
float weightedRadius = jointShapeInfo.sumWeightedRadii / jointShapeInfo.sumVertexWeights;
|
||||||
|
jointShapeInfo.averageRadius = glm::min(weightedRadius, averageRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BUG: the boneBegin and/or boneEnd are incorrect for meshes that are "connected
|
// clear sumVertexWeights (this flags it as a single-mesh joint for later)
|
||||||
// under the bone" without weights. Unfortunately we haven't been able to find it yet.
|
|
||||||
// Although the the mesh vertices are correct in the model-frame, the joint's transform
|
|
||||||
// in the same frame is just BAD.
|
|
||||||
//
|
|
||||||
// HACK WORKAROUND: prevent these shapes from contributing to the collision capsule by setting
|
|
||||||
// some key members of jointShapeInfo to zero:
|
|
||||||
jointShapeInfo.numVertices = 0;
|
|
||||||
jointShapeInfo.sumVertexWeights = 0.0f;
|
jointShapeInfo.sumVertexWeights = 0.0f;
|
||||||
jointShapeInfo.numVertexWeights = 0;
|
|
||||||
jointShapeInfo.boneBegin = glm::vec3(0.0f);
|
|
||||||
jointShapeInfo.averageRadius = 0.0f;
|
|
||||||
}
|
}
|
||||||
extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex);
|
extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex);
|
||||||
|
|
||||||
|
@ -2732,22 +2732,12 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jointShapeInfo.sumVertexWeights > 0.0f) {
|
if (jointShapeInfo.sumVertexWeights > 0.0f) {
|
||||||
|
// mutiple meshes contributed to the bone radius and now that all
|
||||||
|
// contributing meshes are done we can finally compute the boneRadius
|
||||||
joint.boneRadius = jointShapeInfo.sumWeightedRadii / jointShapeInfo.sumVertexWeights;
|
joint.boneRadius = jointShapeInfo.sumWeightedRadii / jointShapeInfo.sumVertexWeights;
|
||||||
}
|
} else {
|
||||||
|
// single-mesh joint
|
||||||
// the joint is "capsule-like" if it had ANY mesh vertices successfully projected onto the bone
|
joint.boneRadius = jointShapeInfo.averageRadius;
|
||||||
// AND its boneRadius is not too close to zero
|
|
||||||
bool collideLikeCapsule = jointShapeInfo.numVertexWeights > 0
|
|
||||||
&& glm::length(jointShapeInfo.boneBegin) > EPSILON;
|
|
||||||
|
|
||||||
if (!collideLikeCapsule) {
|
|
||||||
// this joint's mesh did not successfully project onto the bone axis
|
|
||||||
// so it isn't "capsule-like" and we need to estimate its radius a different way:
|
|
||||||
// the average radius to the average point.
|
|
||||||
if (jointShapeInfo.numVertexWeights == 0
|
|
||||||
&& jointShapeInfo.numVertices > 0) {
|
|
||||||
joint.boneRadius = jointShapeInfo.averageRadius;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());
|
geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());
|
||||||
|
|
|
@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) {
|
||||||
case EntityAdd:
|
case EntityAdd:
|
||||||
case EntityEdit:
|
case EntityEdit:
|
||||||
case EntityData:
|
case EntityData:
|
||||||
return VERSION_ENTITIES_PARTICLE_MODIFICATIONS;
|
return VERSION_ENTITIES_POLYVOX_NEIGHBORS;
|
||||||
case AvatarData:
|
case AvatarData:
|
||||||
return 13;
|
return 13;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -144,5 +144,6 @@ const PacketVersion VERSION_POLYVOX_TEXTURES = 36;
|
||||||
const PacketVersion VERSION_ENTITIES_POLYLINE = 37;
|
const PacketVersion VERSION_ENTITIES_POLYLINE = 37;
|
||||||
const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38;
|
const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38;
|
||||||
const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39;
|
const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39;
|
||||||
|
const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40;
|
||||||
|
|
||||||
#endif // hifi_PacketHeaders_h
|
#endif // hifi_PacketHeaders_h
|
||||||
|
|
Loading…
Reference in a new issue