Conflicts:
	libraries/entities/src/EntityItem.cpp
This commit is contained in:
Andrew Meadows 2015-06-02 15:08:36 -07:00
commit 0e2028b820
59 changed files with 1533 additions and 363 deletions

View file

@ -12,6 +12,12 @@ We have a [homebrew formulas repository](https://github.com/highfidelity/homebre
*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.4.x stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.*
###Qt
Assuming you've installed Qt 5 using the homebrew instructions above, you'll need to set QT_CMAKE_PREFIX_PATH so CMake can find your installation of Qt. For Qt 5.4.1 installed via homebrew, set QT_CMAKE_PREFIX_PATH as follows.
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.4.1/lib/cmake
###Xcode
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
@ -19,4 +25,4 @@ If Xcode is your editor of choice, you can ask CMake to generate Xcode project f
After running cmake, you will have the make files or Xcode project file necessary to build all of the components. Open the hifi.xcodeproj file, choose ALL_BUILD from the Product > Scheme menu (or target drop down), and click Run.
If the build completes successfully, you will have built targets for all components located in the `build/${target_name}/Debug` directories.
If the build completes successfully, you will have built targets for all components located in the `build/${target_name}/Debug` directories.

View file

@ -75,21 +75,6 @@ To prevent these problems, install OpenSSL yourself. Download the following bina
Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
###vhacd
Download it directly from https://github.com/virneo/v-hacd
To build it run the following commands
1. cd src\
2. mkdir build
3. cd build
4. cmake ..
Build using visual studio 2013. Build ALL_BUILD and INSTALL targets both in Release and Debug.
This will create an output folder with include and lib directory inside it.
Either copy the contents of output folder to ENV %HIFI_LIB_DIR%/vhacd or create an environment variable VHACD_ROOT_DIR to this output directory.
###Build High Fidelity using Visual Studio
Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.

View file

@ -3,8 +3,8 @@ set(EXTERNAL_NAME polyvox)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/polyvox-master-2015-5-27.zip
URL_MD5 e3dd09a24df4db29ba370e3bea753388
URL http://hifi-public.s3.amazonaws.com/dependencies/polyvox.zip
URL_MD5 904b840328278c9b36fa7a14be730c34
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
LOG_DOWNLOAD 1
@ -45,7 +45,7 @@ else ()
endif ()
if (WIN32)
if (WIN32)
set(${EXTERNAL_NAME_UPPER}_CORE_LIBRARY ${INSTALL_DIR}/PolyVoxCore/lib/PolyVoxCore.lib CACHE FILEPATH "polyvox core library")
# set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY ${INSTALL_DIR}/PolyVoxUtil/lib/PolyVoxUtil.lib CACHE FILEPATH "polyvox util library")
elseif (APPLE)

View file

@ -1,4 +1,3 @@
// newEditEntities.js
// examples
//
@ -139,6 +138,7 @@ var toolBar = (function () {
newTextButton,
newWebButton,
newZoneButton,
newPolyVoxButton,
browseMarketplaceButton;
function initialize() {
@ -224,6 +224,15 @@ var toolBar = (function () {
visible: false
});
newPolyVoxButton = toolBar.addTool({
imageURL: toolIconUrl + "upload.svg", // XXX need a new icon
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
width: toolWidth,
height: toolHeight,
alpha: 0.9,
visible: false
});
that.setActive(false);
}
@ -266,6 +275,7 @@ var toolBar = (function () {
toolBar.showTool(newTextButton, doShow);
toolBar.showTool(newWebButton, doShow);
toolBar.showTool(newZoneButton, doShow);
toolBar.showTool(newPolyVoxButton, doShow);
};
var RESIZE_INTERVAL = 50;
@ -468,6 +478,24 @@ var toolBar = (function () {
return true;
}
if (newPolyVoxButton === toolBar.clicked(clickedOverlay)) {
var position = getPositionToCreateEntity();
if (position.x > 0 && position.y > 0 && position.z > 0) {
placingEntityID = Entities.addEntity({
type: "PolyVox",
position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS),
DEFAULT_DIMENSIONS),
dimensions: { x: 10, y: 10, z: 10 },
voxelVolumeSize: {x:16, y:16, z:16},
voxelSurfaceStyle: 1
});
} else {
print("Can't create PolyVox: would be out of bounds.");
}
return true;
}
return false;
};
@ -920,7 +948,7 @@ function selectAllEtitiesInCurrentSelectionBox(keepIfTouching) {
var boundingBoxCorner = Vec3.subtract(selectionManager.worldPosition,
Vec3.multiply(selectionManager.worldDimensions, 0.5));
var entities = Entities.findEntitiesInBox(boundingBoxCorner, selectionManager.worldDimensions);
if (!keepIfTouching) {
var isValid;
if (selectionManager.localPosition === null) {
@ -992,7 +1020,7 @@ function handeMenuEvent(menuItem) {
}
}
} else if (menuItem == "Import Entities" || menuItem == "Import Entities from URL") {
var importURL;
if (menuItem == "Import Entities") {
importURL = Window.browse("Select models to import", "", "*.json");

View file

@ -36,8 +36,6 @@ var angularVelocity = {
z: 0
};
var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/CloseClamp.wav");
var releaseSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/ReleaseClamp.wav");
var DROP_DISTANCE = 5.0;
var DROP_COLOR = {
@ -90,10 +88,6 @@ function mousePressEvent(event) {
gravity: {x: 0, y: 0, z: 0}
});
Audio.playSound(grabSound, {
position: props.position,
volume: 0.4
});
}
}
@ -135,11 +129,6 @@ function mouseReleaseEvent() {
});
targetPosition = null;
Audio.playSound(grabSound, {
position: entityProps.position,
volume: 0.25
});
}
}

View file

