Merge pull request #60 from overte-org/feature/voxel_ui

Create App UI for voxels
This commit is contained in:
Dale Glass 2022-07-17 13:23:09 +02:00 committed by GitHub
commit cf45d28a05
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 2054 additions and 15 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

View file

@ -4,6 +4,7 @@
//
// Created by Seth Alves on 5/19/15.
// Copyright 2015 High Fidelity, Inc.
// Copyright 2022 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -272,11 +273,10 @@ QByteArray RenderablePolyVoxEntityItem::volDataToArray(quint16 voxelXSize, quint
withReadLock([&] {
if (isEdged()) {
low += 1;
voxelSize += 2;
}
loop3(low, voxelSize, [&](const ivec3& v){
result[index++] = _volData->getVoxelAt(v.x, v.y, v.z);
loop3(ivec3(0), voxelSize, [&](const ivec3& v){
result[index++] = _volData->getVoxelAt(v.x + low.x, v.y + low.y, v.z + low.z);
});
});
@ -1025,6 +1025,7 @@ void RenderablePolyVoxEntityItem::uncompressVolumeData() {
entity->setVoxelsFromData(QByteArray(1, 0), 1, 1, 1);
return;
}
int rawSize = voxelXSize * voxelYSize * voxelZSize;
QByteArray compressedData;
@ -1047,9 +1048,15 @@ void RenderablePolyVoxEntityItem::uncompressVolumeData() {
void RenderablePolyVoxEntityItem::setVoxelsFromData(QByteArray uncompressedData,
quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) {
// this accepts the payload from uncompressVolumeData
ivec3 low{ 0 };
int index = 0;
withWriteLock([&] {
if (isEdged()) {
low += 1;
}
loop3(ivec3(0), ivec3(voxelXSize, voxelYSize, voxelZSize), [&](const ivec3& v) {
int uncompressedIndex = (v.z * voxelYSize * voxelXSize) + (v.y * voxelZSize) + v.x;
int uncompressedIndex = (v.z * (voxelYSize) * (voxelXSize)) + (v.y * (voxelZSize)) + v.x;
setVoxelInternal(v, uncompressedData[uncompressedIndex]);
});

View file

@ -5,6 +5,7 @@
// Created by Brad Hefta-Gaub on 12/4/13.
// Copyright 2013 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// Copyright 2022 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -1292,6 +1293,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* type: "PolyVox",
* position: position,
* dimensions: { x: 2, y: 2, z: 2 },
* voxelVolumeSize: { x: 16, y: 16, z: 16 },
* voxelSurfaceStyle: 2,
* xTextureURL: texture,
* yTextureURL: texture,
* zTextureURL: texture,

View file

@ -4,6 +4,7 @@
// Persist toolbar by HRS 6/11/15.
// Copyright 2014 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// Copyright 2022 Overte e.V.
//
// This script allows you to edit entities with a new UI/UX for mouse and trackpad based editing
//
@ -11,7 +12,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager,
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EditTools, EditVoxels, EntityListTool, Vec3, SelectionManager,
Overlays, OverlayWebWindow, UserActivityLogger, Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera,
progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, OverlaySystemWindow,
keyUpEventFromUIWindow:true */
@ -36,7 +37,9 @@ Script.include([
"entityList/entityList.js",
"entitySelectionTool/entitySelectionTool.js",
"audioFeedback/audioFeedback.js",
"modules/brokenURLReport.js"
"modules/brokenURLReport.js",
"editModes/editModes.js",
"editModes/editVoxels.js"
]);
var CreateWindow = Script.require('./modules/createWindow.js');
@ -126,6 +129,16 @@ var gridTool = new GridTool({
});
gridTool.setVisible(false);
var editTools = new EditTools({
createToolsWindow: createToolsWindow,
});
var editVoxels = new EditVoxels();
editVoxels.editTools = editTools;
editTools.addListener(editVoxels.updateEditSettings);
editTools.addListener(selectionManager.updateEditSettings);
var entityShapeVisualizerSessionName = "SHAPE_VISUALIZER_" + Uuid.generate();
var EntityShapeVisualizer = Script.require('./modules/entityShapeVisualizer.js');
@ -750,6 +763,92 @@ var toolBar = (function () {
}
}
}
function handleNewPolyVoxDialogResult(result) {
if (result) {
var initialShape = result.initialShapeIndex;
var volumeSizeX = parseInt(result.volumeSizeX);
var volumeSizeY = parseInt(result.volumeSizeY);
var volumeSizeZ = parseInt(result.volumeSizeZ);
var voxelSurfaceStyle = parseInt(result.surfaceStyleIndex);
var voxelPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: volumeSizeZ * -1.6 }));
var polyVoxID = createNewEntity({
type: "PolyVox",
name: "terrain",
dimensions: {
x: volumeSizeX,
y: volumeSizeY,
z: volumeSizeZ
},
voxelVolumeSize: {
x: volumeSizeX,
y: volumeSizeY,
z: volumeSizeZ
},
xTextureURL: result.xTextureURL,
yTextureURL: result.yTextureURL,
zTextureURL: result.zTextureURL,
voxelSurfaceStyle: voxelSurfaceStyle,
collisionless: !(result.collisions),
grab: {
grabbable: result.grabbable
},
});
Entities.editEntity(polyVoxID, {
position: voxelPosition
});
if (polyVoxID){
switch (initialShape) {
case 0:
Entities.setVoxelsInCuboid(polyVoxID, {
x: Math.round(volumeSizeX / 4),
y: Math.round(volumeSizeY / 4),
z: Math.round(volumeSizeZ / 4)
}, {
x: Math.round(volumeSizeX / 2.0),
y: Math.round(volumeSizeY / 2.0),
z: Math.round(volumeSizeZ / 2.0)
}, 255);
break;
// Plane 1/4
case 1:
Entities.setVoxelsInCuboid(polyVoxID, {
x: 0,
y: 0,
z: 0
}, {
x: volumeSizeX,
y: Math.round(volumeSizeY / 4),
z: volumeSizeZ
}, 255);
break;
// Plane 3/4
case 2:
Entities.setVoxelsInCuboid(polyVoxID, {
x: 0,
y: 0,
z: 0
}, {
x: volumeSizeX,
y: Math.round(3 * volumeSizeY / 4),
z: volumeSizeZ
}, 255);
break;
// Single voxel at center
case 3:
Entities.setVoxel(polyVoxID, {
x: Math.round(volumeSizeX / 2),
y: Math.round(volumeSizeY / 2),
z: Math.round(volumeSizeZ / 2)
}, 255);
break;
}
}
}
}
function handleNewMaterialDialogResult(result) {
if (result) {
@ -806,6 +905,13 @@ var toolBar = (function () {
case "newMaterialDialogCancel":
closeExistingDialogWindow();
break;
case "newPolyVoxDialogAdd":
handleNewPolyVoxDialogResult(message.params);
closeExistingDialogWindow();
break;
case "newPolyVoxDialogCancel":
closeExistingDialogWindow();
break;
}
}
@ -912,6 +1018,10 @@ var toolBar = (function () {
closeExistingDialogWindow();
var qmlPath = Script.resolvePath("qml/New" + entityType + "Window.qml");
var DIALOG_WINDOW_SIZE = { x: 500, y: 300 };
if( entityType === "PolyVox" ){
DIALOG_WINDOW_SIZE.x = 600;
DIALOG_WINDOW_SIZE.y = 500;
}
dialogWindow = Desktop.createWindow(qmlPath, {
title: "New " + entityType + " Entity",
additionalFlags: Desktop.ALWAYS_ON_TOP | Desktop.CLOSE_BUTTON_HIDES,
@ -971,6 +1081,8 @@ var toolBar = (function () {
addButton("newMaterialButton", createNewEntityDialogButtonCallback("Material"));
addButton("newPolyVoxButton", createNewEntityDialogButtonCallback("PolyVox"));
var deactivateCreateIfDesktopWindowsHidden = function() {
if (!shouldUseEditTabletApp() && !entityListTool.isVisible() && !createToolsWindow.isVisible()) {
that.setActive(false);
@ -1016,6 +1128,8 @@ var toolBar = (function () {
isActive = active;
activeButton.editProperties({isActive: isActive});
undoHistory.setEnabled(isActive);
editVoxels.setActive(active);
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
@ -1369,7 +1483,7 @@ function mouseClickEvent(event) {
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) &&
(allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (0 < x && sizeOK) {
if (0 < x && sizeOK && selectionManager.editEnabled) {
selectedEntityID = foundEntity;
orientation = MyAvatar.orientation;
intersection = rayPlaneIntersection(pickRay, P, Quat.getForward(orientation));

View file

@ -0,0 +1,181 @@
//
// editModes.js
//
// Created by Karol Suprynowicz on 2022.05.15.
// Copyright 2022 Overte e.V.
//
// Partially based on gridTool.js
// Created by Ryan Huffman on 6 Nov 2014
// Copyright 2014 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// Copyright 2022 Overte e.V.
//
// This script implements a class for managing different edit modes
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
EditTools = function(options) {
var that = {};
var createAppMode = "object";
var voxelEditMode = "single";
var voxelSphereSize = 0.3;
var voxelEditDynamics = "click";
var voxelRemove = false;
var voxelPointerMode = "laser";
var voxelBrushLength = 0.5;
var listeners = [];
var createToolsWindow = options.createToolsWindow;
that.emitUpdate = function() {
var dataString = JSON.stringify({
createAppMode : createAppMode,
voxelEditMode : voxelEditMode,
voxelSphereSize : voxelSphereSize,
voxelEditDynamics : voxelEditDynamics,
voxelRemove : voxelRemove,
voxelPointerMode : voxelPointerMode,
voxelBrushLength : voxelBrushLength,
});
webView.emitScriptEvent(dataString);
createToolsWindow.emitScriptEvent(dataString);
};
that.getCreateAppMode = function() {
return createAppMode;
}
that.setCreateAppMode = function(value) {
createAppMode = value;
that.emitUpdate();
}
that.getVoxelEditMode = function() {
return voxelEditMode;
}
that.setVoxelEditMode = function(value) {
voxelEditMode = value;
that.emitUpdate();
}
that.getVoxelSphereSize = function() {
return voxelSphereSize;
}
that.setVoxelSphereSize = function(value) {
voxelSphereSize = value;
that.emitUpdate();
}
that.getVoxelEditDynamics = function() {
return voxelEditDynamics;
}
that.setVoxelEditDynamics = function(value) {
voxelEditDynamics = value;
that.emitUpdate();
}
that.getVoxelRemove = function() {
return voxelRemove;
}
that.setVoxelRemove = function(value) {
voxelRemove = value;
that.emitUpdate();
}
that.getVoxelPointerMode = function() {
return voxelPointerMode;
}
that.setVoxelPointerMode = function(value) {
voxelPointerMode = value;
that.emitUpdate();
}
that.getVoxelBrushLength = function() {
return voxelBrushLength;
}
that.setVoxelBrushLength = function(value) {
voxelBrushLength = value;
that.emitUpdate();
}
that.update = function(data) {
if (data.type !== "update-edit-tools") {
return;
}
print(JSON.stringify(data));
var needsUpdate = false;
if (data.createAppMode) {
createAppMode = data.createAppMode;
needsUpdate = true;
}
if (data.voxelEditMode) {
voxelEditMode = data.voxelEditMode;
needsUpdate = true;
}
if (data.voxelSphereSize) {
voxelSphereSize = data.voxelSphereSize;
needsUpdate = true;
}
if (data.voxelEditDynamics) {
voxelEditDynamics = data.voxelEditDynamics;
needsUpdate = true;
}
if (data.voxelRemove) {
voxelRemove = data.voxelRemove;
needsUpdate = true;
}
if (data.voxelPointerMode) {
voxelPointerMode = data.voxelPointerMode;
needsUpdate = true;
}
if (data.voxelBrushLength) {
voxelBrushLength = data.voxelBrushLength;
needsUpdate = true;
}
}
var webEventReceived = function(data) {
try {
data = JSON.parse(data);
} catch (e) {
console.log("editModes.js, EditTools.webEventReceived: Cannot parse received JSON data");
return;
}
if (data.type === "init") {
that.emitUpdate();
} else if (data.type === "update-edit-tools") {
that.update(data);
for (var i = 0; i < listeners.length; i++) {
listeners[i] && listeners[i](data);
}
}
};
var webView = null;
webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
webView.webEventReceived.connect(webEventReceived);
createToolsWindow.webEventReceived.addListener(webEventReceived);
that.addListener = function(callback) {
listeners.push(callback);
};
function cleanup() {
}
return that;
}

View file

@ -0,0 +1,687 @@
//
// editModes.js
//
// Created by dr Karol Suprynowicz on 2022.05.17.
// Copyright 2022 Overte e.V.
//
// Based on voxels.js
// Created by Seth Alves on 2015-08-25
// Copyright 2015 High Fidelity, Inc.
//
// Based on entitySelectionTool.js
// Created by Brad hefta-Gaub on 10/1/14.
// Modified by Daniela Fontes * @DanielaFifo and Tiago Andrade @TagoWill on 4/7/2017
// Modified by David Back on 1/9/2018
// Copyright 2014 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors
//
// This script implements voxel edit mode
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include([
"./libraries/utils.js",
"entitySelectionTool/entitySelectionTool.js"
]);
var selectionManager = SelectionManager;
EditVoxels = function() {
var self = this;
var that = {};
const NO_HAND = -1;
var controlHeld = false;
var shiftHeld = false;
var isLeftGripPressed = false;
var isRightGripPressed = false;
var editEnabled = false;
var editSingleVoxels = false;
var editSpheres = false;
var editCubes = false;
var editAdd = true; // Remove voxels if false
var inverseOperation = false; // True when middle mouse button or grip is pressed
var brushPointer = false;
var isActive = true;
var editSphereRadius = 0.15;
var brushLength = 0.5;
// Vector calculated from editSphereRadius for adding/remiving cubes
var cubeSize = null;
// Local plane for continuous voxel editing
// 0 - plane parallel to YZ plane
// 1 - plane parallel to XZ plane
// 2 - plane parallel to YZ plane
var editPlane = 0;
// Is true when mouse button is pressed
var isEditing = false;
var editedVoxelEntity = null;
// Position of last edit in voxel space
var oldEditPosition = null;
// True when original operation added voxels, false otherwise
var lastEditValue = 255;
var isOnUpdateConnected = false;
var isSphereResizingStarted = true;
var sphereResizingInitialHandDistance = 0.1;
var sphereInitialRadius = editSphereRadius;
var sphereEntityID = null;
that.triggerClickMapping = Controller.newMapping(Script.resolvePath('') + '-click-voxels');
that.triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press-voxels');
that.gripPressMapping = Controller.newMapping(Script.resolvePath('') + '-grip-voxels');
that.triggeredHand = NO_HAND;
that.pressedHand = NO_HAND;
var soundAdd = SoundCache.getSound(Script.resourcesPath() + "sounds/Button05.wav");
var soundDelete = SoundCache.getSound(Script.resourcesPath() + "sounds/Tab03.wav");
// Continuous start timer prevents activating continuous mode on short button presses
// and adding multiple voxels when only one was intended
var continuousStartTimerMax = 0.200;
var continuousStartTimer = 0.0;
that.setActive = function(active) {
isActive = (active === true);
}
that.updateEditSettings = function(data) {
if (data.createAppMode) {
if (data.createAppMode === "voxel"){
editEnabled = true;
} else {
editEnabled = false;
}
}
if (data.voxelEditMode) {
editAdd = true;
if (data.voxelRemove) {
editAdd = false;
}
if (data.voxelEditMode === "single") {
editSpheres = false;
editSingleVoxels = true;
editCubes = false;
} else if (data.voxelEditMode === "sphere") {
editSpheres = true;
editSingleVoxels = false;
editCubes = false;
} else if (data.voxelEditMode === "cube") {
editSpheres = false;
editSingleVoxels = false;
editCubes = true;
}
}
if (data.voxelSphereSize) {
editSphereRadius = parseFloat(data.voxelSphereSize) / 2.0;
}
if (data.voxelPointerMode) {
if (data.voxelPointerMode === "brush") {
brushPointer = true;
} else {
brushPointer = false;
}
}
if (data.voxelBrushLength) {
voxelBrushLength = parseFloat(data.voxelBrushLength);
}
}
function floorVector(v) {
return {
x: Math.floor(v.x),
y: Math.floor(v.y),
z: Math.floor(v.z)
};
}
function ceilVector(v) {
return {
x: Math.ceil(v.x),
y: Math.ceil(v.y),
z: Math.ceil(v.z)
};
}
function attemptVoxelChangeForEntity(entityID, pickRayDir, intersectionLocation) {
var wantDebug = false;
if (wantDebug) {
print("=============== eV::attemptVoxelChangeForEntity BEG =======================");
}
var properties = Entities.getEntityProperties(entityID);
if (properties.type != "PolyVox") {
return false;
}
if (!editEnabled || !isActive) {
return false;
}
if (editSingleVoxels === false && editSpheres === false && editCubes === false) {
return false;
}
var voxelOrigin = Entities.worldCoordsToVoxelCoords(entityID, Vec3.subtract(intersectionLocation, pickRayDir));
var voxelPosition = Entities.worldCoordsToVoxelCoords(entityID, intersectionLocation);
var pickRayDirInVoxelSpace = Vec3.subtract(voxelPosition, voxelOrigin);
pickRayDirInVoxelSpace = Vec3.normalize(pickRayDirInVoxelSpace);
var absX = Math.abs(pickRayDirInVoxelSpace.x);
var absY = Math.abs(pickRayDirInVoxelSpace.y);
var absZ = Math.abs(pickRayDirInVoxelSpace.z);
if(absX >= absY && absX >= absZ){
editPlane = 0;
}else if(absY >= absX && absY >= absZ){
editPlane = 1;
}else if(absZ >= absX && absZ >= absY){
editPlane = 2;
}
if (wantDebug) {
print("voxelOrigin: " + JSON.stringify(voxelOrigin));
print("voxelPosition: " + JSON.stringify(voxelPosition));
print("pickRayDirInVoxelSpace: " + JSON.stringify(pickRayDirInVoxelSpace));
}
lastEditValue = 0;
if((editAdd && !inverseOperation) || (!editAdd && inverseOperation)){
lastEditValue = 255;
}
var toDrawPosition = null;
if(lastEditValue === 255){
toDrawPosition = Vec3.subtract(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1));
}else{
toDrawPosition = Vec3.subtract(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, -0.1));
}
if (editSingleVoxels) {
if (wantDebug) {
print("Calling setVoxel");
print("entityID: " + JSON.stringify(entityID));
print("floorVector(toDrawPosition): " + JSON.stringify(floorVector(toDrawPosition)));
}
oldEditPosition = floorVector(toDrawPosition);
if (Entities.setVoxel(entityID, oldEditPosition, lastEditValue)){
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
return true;
}else{
return false;
}
}
if (editSpheres) {
if (wantDebug) {
print("Calling setVoxelSphere");
print("entityID: " + JSON.stringify(entityID));
print("editSphereRadius: " + JSON.stringify(editSphereRadius));
print("floorVector(toDrawPosition): " + JSON.stringify(floorVector(toDrawPosition)));
}
oldEditPosition = floorVector(toDrawPosition);
var toDrawPositionWorld = Entities.voxelCoordsToWorldCoords(entityID, oldEditPosition);
if (Entities.setVoxelSphere(entityID, toDrawPositionWorld, editSphereRadius, lastEditValue)){
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
return true;
}else{
return false;
}
}
if (editCubes) {
if (wantDebug) {
print("Calling setVoxelsInCuboid");
print("entityID: " + JSON.stringify(entityID));
print("editSphereRadius: " + JSON.stringify(editSphereRadius));
print("floorVector(toDrawPosition): " + JSON.stringify(floorVector(toDrawPosition)));
}
oldEditPosition = floorVector(toDrawPosition);
var cubeSizeWorld = {x : editSphereRadius * 2, y : editSphereRadius * 2, z : editSphereRadius * 2};
var zeroVecWorld = {x : 0, y: 0, z: 0};
var zeroVecLocal = Entities.worldCoordsToVoxelCoords(entityID, zeroVecWorld);
var cubeSizeVecLocal = Entities.worldCoordsToVoxelCoords(entityID, cubeSizeWorld);
cubeSize = ceilVector(Vec3.subtract(cubeSizeVecLocal, zeroVecLocal));
var lowPosition = Vec3.subtract(oldEditPosition, Vec3.multiply(cubeSize, 0.5));
if (Entities.setVoxelsInCuboid(entityID, lowPosition, cubeSize, lastEditValue)){
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
return true;
}else{
return false;
}
}
}
function attemptVoxelChange(pickRayDir, intersection) {
var wantDebug = false;
if (wantDebug) {
print("=============== eV::attemptVoxelChange BEG =======================");
}
var ids;
ids = Entities.findEntities(intersection.intersection, editSphereRadius + 1.0);
if (ids.indexOf(intersection.entityID) < 0) {
ids.push(intersection.entityID);
}
if (wantDebug) {
print("Entities: " + JSON.stringify(ids));
}
var success = false;
for (var i = 0; i < ids.length; i++) {
var entityID = ids[i];
success |= attemptVoxelChangeForEntity(entityID, pickRayDir, intersection.intersection)
}
return success;
}
function controllerComputePickRay() {
var hand = triggered() ? that.triggeredHand : that.pressedHand;
var controllerPose = getControllerWorldLocation(hand, true);
if (controllerPose.valid) {
var controllerPosition = controllerPose.translation;
// This gets point direction right, but if you want general quaternion it would be more complicated:
var controllerDirection = Quat.getUp(controllerPose.rotation);
return {origin: controllerPosition, direction: controllerDirection};
}
}
function generalComputePickRay(x, y) {
return controllerComputePickRay() || Camera.computePickRay(x, y);
}
function mousePressEvent(event) {
var wantDebug = false;
var attemptChangeOnEmpty = false;
if (!editEnabled || !isActive) {
return false;
}
if (wantDebug) {
print("=============== eV::mousePressEvent BEG =======================");
}
if (!(event.isLeftButton || event.isMiddleButton) && !triggered()) {
return;
}
if (event.isLeftButton || event.isMiddleButton){
if (event.isMiddleButton){
inverseOperation = true;
}else{
inverseOperation = false;
}
}else{
inverseOperation = false;
if(that.triggeredHand === Controller.Standard.RightHand && Controller.getValue(Controller.Standard.RightGrip) > 0.5){
inverseOperation = true;
}
if(that.triggeredHand === Controller.Standard.LeftHand && Controller.getValue(Controller.Standard.LeftGrip) > 0.5){
inverseOperation = true;
}
}
continuousStartTimer = 0;
var pickRay = generalComputePickRay(event.x, event.y);
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
if (wantDebug) {
print("Pick ray: " + JSON.stringify(pickRay));
print("Intersection: " + JSON.stringify(intersection));
}
if (intersection.intersects) {
if (attemptVoxelChangeForEntity(intersection.entityID, pickRay.direction, intersection.intersection)) {
Script.update.connect(onUpdateHandler);
isOnUpdateConnected = true;
isEditing = true;
editedVoxelEntity = intersection.entityID;
if (wantDebug) {
print("onUpdateHandler connected");
}
return;
}
}
// if the PolyVox entity is empty, we can't pick against its "on" voxels. try picking against its
// bounding box, instead.
if (attemptChangeOnEmpty) {
intersection = Entities.findRayIntersection(pickRay, false); // bounding box picking
if (intersection.intersects) {
if(attemptVoxelChange(pickRay.direction, intersection)){
Script.update.connect(onUpdateHandler);
isOnUpdateConnected = true;
if (wantDebug) {
print("onUpdateHandler connected");
}
}
}
}
}
function mouseReleaseEvent(event) {
var wantDebug = false;
if (wantDebug) {
print("=============== eV::mouseReleaseEvent BEG =======================");
}
if(isOnUpdateConnected){
Script.update.disconnect(onUpdateHandler);
isOnUpdateConnected = false;
isEditing = false;
editedVoxelEntity = null;
}
return;
}
function keyPressEvent(event) {
if (event.text == "CONTROL") {
controlHeld = true;
}
if (event.text == "SHIFT") {
shiftHeld = true;
}
}
function keyReleaseEvent(event) {
if (event.text == "CONTROL") {
controlHeld = false;
}
if (event.text == "SHIFT") {
shiftHeld = false;
}
}
function triggered() {
return that.triggeredHand !== NO_HAND;
};
function pointingAtDesktopWindowOrTablet(hand) {
var pointingAtDesktopWindow = (hand === Controller.Standard.RightHand &&
SelectionManager.pointingAtDesktopWindowRight) ||
(hand === Controller.Standard.LeftHand &&
SelectionManager.pointingAtDesktopWindowLeft);
var pointingAtTablet = (hand === Controller.Standard.RightHand && SelectionManager.pointingAtTabletRight) ||
(hand === Controller.Standard.LeftHand && SelectionManager.pointingAtTabletLeft);
return pointingAtDesktopWindow || pointingAtTablet;
}
function makeClickHandler(hand) {
return function (clicked) {
if (!editEnabled) {
return;
}
// Don't allow both hands to trigger at the same time
if (triggered() && hand !== that.triggeredHand) {
return;
}
if (!triggered() && clicked && !pointingAtDesktopWindowOrTablet(hand)) {
that.triggeredHand = hand;
mousePressEvent({});
} else if (triggered() && !clicked) {
that.triggeredHand = NO_HAND;
mouseReleaseEvent({});
}
};
}
function makePressHandler(hand) {
return function (value) {
if (!editEnabled) {
return;
}
if (value >= TRIGGER_ON_VALUE && !triggered() && !pointingAtDesktopWindowOrTablet(hand)) {
that.pressedHand = hand;
} else {
that.pressedHand = NO_HAND;
if(isOnUpdateConnected){
Script.update.disconnect(onUpdateHandler);
isOnUpdateConnected = false;
}
}
}
}
function getDistanceBetweenControllers(){
var poseLeft = getControllerWorldLocation(Controller.Standard.LeftHand, true);
var poseRight = getControllerWorldLocation(Controller.Standard.RightHand, true);
return Vec3.distance(poseLeft.translation, poseRight.translation);
}
function getEditSpherePosition( radius ){
var poseLeft = getControllerWorldLocation(Controller.Standard.LeftHand, true);
var poseRight = getControllerWorldLocation(Controller.Standard.RightHand, true);
var handsPosition = Vec3.multiply(Vec3.sum(poseLeft.translation, poseRight.translation), 0.5);
return Vec3.sum(handsPosition, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: radius * -2.0 }));
}
function updateSphereResizing(delta) {
var wantDebug = false;
var newDistance = getDistanceBetweenControllers();
var newRadius = (sphereInitialRadius / sphereResizingInitialHandDistance) * newDistance;
var newPosition = getEditSpherePosition(newRadius);
var newDimensions = Vec3.multiply({ x: 1.0, y: 1.0, z: 1.0 }, newRadius * 2.0);
if (wantDebug) {
print("newDistance: " + JSON.stringify(newDistance));
print("newRadius: " + JSON.stringify(newRadius));
print("newPosition: " + JSON.stringify(newPosition));
print("newDimensions: " + JSON.stringify(newDimensions));
}
Entities.editEntity(sphereEntityID, {
position: newPosition,
dimensions: newDimensions
});
if( that.editTools ) {
editTools.setVoxelSphereSize(newRadius * 2);
}
editSphereRadius = newRadius;
}
function startSphereResizing() {
var wantDebug = false;
if (wantDebug) {
print("=============== eV::startSphereResizing BEG =======================");
}
Script.update.connect(updateSphereResizing);
sphereResizingInitialHandDistance = getDistanceBetweenControllers();
sphereInitialRadius = editSphereRadius;
var spherePosition = getEditSpherePosition(sphereInitialRadius);
var sphereDimensions = Vec3.multiply({ x: 1.0, y: 1.0, z: 1.0 }, sphereInitialRadius * 2.0);
sphereEntityID = Entities.addEntity({
type: "Shape",
shape: "Sphere",
name: "voxelEditSphere",
position: spherePosition,
color: { r: 60, g: 100, b: 60 },
alpha: 0.5,
dimensions: sphereDimensions,
collisionless: true,
},"world");
}
function stopSphereResizing() {
var wantDebug = false;
if (wantDebug) {
print("=============== eV::stopSphereResizing BEG =======================");
}
Script.update.disconnect(updateSphereResizing);
if (sphereEntityID !== null) {
Entities.deleteEntity(sphereEntityID);
}
sphereEntityID = null;
}
function makeGripPressHandler(hand) {
return function (value) {
if (!editEnabled) {
return;
}
if (value > 0.5) {
if (hand === Controller.Standard.LeftHand) {
isLeftGripPressed = true;
} else if (hand === Controller.Standard.RightHand) {
isRightGripPressed = true;
}
} else if (value < 0.4){
if (hand === Controller.Standard.LeftHand) {
isLeftGripPressed = false;
} else if (hand === Controller.Standard.RightHand) {
isRightGripPressed = false;
}
}
if ( isLeftGripPressed && isRightGripPressed) {
if( !isSphereResizingStarted ) {
isSphereResizingStarted = true;
startSphereResizing();
}
} else {
if( isSphereResizingStarted ) {
isSphereResizingStarted = false;
stopSphereResizing();
}
}
}
}
function onUpdateHandler(delta){
var wantDebug = false;
if (isEditing === false || editedVoxelEntity === null){
return;
}
continuousStartTimer += delta;
if (continuousStartTimer < continuousStartTimerMax) {
return;
}
// Get pick ray origin and direction
var pickRay = null;
var hand = triggered() ? that.triggeredHand : that.pressedHand;
if (hand === NO_HAND) {
pickRay = Camera.computePickRay(Controller.getValue(Controller.Hardware.Keyboard.MouseX), Controller.getValue(Controller.Hardware.Keyboard.MouseY));
}else{
pickRay = controllerComputePickRay();
}
if (pickRay === null) {
return;
}
// Compute intersection of pick ray with given plane in local coordinates
var globalOriginInVoxelSpace = Entities.worldCoordsToVoxelCoords(editedVoxelEntity, { x: 0, y: 0, z: 0 });
var pickRayDirInVoxelSpace = Vec3.subtract(Entities.worldCoordsToVoxelCoords(editedVoxelEntity, pickRay.direction), globalOriginInVoxelSpace);
var voxelPickRayOrigin = Entities.worldCoordsToVoxelCoords(editedVoxelEntity, pickRay.origin);
pickRayDirInVoxelSpace = Vec3.normalize(pickRayDirInVoxelSpace);
var directionMultiplier = 1.0;
var offsetVector = { x: 0, y: 0, z: 0 };
switch (editPlane) {
// 0 - plane parallel to YZ plane
case 0:
offsetVector.x = 0.5;
offsetVector.y = (offsetVector.x / pickRayDirInVoxelSpace.x) * pickRayDirInVoxelSpace.y;
offsetVector.z = (offsetVector.x / pickRayDirInVoxelSpace.x) * pickRayDirInVoxelSpace.z;
directionMultiplier = (oldEditPosition.x - voxelPickRayOrigin.x) / pickRayDirInVoxelSpace.x;
break;
// 1 - plane parallel to XZ plane
case 1:
offsetVector.y = 0.5;
offsetVector.x = (offsetVector.y / pickRayDirInVoxelSpace.y) * pickRayDirInVoxelSpace.x;
offsetVector.z = (offsetVector.y / pickRayDirInVoxelSpace.y) * pickRayDirInVoxelSpace.z;
directionMultiplier = (oldEditPosition.y - voxelPickRayOrigin.y) / pickRayDirInVoxelSpace.y;
break;
// 2 - plane parallel to XY plane
case 2:
offsetVector.z = 0.5;
offsetVector.x = (offsetVector.z / pickRayDirInVoxelSpace.z) * pickRayDirInVoxelSpace.x;
offsetVector.y = (offsetVector.z / pickRayDirInVoxelSpace.z) * pickRayDirInVoxelSpace.y;
directionMultiplier = (oldEditPosition.z - voxelPickRayOrigin.z) / pickRayDirInVoxelSpace.z;
break;
default:
return;
}
intersectionPoint = Vec3.sum(Vec3.multiply(pickRayDirInVoxelSpace, directionMultiplier), voxelPickRayOrigin);
newEditPosition = floorVector(Vec3.sum(intersectionPoint, offsetVector));
if (newEditPosition === oldEditPosition) {
return;
}
if (wantDebug) {
print("Old edit position: " + JSON.stringify(oldEditPosition));
print("New edit position: " + JSON.stringify(newEditPosition));
print("directionMultiplier: " + JSON.stringify(directionMultiplier) + " pickRay.direction: " + JSON.stringify(pickRay.direction) + " pickRayDirInVoxelSpace: " + JSON.stringify(pickRayDirInVoxelSpace) + " voxelPickRayOrigin: " + JSON.stringify(voxelPickRayOrigin) + " editPlane: " + JSON.stringify(editPlane));
}
if (editSingleVoxels) {
if (Entities.setVoxel(editedVoxelEntity, newEditPosition, lastEditValue)){
oldEditPosition = newEditPosition;
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
}
} else if (editSpheres) {
var toDrawPositionWorld = Entities.voxelCoordsToWorldCoords(editedVoxelEntity, newEditPosition);
if (Entities.setVoxelSphere(editedVoxelEntity, toDrawPositionWorld, editSphereRadius, lastEditValue)){
oldEditPosition = newEditPosition;
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
}
} else if (editCubes) {
var lowPosition = Vec3.subtract(newEditPosition, Vec3.multiply(cubeSize, 0.5));
if (Entities.setVoxelsInCuboid(editedVoxelEntity, lowPosition, cubeSize, lastEditValue)){
oldEditPosition = newEditPosition;
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
}
}
}
function cleanup() {
Controller.mousePressEvent.disconnect(self.mousePressEvent);
Controller.mouseReleaseEvent.disconnect(self.mouseReleaseEvent);
Controller.keyPressEvent.disconnect(self.keyPressEvent);
Controller.keyReleaseEvent.disconnect(self.keyReleaseEvent);
}
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Controller.keyPressEvent.connect(keyPressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent);
that.triggerClickMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand));
that.triggerClickMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand));
that.triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand));
that.triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand));
that.gripPressMapping.from(Controller.Standard.LeftGrip).peek().to(makeGripPressHandler(Controller.Standard.LeftHand));
that.gripPressMapping.from(Controller.Standard.RightGrip).peek().to(makeGripPressHandler(Controller.Standard.RightHand));
that.enableTriggerMapping = function() {
that.triggerClickMapping.enable();
that.triggerPressMapping.enable();
that.gripPressMapping.enable();
};
that.disableTriggerMapping = function() {
that.triggerClickMapping.disable();
that.triggerPressMapping.disable();
that.gripPressMapping.disable();
};
that.enableTriggerMapping();
Script.scriptEnding.connect(cleanup);
Script.scriptEnding.connect(that.disableTriggerMapping);
return that;
}

View file

@ -3,6 +3,7 @@
// Created by Ryan Huffman on 13 Nov 2014
// Copyright 2014 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// Copyright 2022 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -1326,6 +1327,57 @@ const GROUPS = [
}
]
},
{
id: "polyvox",
label: "POLYVOX",
properties: [
{
label: "Volume Size",
type: "vec3",
vec3Type: "xyz",
step: 1.0,
decimals: 0,
subLabels: [ "x", "y", "z" ],
unit: "",
propertyID: "voxelVolumeSize",
},
{
label: "Texture preset",
type: "dropdown",
options: { 0 : "None", 1 : "Grass + ground", 2 : "Bricks", 3 : "Stone",
4: "Concrete", 5 : "Rock"},
propertyID: "polyVoxPreset",
onDropdownChange: createPolyVoxPresetChangedFunction,
skipPropertyUpdate: true,
},
{
label: "Surface Style",
type: "dropdown",
options: { 0: "Marching cubes", 1: "Cubic",
2: "Edged cubic", 3: "Edged marching cubes" },
propertyID: "voxelSurfaceStyle",
propertyName: "voxelSurfaceStyle",
},
{
label: "X Texture URL",
type: "string",
propertyID: "xTextureURL",
propertyName: "xTextureURL",
},
{
label: "Y Texture URL",
type: "string",
propertyID: "yTextureURL",
propertyName: "yTextureURL",
},
{
label: "Z Texture URL",
type: "string",
propertyID: "zTextureURL",
propertyName: "zTextureURL",
},
]
},
{
id: "spatial",
label: "SPATIAL",
@ -1705,7 +1757,7 @@ const GROUPS_PER_TYPE = {
ParticleEffect: [ 'base', 'particles', 'particles_emit', 'particles_size', 'particles_color',
'particles_behavior', 'particles_constraints', 'spatial', 'behavior', 'scripts', 'physics' ],
PolyLine: [ 'base', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
PolyVox: [ 'base', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
PolyVox: [ 'base', 'polyvox', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
Grid: [ 'base', 'grid', 'spatial', 'behavior', 'scripts', 'physics' ],
Multiple: [ 'base', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
};
@ -2446,7 +2498,8 @@ function createStringProperty(property, elProperty) {
elInput.addEventListener('change', createEmitTextPropertyUpdateFunction(property));
if (propertyData.onChange !== undefined) {
if (propertyData.
onChange !== undefined) {
elInput.addEventListener('change', propertyData.onChange);
}
@ -3197,6 +3250,55 @@ function parentIDChanged() {
}
}
function createPolyVoxPresetChangedFunction(property) {
return function() {
property.elInput.classList.remove('multi-diff');
var xTextureURL = "";
var yTextureURL = "";
var zTextureURL = "";
switch (parseInt(this.value)) {
// Clear texture entries
case 0:
xTextureURL = "";
yTextureURL = "";
zTextureURL = "";
break;
// Grass + ground
case 1:
xTextureURL = "qrc:///serverless/Textures/ground_5-2K/2K-ground_5-diffuse.jpg";
yTextureURL = "qrc:///serverless/Textures/ground_grass_gen_05.png";
zTextureURL = "qrc:///serverless/Textures/ground_5-2K/2K-ground_5-diffuse.jpg";
break;
// Bricks
case 2:
xTextureURL = "qrc:///serverless/Textures/2K-wall_stone_2-diffuse_l.jpg";
yTextureURL = "qrc:///serverless/Textures/2K-stone_floor_3-diffuse_l.jpg";
zTextureURL = "qrc:///serverless/Textures/2K-wall_stone_2-diffuse_l.jpg";
break;
// Stone
case 3:
xTextureURL = "qrc:///serverless/Textures/wall_l.png";
yTextureURL = "qrc:///serverless/Textures/floor_l.png";
zTextureURL = "qrc:///serverless/Textures/wall_l.png";
break;
// Concrete
case 4:
xTextureURL = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
yTextureURL = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
zTextureURL = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
break;
// Rock
case 5:
xTextureURL = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
yTextureURL = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
zTextureURL = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
break;
}
updateProperty("xTextureURL", xTextureURL, false);
updateProperty("yTextureURL", yTextureURL, false);
updateProperty("zTextureURL", zTextureURL, false);
};
}
/**
* BUTTON CALLBACKS
@ -4756,7 +4858,16 @@ function loaded() {
let propertyID = elDropdown.getAttribute("propertyID");
let property = properties[propertyID];
property.elInput = dt;
dt.addEventListener('change', createEmitTextPropertyUpdateFunction(property));
if (property.data.
skipPropertyUpdate !== true) {
dt.addEventListener('change', createEmitTextPropertyUpdateFunction(property));
}
if (property.data.
onDropdownChange !== undefined) {
dt.addEventListener('change', property.data.onDropdownChange(property));
}
}
document.addEventListener('click', function(ev) { closeAllDropdowns() }, true);

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -6,6 +6,7 @@
// Modified by David Back on 1/9/2018
// Copyright 2014 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors
// Copyright 2022 Overte e.V.
//
// This script implements a class useful for building tools for editing entities.
//
@ -99,6 +100,9 @@ SelectionManager = (function() {
}
if (messageParsed.method === "selectEntity") {
if (!that.editEnabled) {
return;
}
if (!SelectionDisplay.triggered() || SelectionDisplay.triggeredHand === messageParsed.hand) {
if (wantDebug) {
print("setting selection to " + messageParsed.entityID);
@ -187,6 +191,21 @@ SelectionManager = (function() {
that.pointingAtDesktopWindowRight = false;
that.pointingAtTabletLeft = false;
that.pointingAtTabletRight = false;
that.editEnabled = true;
that.updateEditSettings = function(data) {
if (data.createAppMode) {
if (data.createAppMode === "object"){
that.editEnabled = true;
} else {
that.editEnabled = false;
if(that.hasSelection()){
that.clearSelections();
}
}
}
}
that.saveProperties = function() {
that.savedProperties = {};
@ -1303,6 +1322,9 @@ SelectionDisplay = (function() {
}
function makeClickHandler(hand) {
return function (clicked) {
if (!SelectionManager.editEnabled) {
return;
}
// Don't allow both hands to trigger at the same time
if (that.triggered() && hand !== that.triggeredHand) {
return;
@ -1318,6 +1340,9 @@ SelectionDisplay = (function() {
}
function makePressHandler(hand) {
return function (value) {
if (!SelectionManager.editEnabled) {
return;
}
if (value >= TRIGGER_ON_VALUE && !that.triggered() && !pointingAtDesktopWindowOrTablet(hand)) {
that.pressedHand = hand;
that.updateHighlight({});
@ -1413,6 +1438,9 @@ SelectionDisplay = (function() {
if (wantDebug) {
print("=============== eST::MousePressEvent BEG =======================");
}
if (!SelectionManager.editEnabled) {
return;
}
if (!event.isLeftButton && !that.triggered()) {
// EARLY EXIT-(if another mouse button than left is pressed ignore it)
return false;

View file

@ -178,6 +178,18 @@ TabBar {
editTabView.currentIndex = 2
}
}
NewEntityButton {
icon: "icons/voxels.svg"
text: "VOXELS"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newPolyVoxButton" }
});
editTabView.currentIndex = 2
}
}
}
HifiControls.Button {
@ -274,7 +286,7 @@ TabBar {
}
EditTabButton {
title: "GRID"
title: "TOOLS"
active: true
enabled: true
property string originalUrl: ""

View file

@ -184,6 +184,18 @@ TabBar {
editTabView.currentIndex = tabIndex.properties
}
}
NewEntityButton {
icon: "icons/voxels.svg"
text: "VOXELS"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newPolyVoxButton" }
});
editTabView.currentIndex = tabIndex.properties
}
}
}
HifiControls.Button {
@ -264,7 +276,7 @@ TabBar {
}
EditTabButton {
title: "GRID"
title: "TOOLS"
active: true
enabled: true
property string originalUrl: ""

View file

@ -0,0 +1,560 @@
//
// NewPolyVoxDialog.qml
// Created by dr Karol Suprynowicz on 2022.05.17.
// based on NewModelDialog.qml
// qml/hifi
//
// Copyright 2017 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors
// Copyright 2022 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Dialogs 1.2 as OriginalDialogs
import stylesUit 1.0
import controlsUit 1.0
import hifi.dialogs 1.0
Rectangle {
id: newPolyVoxDialog
// width: parent.width
// height: parent.height
HifiConstants { id: hifi }
color: hifi.colors.baseGray;
signal sendToScript(var message);
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
property bool keyboardRasied: false
function errorMessageBox(message) {
try {
return desktop.messageBox({
icon: hifi.icons.warning,
defaultButton: OriginalDialogs.StandardButton.Ok,
title: "Error",
text: message
});
} catch(e) {
Window.alert(message);
}
}
Item {
id: column1
anchors.rightMargin: 10
anchors.leftMargin: 10
anchors.bottomMargin: 10
anchors.topMargin: 0
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: keyboard.top
ComboBox {
id: texturePreset
currentIndex: 0
property var texturePresetArray: ["Material presets",
"Grass + ground",
"Bricks",
"Stone",
"Concrete",
"Rock"]
width: 200
z: 100
transformOrigin: Item.Center
model: texturePresetArray
onCurrentIndexChanged: {
switch (currentIndex) {
// Clear texture entries
case 0:
xTextureURL.text = "";
yTextureURL.text = "";
zTextureURL.text = "";
break;
// Grass + ground
case 1:
xTextureURL.text = "qrc:///serverless/Textures/ground_5-2K/2K-ground_5-diffuse.jpg";
yTextureURL.text = "qrc:///serverless/Textures/ground_grass_gen_05.png";
zTextureURL.text = "qrc:///serverless/Textures/ground_5-2K/2K-ground_5-diffuse.jpg";
break;
// Bricks
case 2:
xTextureURL.text = "qrc:///serverless/Textures/2K-wall_stone_2-diffuse_l.jpg";
yTextureURL.text = "qrc:///serverless/Textures/2K-stone_floor_3-diffuse_l.jpg";
zTextureURL.text = "qrc:///serverless/Textures/2K-wall_stone_2-diffuse_l.jpg";
break;
// Stone
case 3:
xTextureURL.text = "qrc:///serverless/Textures/wall_l.png";
yTextureURL.text = "qrc:///serverless/Textures/floor_l.png";
zTextureURL.text = "qrc:///serverless/Textures/wall_l.png";
break;
// Concrete
case 4:
xTextureURL.text = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
yTextureURL.text = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
zTextureURL.text = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
break;
// Rock
case 5:
xTextureURL.text = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
yTextureURL.text = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
zTextureURL.text = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
break;
}
}
}
Text {
id: text1
anchors.top: texturePreset.bottom
anchors.topMargin: 5
text: qsTr("X Texture URL")
color: "#ffffff"
font.pixelSize: 12
}
TextInput {
id: xTextureURL
height: 20
text: qsTr("")
color: "white"
anchors.top: text1.bottom
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
font.pixelSize: 12
onAccepted: {
newPolyVoxDialog.keyboardEnabled = false;
}
onTextChanged : {
if (xTextureURL.text.length === 0){
button1.enabled = false;
} else {
button1.enabled = true;
}
}
MouseArea {
anchors.fill: parent
onClicked: {
newPolyVoxDialog.keyboardEnabled = HMD.active
parent.focus = true;
parent.forceActiveFocus();
xTextureURL.cursorPosition = xTextureURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
}
}
}
Rectangle {
id: textInputBox1
color: "white"
anchors.fill: xTextureURL
opacity: 0.1
}
Text {
id: text2
text: qsTr("Y Texture URL")
color: "#ffffff"
font.pixelSize: 12
anchors.top: textInputBox1.bottom
anchors.topMargin: 5
}
TextInput {
id: yTextureURL
height: 20
text: qsTr("")
color: "white"
anchors.top: text2.bottom
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
font.pixelSize: 12
onAccepted: {
newPolyVoxDialog.keyboardEnabled = false;
}
onTextChanged : {
if (yTextureURL.text.length === 0){
button1.enabled = false;
} else {
button1.enabled = true;
}
}
MouseArea {
anchors.fill: parent
onClicked: {
newPolyVoxDialog.keyboardEnabled = HMD.active
parent.focus = true;
parent.forceActiveFocus();
yTextureURL.cursorPosition = yTextureURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
}
}
}
Rectangle {
id: textInputBox2
color: "white"
anchors.fill: yTextureURL
opacity: 0.1
}
Text {
id: text3
text: qsTr("Z Texture URL")
color: "#ffffff"
font.pixelSize: 12
anchors.top: textInputBox2.bottom
anchors.topMargin: 5
}
TextInput {
id: zTextureURL
height: 20
text: qsTr("")
color: "white"
anchors.top: text3.bottom
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
font.pixelSize: 12
onAccepted: {
newPolyVoxDialog.keyboardEnabled = false;
}
onTextChanged : {
if (zTextureURL.text.length === 0){
button1.enabled = false;
} else {
button1.enabled = true;
}
}
MouseArea {
anchors.fill: parent
onClicked: {
newPolyVoxDialog.keyboardEnabled = HMD.active
parent.focus = true;
parent.forceActiveFocus();
zTextureURL.cursorPosition = zTextureURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
}
}
}
Rectangle {
id: textInputBox3
color: "white"
anchors.fill: zTextureURL
opacity: 0.1
}
Text {
id: textVolumeSize
text: qsTr("Volume Size (number of voxels along the edge)")
color: "#ffffff"
font.pixelSize: 12
anchors.top: zTextureURL.bottom
anchors.topMargin: 5
}
Row {
id: rowVolumeSize
height: 50
spacing: 30
anchors.top: textVolumeSize.bottom
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
Text {
id: textVolumeSizeX
text: qsTr("X")
color: "#ffffff"
font.pixelSize: 12
}
TextInput {
id: volumeSizeX
height: 20
width: 50
anchors.left: textVolumeSizeX.right
anchors.leftMargin: 3
text: qsTr("16")
color: "white"
font.pixelSize: 12
validator: IntValidator{bottom: 8; top: 64;}
onAccepted: {
newPolyVoxDialog.keyboardEnabled = false;
}
MouseArea {
anchors.fill: parent
onClicked: {
newPolyVoxDialog.keyboardEnabled = HMD.active
parent.focus = true;
parent.forceActiveFocus();
volumeSizeX.cursorPosition = volumeSizeX.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
}
}
}
Rectangle {
id: textInputBoxVolumeSizeX
color: "white"
anchors.fill: volumeSizeX
opacity: 0.1
}
Text {
id: textVolumeSizeY
text: qsTr("Y")
color: "#ffffff"
font.pixelSize: 12
anchors.left: volumeSizeX.right
anchors.leftMargin: 5
}
TextInput {
id: volumeSizeY
height: 20
width: 50
anchors.left: textVolumeSizeY.right
anchors.leftMargin: 3
text: qsTr("16")
color: "white"
font.pixelSize: 12
validator: IntValidator{bottom: 8; top: 64;}
onAccepted: {
newPolyVoxDialog.keyboardEnabled = false;
}
MouseArea {
anchors.fill: parent
onClicked: {
newPolyVoxDialog.keyboardEnabled = HMD.active
parent.focus = true;
parent.forceActiveFocus();
volumeSizeY.cursorPosition = volumeSizeY.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
}
}
}
Rectangle {
id: textInputBoxVolumeSizeY
color: "white"
anchors.fill: volumeSizeY
opacity: 0.1
}
Text {
id: textVolumeSizeZ
text: qsTr("X")
color: "#ffffff"
font.pixelSize: 12
anchors.left: volumeSizeY.right
anchors.leftMargin: 5
}
TextInput {
id: volumeSizeZ
height: 20
width: 50
anchors.left: textVolumeSizeZ.right
anchors.leftMargin: 3
text: qsTr("16")
color: "white"
font.pixelSize: 12
validator: IntValidator{bottom: 8; top: 64;}
onAccepted: {
newPolyVoxDialog.keyboardEnabled = false;
}
MouseArea {
anchors.fill: parent
onClicked: {
newPolyVoxDialog.keyboardEnabled = HMD.active
parent.focus = true;
parent.forceActiveFocus();
volumeSizeZ.cursorPosition = volumeSizeZ.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
}
}
}
Rectangle {
id: textInputBoxVolumeSizeZ
color: "white"
anchors.fill: volumeSizeZ
opacity: 0.1
}
}
Row {
id: row1
height: 400
spacing: 30
anchors.top: rowVolumeSize.bottom
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
Column {
id: column2
width: 200
height: 600
spacing: 10
CheckBox {
id: grabbable
text: qsTr("Grabbable")
}
CheckBox {
id: collisions
text: qsTr("Collisions")
}
Row {
id: row2
width: 200
height: 400
spacing: 20
}
}
Column {
id: column3
height: 400
spacing: 10
Text {
id: text4
text: qsTr("Voxel type")
color: "#ffffff"
font.pixelSize: 12
}
ComboBox {
id: surfaceStyle
currentIndex: 3
property var surfaceStyleArray: ["Marching Cubes",
"Cubic",
"Edged Cubic",
"Edged Marching Cubes"]
width: 200
z: 100
transformOrigin: Item.Center
model: surfaceStyleArray
}
Text {
id: textInitialShape
text: qsTr("Initial shape")
color: "#ffffff"
font.pixelSize: 12
}
ComboBox {
id: initialShape
currentIndex: 0
property var initialShapeArray: ["Box",
"Plane, 1/4 full",
"Plane, 3/4 full",
"Single voxel",
]
width: 200
z: 100
transformOrigin: Item.Center
model: initialShapeArray
}
Row {
id: row3
width: 200
height: 400
spacing: 5
anchors.horizontalCenter: column3.horizontalCenter
anchors.horizontalCenterOffset: -20
Button {
id: button1
text: qsTr("Create")
z: -1
enabled: false
onClicked: {
newPolyVoxDialog.sendToScript({
method: "newPolyVoxDialogAdd",
params: {
xTextureURL: xTextureURL.text,
yTextureURL: yTextureURL.text,
zTextureURL: zTextureURL.text,
volumeSizeX: volumeSizeX.text,
volumeSizeY: volumeSizeY.text,
volumeSizeZ: volumeSizeZ.text,
surfaceStyleIndex: surfaceStyle.currentIndex,
initialShapeIndex: initialShape.currentIndex,
grabbable: grabbable.checked,
collisions: collisions.checked,
}
});
}
}
Button {
id: button2
z: -1
text: qsTr("Cancel")
onClicked: {
newPolyVoxDialog.sendToScript({method: "newPolyVoxDialogCancel"})
}
}
}
}
}
}
Keyboard {
id: keyboard
raised: parent.keyboardEnabled && parent.keyboardRaised
numeric: parent.punctuationMode
anchors {
bottom: parent.bottom
bottomMargin: 40
left: parent.left
right: parent.right
}
}
}

View file

@ -0,0 +1,20 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
StackView {
id: stackView
anchors.fill: parent
anchors.leftMargin: 10
anchors.rightMargin: 10
anchors.topMargin: 40
signal sendToScript(var message);
NewPolyVoxDialog {
id: dialog
anchors.fill: parent
Component.onCompleted:{
dialog.sendToScript.connect(stackView.sendToScript);
}
}
}

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 50 50"
style="enable-background:new 0 0 50 50;"
xml:space="preserve"
sodipodi:docname="voxels.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs27" /><sodipodi:namedview
id="namedview25"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="17.42"
inkscape:cx="25.028703"
inkscape:cy="20.407577"
inkscape:window-width="1918"
inkscape:window-height="1042"
inkscape:window-x="1920"
inkscape:window-y="18"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<style
type="text/css"
id="style2">
.st0{opacity:0.9;}
.st1{fill:#1E1E1E;}
.st2{fill:#EAEAEA;}
</style>
<path
class="st2"
d="M 42.986179,11.33074 34.367376,6.3639716 c -0.438244,-0.2921628 -1.02257,-0.2921628 -1.460814,0 L 25.164247,10.892495 17.129769,6.2178902 c -0.438244,-0.2921628 -1.02257,-0.2921628 -1.460814,0 L 7.196233,11.184658 C 6.7579887,11.476821 6.4658259,11.915065 6.4658259,12.35331 v 9.933535 c 0,0.438244 0.2921628,1.02257 0.7304071,1.168651 l 7.888397,4.528524 v 9.057048 c 0,0.438244 0.292162,1.02257 0.730407,1.168651 l 8.618803,4.966768 c 0.292163,0.146081 0.438244,0.146081 0.730407,0.146081 0.292163,0 0.438244,0 0.730407,-0.146081 l 8.618803,-4.966768 c 0.438245,-0.292163 0.730407,-0.730407 0.730407,-1.168651 v -8.910966 l 7.888397,-4.528524 c 0.438244,-0.292163 0.730407,-0.730407 0.730407,-1.168652 V 12.499391 C 43.716586,12.061147 43.424423,11.622902 42.986179,11.33074 Z m -2.04514,8.910965 -5.989337,-3.505954 V 9.8699255 l 5.989337,3.5059535 z m -7.011907,5.551094 -7.304071,-4.236361 v -8.180559 l 5.989338,-3.5059535 v 6.8658255 l -2.921628,1.752977 c -0.584326,0.292163 -0.730407,1.02257 -0.438244,1.606896 0.292162,0.438244 0.584325,0.584326 1.022569,0.584326 0.146082,0 0.438245,0 0.584326,-0.146082 l 2.921628,-1.752977 5.989338,3.505954 z m -7.596234,5.697175 v -6.719745 l 5.989338,3.505954 v 6.719745 z M 23.703433,20.095624 17.714095,16.58967 V 9.7238441 l 5.989338,3.5059539 z M 9.2413727,13.229798 15.230711,9.7238441 V 16.58967 l -3.213791,1.899058 c -0.584326,0.292163 -0.730407,1.02257 -0.438244,1.606896 0.292163,0.438244 0.584325,0.584326 1.02257,0.584326 0.146081,0 0.438244,0 0.584325,-0.146082 l 3.213791,-1.899058 5.989338,3.505954 -5.989338,3.505954 -7.1579893,-4.09028 z m 15.9228743,27.317224 -7.157989,-4.09028 v -8.180559 l 5.989338,-3.505954 v 6.865826 l -2.921629,1.606896 c -0.584325,0.292163 -0.730407,1.02257 -0.438244,1.606895 0.292163,0.438245 0.584326,0.584326 1.02257,0.584326 0.146082,0 0.438244,0 0.584326,-0.146081 l 2.921628,-1.606896 5.989338,3.505954 z"
id="path10"
style="stroke-width:1.46081;fill:#000000" />
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -4,6 +4,7 @@
// Created by Ryan Huffman on 13 Nov 2014
// Copyright 2014 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// Copyright 2022 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -2062,6 +2063,42 @@ div.entity-list-menu {
cursor: pointer;
}
div.tools-select-menu {
position: relative;
display: none;
width: 370px;
height: 0px;
top: 0px;
left: 8px;
right: 0;
bottom: 0;
border-style: solid;
border-color: #505050;
border-width: 1px;
background-color: #c0c0c0;
z-index: 2;
cursor: pointer;
}
div.tools-help-popup {
font-family: FiraSans-SemiBold;
font-size: 15px;
position: relative;
display: none;
width: 690px;
height: auto;
top: 0px;
left: 8px;
right: 0;
bottom: 0;
border-style: solid;
border-color: #505050;
border-width: 1px;
background-color: #404040;
z-index: 2;
cursor: pointer;
}
div.menu-separator{
width: 100%;
height: 2px;

View file

@ -3,6 +3,7 @@
//
// Created by Ryan Huffman on 6 Nov 2014
// Copyright 2014 High Fidelity, Inc.
// Copyright 2022 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -20,7 +21,80 @@
<script type="text/javascript" src="js/gridControls.js"></script>
</head>
<body onload='loaded();'>
<div id="mode-section" class="section">
<div class="property container">
<label for="create-app-mode">Create app mode </label>
<div class="property container">
<input name="create-app-mode" type="button" class="entity-list-menutitle" id="create-app-mode" value="Create app mode&#9662;" />
</div>
</div>
<div class="tools-select-menu" id="edit-mode-menu" >
<button class="menu-button" id="edit-mode-object" >
<div class = "menu-item">
<div class = "menu-item-caption">Object mode</div>
<div class = "menu-item-shortcut"></div>
</div>
</button>
<button class="menu-button" id="edit-mode-voxel" >
<div class = "menu-item">
<div class = "menu-item-caption">Voxel edit mode</div>
<div class = "menu-item-shortcut"></div>
</div>
</button>
</div>
</div>
<div id="voxels-section" class="section">
<h2>Voxel edit settings</h2>
<div class="property container">
<label for="voxel-edit-mode">Voxel edit mode </label>
<div class="property container">
<input name="voxel-edit-mode" type="button" class="entity-list-menutitle" id="voxel-edit-mode" value="Voxel edit mode&#9662;" />
</div>
<label for="voxel-sphere-size">&nbsp;&nbsp;Sphere/cube size <span class="unit">m</span></label>
<div class="number">
<input type="number" id="voxel-sphere-size" min="0.01" step="0.2" />
</div>
</div>
<div class="tools-select-menu" id="voxel-edit-mode-menu" >
<button class="menu-button" id="voxel-edit-mode-single" >
<div class = "menu-item">
<div class = "menu-item-caption">Single voxels</div>
<div class = "menu-item-shortcut"></div>
</div>
</button>
<button class="menu-button" id="voxel-edit-mode-sphere" >
<div class = "menu-item">
<div class = "menu-item-caption">Spheres</div>
<div class = "menu-item-shortcut"></div>
</div>
</button>
<button class="menu-button" id="voxel-edit-mode-cube" >
<div class = "menu-item">
<div class = "menu-item-caption">Cubes</div>
<div class = "menu-item-shortcut"></div>
</div>
</button>
</div>
<div class="property container">
<label for="voxel-remove">&nbsp;&nbsp;Remove voxels</label>
<div style="width: 100%">
<input type='checkbox' id="voxel-remove" style="width: 100%">
<label for="voxel-remove">&nbsp;</label>
</div>
<div class="property container">
<input name="voxel-help-button" type="button" class="entity-list-menutitle" id="voxel-help-button" value="Voxel edit help&#9662;" />
</div>
</div>
<div class="tools-help-popup" id="voxel-help-popup" >
<p>To edit voxels, Voxel Edit Mode needs to be selected.</p>
<p>Desktop mode:</p>
<p>Click the left mouse button to add a voxel. Click the middle mouse button to remove a voxel. Hold the mouse button and move the mouse to add or remove voxels in a single plane. The plane is determined by the direction in which you are looking when first voxel is added or removed (for example, look downwards to draw in horizontal plane).</p>
<p>VR mode:</p>
<p>Press the trigger to add a voxel. Press the trigger while holding the grip to remove a voxel. Hold the trigger and move the controller to add or remove voxels in a single plane. The plane is determined by the direction in which the controller's ray points when the first voxel is added or removed (for example point downwards to draw in the horizontal plane). Hold both grips and move your hands together or apart to change the size of the edit sphere.</p>
</div>
</div>
<div id="grid-section" class="section">
<h2>Grid settings</h2>
<div class="property container">
<label for="horiz-grid-visible">Visible</label>
<div style="width: 100%">
@ -67,5 +141,6 @@
</div>
</div>
</div>
<div id="menuBackgroundOverlay" ></div>
</body>
</html>

View file

@ -2,12 +2,30 @@
//
// Created by Ryan Huffman on 6 Nov 2014
// Copyright 2014 High Fidelity, Inc.
// Copyright 2022 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
var createAppModeValue = "";
var voxelEditModeValue = "";
function loaded() {
openEventBridge(function() {
elCreateAppModeMenu = document.getElementById("create-app-mode");
elEditModeObject = document.getElementById("edit-mode-object");
elEditModeVoxel = document.getElementById("edit-mode-voxel");
elVoxelEditModeMenu = document.getElementById("voxel-edit-mode");
elVoxelEditModeSingle = document.getElementById("voxel-edit-mode-single");
elVoxelEditModeSphere = document.getElementById("voxel-edit-mode-sphere");
elVoxelEditModeCube = document.getElementById("voxel-edit-mode-cube");
elMenuBackgroundOverlay = document.getElementById("menuBackgroundOverlay");
elVoxelHelpButton = document.getElementById("voxel-help-button");
elVoxelHelpPopup = document.getElementById("voxel-help-popup");
elVoxelSphereSize = document.getElementById("voxel-sphere-size");
elVoxelRemove = document.getElementById("voxel-remove");
elPosY = document.getElementById("horiz-y");
elMinorSpacing = document.getElementById("minor-spacing");
elMajorSpacing = document.getElementById("major-spacing");
@ -16,10 +34,102 @@ function loaded() {
elMoveToSelection = document.getElementById("move-to-selection");
elMoveToAvatar = document.getElementById("move-to-avatar");
elCreateAppModeMenu.onclick = function() {
document.getElementById("menuBackgroundOverlay").style.display = "block";
document.getElementById("edit-mode-menu").style.display = "block";
};
elVoxelEditModeMenu.onclick = function() {
document.getElementById("menuBackgroundOverlay").style.display = "block";
document.getElementById("voxel-edit-mode-menu").style.display = "block";
};
elVoxelHelpButton.onclick = function() {
document.getElementById("menuBackgroundOverlay").style.display = "block";
document.getElementById("voxel-help-popup").style.display = "block";
};
elMenuBackgroundOverlay.onclick = function() {
closeAllEntityListMenu();
};
elEditModeObject.onclick = function() {
createAppModeValue = "object";
elCreateAppModeMenu.value = "Object mode\u25BE";
emitUpdateEditTools();
closeAllEntityListMenu();
};
elEditModeVoxel.onclick = function() {
createAppModeValue = "voxel";
elCreateAppModeMenu.value = "Voxel edit mode\u25BE";
emitUpdateEditTools();
closeAllEntityListMenu();
};
elVoxelEditModeSingle.onclick = function() {
voxelEditModeValue = "single";
elVoxelEditModeMenu.value = "Single voxels\u25BE";
emitUpdateEditTools();
closeAllEntityListMenu();
};
elVoxelEditModeSphere.onclick = function() {
voxelEditModeValue = "sphere";
elVoxelEditModeMenu.value = "Spheres\u25BE";
emitUpdateEditTools();
closeAllEntityListMenu();
};
elVoxelEditModeCube.onclick = function() {
voxelEditModeValue = "cube";
elVoxelEditModeMenu.value = "Cubes\u25BE";
emitUpdateEditTools();
closeAllEntityListMenu();
};
elVoxelHelpPopup.onclick = function() {
closeAllEntityListMenu();
};
if (window.EventBridge !== undefined) {
EventBridge.scriptEventReceived.connect(function(data) {
data = JSON.parse(data);
if (data.createAppMode !== undefined) {
if (data.createAppMode === "object") {
createAppModeValue = data.createAppMode;
elCreateAppModeMenu.value = "Object mode\u25BE";
}
if (data.createAppMode === "voxel") {
createAppModeValue = data.createAppMode;
elCreateAppModeMenu.value = "Voxel edit mode\u25BE";
}
}
if (data.voxelEditMode !== undefined) {
if (data.voxelEditMode === "single") {
voxelEditModeValue = data.voxelEditMode;
elVoxelEditModeMenu.value = "Single voxels\u25BE";
}
if (data.voxelEditMode === "sphere") {
voxelEditModeValue = data.voxelEditMode;
elVoxelEditModeMenu.value = "Spheres\u25BE";
}
if (data.voxelEditMode === "cube") {
voxelEditModeValue = data.voxelEditMode;
elVoxelEditModeMenu.value = "Cubes\u25BE";
}
}
if (data.voxelSphereSize !== undefined) {
elVoxelSphereSize.value = data.voxelSphereSize;
}
if (data.voxelRemove !== undefined) {
elVoxelRemove.checked = data.voxelRemove == true;
}
if (data.origin) {
var origin = data.origin;
elPosY.value = origin.y;
@ -60,8 +170,20 @@ function loaded() {
}));
}
function emitUpdateEditTools() {
EventBridge.emitWebEvent(JSON.stringify({
type: "update-edit-tools",
createAppMode: createAppModeValue,
voxelEditMode: voxelEditModeValue,
voxelSphereSize: elVoxelSphereSize.value,
voxelRemove: elVoxelRemove.checked,
}));
}
}
elVoxelSphereSize.addEventListener("change", emitUpdateEditTools);
elVoxelRemove.addEventListener("change", emitUpdateEditTools);
elPosY.addEventListener("change", emitUpdate);
elMinorSpacing.addEventListener("change", emitUpdate);
elMajorSpacing.addEventListener("change", emitUpdate);
@ -154,8 +276,16 @@ function loaded() {
}));
}, false);
function closeAllEntityListMenu() {
document.getElementById("menuBackgroundOverlay").style.display = "none";
document.getElementById("edit-mode-menu").style.display = "none";
document.getElementById("voxel-edit-mode-menu").style.display = "none";
document.getElementById("voxel-help-popup").style.display = "none";
}
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
document.addEventListener("contextmenu", function (event) {
event.preventDefault();
}, false);
}

View file

@ -508,4 +508,4 @@
});
</script>
</body>
</html>
</html>

View file

@ -3,6 +3,7 @@
// Created by Ryan Huffman on 6 Nov 2014
// Copyright 2014 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
// Copyright 2022 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -196,8 +197,11 @@ Grid = function() {
};
that.update = function(data) {
var gridNeedsUpdate = false;
if (data.snapToGrid !== undefined) {
snapToGrid = data.snapToGrid;
var gridNeedsUpdate = true;
}
if (data.origin) {
@ -206,29 +210,37 @@ Grid = function() {
pos.y = pos.y === undefined ? origin.y : parseFloat(pos.y);
pos.z = pos.z === undefined ? origin.z : parseFloat(pos.z);
that.setPosition(pos, true);
var gridNeedsUpdate = true;
}
if (data.minorGridEvery) {
minorGridEvery = data.minorGridEvery;
var gridNeedsUpdate = true;
}
if (data.majorGridEvery) {
majorGridEvery = data.majorGridEvery;
var gridNeedsUpdate = true;
}
if (data.gridColor) {
gridColor = data.gridColor;
var gridNeedsUpdate = true;
}
if (data.gridSize) {
halfSize = data.gridSize;
var gridNeedsUpdate = true;
}
if (data.visible !== undefined) {
that.setVisible(data.visible, true);
var gridNeedsUpdate = true;
}
updateGrid(true);
if (gridNeedsUpdate) {
updateGrid(true);
}
};
function updateGrid(noUpdate) {

View file

@ -546,4 +546,4 @@ function cleanup() {
Controller.mousePressEvent.connect(mousePressEvent);
Controller.keyPressEvent.connect(keyPressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent);
Script.scriptEnding.connect(cleanup);
Script.scriptEnding.connect(cleanup);