Merge pull request #60 from overte-org/feature/voxel_ui
Create App UI for voxels
After Width: | Height: | Size: 4.5 MiB |
After Width: | Height: | Size: 4.9 MiB |
After Width: | Height: | Size: 4.6 MiB |
After Width: | Height: | Size: 3.5 MiB |
BIN
interface/resources/serverless/Textures/floor_l.png
Normal file
After Width: | Height: | Size: 3.2 MiB |
After Width: | Height: | Size: 4 MiB |
BIN
interface/resources/serverless/Textures/ground_grass_gen_05.png
Normal file
After Width: | Height: | Size: 2.6 MiB |
BIN
interface/resources/serverless/Textures/wall_l.png
Normal file
After Width: | Height: | Size: 3.5 MiB |
|
@ -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]);
|
||||
});
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
181
scripts/system/create/editModes/editModes.js
Normal 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;
|
||||
}
|
687
scripts/system/create/editModes/editVoxels.js
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
|
|
BIN
scripts/system/create/entityProperties/html/tabs/polyvox.png
Normal file
After Width: | Height: | Size: 2 KiB |
|
@ -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;
|
||||
|
|
|
@ -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: ""
|
||||
|
|
|
@ -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: ""
|
||||
|
|
560
scripts/system/create/qml/NewPolyVoxDialog.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
20
scripts/system/create/qml/NewPolyVoxWindow.qml
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
50
scripts/system/create/qml/icons/voxels.svg
Normal 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 |
|
@ -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;
|
||||
|
|
|
@ -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▾" />
|
||||
</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▾" />
|
||||
</div>
|
||||
<label for="voxel-sphere-size"> 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"> Remove voxels</label>
|
||||
<div style="width: 100%">
|
||||
<input type='checkbox' id="voxel-remove" style="width: 100%">
|
||||
<label for="voxel-remove"> </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▾" />
|
||||
</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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -508,4 +508,4 @@
|
|||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|