@ -21,11 +21,11 @@
els[i].setAttribute('disabled', 'disabled');
}
}
function showElements(els, show) {
for (var i = 0; i < els.length; i++) {
els[i].style.display = (show) ? 'block' : 'none';
}
}
}
function createEmitCheckedPropertyUpdateFunction(propertyName) {
@ -344,7 +344,7 @@
var elZoneAtmosphereCenterY = document.getElementById("property-zone-atmosphere-center-y");
var elZoneAtmosphereCenterZ = document.getElementById("property-zone-atmosphere-center-z");
var elCenterAtmosphereToZone = document.getElementById("center-atmosphere-in-zone");
var elZoneAtmosphereInnerRadius = document.getElementById("property-zone-atmosphere-inner-radius");
var elZoneAtmosphereOuterRadius = document.getElementById("property-zone-atmosphere-outer-radius");
var elZoneAtmosphereMieScattering = document.getElementById("property-zone-atmosphere-mie-scattering");
@ -354,6 +354,12 @@
var elZoneAtmosphereScatteringWavelengthsZ = document.getElementById("property-zone-atmosphere-scattering-wavelengths-z");
var elZoneAtmosphereHasStars = document.getElementById("property-zone-atmosphere-has-stars");
var elPolyVoxSelections = document.querySelectorAll(".poly-vox-section");
var elVoxelVolumeSizeX = document.getElementById("property-voxel-volume-size-x");
var elVoxelVolumeSizeY = document.getElementById("property-voxel-volume-size-y");
var elVoxelVolumeSizeZ = document.getElementById("property-voxel-volume-size-z");
var elVoxelSurfaceStyle = document.getElementById("property-voxel-surface-style");
if (window.EventBridge !== undefined) {
EventBridge.scriptEventReceived.connect(function(data) {
@ -571,7 +577,7 @@
elZoneAtmosphereScatteringWavelengthsY.value = properties.atmosphere.scatteringWavelengths.y;
elZoneAtmosphereScatteringWavelengthsZ.value = properties.atmosphere.scatteringWavelengths.z;
elZoneAtmosphereHasStars.checked = properties.atmosphere.hasStars;
showElements(document.getElementsByClassName('skybox-section'), elZoneBackgroundMode.value == 'skybox');
showElements(document.getElementsByClassName('atmosphere-section'), elZoneBackgroundMode.value == 'atmosphere');
} else if (properties.type == "ParticleEffect") {
@ -588,6 +594,11 @@
elParticleEmitStrength.value = properties.emitStrength.toFixed(2);
elParticleLocalGravity.value = properties.localGravity.toFixed(2);
elParticleRadius.value = properties.particleRadius.toFixed(3);
} else if (properties.type == "PolyVox") {
elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2);
elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2);
elVoxelVolumeSizeZ.value = properties.voxelVolumeSize.z.toFixed(2);
elVoxelSurfaceStyle.value = properties.voxelSurfaceStyle;
}
if (selected) {
@ -704,7 +715,7 @@
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
elWebSourceURL.addEventListener('change', createEmitTextPropertyUpdateFunction('sourceUrl'));
elParticleMaxParticles.addEventListener('change', createEmitNumberPropertyUpdateFunction('maxParticles'));
elParticleLifeSpan.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifespan'));
elParticleEmitRate.addEventListener('change', createEmitNumberPropertyUpdateFunction('emitRate'));
@ -810,7 +821,7 @@
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox');
}
});
elZoneSkyboxURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('skybox','url'));
var zoneAtmosphereCenterChangeFunction = createEmitGroupVec3PropertyUpdateFunction(
@ -818,8 +829,8 @@
elZoneAtmosphereCenterX.addEventListener('change', zoneAtmosphereCenterChangeFunction);
elZoneAtmosphereCenterY.addEventListener('change', zoneAtmosphereCenterChangeFunction);
elZoneAtmosphereCenterZ.addEventListener('change', zoneAtmosphereCenterChangeFunction);
elZoneAtmosphereInnerRadius.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','innerRadius'));
elZoneAtmosphereOuterRadius.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','outerRadius'));
elZoneAtmosphereMieScattering.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','mieScattering'));
@ -832,6 +843,13 @@
elZoneAtmosphereScatteringWavelengthsZ.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction);
elZoneAtmosphereHasStars.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('atmosphere','hasStars'));
var voxelVolumeSizeChangeFunction = createEmitVec3PropertyUpdateFunction(
'voxelVolumeSize', elVoxelVolumeSizeX, elVoxelVolumeSizeY, elVoxelVolumeSizeZ);
elVoxelVolumeSizeX.addEventListener('change', voxelVolumeSizeChangeFunction);
elVoxelVolumeSizeY.addEventListener('change', voxelVolumeSizeChangeFunction);
elVoxelVolumeSizeZ.addEventListener('change', voxelVolumeSizeChangeFunction);
elVoxelSurfaceStyle.addEventListener('change', createEmitTextPropertyUpdateFunction('voxelSurfaceStyle'));
elMoveSelectionToGrid.addEventListener("click", function() {
EventBridge.emitWebEvent(JSON.stringify({
@ -973,6 +991,24 @@
</div>
</div>
<div class="poly-vox-section property">
<div class="label">Voxel Volume Size</div>
<div class="value">
<div class="input-area">X <br><input class="coord" type='number' id="property-voxel-volume-size-x"></input></div>
<div class="input-area">Y <br><input class="coord" type='number' id="property-voxel-volume-size-y"></input></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-voxel-volume-size-z"></input></div>
</div>
<div class="label">Surface Extractor</div>
<div class="value">
<select name="SelectVoxelSurfaceStyle" id="property-voxel-surface-style">
<option value='0'>marching cubes</option>
<option value='1'>cubic</option>
<option value='2'>edged cubic</option>
</select>
</div>
</div>
<div class="property">
<div class="label">Rotation</div>
<div class="value">
@ -1107,19 +1143,19 @@
<input type="text" id="property-web-source-url" class="url"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Max Particles</div>
<div class="value">
<input type='number' id="property-particle-maxparticles" min="0" max="2048" step="1"></input>
</div>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Life Span</div>
<div class="value">
<input type='number' id="property-particle-lifespan" min="0" step="0.1"></input>
</div>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Emission Rate</div>
<div class="value">
@ -1152,7 +1188,7 @@
<input class="coord" type='number' id="property-particle-radius" min="0" step="0.005"></input>
</div>
</div>
<div class="model-section property">
<div class="label">Model URL</div>
<div class="value">
@ -1167,7 +1203,7 @@
<option value='box'>box</option>
<option value='sphere'>sphere</option>
<option value='compound'>compound</option>
</select>
</select>
</div>
</div>
<div class="model-section zone-section property">
@ -1346,7 +1382,7 @@
<input type='checkbox' id="property-zone-stage-automatic-hour-day">
</span>
</div>
<div class="zone-section property">
<div class="label">Stage Day</div>
<div class="value">

View file

@ -98,6 +98,21 @@ EntityPropertyDialogBox = (function () {
index++;
}
if (properties.type == "PolyVox") {
array.push({ label: "Voxel Space Size:", type: "header" });
index++;
array.push({ label: "X:", value: properties.voxelVolumeSize.x.toFixed(decimals) });
index++;
array.push({ label: "Y:", value: properties.voxelVolumeSize.y.toFixed(decimals) });
index++;
array.push({ label: "Z:", value: properties.voxelVolumeSize.z.toFixed(decimals) });
index++;
array.push({ label: "Surface Extractor", value: properties.voxelSurfaceStyle });
index++;
}
array.push({ label: "Position:", type: "header" });
index++;
array.push({ label: "X:", value: properties.position.x.toFixed(decimals) });
@ -333,6 +348,16 @@ EntityPropertyDialogBox = (function () {
properties.backgroundColor.blue = array[index++].value;
}
if (properties.type == "PolyVox") {
properties.shapeType = array[index++].value;
index++; // skip header
properties.voxelVolumeSize.x = array[index++].value;
properties.voxelVolumeSize.y = array[index++].value;
properties.voxelVolumeSize.z = array[index++].value;
properties.voxelSurfaceStyle = array[index++].value;
}
index++; // skip header
properties.position.x = array[index++].value;
properties.position.y = array[index++].value;

View file

@ -1,5 +1,5 @@
var controlHeld = false;
var shiftHeld = false;
function mousePressEvent(event) {
@ -15,9 +15,11 @@ function mousePressEvent(event) {
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
if (controlHeld) {
Entities.setVoxelSphere(id, intersection.intersection, 1.2, 0);
Entities.setVoxelSphere(id, intersection.intersection, 1.0, 0);
} else if (shiftHeld) {
Entities.setAllVoxels(id, 255);
} else {
Entities.setVoxelSphere(id, intersection.intersection, 1.2, 255);
Entities.setVoxelSphere(id, intersection.intersection, 1.0, 255);
}
}
}
@ -28,6 +30,9 @@ function keyPressEvent(event) {
if (event.text == "CONTROL") {
controlHeld = true;
}
if (event.text == "SHIFT") {
shiftHeld = true;
}
}
@ -35,6 +40,9 @@ function keyReleaseEvent(event) {
if (event.text == "CONTROL") {
controlHeld = false;
}
if (event.text == "SHIFT") {
shiftHeld = false;
}
}

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="pomodoro"
x="0px"
y="0px"
width="100"
height="100"
viewBox="-7.125 -7.328 100 100"
enable-background="new -7.125 -7.328 100 91.57"
xml:space="preserve"
inkscape:version="0.91 r13725"
sodipodi:docname="address-bar-error-close.svg"><metadata
id="metadata4143"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4141" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1840"
inkscape:window-height="1057"
id="namedview4139"
showgrid="false"
inkscape:zoom="4.8487496"
inkscape:cx="50"
inkscape:cy="37.53545"
inkscape:window-x="72"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="pomodoro" /><path
d="m 42.8705,-2.3280001 c -24.8688,0 -44.9955,20.1618001 -44.9955,45.0045001 0,24.8733 20.1267,44.9955 44.9955,44.9955 24.8427,0 45.0045,-20.1222 45.0045,-44.9955 0,-24.8427 -20.1618,-45.0045001 -45.0045,-45.0045001 z M 67.1066,57.126 57.329,66.9036 42.6293,52.221 27.9422,66.9036 18.1511,57.126 32.8247,42.4443 18.1511,27.7482 27.9422,17.9796 42.6284,32.6487 57.3281,17.9796 67.1057,27.7482 52.424,42.4434 67.1066,57.126 Z"
id="path4137"
inkscape:connector-curvature="0" /><path
style="fill:#787878;fill-opacity:1;stroke:none;stroke-opacity:1"
d="M 38.400102,87.62655 C 28.705316,86.39839 21.084707,83.18102 13.982682,77.31765 5.5185024,70.329714 -0.09877759,60.244376 -1.7904936,48.998291 -2.1921426,46.328239 -2.2434696,39.677941 -1.8825126,37.07572 0.23131941,21.836625 9.4778634,8.9272213 23.005945,2.3281243 c 9.805646,-4.783264 20.444414,-5.902737 30.964952,-3.25830896 7.357662,1.849413 14.403738,5.75570696 19.976698,11.07495366 7.36697,7.031569 12.03213,16.084669 13.58981,26.37208 0.45133,2.980701 0.44981,9.518147 -0.003,12.481442 -0.72914,4.772737 -2.08456,9.199896 -4.04575,13.214497 -2.40852,4.930297 -4.94684,8.502038 -8.75077,12.313422 -6.78153,6.79482 -14.822805,10.95587 -24.504932,12.68035 -1.787127,0.3183 -3.134188,0.40875 -6.708441,0.45045 -2.459762,0.0287 -4.765789,0.0149 -5.124505,-0.0304 z m -3.02899,-27.869116 7.314939,-7.311007 7.360877,7.35692 7.360872,7.356917 4.983865,-4.982378 4.98386,-4.982378 -7.359111,-7.358686 -7.359105,-7.358687 7.359105,-7.358687 7.359111,-7.358686 -4.98387,-4.982383 -4.983864,-4.982384 -7.407456,7.393329 -7.407456,7.393328 -7.360652,-7.342464 -7.36065,-7.342467 -4.922357,4.916384 -4.922356,4.916381 7.300528,7.417269 7.300528,7.417267 -7.362706,7.362244 -7.362709,7.362244 4.890918,4.889465 c 2.690008,2.689205 4.974582,4.889463 5.076835,4.889463 0.102254,0 3.477639,-3.289951 7.500854,-7.311004 z"
id="path4145"
inkscape:connector-curvature="0" /></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
<path fill="#000000" d="M50.291,0.07c-18.706,0-33.871,15.165-33.871,33.87c0,0.401,0.013,0.81,0.03,1.221 c0.127,3.558,0.798,6.976,1.939,10.173c7.226,23.752,31.901,54.736,31.901,54.736s24.674-30.982,31.901-54.734 c1.143-3.197,1.812-6.617,1.939-10.175c0.02-0.411,0.031-0.819,0.031-1.221C84.162,15.235,68.998,0.07,50.291,0.07z M51.013,58.386 c-2.479,0-4.664-2.126-4.664-4.664c0-2.479,2.184-4.723,4.664-4.723s4.724,2.243,4.724,4.723 C55.736,56.26,53.551,58.386,51.013,58.386z M50.481,45.811c-1.062-6.376-2.479-12.634-3.601-19.01 c-0.236-1.357-0.295-2.302-0.295-3.66c0-2.716,1.299-5.667,4.428-5.667c3.483,0,4.428,3.011,4.428,6.021 c0,1.181-0.059,2.538-0.295,3.66c-1.181,6.199-2.302,12.457-3.483,18.655H50.481z"/>
</svg>

After

Width:  |  Height:  |  Size: 954 B

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 49 49" enable-background="new 0 0 49 49" xml:space="preserve">
<g>
<g>
<path fill="#333" d="M49,46c0,1.7-1.3,3-3,3H3c-1.7,0-3-1.3-3-3V3c0-1.7,1.3-3,3-3h43c1.7,0,3,1.3,3,3V46z"/>
</g>
<g>
<g id="Your_Icon_11_">
<g>
<polygon fill="#E7EEEE" points="23.6,19.9 15.1,19.9 15.1,27.8 23.6,27.8 23.6,33.8 33,23.9 23.6,14 "/>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 759 B

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 49 49" enable-background="new 0 0 49 49" xml:space="preserve">
<g>
<g>
<path fill="#0E7077" d="M49,46c0,1.7-1.3,3-3,3H3c-1.7,0-3-1.3-3-3V3c0-1.7,1.3-3,3-3h43c1.7,0,3,1.3,3,3V46z"/>
</g>
<g>
<g id="Your_Icon_11_">
<g>
<polygon fill="#E7EEEE" points="23.6,19.9 15.1,19.9 15.1,27.8 23.6,27.8 23.6,33.8 33,23.9 23.6,14 "/>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 762 B

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="1440"
height="200"
data-icon="map-marker"
data-container-transform="translate(24)"
viewBox="0 0 1440 200"
id="svg4136"
inkscape:version="0.91 r13725"
sodipodi:docname="address-bar.svg">
<metadata
id="metadata4144">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4142" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1840"
inkscape:window-height="1057"
id="namedview4140"
showgrid="false"
inkscape:zoom="0.8671875"
inkscape:cx="707.02439"
inkscape:cy="52.468468"
inkscape:window-x="72"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4136" />
<rect
style="fill:#ededed;fill-opacity:1;stroke:none;stroke-linejoin:round;stroke-opacity:1"
id="rect4141"
width="1280"
height="140"
x="160"
y="30"
rx="16.025024"
ry="17.019567" />
<circle
style="fill:#b8b8b8;fill-opacity:1;stroke:none;stroke-opacity:1"
id="path4146"
cx="100"
cy="100"
r="100" />
<path
d="m 100,36.000005 c -22.1,0 -40,17.9 -40,39.999995 0,30 40,88 40,88 0,0 40,-58 40,-88 0,-22.099995 -17.9,-39.999995 -40,-39.999995 z m 0,22 c 9.9,0 18,8.099995 18,17.999995 0,9.9 -8.1,18 -18,18 -9.9,0 -18,-8.1 -18,-18 0,-9.9 8.1,-17.999995 18,-17.999995 z"
id="path4138"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -1,91 +1,145 @@
//
// AddressBarDialog.qml
//
// Created by Austin Davis on 2015/04/14
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import Hifi 1.0
import QtQuick 2.3
import QtQuick.Controls 1.2
import "controls"
import "styles"
Dialog {
Item {
id: root
HifiConstants { id: hifi }
title: "Go to..."
objectName: "AddressBarDialog"
contentImplicitWidth: addressBarDialog.implicitWidth
contentImplicitHeight: addressBarDialog.implicitHeight
destroyOnCloseButton: false
property int animationDuration: hifi.effects.fadeInDuration
property bool destroyOnInvisible: false
onVisibleChanged: {
if (!visible) {
reset();
}
implicitWidth: addressBarDialog.implicitWidth
implicitHeight: addressBarDialog.implicitHeight
x: parent ? parent.width / 2 - width / 2 : 0
y: parent ? parent.height / 2 - height / 2 : 0
property int maximumX: parent ? parent.width - width : 0
property int maximumY: parent ? parent.height - height : 0
AddressBarDialog {
id: addressBarDialog
implicitWidth: backgroundImage.width
implicitHeight: backgroundImage.height
Image {
id: backgroundImage
source: "../images/address-bar.svg"
width: 576
height: 80
property int inputAreaHeight: 56 // Height of the background's input area
property int inputAreaStep: (height - inputAreaHeight) / 2
TextInput {
id: addressLine
anchors {
fill: parent
leftMargin: parent.height + hifi.layout.spacing * 2
rightMargin: hifi.layout.spacing * 2
topMargin: parent.inputAreaStep + hifi.layout.spacing
bottomMargin: parent.inputAreaStep + hifi.layout.spacing
}
font.pointSize: 15
helperText: "Go to: place, @user, /path, network address"
onAccepted: {
event.accepted = true // Generates erroneous error in program log, "ReferenceError: event is not defined".
addressBarDialog.loadAddress(addressLine.text)
}
}
MouseArea {
// Drag the icon
width: parent.height
height: parent.height
x: 0
y: 0
drag {
target: root
minimumX: -parent.inputAreaStep
minimumY: -parent.inputAreaStep
maximumX: root.parent ? root.maximumX : 0
maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0
}
}
MouseArea {
// Drag the input rectangle
width: parent.width - parent.height
height: parent.inputAreaHeight
x: parent.height
y: parent.inputAreaStep
drag {
target: root
minimumX: -parent.inputAreaStep
minimumY: -parent.inputAreaStep
maximumX: root.parent ? root.maximumX : 0
maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0
}
}
}
}
// The UI enables an object, rather than manipulating its visibility, so that we can do animations in both directions.
// Because visibility and enabled are booleans, they cannot be animated. So when enabled is changed, we modify a property
// that can be animated, like scale or opacity, and then when the target animation value is reached, we can modify the
// visibility.
enabled: false
opacity: 0.0
onEnabledChanged: {
opacity = enabled ? 1.0 : 0.0
if (enabled) {
addressLine.forceActiveFocus();
}
}
onParentChanged: {
if (enabled && visible) {
addressLine.forceActiveFocus();
Behavior on opacity {
// Animate opacity.
NumberAnimation {
duration: animationDuration
easing.type: Easing.OutCubic
}
}
onOpacityChanged: {
// Once we're transparent, disable the dialog's visibility.
visible = (opacity != 0.0)
}
onVisibleChanged: {
if (!visible) {
reset()
// Some dialogs should be destroyed when they become invisible.
if (destroyOnInvisible) {
destroy()
}
}
}
function reset() {
addressLine.text = ""
goButton.source = "../images/address-bar-submit.svg"
}
AddressBarDialog {
id: addressBarDialog
// The client area
x: root.clientX
y: root.clientY
implicitWidth: 512
implicitHeight: border.height + hifi.layout.spacing * 4
Border {
id: border
height: 64
anchors.left: parent.left
anchors.leftMargin: hifi.layout.spacing * 2
anchors.right: goButton.left
anchors.rightMargin: hifi.layout.spacing
anchors.verticalCenter: parent.verticalCenter
TextInput {
id: addressLine
anchors.fill: parent
helperText: "domain, location, @user, /x,y,z"
anchors.margins: hifi.layout.spacing
onAccepted: {
event.accepted
addressBarDialog.loadAddress(addressLine.text)
}
}
}
Image {
id: goButton
width: 32
height: 32
anchors.right: parent.right
anchors.rightMargin: hifi.layout.spacing * 2
source: "../images/address-bar-submit.svg"
anchors.verticalCenter: parent.verticalCenter
MouseArea {
anchors.fill: parent
onClicked: {
parent.source = "../images/address-bar-submit-active.svg"
addressBarDialog.loadAddress(addressLine.text)
}
}
}
}
Keys.onEscapePressed: {
enabled = false;
}
function toggleOrGo() {
@ -95,8 +149,22 @@ Dialog {
addressBarDialog.loadAddress(addressLine.text)
}
}
Keys.onEscapePressed: {
enabled = false
}
Keys.onPressed: {
switch(event.key) {
case Qt.Key_W:
if (event.modifiers == Qt.ControlModifier) {
event.accepted = true
enabled = false
}
break
}
}
Keys.onReturnPressed: toggleOrGo()
Keys.onEnterPressed: toggleOrGo()
}

View file

@ -0,0 +1,152 @@
//
// ErrorDialog.qml
//
// Created by David Rowe on 30 May 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import Hifi 1.0 as Hifi
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import "controls"
import "styles"
Item {
id: root
HifiConstants { id: hifi }
property int animationDuration: hifi.effects.fadeInDuration
property bool destroyOnInvisible: true
Component.onCompleted: {
enabled = true
}
onParentChanged: {
if (visible && enabled) {
forceActiveFocus();
}
}
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
x: parent ? parent.width / 2 - width / 2 : 0
y: parent ? parent.height / 2 - height / 2 : 0
Hifi.ErrorDialog {
id: content
implicitWidth: box.width
implicitHeight: icon.height + hifi.layout.spacing * 2
Border {
id: box
width: 512
color: "#ebebeb"
radius: 2
border.width: 1
border.color: "#000000"
Image {
id: icon
source: "../images/address-bar-error-icon.svg"
width: 40
height: 40
anchors {
left: parent.left
leftMargin: hifi.layout.spacing
verticalCenter: parent.verticalCenter
}
}
Text {
id: messageText
font.pointSize: 10
font.weight: Font.Bold
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
text: content.text
}
Image {
source: "../images/address-bar-error-close.svg"
width: 20
height: 20
anchors {
right: parent.right
rightMargin: hifi.layout.spacing * 2
verticalCenter: parent.verticalCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
content.accept();
}
}
}
}
}
// The UI enables an object, rather than manipulating its visibility, so that we can do animations in both directions.
// Because visibility and enabled are booleans, they cannot be animated. So when enabled is changed, we modify a property
// that can be animated, like scale or opacity, and then when the target animation value is reached, we can modify the
// visibility.
enabled: false
opacity: 0.0
onEnabledChanged: {
opacity = enabled ? 1.0 : 0.0
}
Behavior on opacity {
// Animate opacity.
NumberAnimation {
duration: animationDuration
easing.type: Easing.OutCubic
}
}
onOpacityChanged: {
// Once we're transparent, disable the dialog's visibility.
visible = (opacity != 0.0)
}
onVisibleChanged: {
if (!visible) {
// Some dialogs should be destroyed when they become invisible.
if (destroyOnInvisible) {
destroy()
}
}
}
Keys.onPressed: {
if (event.modifiers === Qt.ControlModifier)
switch (event.key) {
case Qt.Key_W:
event.accepted = true
content.accept()
break
} else switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
content.accept()
break
}
}
}

View file

@ -31,7 +31,7 @@ DialogBase {
* Support for animating the dialog in and out.
*/
enabled: false
scale: 0.0
opacity: 1.0
// The offscreen UI will enable an object, rather than manipulating it's
// visibility, so that we can do animations in both directions. Because
@ -40,20 +40,20 @@ DialogBase {
// opacity, and then when the target animation value is reached, we can
// modify the visibility
onEnabledChanged: {
scale = enabled ? 1.0 : 0.0
opacity = enabled ? 1.0 : 0.0
}
// The actual animator
Behavior on scale {
Behavior on opacity {
NumberAnimation {
duration: root.animationDuration
easing.type: Easing.InOutBounce
duration: animationDuration
easing.type: Easing.OutCubic
}
}
// Once we're scaled to 0, disable the dialog's visibility
onScaleChanged: {
visible = (scale != 0.0);
// Once we're transparent, disable the dialog's visibility
onOpacityChanged: {
visible = (opacity != 0.0);
}
// Some dialogs should be destroyed when they become invisible,

View file

@ -56,6 +56,6 @@ Item {
QtObject {
id: effects
readonly property int fadeInDuration: 400
readonly property int fadeInDuration: 300
}
}

View file

@ -55,40 +55,41 @@
#include <QMessageBox>
#include <QJsonDocument>
#include <AddressManager.h>
#include <AccountManager.h>
#include <AddressManager.h>
#include <AmbientOcclusionEffect.h>
#include <AudioInjector.h>
#include <DeferredLightingEffect.h>
#include <DependencyManager.h>
#include <EntityScriptingInterface.h>
#include <ErrorDialog.h>
#include <GlowEffect.h>
#include <HFActionEvent.h>
#include <HFBackEvent.h>
#include <VrMenu.h>
#include <InfoView.h>
#include <LogHandler.h>
#include <MainWindow.h>
#include <MessageDialog.h>
#include <ModelEntityItem.h>
#include <NetworkAccessManager.h>
#include <NetworkingConstants.h>
#include <ObjectMotionState.h>
#include <OctalCode.h>
#include <OctreeSceneStats.h>
#include <ObjectMotionState.h>
#include <PacketHeaders.h>
#include <PathUtils.h>
#include <PerfStat.h>
#include <PhysicsEngine.h>
#include <ProgramObject.h>
#include <ResourceCache.h>
#include <SceneScriptingInterface.h>
#include <ScriptCache.h>
#include <SettingHandle.h>
#include <SoundCache.h>
#include <TextRenderer.h>
#include <UserActivityLogger.h>
#include <UUID.h>
#include <MessageDialog.h>
#include <InfoView.h>
#include <SceneScriptingInterface.h>
#include <VrMenu.h>
#include "Application.h"
#include "AudioClient.h"
@ -799,6 +800,7 @@ void Application::initializeGL() {
void Application::initializeUi() {
AddressBarDialog::registerType();
ErrorDialog::registerType();
LoginDialog::registerType();
MessageDialog::registerType();
VrMenu::registerType();
@ -3103,20 +3105,27 @@ PickRay Application::computePickRay(float x, float y) const {
QImage Application::renderAvatarBillboard() {
auto primaryFramebuffer = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer));
// clear the alpha channel so the background is transparent
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
// the "glow" here causes an alpha of one
Glower glower;
const int BILLBOARD_SIZE = 64;
renderRearViewMirror(QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE,
BILLBOARD_SIZE, BILLBOARD_SIZE),
true);
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return image;
}
@ -3160,7 +3169,7 @@ const ViewFrustum* Application::getDisplayViewFrustum() const {
return &_displayViewFrustum;
}
void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs::RenderSide renderSide) {
void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, bool billboard, RenderArgs::RenderSide renderSide) {
activeRenderingThread = QThread::currentThread();
PROFILE_RANGE(__FUNCTION__);
PerformanceTimer perfTimer("display");
@ -3376,7 +3385,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
false, selfAvatarOnly);
}
{
if (!billboard) {
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity(), skyStage->getSunLight()->getAmbientIntensity());
@ -3579,7 +3588,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
// render rear mirror view
glPushMatrix();
displaySide(_mirrorCamera, true);
displaySide(_mirrorCamera, true, billboard);
glPopMatrix();
if (!billboard) {

View file

@ -270,7 +270,7 @@ public:
QImage renderAvatarBillboard();
void displaySide(Camera& whichCamera, bool selfAvatarOnly = false, RenderArgs::RenderSide renderSide = RenderArgs::MONO);
void displaySide(Camera& whichCamera, bool selfAvatarOnly = false, bool billboard = false, RenderArgs::RenderSide renderSide = RenderArgs::MONO);
/// Stores the current modelview matrix as the untranslated view matrix to use for transforms and the supplied vector as
/// the view matrix translation.

View file

@ -93,22 +93,24 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
if (_isFaceTrackerConnected) {
_blendshapeCoefficients = faceTracker->getBlendshapeCoefficients();
if (typeid(*faceTracker) == typeid(DdeFaceTracker)
&& Menu::getInstance()->isOptionChecked(MenuOption::UseAudioForMouth)) {
if (typeid(*faceTracker) == typeid(DdeFaceTracker)) {
calculateMouthShapes();
if (Menu::getInstance()->isOptionChecked(MenuOption::UseAudioForMouth)) {
calculateMouthShapes();
const int JAW_OPEN_BLENDSHAPE = 21;
const int MMMM_BLENDSHAPE = 34;
const int FUNNEL_BLENDSHAPE = 40;
const int SMILE_LEFT_BLENDSHAPE = 28;
const int SMILE_RIGHT_BLENDSHAPE = 29;
_blendshapeCoefficients[JAW_OPEN_BLENDSHAPE] += _audioJawOpen;
_blendshapeCoefficients[SMILE_LEFT_BLENDSHAPE] += _mouth4;
_blendshapeCoefficients[SMILE_RIGHT_BLENDSHAPE] += _mouth4;
_blendshapeCoefficients[MMMM_BLENDSHAPE] += _mouth2;
_blendshapeCoefficients[FUNNEL_BLENDSHAPE] += _mouth3;
const int JAW_OPEN_BLENDSHAPE = 21;
const int MMMM_BLENDSHAPE = 34;
const int FUNNEL_BLENDSHAPE = 40;
const int SMILE_LEFT_BLENDSHAPE = 28;
const int SMILE_RIGHT_BLENDSHAPE = 29;
_blendshapeCoefficients[JAW_OPEN_BLENDSHAPE] += _audioJawOpen;
_blendshapeCoefficients[SMILE_LEFT_BLENDSHAPE] += _mouth4;
_blendshapeCoefficients[SMILE_RIGHT_BLENDSHAPE] += _mouth4;
_blendshapeCoefficients[MMMM_BLENDSHAPE] += _mouth2;
_blendshapeCoefficients[FUNNEL_BLENDSHAPE] += _mouth3;
}
applyEyelidOffset(getFinalOrientationInWorldFrame());
}
}
}
@ -203,6 +205,9 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
_mouth3,
_mouth4,
_blendshapeCoefficients);
applyEyelidOffset(getOrientation());
} else {
_saccade = glm::vec3();
}
@ -218,7 +223,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
}
}
_eyePosition = calculateAverageEyePosition();
}
void Head::calculateMouthShapes() {
@ -249,6 +253,32 @@ void Head::calculateMouthShapes() {
_mouth4 = glm::mix(_audioJawOpen, _mouth4, SMILE_PERIOD + randFloat() * SMILE_RANDOM_PERIOD);
}
void Head::applyEyelidOffset(glm::quat headOrientation) {
// Adjusts the eyelid blendshape coefficients so that the eyelid follows the iris as the head pitches.
glm::quat eyeRotation = rotationBetween(headOrientation * IDENTITY_FRONT, getCorrectedLookAtPosition() - _eyePosition);
eyeRotation = eyeRotation * glm::angleAxis(safeEulerAngles(headOrientation).y, IDENTITY_UP); // Rotation w.r.t. head
float eyePitch = safeEulerAngles(eyeRotation).x;
const float EYE_PITCH_TO_COEFFICIENT = 1.6f; // Empirically determined
const float MAX_EYELID_OFFSET = 0.8f; // So that don't fully close eyes when looking way down
float eyelidOffset = glm::clamp(-eyePitch * EYE_PITCH_TO_COEFFICIENT, -1.0f, MAX_EYELID_OFFSET);
for (int i = 0; i < 2; i++) {
const int LEFT_EYE = 8;
float eyeCoefficient = _blendshapeCoefficients[i] - _blendshapeCoefficients[LEFT_EYE + i]; // Raw value
eyeCoefficient = glm::clamp(eyelidOffset + eyeCoefficient * (1.0f - eyelidOffset), -1.0f, 1.0f);
if (eyeCoefficient > 0.0f) {
_blendshapeCoefficients[i] = eyeCoefficient;
_blendshapeCoefficients[LEFT_EYE + i] = 0.0f;
} else {
_blendshapeCoefficients[i] = 0.0f;
_blendshapeCoefficients[LEFT_EYE + i] = -eyeCoefficient;
}
}
}
void Head::relaxLean(float deltaTime) {
// restore rotation, lean to neutral positions
const float LEAN_RELAXATION_PERIOD = 0.25f; // seconds

View file

@ -155,6 +155,7 @@ private:
// private methods
void renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition);
void calculateMouthShapes();
void applyEyelidOffset(glm::quat headOrientation);
friend class FaceModel;
};

View file

@ -36,12 +36,10 @@ void AddressBarDialog::loadAddress(const QString& address) {
}
void AddressBarDialog::displayAddressOfflineMessage() {
OffscreenUi::information("Address offline",
"That user or place is currently offline.");
OffscreenUi::error("That user or place is currently offline");
}
void AddressBarDialog::displayAddressNotFoundMessage() {
OffscreenUi::information("Address not found",
"There is no address information for that user or place.");
OffscreenUi::error("There is no address information for that user or place");
}

View file

@ -507,7 +507,6 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
QPoint rv;
auto canvasSize = qApp->getCanvasSize();
if (qApp->isHMDMode()) {
float t;
glm::vec2 polar = getPolarCoordinates(*palm);
glm::vec2 point = sphericalToScreen(-polar);
rv.rx() = point.x;

View file

@ -82,7 +82,10 @@ void AvatarAppearanceDialog::setUseFullAvatar(bool useFullAvatar) {
ui.useFullAvatar->setChecked(_useFullAvatar);
ui.useSeparateBodyAndHead->setChecked(!_useFullAvatar);
DependencyManager::get<DialogsManager>()->getPreferencesDialog()->avatarDescriptionChanged();
QPointer<PreferencesDialog> prefs = DependencyManager::get<DialogsManager>()->getPreferencesDialog();
if (prefs) { // Preferences dialog may have been closed
prefs->avatarDescriptionChanged();
}
}
void AvatarAppearanceDialog::headURLChanged(const QString& newValue, const QString& modelName) {
@ -106,7 +109,10 @@ void AvatarAppearanceDialog::fullAvatarURLChanged(const QString& newValue, const
void AvatarAppearanceDialog::accept() {
saveAvatarAppearance();
DependencyManager::get<DialogsManager>()->getPreferencesDialog()->avatarDescriptionChanged();
QPointer<PreferencesDialog> prefs = DependencyManager::get<DialogsManager>()->getPreferencesDialog();
if (prefs) { // Preferences dialog may have been closed
prefs->avatarDescriptionChanged();
}
close();
delete _marketplaceWindow;

View file

@ -17,4 +17,10 @@ find_package(PolyVox REQUIRED)
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})
# for changing the pitch of collision sounds
add_dependency_external_projects(soxr)
find_package(Soxr REQUIRED)
target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES})
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS})
link_hifi_libraries(shared gpu script-engine render-utils)

View file

@ -27,6 +27,8 @@
#include <ScriptEngine.h>
#include <TextureCache.h>
#include <SoundCache.h>
#include <soxr.h>
#include <AudioConstants.h>
#include "EntityTreeRenderer.h"
@ -1133,7 +1135,7 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
const float energy = mass * linearVelocity * linearVelocity / 2.0f;
const glm::vec3 position = collision.contactPoint;
const float COLLISION_ENERGY_AT_FULL_VOLUME = 0.5f;
const float COLLISION_MINIMUM_VOLUME = 0.001f;
const float COLLISION_MINIMUM_VOLUME = 0.005f;
const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME);
if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) {
return;
@ -1149,7 +1151,7 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
}
// This is a hack. Quiet sound aren't really heard at all, so we compress everything to the range [1-c, 1], if we play it all.
const float COLLISION_SOUND_COMPRESSION_RANGE = 0.7f;
const float COLLISION_SOUND_COMPRESSION_RANGE = 1.0f; // This section could be removed when the value is 1, but let's see how it goes.
float volume = energyFactorOfFull;
volume = (volume * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);
@ -1158,7 +1160,30 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
options.stereo = sound->isStereo();
options.position = position;
options.volume = volume;
AudioInjector* injector = new AudioInjector(sound.data(), options);
// Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2)
const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;
QByteArray samples = sound->getByteArray();
soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I);
soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
const int channelCount = sound->isStereo() ? 2 : 1;
const float factor = log(1.0f + (entity->getMaximumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
const int standardRate = AudioConstants::SAMPLE_RATE;
const int resampledRate = standardRate * factor;
const int nInputSamples = samples.size() / sizeof(int16_t);
const int nOutputSamples = nInputSamples * factor;
QByteArray resampled(nOutputSamples * sizeof(int16_t), '\0');
const int16_t* receivedSamples = reinterpret_cast<const int16_t*>(samples.data());
soxr_error_t soxError = soxr_oneshot(standardRate, resampledRate, channelCount,
receivedSamples, nInputSamples, NULL,
reinterpret_cast<int16_t*>(resampled.data()), nOutputSamples, NULL,
&spec, &qualitySpec, 0);
if (soxError) {
qCDebug(entitiesrenderer) << "Unable to resample" << collisionSoundURL << "from" << nInputSamples << "@" << standardRate << "to" << nOutputSamples << "@" << resampledRate;
resampled = samples;
}
AudioInjector* injector = new AudioInjector(resampled, options);
injector->setLocalAudioInterface(_localAudioInterface);
injector->triggerDeleteAfterFinish();
QThread* injectorThread = new QThread();
@ -1180,7 +1205,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
return;
}
// Don't respond to small continuous contacts.
const float COLLISION_MINUMUM_PENETRATION = 0.005f;
const float COLLISION_MINUMUM_PENETRATION = 0.002f;
if ((collision.type != CONTACT_EVENT_TYPE_START) && (glm::length(collision.penetration) < COLLISION_MINUMUM_PENETRATION)) {
return;
}

View file

@ -12,6 +12,7 @@
#include <glm/gtx/quaternion.hpp>
#include <gpu/GPUConfig.h>
#include <GeometryCache.h>
#include <DeferredLightingEffect.h>
#include <PerfStat.h>
@ -30,12 +31,20 @@ void RenderableLineEntityItem::render(RenderArgs* args) {
glm::quat rotation = getRotation();
glm::vec4 lineColor(toGlm(getXColor()), getLocalRenderAlpha());
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glLineWidth(getLineWidth());
auto geometryCache = DependencyManager::get<GeometryCache>();
if (_lineVerticesID == GeometryCache::UNKNOWN_ID) {
_lineVerticesID = geometryCache ->allocateID();
}
//TODO: Figure out clean , efficient way to do relative line positioning. For now we'll just use absolute positioning.
//glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glm::vec3 p1 = {0.0f, 0.0f, 0.0f};
glm::vec3& p2 = dimensions;
DependencyManager::get<DeferredLightingEffect>()->renderLine(p1, p2, lineColor, lineColor);
if (_pointsChanged) {
geometryCache->updateVertices(_lineVerticesID, getLinePoints(), lineColor);
_pointsChanged = false;
}
geometryCache->renderVertices(gpu::LINE_STRIP, _lineVerticesID);
glPopMatrix();
RenderableDebugableEntityItem::render(this, args);

View file

@ -14,15 +14,21 @@
#include <LineEntityItem.h>
#include "RenderableDebugableEntityItem.h"
#include <GeometryCache.h>
class RenderableLineEntityItem : public LineEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
LineEntityItem(entityItemID, properties) { }
LineEntityItem(entityItemID, properties),
_lineVerticesID(GeometryCache::UNKNOWN_ID)
{ }
virtual void render(RenderArgs* args);
protected:
int _lineVerticesID;
};

View file

@ -33,22 +33,63 @@
#include "EntityTreeRenderer.h"
#include "RenderablePolyVoxEntityItem.h"
EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderablePolyVoxEntityItem(entityID, properties));
}
RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID,
const EntityItemProperties& properties) :
PolyVoxEntityItem(entityItemID, properties) {
model::Mesh* mesh = new model::Mesh();
model::MeshPointer meshPtr(mesh);
_modelGeometry.setMesh(meshPtr);
setVoxelVolumeSize(_voxelVolumeSize);
}
RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() {
delete _volData;
}
void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
bool inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
int x, int y, int z) {
// x, y, z are in user voxel-coords, not adjusted-for-edge voxel-coords.
switch (surfaceStyle) {
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
case PolyVoxEntityItem::SURFACE_CUBIC:
if (x < 0 || y < 0 || z < 0 ||
x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()) {
return false;
}
return true;
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
if (x < 0 || y < 0 || z < 0 ||
x >= vol->getWidth() - 2 || y >= vol->getHeight() - 2 || z >= vol->getDepth() - 2) {
return false;
}
return true;
}
return false;
}
bool inBounds(const PolyVox::SimpleVolume<uint8_t>* vol, int x, int y, int z) {
// x, y, z are in polyvox volume coords
return !(x < 0 || y < 0 || z < 0 || x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth());
}
void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
if (_volData && voxelVolumeSize == _voxelVolumeSize) {
return;
}
qDebug() << "resetting voxel-space size";
#ifdef WANT_DEBUG
qDebug() << "resetting voxel-space size" << voxelVolumeSize.x << voxelVolumeSize.y << voxelVolumeSize.z;
#endif
PolyVoxEntityItem::setVoxelVolumeSize(voxelVolumeSize);
@ -56,14 +97,69 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize)
delete _volData;
}
PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize[0] - 1, // -1 because these corners are inclusive
_voxelVolumeSize[1] - 1,
_voxelVolumeSize[2] - 1);
_onCount = 0;
_volData = new PolyVox::SimpleVolume<uint8_t>(PolyVox::Region(lowCorner, highCorner));
if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
// with _EDGED_ we maintain an extra box of voxels around those that the user asked for. This
// changes how the surface extractor acts -- mainly it becomes impossible to have holes in the
// generated mesh. The non _EDGED_ modes will leave holes in the mesh at the edges of the
// voxel space.
PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x + 1, // -1 + 2 because these corners are inclusive
_voxelVolumeSize.y + 1,
_voxelVolumeSize.z + 1);
_volData = new PolyVox::SimpleVolume<uint8_t>(PolyVox::Region(lowCorner, highCorner));
} else {
PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x - 1, // -1 because these corners are inclusive
_voxelVolumeSize.y - 1,
_voxelVolumeSize.z - 1);
_volData = new PolyVox::SimpleVolume<uint8_t>(PolyVox::Region(lowCorner, highCorner));
}
// having the "outside of voxel-space" value be 255 has helped me notice some problems.
_volData->setBorderValue(255);
#ifdef WANT_DEBUG
qDebug() << " new size is" << _volData->getWidth() << _volData->getHeight() << _volData->getDepth();
#endif
// I'm not sure this is needed... the docs say that each element is initialized with its default
// constructor. I'll leave it here for now.
for (int z = 0; z < _volData->getDepth(); z++) {
for (int y = 0; y < _volData->getHeight(); y++) {
for (int x = 0; x < _volData->getWidth(); x++) {
_volData->setVoxelAt(x, y, z, 0);
}
}
}
// It's okay to decompress the old data here, because the data includes its original dimensions along
// with the voxel data, and writing voxels outside the bounds of the new space is harmless. This allows
// adjusting of the voxel-space size without overly mangling the shape. Shrinking the space and then
// restoring the previous size (without any edits in between) will put the original shape back.
decompressVolumeData();
}
void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {
if (voxelSurfaceStyle == _voxelSurfaceStyle) {
return;
}
// if we are switching to or from "edged" we need to force a resize of _volData.
if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC ||
_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
if (_volData) {
delete _volData;
}
_volData = nullptr;
PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle);
setVoxelVolumeSize(_voxelVolumeSize);
} else {
PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle);
}
_needsModelReload = true;
}
void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
if (voxelData == _voxelData) {
@ -73,57 +169,138 @@ void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
decompressVolumeData();
}
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
switch (_voxelSurfaceStyle) {
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
return scale / 2.0f;
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
return scale / -2.0f;
case PolyVoxEntityItem::SURFACE_CUBIC:
return scale / 2.0f;
}
return glm::vec3(0.0f, 0.0f, 0.0f);
}
glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
glm::vec3 center = getCenter();
glm::vec3 position = getPosition();
glm::vec3 positionToCenter = center - position;
positionToCenter -= _dimensions * glm::vec3(0.5f, 0.5f, 0.5f) - getSurfacePositionAdjustment();
glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
glm::mat4 scaled = glm::scale(centerToCorner, scale);
return scaled;
}
glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const {
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
glm::mat4 scaled = glm::scale(glm::mat4(), scale);
glm::mat4 centerToCorner = glm::translate(scaled, _voxelVolumeSize / -2.0f);
glm::mat4 rotation = glm::mat4_cast(_rotation);
glm::mat4 translation = glm::translate(getCenter());
return translation * rotation * centerToCorner;
glm::mat4 translation = glm::translate(getPosition());
return translation * rotation * voxelToLocalMatrix();
}
glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const {
glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix());
return worldToModelMatrix;
}
uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) {
assert(_volData);
if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) {
return 0;
}
// if _voxelSurfaceStyle is SURFACE_EDGED_CUBIC, we maintain an extra layer of
// voxels all around the requested voxel space. Having the empty voxels around
// the edges changes how the surface extractor behaves.
if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
return _volData->getVoxelAt(x + 1, y + 1, z + 1);
}
return _volData->getVoxelAt(x, y, z);
}
void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) {
assert(_volData);
if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) {
return;
}
if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
_volData->setVoxelAt(x + 1, y + 1, z + 1, toValue);
} else {
_volData->setVoxelAt(x, y, z, toValue);
}
}
void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toValue) {
// keep _onCount up to date
if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) {
return;
}
uint8_t uVoxelValue = getVoxel(x, y, z);
if (toValue != 0) {
if (uVoxelValue == 0) {
_onCount++;
}
} else {
// toValue == 0
if (uVoxelValue != 0) {
_onCount--;
assert(_onCount >= 0);
}
}
}
void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) {
for (int z = 0; z < _voxelVolumeSize.z; z++) {
for (int y = 0; y < _voxelVolumeSize.y; y++) {
for (int x = 0; x < _voxelVolumeSize.x; x++) {
updateOnCount(x, y, z, toValue);
setVoxel(x, y, z, toValue);
}
}
}
compressVolumeData();
}
void RenderablePolyVoxEntityItem::setVoxelInVolume(glm::vec3 position, uint8_t toValue) {
updateOnCount(position.x, position.y, position.z, toValue);
setVoxel(position.x, position.y, position.z, toValue);
}
void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) {
// This three-level for loop iterates over every voxel in the volume
for (int z = 0; z < _volData->getDepth(); z++) {
for (int y = 0; y < _volData->getHeight(); y++) {
for (int x = 0; x < _volData->getWidth(); x++) {
for (int z = 0; z < _voxelVolumeSize.z; z++) {
for (int y = 0; y < _voxelVolumeSize.y; y++) {
for (int x = 0; x < _voxelVolumeSize.x; x++) {
// Store our current position as a vector...
glm::vec3 pos(x, y, z);
glm::vec3 pos(x + 0.5f, y + 0.5f, z + 0.5f); // consider voxels cenetered on their coordinates
// And compute how far the current position is from the center of the volume
float fDistToCenter = glm::distance(pos, center);
// If the current voxel is less than 'radius' units from the center then we make it solid.
if (fDistToCenter <= radius) {
_volData->setVoxelAt(x, y, z, toValue);
updateOnCount(x, y, z, toValue);
setVoxel(x, y, z, toValue);
}
}
}
}
compressVolumeData();
_needsModelReload = true;
}
void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) {
// glm::vec3 centerVoxelCoords = worldToVoxelCoordinates(centerWorldCoords);
glm::vec4 centerVoxelCoords = worldToVoxelMatrix() * glm::vec4(centerWorldCoords, 1.0f);
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
float scaleY = scale[0];
float scaleY = scale.y;
float radiusVoxelCoords = radiusWorldCoords / scaleY;
setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue);
}
void RenderablePolyVoxEntityItem::getModel() {
if (!_volData) {
// this will cause the allocation of _volData
setVoxelVolumeSize(_voxelVolumeSize);
}
// A mesh object to hold the result of surface extraction
PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> polyVoxMesh;
@ -134,6 +311,7 @@ void RenderablePolyVoxEntityItem::getModel() {
surfaceExtractor.execute();
break;
}
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
case PolyVoxEntityItem::SURFACE_CUBIC: {
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
@ -143,24 +321,25 @@ void RenderablePolyVoxEntityItem::getModel() {
}
// convert PolyVox mesh to a Sam mesh
model::Mesh* mesh = new model::Mesh();
model::MeshPointer meshPtr(mesh);
auto mesh = _modelGeometry.getMesh();
const std::vector<uint32_t>& vecIndices = polyVoxMesh.getIndices();
auto indexBuffer = new gpu::Buffer(vecIndices.size() * sizeof(uint32_t), (gpu::Byte*)vecIndices.data());
auto indexBufferPtr = gpu::BufferPointer(indexBuffer);
mesh->setIndexBuffer(gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW)));
auto indexBufferView = new gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW));
mesh->setIndexBuffer(*indexBufferView);
const std::vector<PolyVox::PositionMaterialNormal>& vecVertices = polyVoxMesh.getVertices();
auto vertexBuffer = new gpu::Buffer(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal),
(gpu::Byte*)vecVertices.data());
auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer);
mesh->setVertexBuffer(gpu::BufferView(vertexBufferPtr,
0,
vertexBufferPtr->getSize() - sizeof(float) * 3,
sizeof(PolyVox::PositionMaterialNormal),
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
auto vertexBufferView = new gpu::BufferView(vertexBufferPtr,
0,
vertexBufferPtr->getSize() - sizeof(float) * 3,
sizeof(PolyVox::PositionMaterialNormal),
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW));
mesh->setVertexBuffer(*vertexBufferView);
mesh->addAttribute(gpu::Stream::NORMAL,
gpu::BufferView(vertexBufferPtr,
sizeof(float) * 3,
@ -168,15 +347,28 @@ void RenderablePolyVoxEntityItem::getModel() {
sizeof(PolyVox::PositionMaterialNormal),
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
// auto normalAttrib = mesh->getAttributeBuffer(gpu::Stream::NORMAL);
// for (auto normal = normalAttrib.begin<glm::vec3>(); normal != normalAttrib.end<glm::vec3>(); normal++) {
// (*normal) = -(*normal);
// }
// mesh->addAttribute(gpu::Stream::TEXCOORD,
// gpu::BufferView(vertexBufferPtr,
// sizeof(float) * 2,
// vertexBufferPtr->getSize() - sizeof(float) * 2,
// sizeof(PolyVox::PositionMaterialNormal),
// gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::RAW)));
#ifdef WANT_DEBUG
qDebug() << "---- vecIndices.size() =" << vecIndices.size();
qDebug() << "---- vecVertices.size() =" << vecVertices.size();
#endif
_modelGeometry.setMesh(meshPtr);
_needsModelReload = false;
}
@ -188,20 +380,9 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
getModel();
}
glm::vec3 position = getPosition();
glm::vec3 dimensions = getDimensions();
glm::vec3 scale = dimensions / _voxelVolumeSize;
glm::vec3 center = getCenter();
glm::quat rotation = getRotation();
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glm::vec3 positionToCenter = center - position;
// make the rendered voxel volume be centered on the entity's position
positionToCenter -= _dimensions * glm::vec3(0.5f,0.5f,0.5f);
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
glScalef(scale.x, scale.y, scale.z);
glm::mat4 m = voxelToWorldMatrix();
glMultMatrixf(&m[0][0]);
auto mesh = _modelGeometry.getMesh();
gpu::Batch batch;
@ -221,9 +402,20 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
class RaycastFunctor
{
public:
RaycastFunctor() : _result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)) { }
RaycastFunctor(PolyVox::SimpleVolume<uint8_t>* vol) :
_result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)),
_vol(vol) {
}
bool operator()(PolyVox::SimpleVolume<unsigned char>::Sampler& sampler)
{
int x = sampler.getPosition().getX();
int y = sampler.getPosition().getY();
int z = sampler.getPosition().getZ();
if (!inBounds(_vol, x, y, z)) {
return true;
}
if (sampler.getVoxel() == 0) {
return true; // keep raycasting
}
@ -232,6 +424,7 @@ public:
return false;
}
glm::vec4 _result;
const PolyVox::SimpleVolume<uint8_t>* _vol = nullptr;
};
bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin,
@ -247,33 +440,45 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
return true;
}
// the PolyVox ray intersection code requires a near and far point.
glm::mat4 wtvMatrix = worldToVoxelMatrix();
glm::vec3 farPoint = origin + direction;
glm::vec3 normDirection = glm::normalize(direction);
// set ray cast length to long enough to cover all of the voxel space
float distanceToEntity = glm::distance(origin, _position);
float largestDimension = glm::max(_dimensions.x, _dimensions.y, _dimensions.z) * 2.0f;
glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension);
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 1.0f);
glm::vec4 directionInVoxel = farInVoxel - originInVoxel;
PolyVox::Vector3DFloat start(originInVoxel[0], originInVoxel[1], originInVoxel[2]);
PolyVox::Vector3DFloat pvDirection(directionInVoxel[0], directionInVoxel[1], directionInVoxel[2]);
pvDirection.normalise();
// the PolyVox ray intersection code requires a near and far point.
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
float distanceToEntity = glm::distance(origin, _position);
float largestDimension = glm::max(_dimensions[0], _dimensions[1], _dimensions[2]);
// set ray cast length to long enough to cover all of the voxel space
pvDirection *= (distanceToEntity + largestDimension) / glm::min(scale[0], scale[1], scale[2]);
PolyVox::Vector3DFloat startPoint(originInVoxel.x, originInVoxel.y, originInVoxel.z);
// PolyVox::Vector3DFloat pvDirection(directionInVoxel.x, directionInVoxel.y, directionInVoxel.z);
PolyVox::Vector3DFloat endPoint(farInVoxel.x, farInVoxel.y, farInVoxel.z);
PolyVox::RaycastResult raycastResult;
RaycastFunctor callback;
raycastResult = PolyVox::raycastWithDirection(_volData, start, pvDirection, callback);
RaycastFunctor callback(_volData);
raycastResult = PolyVox::raycastWithEndpoints(_volData, startPoint, endPoint, callback);
if (raycastResult == PolyVox::RaycastResults::Completed) {
// the ray completed its path -- nothing was hit.
return false;
}
glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * callback._result;
glm::vec4 result = callback._result;
switch (_voxelSurfaceStyle) {
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
result -= glm::vec4(1, 1, 1, 0); // compensate for the extra voxel border
break;
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
case PolyVoxEntityItem::SURFACE_CUBIC:
break;
}
result -= glm::vec4(0.5f, 0.5f, 0.5f, 0.0f);
glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * result;
distance = glm::distance(glm::vec3(intersectedWorldPosition), origin);
@ -286,51 +491,195 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
// compress the data in _volData and save the results. The compressed form is used during
// saves to disk and for transmission over the wire
void RenderablePolyVoxEntityItem::compressVolumeData() {
int rawSize = _volData->getDepth() * _volData->getHeight() * _volData->getWidth();
quint16 voxelXSize = _voxelVolumeSize.x;
quint16 voxelYSize = _voxelVolumeSize.y;
quint16 voxelZSize = _voxelVolumeSize.z;
int rawSize = voxelXSize * voxelYSize * voxelZSize;
QByteArray uncompressedData = QByteArray(rawSize, '\0');
for (int z = 0; z < _volData->getDepth(); z++) {
for (int y = 0; y < _volData->getHeight(); y++) {
for (int x = 0; x < _volData->getWidth(); x++) {
uint8_t uVoxelValue = _volData->getVoxelAt(x, y, z);
int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x;
for (int z = 0; z < voxelZSize; z++) {
for (int y = 0; y < voxelYSize; y++) {
for (int x = 0; x < voxelXSize; x++) {
uint8_t uVoxelValue = getVoxel(x, y, z);
int uncompressedIndex =
z * voxelYSize * voxelXSize +
y * voxelXSize +
x;
uncompressedData[uncompressedIndex] = uVoxelValue;
}
}
}
QByteArray newVoxelData = qCompress(uncompressedData, 9);
// HACK -- until we have a way to allow for properties larger than MTU, don't update.
if (newVoxelData.length() < 1200) {
QByteArray newVoxelData;
QDataStream writer(&newVoxelData, QIODevice::WriteOnly | QIODevice::Truncate);
writer << voxelXSize << voxelYSize << voxelZSize;
QByteArray compressedData = qCompress(uncompressedData, 9);
writer << compressedData;
// make sure the compressed data can be sent over the wire-protocol
if (newVoxelData.size() < 1150) {
_voxelData = newVoxelData;
#ifdef WANT_DEBUG
qDebug() << "-------------- voxel compresss --------------";
qDebug() << "raw-size =" << rawSize << " compressed-size =" << newVoxelData.size();
#endif
} else {
// HACK -- until we have a way to allow for properties larger than MTU, don't update.
#ifdef WANT_DEBUG
qDebug() << "voxel data too large, reverting change.";
// revert
#endif
// revert the active voxel-space to the last version that fit.
decompressVolumeData();
}
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
_needsModelReload = true;
}
// take compressed data and decompreess it into _volData.
// take compressed data and expand it into _volData.
void RenderablePolyVoxEntityItem::decompressVolumeData() {
int rawSize = _volData->getDepth() * _volData->getHeight() * _volData->getWidth();
QByteArray uncompressedData = QByteArray(rawSize, '\0');
QDataStream reader(_voxelData);
quint16 voxelXSize, voxelYSize, voxelZSize;
reader >> voxelXSize;
reader >> voxelYSize;
reader >> voxelZSize;
uncompressedData = qUncompress(_voxelData);
if (voxelXSize == 0 || voxelXSize > MAX_VOXEL_DIMENSION ||
voxelYSize == 0 || voxelYSize > MAX_VOXEL_DIMENSION ||
voxelZSize == 0 || voxelZSize > MAX_VOXEL_DIMENSION) {
qDebug() << "voxelSize is not reasonable, skipping decompressions."
<< voxelXSize << voxelYSize << voxelZSize;
return;
}
int rawSize = voxelXSize * voxelYSize * voxelZSize;
QByteArray compressedData;
reader >> compressedData;
QByteArray uncompressedData = qUncompress(compressedData);
for (int z = 0; z < _volData->getDepth(); z++) {
for (int y = 0; y < _volData->getHeight(); y++) {
for (int x = 0; x < _volData->getWidth(); x++) {
int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x;
_volData->setVoxelAt(x, y, z, uncompressedData[uncompressedIndex]);
if (uncompressedData.size() != rawSize) {
qDebug() << "PolyVox decompress -- size is (" << voxelXSize << voxelYSize << voxelZSize << ")" <<
"so expected uncompressed length of" << rawSize << "but length is" << uncompressedData.size();
return;
}
for (int z = 0; z < voxelZSize; z++) {
for (int y = 0; y < voxelYSize; y++) {
for (int x = 0; x < voxelXSize; x++) {
int uncompressedIndex = (z * voxelYSize * voxelXSize) + (y * voxelZSize) + x;
updateOnCount(x, y, z, uncompressedData[uncompressedIndex]);
setVoxel(x, y, z, uncompressedData[uncompressedIndex]);
}
}
}
_needsModelReload = true;
#ifdef WANT_DEBUG
qDebug() << "--------------- voxel decompress ---------------";
qDebug() << "raw-size =" << rawSize << " compressed-size =" << _voxelData.size();
#endif
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
_needsModelReload = true;
getModel();
}
// virtual
ShapeType RenderablePolyVoxEntityItem::getShapeType() const {
if (_onCount > 0) {
return SHAPE_TYPE_COMPOUND;
}
return SHAPE_TYPE_NONE;
}
bool RenderablePolyVoxEntityItem::isReadyToComputeShape() {
if (_needsModelReload) {
return false;
}
#ifdef WANT_DEBUG
qDebug() << "RenderablePolyVoxEntityItem::isReadyToComputeShape" << (!_needsModelReload);
#endif
return true;
}
void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
#ifdef WANT_DEBUG
qDebug() << "RenderablePolyVoxEntityItem::computeShapeInfo";
#endif
ShapeType type = getShapeType();
if (type != SHAPE_TYPE_COMPOUND) {
EntityItem::computeShapeInfo(info);
return;
}
_points.clear();
unsigned int i = 0;
glm::mat4 wToM = voxelToLocalMatrix();
AABox box;
for (int z = 0; z < _voxelVolumeSize.z; z++) {
for (int y = 0; y < _voxelVolumeSize.y; y++) {
for (int x = 0; x < _voxelVolumeSize.x; x++) {
if (getVoxel(x, y, z) > 0) {
QVector<glm::vec3> pointsInPart;
float offL = -0.5f;
float offH = 0.5f;
// float offL = 0.0f;
// float offH = 1.0f;
glm::vec3 p000 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offL, 1.0f));
glm::vec3 p001 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offH, 1.0f));
glm::vec3 p010 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offL, 1.0f));
glm::vec3 p011 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offH, 1.0f));
glm::vec3 p100 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offL, 1.0f));
glm::vec3 p101 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offH, 1.0f));
glm::vec3 p110 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offL, 1.0f));
glm::vec3 p111 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offH, 1.0f));
box += p000;
box += p001;
box += p010;
box += p011;
box += p100;
box += p101;
box += p110;
box += p111;
pointsInPart << p000;
pointsInPart << p001;
pointsInPart << p010;
pointsInPart << p011;
pointsInPart << p100;
pointsInPart << p101;
pointsInPart << p110;
pointsInPart << p111;
// add next convex hull
QVector<glm::vec3> newMeshPoints;
_points << newMeshPoints;
// add points to the new convex hull
_points[i++] << pointsInPart;
}
}
}
}
if (_points.isEmpty()) {
EntityItem::computeShapeInfo(info);
return;
}
glm::vec3 collisionModelDimensions = box.getDimensions();
QByteArray b64 = _voxelData.toBase64();
info.setParams(type, collisionModelDimensions, QString(b64));
info.setConvexHulls(_points);
}

View file

@ -21,8 +21,7 @@ class RenderablePolyVoxEntityItem : public PolyVoxEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
PolyVoxEntityItem(entityItemID, properties) { }
RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual ~RenderablePolyVoxEntityItem();
@ -34,6 +33,10 @@ public:
// _needsModelReload = true;
}
virtual uint8_t getVoxel(int x, int y, int z);
virtual void setVoxel(int x, int y, int z, uint8_t toValue);
void updateOnCount(int x, int y, int z, uint8_t new_value);
void render(RenderArgs* args);
virtual bool supportsDetailedRayIntersection() const { return true; }
@ -41,27 +44,47 @@ public:
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject, bool precisionPicking) const;
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle);
void getModel();
virtual void setVoxelData(QByteArray voxelData);
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
glm::vec3 getSurfacePositionAdjustment() const;
glm::mat4 voxelToWorldMatrix() const;
glm::mat4 voxelToLocalMatrix() const;
glm::mat4 worldToVoxelMatrix() const;
virtual ShapeType getShapeType() const;
virtual bool isReadyToComputeShape();
virtual void computeShapeInfo(ShapeInfo& info);
// coords are in voxel-volume space
virtual void setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue);
// coords are in world-space
virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue);
virtual void setAll(uint8_t toValue);
virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue);
private:
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
// may not match _voxelVolumeSize.
void compressVolumeData();
void decompressVolumeData();
PolyVox::SimpleVolume<uint8_t>* _volData = nullptr;
model::Geometry _modelGeometry;
bool _needsModelReload = true;
QVector<QVector<glm::vec3>> _points; // XXX
int _onCount = 0; // how many non-zero voxels are in _volData
};

View file

@ -903,6 +903,7 @@ EntityItemProperties EntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(damping, getDamping);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(restitution, getRestitution);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(friction, getFriction);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(created, getCreated);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifetime, getLifetime);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(script, getScript);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionSoundURL, getCollisionSoundURL);
@ -963,6 +964,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulatorID, updateSimulatorID);
@ -1008,11 +1010,13 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
}
void EntityItem::recordCreationTime() {
assert(_created == UNKNOWN_CREATED_TIME);
_created = usecTimestampNow();
if (_created == UNKNOWN_CREATED_TIME) {
_created = usecTimestampNow();
}
auto now = usecTimestampNow();
_lastEdited = _created;
_lastUpdated = _created;
_lastSimulated = _created;
_lastUpdated = now;
_lastSimulated = now;
}
@ -1320,6 +1324,13 @@ void EntityItem::updateLifetime(float value) {
}
}
void EntityItem::updateCreated(uint64_t value) {
if (_created != value) {
_created = value;
_dirtyFlags |= EntityItem::DIRTY_LIFETIME;
}
}
void EntityItem::setSimulatorID(const QUuid& value) {
_simulatorID = value;
_simulatorIDChangedTime = usecTimestampNow();

View file

@ -228,6 +228,9 @@ public:
float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity
void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity
quint64 getCreated() const { return _created; } /// get the created-time in useconds for the entity
void setCreated(quint64 value) { _created = value; } /// set the created-time in useconds for the entity
/// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted
bool isImmortal() const { return _lifetime == ENTITY_ITEM_IMMORTAL_LIFETIME; }
@ -325,6 +328,7 @@ public:
void updateIgnoreForCollisions(bool value);
void updateCollisionsWillMove(bool value);
void updateLifetime(float value);
void updateCreated(uint64_t value);
virtual void updateShapeType(ShapeType type) { /* do nothing */ }
uint32_t getDirtyFlags() const { return _dirtyFlags; }

View file

@ -27,6 +27,7 @@
#include "TextEntityItem.h"
#include "ZoneEntityItem.h"
#include "PolyVoxEntityItem.h"
#include "LineEntityItem.h"
AtmospherePropertyGroup EntityItemProperties::_staticAtmosphere;
SkyboxPropertyGroup EntityItemProperties::_staticSkybox;
@ -48,6 +49,7 @@ CONSTRUCT_PROPERTY(damping, ENTITY_ITEM_DEFAULT_DAMPING),
CONSTRUCT_PROPERTY(restitution, ENTITY_ITEM_DEFAULT_RESTITUTION),
CONSTRUCT_PROPERTY(friction, ENTITY_ITEM_DEFAULT_FRICTION),
CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME),
CONSTRUCT_PROPERTY(created, UNKNOWN_CREATED_TIME),
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
CONSTRUCT_PROPERTY(color, ),
@ -94,12 +96,13 @@ CONSTRUCT_PROPERTY(voxelSurfaceStyle, PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_S
CONSTRUCT_PROPERTY(name, ENTITY_ITEM_DEFAULT_NAME),
CONSTRUCT_PROPERTY(backgroundMode, BACKGROUND_MODE_INHERIT),
CONSTRUCT_PROPERTY(sourceUrl, ""),
CONSTRUCT_PROPERTY(lineWidth, LineEntityItem::DEFAULT_LINE_WIDTH),
CONSTRUCT_PROPERTY(linePoints, QVector<glm::vec3>()),
_id(UNKNOWN_ENTITY_ID),
_idSet(false),
_lastEdited(0),
_created(UNKNOWN_CREATED_TIME),
_type(EntityTypes::Unknown),
_glowLevel(0.0f),
@ -176,6 +179,11 @@ QString EntityItemProperties::getAnimationSettings() const {
return jsonByteString;
}
void EntityItemProperties::setCreated(QDateTime &v) {
_created = v.toMSecsSinceEpoch() * 1000; // usec per msec
qDebug() << "EntityItemProperties::setCreated QDateTime" << v << _created;
}
void EntityItemProperties::debugDump() const {
qCDebug(entities) << "EntityItemProperties...";
qCDebug(entities) << " _type=" << EntityTypes::getEntityTypeName(_type);
@ -194,13 +202,6 @@ void EntityItemProperties::debugDump() const {
props.debugDumpBits();
}
void EntityItemProperties::setCreated(quint64 usecTime) {
_created = usecTime;
if (_lastEdited < _created) {
_lastEdited = _created;
}
}
void EntityItemProperties::setLastEdited(quint64 usecTime) {
_lastEdited = usecTime > _created ? usecTime : _created;
}
@ -344,7 +345,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
CHECK_PROPERTY_CHANGE(PROP_VOXEL_DATA, voxelData);
CHECK_PROPERTY_CHANGE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle);
CHECK_PROPERTY_CHANGE(PROP_LINE_WIDTH, lineWidth);
CHECK_PROPERTY_CHANGE(PROP_LINE_POINTS, linePoints);
changedProperties += _stage.getChangedProperties();
changedProperties += _atmosphere.getChangedProperties();
changedProperties += _skybox.getChangedProperties();
@ -375,10 +377,16 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(friction);
COPY_PROPERTY_TO_QSCRIPTVALUE(density);
COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime);
if (!skipDefaults) {
if (!skipDefaults || _lifetime != defaultEntityProperties._lifetime) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable
}
auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec
created.setTimeSpec(Qt::OffsetFromUTC);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(created, created.toString(Qt::ISODate));
COPY_PROPERTY_TO_QSCRIPTVALUE(script);
COPY_PROPERTY_TO_QSCRIPTVALUE(registrationPoint);
COPY_PROPERTY_TO_QSCRIPTVALUE(angularVelocity);
@ -426,10 +434,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelVolumeSize);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelData);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelSurfaceStyle);
COPY_PROPERTY_TO_QSCRIPTVALUE(lineWidth);
COPY_PROPERTY_TO_QSCRIPTVALUE(linePoints);
// Sitting properties support
if (!skipDefaults) {
@ -471,7 +480,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
return properties;
}
void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool honorReadOnly) {
QScriptValue typeScriptValue = object.property("type");
if (typeScriptValue.isValid()) {
setType(typeScriptValue.toVariant().toString());
@ -512,7 +521,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE(locked, bool, setLocked);
COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures);
COPY_PROPERTY_FROM_QSCRIPTVALUE(userData, QString, setUserData);
//COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID); DO NOT accept this info from QScriptValue
COPY_PROPERTY_FROM_QSCRIPTVALUE(text, QString, setText);
COPY_PROPERTY_FROM_QSCRIPTVALUE(lineHeight, float, setLineHeight);
COPY_PROPERTY_FROM_QSCRIPTVALUE(textColor, xColor, setTextColor);
@ -535,10 +543,20 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightDirection, glmVec3, setKeyLightDirection);
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(backgroundMode, BackgroundMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelSurfaceStyle, uint16_t, setVoxelSurfaceStyle);
COPY_PROPERTY_FROM_QSCRIPTVALUE(lineWidth, float, setLineWidth);
COPY_PROPERTY_FROM_QSCRIPTVALUE(linePoints, qVectorVec3, setLinePoints);
if (!honorReadOnly) {
// this is used by the json reader to set things that we don't want javascript to able to affect.
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(created, QDateTime, setCreated, [this]() {
auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec
return result;
});
COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID);
}
_stage.copyFromScriptValue(object, _defaultSettings);
_atmosphere.copyFromScriptValue(object, _defaultSettings);
@ -554,10 +572,15 @@ QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine,
return properties.copyToScriptValue(engine, true);
}
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties) {
properties.copyFromScriptValue(object);
void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue &object, EntityItemProperties& properties) {
properties.copyFromScriptValue(object, false);
}
void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object, EntityItemProperties& properties) {
properties.copyFromScriptValue(object, true);
}
// TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the
// encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar
// to how we handle this in the Octree streaming case.
@ -763,6 +786,11 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, properties.getVoxelSurfaceStyle());
}
if (properties.getType() == EntityTypes::Line) {
APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, properties.getLineWidth());
APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, properties.getLinePoints());
}
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
@ -1003,6 +1031,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle);
}
if (properties.getType() == EntityTypes::Line) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_WIDTH, float, setLineWidth);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_POINTS, QVector<glm::vec3>, setLinePoints);
}
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
@ -1107,10 +1140,13 @@ void EntityItemProperties::markAllChanged() {
_skybox.markAllChanged();
_sourceUrlChanged = true;
_voxelVolumeSizeChanged = true;
_voxelDataChanged = true;
_voxelSurfaceStyleChanged = true;
_lineWidthChanged = true;
_linePointsChanged = true;
}
/// The maximum bounding cube for the entity, independent of it's rotation.

View file

@ -63,7 +63,7 @@ public:
void setType(EntityTypes::EntityType type) { _type = type; }
virtual QScriptValue copyToScriptValue(QScriptEngine* engine, bool skipDefaults) const;
virtual void copyFromScriptValue(const QScriptValue& object);
virtual void copyFromScriptValue(const QScriptValue& object, bool honorReadOnly);
// editing related features supported by all entities
quint64 getLastEdited() const { return _lastEdited; }
@ -96,6 +96,7 @@ public:
DEFINE_PROPERTY(PROP_RESTITUTION, Restitution, restitution, float);
DEFINE_PROPERTY(PROP_FRICTION, Friction, friction, float);
DEFINE_PROPERTY(PROP_LIFETIME, Lifetime, lifetime, float);
DEFINE_PROPERTY(PROP_CREATED, Created, created, quint64);
DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString);
DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString);
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
@ -145,6 +146,8 @@ public:
DEFINE_PROPERTY_GROUP(Atmosphere, atmosphere, AtmospherePropertyGroup);
DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup);
DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString);
DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float);
DEFINE_PROPERTY_REF(LINE_POINTS, LinePoints, linePoints, QVector<glm::vec3>);
static QString getBackgroundModeString(BackgroundMode mode);
@ -153,8 +156,6 @@ public:
float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); }
float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
quint64 getCreated() const { return _created; }
void setCreated(quint64 usecTime);
bool hasCreatedTime() const { return (_created != UNKNOWN_CREATED_TIME); }
bool containsBoundsProperties() const { return (_positionChanged || _dimensionsChanged); }
@ -195,13 +196,14 @@ public:
void setVoxelDataDirty() { _voxelDataChanged = true; }
void setCreated(QDateTime& v);
bool hasTerseUpdateChanges() const;
private:
QUuid _id;
bool _idSet;
quint64 _lastEdited;
quint64 _created;
EntityTypes::EntityType _type;
void setType(const QString& typeName) { _type = EntityTypes::getEntityTypeFromName(typeName); }
@ -221,7 +223,8 @@ private:
Q_DECLARE_METATYPE(EntityItemProperties);
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue &object, EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object, EntityItemProperties& properties);
// define these inline here so the macros work

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QDateTime>
#ifndef hifi_EntityItemPropertiesMacros_h
#define hifi_EntityItemPropertiesMacros_h
@ -95,14 +97,13 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { ret
inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { return xColorToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector<glm::vec3>& v) {return qVectorVec3ToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
QByteArray b64 = v.toBase64();
return QScriptValue(QString(b64));
}
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
QScriptValue groupProperties = properties.property(#g); \
@ -131,6 +132,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
typedef glm::vec3 glmVec3;
typedef glm::quat glmQuat;
typedef QVector<glm::vec3> qVectorVec3;
inline float float_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); }
inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
@ -138,6 +140,14 @@ inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); }
inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
inline QDateTime QDateTime_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true;
auto result = QDateTime::fromString(v.toVariant().toString().trimmed(), Qt::ISODate);
// result.setTimeSpec(Qt::OffsetFromUTC);
return result;
}
inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true;
@ -145,8 +155,6 @@ inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool&
return QByteArray::fromBase64(b64.toUtf8());
}
inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x");
@ -167,6 +175,11 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal
return glm::vec3(0);
}
inline qVectorVec3 qVectorVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true;
return qVectorVec3FromScriptValue(v);
}
inline glmQuat glmQuat_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x");

View file

@ -114,6 +114,10 @@ enum EntityPropertyList {
PROP_VOXEL_DATA,
PROP_VOXEL_SURFACE_STYLE,
//for lines
PROP_LINE_WIDTH,
PROP_LINE_POINTS,
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties ABOVE this line
PROP_AFTER_LAST_ITEM,

View file

@ -17,7 +17,6 @@
#include "ModelEntityItem.h"
#include "ZoneEntityItem.h"
#include "EntitiesLogging.h"
#include "PolyVoxEntityItem.h"
EntityScriptingInterface::EntityScriptingInterface() :
@ -371,7 +370,7 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra
quuidFromScriptValue(entityIDValue, value.entityID);
QScriptValue entityPropertiesValue = object.property("properties");
if (entityPropertiesValue.isValid()) {
EntityItemPropertiesFromScriptValue(entityPropertiesValue, value.properties);
EntityItemPropertiesFromScriptValueHonorReadOnly(entityPropertiesValue, value.properties);
}
value.distance = object.property("distance").toVariant().toFloat();
@ -396,7 +395,8 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra
}
bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
bool EntityScriptingInterface::setVoxels(QUuid entityID,
std::function<void(PolyVoxEntityItem&)> actor) {
if (!_entityTree) {
return false;
}
@ -416,7 +416,7 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c
PolyVoxEntityItem* polyVoxEntity = static_cast<PolyVoxEntityItem*>(entity.get());
_entityTree->lockForWrite();
polyVoxEntity->setSphere(center, radius, value);
actor(*polyVoxEntity);
entity->setLastEdited(now);
entity->setLastBroadcast(now);
_entityTree->unlock();
@ -431,3 +431,24 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c
queueEntityMessage(PacketTypeEntityEdit, entityID, properties);
return true;
}
bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {
polyVoxEntity.setSphere(center, radius, value);
});
}
bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) {
return setVoxels(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) {
polyVoxEntity.setVoxelInVolume(position, value);
});
}
bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) {
return setVoxels(entityID, [value](PolyVoxEntityItem& polyVoxEntity) {
polyVoxEntity.setAll(value);
});
}

View file

@ -21,6 +21,7 @@
#include <Octree.h>
#include <OctreeScriptingInterface.h>
#include <RegisteredMetaTypes.h>
#include "PolyVoxEntityItem.h"
#include "EntityEditPacketSender.h"
@ -117,7 +118,10 @@ public slots:
Q_INVOKABLE void setSendPhysicsUpdates(bool value);
Q_INVOKABLE bool getSendPhysicsUpdates() const;
bool setVoxels(QUuid entityID, std::function<void(PolyVoxEntityItem&)> actor);
Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value);
Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value);
Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value);
Q_INVOKABLE void dumpTree() const;

View file

@ -1055,7 +1055,7 @@ bool EntityTree::readFromMap(QVariantMap& map) {
QVariantMap entityMap = entityVariant.toMap();
QScriptValue entityScriptValue = variantMapToScriptValue(entityMap, scriptEngine);
EntityItemProperties properties;
EntityItemPropertiesFromScriptValue(entityScriptValue, properties);
EntityItemPropertiesFromScriptValueIgnoreReadOnly(entityScriptValue, properties);
EntityItemID entityItemID;
if (entityMap.contains("id")) {

View file

@ -20,24 +20,41 @@
#include "EntityTreeElement.h"
const float LineEntityItem::DEFAULT_LINE_WIDTH = 2.0f;
EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer result { new LineEntityItem(entityID, properties) };
return result;
}
LineEntityItem::LineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID)
EntityItem(entityItemID) ,
_lineWidth(DEFAULT_LINE_WIDTH),
_pointsChanged(true),
_points(QVector<glm::vec3>(0))
{
_type = EntityTypes::Line;
_created = properties.getCreated();
setProperties(properties);
}
EntityItemProperties LineEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
properties._color = getXColor();
properties._colorChanged = false;
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineWidth, getLineWidth);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints);
properties._glowLevel = getGlowLevel();
properties._glowLevelChanged = false;
@ -48,8 +65,11 @@ EntityItemProperties LineEntityItem::getProperties() const {
bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineWidth, setLineWidth);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(linePoints, setLinePoints);
if (somethingChanged) {
bool wantDebug = false;
@ -64,7 +84,12 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
return somethingChanged;
}
int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
_points = points;
_pointsChanged = true;
}
int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
@ -72,6 +97,9 @@ int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
READ_ENTITY_PROPERTY(PROP_LINE_WIDTH, float, setLineWidth);
READ_ENTITY_PROPERTY(PROP_LINE_POINTS, QVector<glm::vec3>, setLinePoints);
return bytesRead;
}
@ -81,6 +109,8 @@ int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
EntityPropertyFlags LineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_COLOR;
requestedProperties += PROP_LINE_WIDTH;
requestedProperties += PROP_LINE_POINTS;
return requestedProperties;
}
@ -95,6 +125,8 @@ void LineEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, getLineWidth());
APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, getLinePoints());
}
void LineEntityItem::debugDump() const {

View file

@ -51,6 +51,13 @@ class LineEntityItem : public EntityItem {
_color[BLUE_INDEX] = value.blue;
}
void setLineWidth(float lineWidth){ _lineWidth = lineWidth; }
float getLineWidth() const{ return _lineWidth; }
void setLinePoints(const QVector<glm::vec3>& points);
const QVector<glm::vec3>& getLinePoints() const{ return _points; }
virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; }
// never have a ray intersection pick a LineEntityItem.
@ -60,9 +67,13 @@ class LineEntityItem : public EntityItem {
void** intersectedObject, bool precisionPicking) const { return false; }
virtual void debugDump() const;
static const float DEFAULT_LINE_WIDTH;
protected:
rgbColor _color;
float _lineWidth;
bool _pointsChanged;
QVector<glm::vec3> _points;
};
#endif // hifi_LineEntityItem_h

View file

@ -22,7 +22,8 @@
const glm::vec3 PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE = glm::vec3(32, 32, 32);
const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(qCompress(QByteArray(0), 9));
const float PolyVoxEntityItem::MAX_VOXEL_DIMENSION = 32.0f;
const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(qCompress(QByteArray(0), 9)); // XXX
const PolyVoxEntityItem::PolyVoxSurfaceStyle PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE =
PolyVoxEntityItem::SURFACE_MARCHING_CUBES;
@ -41,6 +42,40 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const Ent
setProperties(properties);
}
void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
assert((int)_voxelVolumeSize.x == _voxelVolumeSize.x);
assert((int)_voxelVolumeSize.y == _voxelVolumeSize.y);
assert((int)_voxelVolumeSize.z == _voxelVolumeSize.z);
_voxelVolumeSize = voxelVolumeSize;
if (_voxelVolumeSize.x < 1) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to 1";
_voxelVolumeSize.x = 1;
}
if (_voxelVolumeSize.x > MAX_VOXEL_DIMENSION) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to max";
_voxelVolumeSize.x = MAX_VOXEL_DIMENSION;
}
if (_voxelVolumeSize.y < 1) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to 1";
_voxelVolumeSize.y = 1;
}
if (_voxelVolumeSize.y > MAX_VOXEL_DIMENSION) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to max";
_voxelVolumeSize.y = MAX_VOXEL_DIMENSION;
}
if (_voxelVolumeSize.z < 1) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to 1";
_voxelVolumeSize.z = 1;
}
if (_voxelVolumeSize.z > MAX_VOXEL_DIMENSION) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to max";
_voxelVolumeSize.z = MAX_VOXEL_DIMENSION;
}
}
EntityItemProperties PolyVoxEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize);
@ -114,4 +149,3 @@ void PolyVoxEntityItem::debugDump() const {
qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions);
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
}

View file

@ -40,19 +40,7 @@ class PolyVoxEntityItem : public EntityItem {
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
void setXColor(const xColor& value) {
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
}
virtual ShapeType getShapeType() const { return SHAPE_TYPE_POLYVOX; }
// never have a ray intersection pick a PolyVoxEntityItem.
virtual bool supportsDetailedRayIntersection() const { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@ -61,7 +49,7 @@ class PolyVoxEntityItem : public EntityItem {
virtual void debugDump() const;
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { _voxelVolumeSize = voxelVolumeSize; }
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
virtual const glm::vec3& getVoxelVolumeSize() const { return _voxelVolumeSize; }
virtual void setVoxelData(QByteArray voxelData) { _voxelData = voxelData; }
@ -69,16 +57,19 @@ class PolyVoxEntityItem : public EntityItem {
enum PolyVoxSurfaceStyle {
SURFACE_MARCHING_CUBES,
SURFACE_CUBIC
SURFACE_CUBIC,
SURFACE_EDGED_CUBIC
};
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; }
virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) {
_voxelSurfaceStyle = (PolyVoxSurfaceStyle) voxelSurfaceStyle;
setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle);
}
virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; }
static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE;
static const float MAX_VOXEL_DIMENSION;
static const QByteArray DEFAULT_VOXEL_DATA;
static const PolyVoxSurfaceStyle DEFAULT_VOXEL_SURFACE_STYLE;
@ -88,8 +79,15 @@ class PolyVoxEntityItem : public EntityItem {
// coords are in world-space
virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue) {}
virtual void setAll(uint8_t toValue) {}
virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue) {}
virtual uint8_t getVoxel(int x, int y, int z) { return 0; }
virtual void setVoxel(int x, int y, int z, uint8_t toValue) {}
protected:
rgbColor _color;
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
QByteArray _voxelData;
PolyVoxSurfaceStyle _voxelSurfaceStyle;

View file

@ -73,7 +73,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketTypeEntityAdd:
case PacketTypeEntityEdit:
case PacketTypeEntityData:
return VERSION_NO_ENTITY_ID_SWAP;
return VERSION_ENTITIES_LINE_POINTS;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:
@ -135,7 +135,6 @@ QString nameForPacketType(PacketType packetType) {
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAdd);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEdit);
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleEntitiesFix);
default:
return QString("Type: ") + QString::number((int)packetType);
}

View file

@ -79,8 +79,7 @@ enum PacketType {
PacketTypeSignedTransactionPayment,
PacketTypeIceServerHeartbeat, // 50
PacketTypeUnverifiedPing,
PacketTypeUnverifiedPingReply,
PacketTypeParticleEntitiesFix
PacketTypeUnverifiedPingReply
};
typedef char PacketVersion;
@ -183,5 +182,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25;
const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26;
const PacketVersion VERSION_NO_ENTITY_ID_SWAP = 27;
const PacketVersion VERSION_ENTITIES_PARTICLE_FIX = 28;
const PacketVersion VERSION_ENTITIES_LINE_POINTS = 29;
#endif // hifi_PacketHeaders_h

View file

@ -2096,7 +2096,15 @@ void Octree::writeToJSONFile(const char* fileName, OctreeElement* element) {
top = _rootElement;
}
// include the "bitstream" version
PacketType expectedType = expectedDataPacketType();
PacketVersion expectedVersion = versionForPacketType(expectedType);
entityDescription["Version"] = (int) expectedVersion;
// store the entity data
bool entityDescriptionSuccess = writeToMap(entityDescription, top, true);
// convert the QVariantMap to JSON
if (entityDescriptionSuccess && persistFile.open(QIODevice::WriteOnly)) {
persistFile.write(QJsonDocument::fromVariant(entityDescription).toJson());
} else {

View file

@ -325,6 +325,7 @@ bool OctreePacketData::appendValue(uint8_t value) {
bool OctreePacketData::appendValue(uint16_t value) {
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
if (success) {
@ -358,6 +359,7 @@ bool OctreePacketData::appendValue(quint64 value) {
}
bool OctreePacketData::appendValue(float value) {
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
@ -379,6 +381,17 @@ bool OctreePacketData::appendValue(const glm::vec3& value) {
return success;
}
bool OctreePacketData::appendValue(const QVector<glm::vec3>& value) {
uint16_t qVecSize = value.size();
bool success = appendValue(qVecSize);
success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3));
if (success) {
_bytesOfValues += qVecSize * sizeof(glm::vec3);
_totalBytesOfValues += qVecSize * sizeof(glm::vec3);
}
return success;
}
bool OctreePacketData::appendValue(const glm::quat& value) {
const size_t VALUES_PER_QUAT = 4;
const size_t PACKED_QUAT_SIZE = sizeof(uint16_t) * VALUES_PER_QUAT;
@ -585,6 +598,15 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, xColor
return sizeof(rgbColor);
}
int OctreePacketData::unpackDataFromBytes(const unsigned char *dataBytes, QVector<glm::vec3>& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(uint16_t));
dataBytes += sizeof(length);
result.resize(length);
memcpy(result.data(), dataBytes, length * sizeof(glm::vec3));
return sizeof(uint16_t) + length * sizeof(glm::vec3);
}
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(length));

View file

@ -162,6 +162,9 @@ public:
/// appends a non-position vector to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const glm::vec3& value);
//appends a QVector of vec3's to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const QVector<glm::vec3>& value);
/// appends a packed quat to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const glm::quat& value);
@ -185,7 +188,7 @@ public:
bool appendRawData(const unsigned char* data, int length);
bool appendRawData(QByteArray data);
/// returns a byte offset from beginning of the uncompressed stream based on offset from end.
/// returns a byte offset from beginning of the uncompressed stream based on offset from end.
/// Positive offsetFromEnd returns that many bytes before the end of uncompressed stream
int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; }
@ -241,8 +244,10 @@ public:
static int unpackDataFromBytes(const unsigned char* dataBytes, QString& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<glm::vec3>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result);
private:
/// appends raw bytes, might fail if byte would cause packet to be too large
bool append(const unsigned char* data, int length);

View file

@ -660,7 +660,6 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, con
void GeometryCache::updateVertices(int id, const QVector<glm::vec3>& points, const glm::vec4& color) {
BatchItemDetails& details = _registeredVertices[id];
if (details.isCreated) {
details.clear();
#ifdef WANT_DEBUG
@ -799,7 +798,7 @@ void GeometryCache::renderVertices(gpu::Primitive primitiveType, int id) {
batch.setInputFormat(details.streamFormat);
batch.setInputStream(0, *details.stream);
batch.draw(primitiveType, details.vertices, 0);
gpu::GLBackend::renderBatch(batch);
glDisableClientState(GL_VERTEX_ARRAY);

View file

@ -515,7 +515,6 @@ private:
Q_DECLARE_METATYPE(QPointer<Model>)
Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>)
Q_DECLARE_METATYPE(QVector<glm::vec3>)
/// Handle management of pending models that need blending
class ModelBlender : public QObject, public Dependency {

View file

@ -318,7 +318,7 @@ void ScriptEngine::init() {
registerAvatarTypes(this);
registerAudioMetaTypes(this);
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue);
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);
qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);

View file

@ -27,6 +27,7 @@ static int pickRayMetaTypeId = qRegisterMetaType<PickRay>();
static int collisionMetaTypeId = qRegisterMetaType<Collision>();
void registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);
qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
@ -72,6 +73,26 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) {
vec3.z = object.property("z").toVariant().toFloat();
}
QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector){
QScriptValue array = engine->newArray();
for (int i = 0; i < vector.size(); i++) {
array.setProperty(i, vec3toScriptValue(engine, vector.at(i)));
}
return array;
}
QVector<glm::vec3> qVectorVec3FromScriptValue(const QScriptValue& array){
QVector<glm::vec3> newVector;
int length = array.property("length").toInteger();
for (int i = 0; i < length; i++) {
glm::vec3 newVec3 = glm::vec3();
vec3FromScriptValue(array.property(i), newVec3);
newVector << newVec3;
}
return newVector;
}
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) {
QScriptValue obj = engine->newObject();
obj.setProperty("x", vec2.x);

View file

@ -28,6 +28,7 @@ Q_DECLARE_METATYPE(glm::vec3)
Q_DECLARE_METATYPE(glm::vec2)
Q_DECLARE_METATYPE(glm::quat)
Q_DECLARE_METATYPE(xColor)
Q_DECLARE_METATYPE(QVector<glm::vec3>)
void registerMetaTypes(QScriptEngine* engine);
@ -55,6 +56,9 @@ void qColorFromScriptValue(const QScriptValue& object, QColor& color);
QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url);
void qURLFromScriptValue(const QScriptValue& object, QUrl& url);
QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector);
QVector<glm::vec3> qVectorVec3FromScriptValue( const QScriptValue& array);
class PickRay {
public:
PickRay() : origin(0.0f), direction(0.0f) { }

View file

@ -46,7 +46,7 @@ namespace Setting {
QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString());
QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
// Let's set up the settings Private instance on it's own thread
// Let's set up the settings Private instance on its own thread
QThread* thread = new QThread();
Q_CHECK_PTR(thread);
thread->setObjectName("Settings Thread");

View file

@ -35,8 +35,7 @@ enum ShapeType {
SHAPE_TYPE_CYLINDER_X,
SHAPE_TYPE_CYLINDER_Y,
SHAPE_TYPE_CYLINDER_Z,
SHAPE_TYPE_LINE,
SHAPE_TYPE_POLYVOX
SHAPE_TYPE_LINE
};
class ShapeInfo {

View file

@ -0,0 +1,38 @@
//
// ErrorDialog.cpp
//
// Created by David Rowe on 30 May 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ErrorDialog.h"
HIFI_QML_DEF(ErrorDialog)
ErrorDialog::ErrorDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) {
}
ErrorDialog::~ErrorDialog() {
}
QString ErrorDialog::text() const {
return _text;
}
void ErrorDialog::setVisible(bool v) {
OffscreenQmlDialog::setVisible(v);
}
void ErrorDialog::setText(const QString& arg) {
if (arg != _text) {
_text = arg;
emit textChanged();
}
}
void ErrorDialog::accept() {
OffscreenQmlDialog::accept();
}

View file

@ -0,0 +1,46 @@
//
// ErrorDialog.h
//
// Created by David Rowe on 30 May 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef hifi_ErrorDialog_h
#define hifi_ErrorDialog_h
#include "OffscreenQmlDialog.h"
class ErrorDialog : public OffscreenQmlDialog
{
Q_OBJECT
HIFI_QML_DECL
private:
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
public:
ErrorDialog(QQuickItem* parent = 0);
virtual ~ErrorDialog();
QString text() const;
public slots:
virtual void setVisible(bool v);
void setText(const QString& arg);
signals:
void textChanged();
protected slots:
virtual void accept();
private:
QString _text;
};
#endif // hifi_ErrorDialog_h

View file

@ -13,6 +13,7 @@
#include <QOpenGLDebugLogger>
#include <QGLWidget>
#include <QtQml>
#include "ErrorDialog.h"
#include "MessageDialog.h"
@ -130,6 +131,15 @@ void OffscreenUi::critical(const QString& title, const QString& text,
static_cast<QMessageBox::Icon>(MessageDialog::Critical), buttons);
}
void OffscreenUi::error(const QString& text) {
ErrorDialog* pDialog{ nullptr };
ErrorDialog::show([&](QQmlContext* ctx, QObject* item) {
pDialog = item->findChild<ErrorDialog*>();
pDialog->setText(text);
});
pDialog->setEnabled(true);
}
OffscreenUi::ButtonCallback OffscreenUi::NO_OP_CALLBACK = [](QMessageBox::StandardButton) {};

View file

@ -115,6 +115,8 @@ public:
static void critical(const QString& title, const QString& text,
ButtonCallback callback = NO_OP_CALLBACK,
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
static void error(const QString& text); // Interim dialog in new style
};
#endif