mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels
This commit is contained in:
commit
09ad4046f8
9 changed files with 928 additions and 135 deletions
151
examples/clipboardExample.js
Normal file
151
examples/clipboardExample.js
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
//
|
||||||
|
// clipboardExample.js
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 1/28/14.
|
||||||
|
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// This is an example script that demonstrates use of the Clipboard class
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
var selectedVoxel = { x: 0, y: 0, z: 0, s: 0 };
|
||||||
|
var selectedSize = 4;
|
||||||
|
|
||||||
|
function printKeyEvent(eventName, event) {
|
||||||
|
print(eventName);
|
||||||
|
print(" event.key=" + event.key);
|
||||||
|
print(" event.text=" + event.text);
|
||||||
|
print(" event.isShifted=" + event.isShifted);
|
||||||
|
print(" event.isControl=" + event.isControl);
|
||||||
|
print(" event.isMeta=" + event.isMeta);
|
||||||
|
print(" event.isAlt=" + event.isAlt);
|
||||||
|
print(" event.isKeypad=" + event.isKeypad);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function keyPressEvent(event) {
|
||||||
|
var debug = false;
|
||||||
|
if (debug) {
|
||||||
|
printKeyEvent("keyPressEvent", event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyReleaseEvent(event) {
|
||||||
|
var debug = false;
|
||||||
|
if (debug) {
|
||||||
|
printKeyEvent("keyReleaseEvent", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this sample uses Alt+ as the key codes for these clipboard items
|
||||||
|
if ((event.key == 199 || event.key == 67 || event.text == "C" || event.text == "c") && event.isAlt) {
|
||||||
|
print("the Alt+C key was pressed");
|
||||||
|
Clipboard.copyVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||||
|
}
|
||||||
|
if ((event.key == 8776 || event.key == 88 || event.text == "X" || event.text == "x") && event.isAlt) {
|
||||||
|
print("the Alt+X key was pressed");
|
||||||
|
Clipboard.cutVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||||
|
}
|
||||||
|
if ((event.key == 8730 || event.key == 86 || event.text == "V" || event.text == "v") && event.isAlt) {
|
||||||
|
print("the Alt+V key was pressed");
|
||||||
|
Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||||
|
}
|
||||||
|
if (event.text == "DELETE" || event.text == "BACKSPACE") {
|
||||||
|
print("the DELETE/BACKSPACE key was pressed");
|
||||||
|
Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((event.text == "E" || event.text == "e") && event.isMeta) {
|
||||||
|
print("the Ctl+E key was pressed");
|
||||||
|
Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||||
|
}
|
||||||
|
if ((event.text == "I" || event.text == "i") && event.isMeta) {
|
||||||
|
print("the Ctl+I key was pressed");
|
||||||
|
Clipboard.importVoxels();
|
||||||
|
}
|
||||||
|
if ((event.key == 78 || event.text == "N" || event.text == "n") && event.isMeta) {
|
||||||
|
print("the Ctl+N key was pressed, nudging to left 1 meter");
|
||||||
|
Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map keyPress and mouse move events to our callbacks
|
||||||
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
|
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||||
|
|
||||||
|
var selectCube = Overlays.addOverlay("cube", {
|
||||||
|
position: { x: 0, y: 0, z: 0},
|
||||||
|
size: selectedSize,
|
||||||
|
color: { red: 255, green: 255, blue: 0},
|
||||||
|
alpha: 1,
|
||||||
|
solid: false,
|
||||||
|
visible: false,
|
||||||
|
lineWidth: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function mouseMoveEvent(event) {
|
||||||
|
|
||||||
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
|
||||||
|
var debug = false;
|
||||||
|
if (debug) {
|
||||||
|
print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y);
|
||||||
|
print("called Camera.computePickRay()");
|
||||||
|
print("computePickRay origin=" + pickRay.origin.x + ", " + pickRay.origin.y + ", " + pickRay.origin.z);
|
||||||
|
print("computePickRay direction=" + pickRay.direction.x + ", " + pickRay.direction.y + ", " + pickRay.direction.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
var intersection = Voxels.findRayIntersection(pickRay);
|
||||||
|
|
||||||
|
if (intersection.intersects) {
|
||||||
|
if (debug) {
|
||||||
|
print("intersection voxel.red/green/blue=" + intersection.voxel.red + ", "
|
||||||
|
+ intersection.voxel.green + ", " + intersection.voxel.blue);
|
||||||
|
print("intersection voxel.x/y/z/s=" + intersection.voxel.x + ", "
|
||||||
|
+ intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s);
|
||||||
|
print("intersection face=" + intersection.face);
|
||||||
|
print("intersection distance=" + intersection.distance);
|
||||||
|
print("intersection intersection.x/y/z=" + intersection.intersection.x + ", "
|
||||||
|
+ intersection.intersection.y + ", " + intersection.intersection.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var x = Math.floor(intersection.voxel.x / selectedSize) * selectedSize;
|
||||||
|
var y = Math.floor(intersection.voxel.y / selectedSize) * selectedSize;
|
||||||
|
var z = Math.floor(intersection.voxel.z / selectedSize) * selectedSize;
|
||||||
|
selectedVoxel = { x: x, y: y, z: z, s: selectedSize };
|
||||||
|
Overlays.editOverlay(selectCube, { position: selectedVoxel, size: selectedSize, visible: true } );
|
||||||
|
} else {
|
||||||
|
Overlays.editOverlay(selectCube, { visible: false } );
|
||||||
|
selectedVoxel = { x: 0, y: 0, z: 0, s: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||||
|
|
||||||
|
function wheelEvent(event) {
|
||||||
|
var debug = false;
|
||||||
|
if (debug) {
|
||||||
|
print("wheelEvent");
|
||||||
|
print(" event.x,y=" + event.x + ", " + event.y);
|
||||||
|
print(" event.delta=" + event.delta);
|
||||||
|
print(" event.orientation=" + event.orientation);
|
||||||
|
print(" event.isLeftButton=" + event.isLeftButton);
|
||||||
|
print(" event.isRightButton=" + event.isRightButton);
|
||||||
|
print(" event.isMiddleButton=" + event.isMiddleButton);
|
||||||
|
print(" event.isShifted=" + event.isShifted);
|
||||||
|
print(" event.isControl=" + event.isControl);
|
||||||
|
print(" event.isMeta=" + event.isMeta);
|
||||||
|
print(" event.isAlt=" + event.isAlt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.wheelEvent.connect(wheelEvent);
|
||||||
|
|
||||||
|
function scriptEnding() {
|
||||||
|
Overlays.deleteOverlay(selectCube);
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
|
@ -72,6 +72,10 @@ audioOptions.volume = 0.5;
|
||||||
var editToolsOn = false; // starts out off
|
var editToolsOn = false; // starts out off
|
||||||
|
|
||||||
|
|
||||||
|
// previewAsVoxel - by default, we will preview adds/deletes/recolors as just 4 lines on the intersecting face. But if you
|
||||||
|
// the preview to show a full voxel then set this to true and the voxel will be displayed for voxel editing
|
||||||
|
var previewAsVoxel = false;
|
||||||
|
|
||||||
var voxelPreview = Overlays.addOverlay("cube", {
|
var voxelPreview = Overlays.addOverlay("cube", {
|
||||||
position: { x: 0, y: 0, z: 0},
|
position: { x: 0, y: 0, z: 0},
|
||||||
size: 1,
|
size: 1,
|
||||||
|
@ -81,14 +85,54 @@ var voxelPreview = Overlays.addOverlay("cube", {
|
||||||
visible: false,
|
visible: false,
|
||||||
lineWidth: 4
|
lineWidth: 4
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var linePreviewTop = Overlays.addOverlay("line3d", {
|
||||||
|
position: { x: 0, y: 0, z: 0},
|
||||||
|
end: { x: 0, y: 0, z: 0},
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
visible: false,
|
||||||
|
lineWidth: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
var linePreviewBottom = Overlays.addOverlay("line3d", {
|
||||||
|
position: { x: 0, y: 0, z: 0},
|
||||||
|
end: { x: 0, y: 0, z: 0},
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
visible: false,
|
||||||
|
lineWidth: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
var linePreviewLeft = Overlays.addOverlay("line3d", {
|
||||||
|
position: { x: 0, y: 0, z: 0},
|
||||||
|
end: { x: 0, y: 0, z: 0},
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
visible: false,
|
||||||
|
lineWidth: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
var linePreviewRight = Overlays.addOverlay("line3d", {
|
||||||
|
position: { x: 0, y: 0, z: 0},
|
||||||
|
end: { x: 0, y: 0, z: 0},
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
visible: false,
|
||||||
|
lineWidth: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// these will be used below
|
||||||
|
var sliderWidth = 158;
|
||||||
|
var sliderHeight = 35;
|
||||||
|
|
||||||
// These will be our "overlay IDs"
|
// These will be our "overlay IDs"
|
||||||
var swatches = new Array();
|
var swatches = new Array();
|
||||||
var swatchHeight = 54;
|
var swatchHeight = 54;
|
||||||
var swatchWidth = 31;
|
var swatchWidth = 31;
|
||||||
var swatchesWidth = swatchWidth * numColors;
|
var swatchesWidth = swatchWidth * numColors;
|
||||||
var swatchesX = (windowDimensions.x - swatchesWidth) / 2;
|
var swatchesX = (windowDimensions.x - (swatchesWidth + sliderWidth)) / 2;
|
||||||
var swatchesY = windowDimensions.y - swatchHeight;
|
var swatchesY = windowDimensions.y - swatchHeight;
|
||||||
|
|
||||||
// create the overlays, position them in a row, set their colors, and for the selected one, use a different source image
|
// create the overlays, position them in a row, set their colors, and for the selected one, use a different source image
|
||||||
|
@ -115,6 +159,143 @@ for (s = 0; s < numColors; s++) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// These will be our tool palette overlays
|
||||||
|
var numberOfTools = 5;
|
||||||
|
var toolHeight = 40;
|
||||||
|
var toolWidth = 62;
|
||||||
|
var toolsHeight = toolHeight * numberOfTools;
|
||||||
|
var toolsX = 0;
|
||||||
|
var toolsY = (windowDimensions.y - toolsHeight) / 2;
|
||||||
|
|
||||||
|
var addToolAt = 0;
|
||||||
|
var deleteToolAt = 1;
|
||||||
|
var recolorToolAt = 2;
|
||||||
|
var eyedropperToolAt = 3;
|
||||||
|
var selectToolAt = 4;
|
||||||
|
var toolSelectedColor = { red: 255, green: 255, blue: 255 };
|
||||||
|
var notSelectedColor = { red: 128, green: 128, blue: 128 };
|
||||||
|
|
||||||
|
var addTool = Overlays.addOverlay("image", {
|
||||||
|
x: 0, y: 0, width: toolWidth, height: toolHeight,
|
||||||
|
subImage: { x: 0, y: toolHeight * addToolAt, width: toolWidth, height: toolHeight },
|
||||||
|
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg",
|
||||||
|
color: toolSelectedColor,
|
||||||
|
visible: false,
|
||||||
|
alpha: 0.9
|
||||||
|
});
|
||||||
|
|
||||||
|
var deleteTool = Overlays.addOverlay("image", {
|
||||||
|
x: 0, y: 0, width: toolWidth, height: toolHeight,
|
||||||
|
subImage: { x: 0, y: toolHeight * deleteToolAt, width: toolWidth, height: toolHeight },
|
||||||
|
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg",
|
||||||
|
color: toolSelectedColor,
|
||||||
|
visible: false,
|
||||||
|
alpha: 0.9
|
||||||
|
});
|
||||||
|
|
||||||
|
var recolorTool = Overlays.addOverlay("image", {
|
||||||
|
x: 0, y: 0, width: toolWidth, height: toolHeight,
|
||||||
|
subImage: { x: 0, y: toolHeight * recolorToolAt, width: toolWidth, height: toolHeight },
|
||||||
|
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg",
|
||||||
|
color: toolSelectedColor,
|
||||||
|
visible: false,
|
||||||
|
alpha: 0.9
|
||||||
|
});
|
||||||
|
|
||||||
|
var eyedropperTool = Overlays.addOverlay("image", {
|
||||||
|
x: 0, y: 0, width: toolWidth, height: toolHeight,
|
||||||
|
subImage: { x: 0, y: toolHeight * eyedropperToolAt, width: toolWidth, height: toolHeight },
|
||||||
|
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg",
|
||||||
|
color: toolSelectedColor,
|
||||||
|
visible: false,
|
||||||
|
alpha: 0.9
|
||||||
|
});
|
||||||
|
|
||||||
|
var selectTool = Overlays.addOverlay("image", {
|
||||||
|
x: 0, y: 0, width: toolWidth, height: toolHeight,
|
||||||
|
subImage: { x: 0, y: toolHeight * selectToolAt, width: toolWidth, height: toolHeight },
|
||||||
|
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg",
|
||||||
|
color: toolSelectedColor,
|
||||||
|
visible: false,
|
||||||
|
alpha: 0.9
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// This will create a couple of image overlays that make a "slider", we will demonstrate how to trap mouse messages to
|
||||||
|
// move the slider
|
||||||
|
|
||||||
|
// see above...
|
||||||
|
//var sliderWidth = 158;
|
||||||
|
//var sliderHeight = 35;
|
||||||
|
|
||||||
|
var sliderX = swatchesX + swatchesWidth;
|
||||||
|
var sliderY = windowDimensions.y - sliderHeight;
|
||||||
|
var slider = Overlays.addOverlay("image", {
|
||||||
|
// alternate form of expressing bounds
|
||||||
|
bounds: { x: sliderX, y: sliderY, width: sliderWidth, height: sliderHeight},
|
||||||
|
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/slider.png",
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// The slider is handled in the mouse event callbacks.
|
||||||
|
var isMovingSlider = false;
|
||||||
|
var thumbClickOffsetX = 0;
|
||||||
|
|
||||||
|
// This is the thumb of our slider
|
||||||
|
var minThumbX = 30; // relative to the x of the slider
|
||||||
|
var maxThumbX = minThumbX + 65;
|
||||||
|
var thumbExtents = maxThumbX - minThumbX;
|
||||||
|
var thumbX = (minThumbX + maxThumbX) / 2;
|
||||||
|
var thumbY = sliderY + 9;
|
||||||
|
var thumb = Overlays.addOverlay("image", {
|
||||||
|
x: sliderX + thumbX,
|
||||||
|
y: thumbY,
|
||||||
|
width: 18,
|
||||||
|
height: 17,
|
||||||
|
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/thumb.png",
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
|
||||||
|
var pointerVoxelScale = 0; // this is the voxel scale used for click to add or delete
|
||||||
|
var pointerVoxelScaleSet = false; // if voxel scale has not yet been set, we use the intersection size
|
||||||
|
|
||||||
|
var pointerVoxelScaleSteps = 8; // the number of slider position steps
|
||||||
|
var pointerVoxelScaleOriginStep = 3; // the position of slider for the 1 meter size voxel
|
||||||
|
var pointerVoxelScaleMin = Math.pow(2, (1-pointerVoxelScaleOriginStep));
|
||||||
|
var pointerVoxelScaleMax = Math.pow(2, (pointerVoxelScaleSteps-pointerVoxelScaleOriginStep));
|
||||||
|
var thumbDeltaPerStep = thumbExtents / (pointerVoxelScaleSteps - 1);
|
||||||
|
|
||||||
|
function calcThumbFromScale(scale) {
|
||||||
|
var scaleLog = Math.log(scale)/Math.log(2);
|
||||||
|
var thumbStep = scaleLog + pointerVoxelScaleOriginStep;
|
||||||
|
if (thumbStep < 1) {
|
||||||
|
thumbStep = 1;
|
||||||
|
}
|
||||||
|
if (thumbStep > pointerVoxelScaleSteps) {
|
||||||
|
thumbStep = pointerVoxelScaleSteps;
|
||||||
|
}
|
||||||
|
thumbX = (thumbDeltaPerStep * (thumbStep - 1)) + minThumbX;
|
||||||
|
Overlays.editOverlay(thumb, { x: thumbX + sliderX } );
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcScaleFromThumb(newThumbX) {
|
||||||
|
// newThumbX is the pixel location relative to start of slider,
|
||||||
|
// we need to figure out the actual offset in the allowed slider area
|
||||||
|
thumbAt = newThumbX - minThumbX;
|
||||||
|
thumbStep = Math.floor((thumbAt/ thumbExtents) * (pointerVoxelScaleSteps-1)) + 1;
|
||||||
|
pointerVoxelScale = Math.pow(2, (thumbStep-pointerVoxelScaleOriginStep));
|
||||||
|
// now reset the display accordingly...
|
||||||
|
calcThumbFromScale(pointerVoxelScale);
|
||||||
|
|
||||||
|
// if the user moved the thumb, then they are fixing the voxel scale
|
||||||
|
pointerVoxelScaleSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
function setAudioPosition() {
|
function setAudioPosition() {
|
||||||
var camera = Camera.getPosition();
|
var camera = Camera.getPosition();
|
||||||
var forwardVector = Quat.getFront(MyAvatar.orientation);
|
var forwardVector = Quat.getFront(MyAvatar.orientation);
|
||||||
|
@ -144,85 +325,225 @@ var trackLastMouseX = 0;
|
||||||
var trackLastMouseY = 0;
|
var trackLastMouseY = 0;
|
||||||
var trackAsDelete = false;
|
var trackAsDelete = false;
|
||||||
var trackAsRecolor = false;
|
var trackAsRecolor = false;
|
||||||
|
var trackAsEyedropper = false;
|
||||||
|
var trackAsOrbit = false;
|
||||||
|
|
||||||
function showPreviewVoxel() {
|
function calculateVoxelFromIntersection(intersection, operation) {
|
||||||
if (editToolsOn) {
|
//print("calculateVoxelFromIntersection() operation="+operation);
|
||||||
var voxelColor;
|
var resultVoxel;
|
||||||
|
|
||||||
|
var voxelSize;
|
||||||
|
if (pointerVoxelScaleSet) {
|
||||||
|
voxelSize = pointerVoxelScale;
|
||||||
|
} else {
|
||||||
|
voxelSize = intersection.voxel.s;
|
||||||
|
}
|
||||||
|
|
||||||
var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY);
|
// first, calculate the enclosed voxel of size voxelSize that the intersection point falls inside of.
|
||||||
var intersection = Voxels.findRayIntersection(pickRay);
|
// if you have a voxelSize that's smaller than the voxel you're intersecting, this calculation will result
|
||||||
|
// in the subvoxel that the intersection point falls in
|
||||||
|
var x = Math.floor(intersection.intersection.x / voxelSize) * voxelSize;
|
||||||
|
var y = Math.floor(intersection.intersection.y / voxelSize) * voxelSize;
|
||||||
|
var z = Math.floor(intersection.intersection.z / voxelSize) * voxelSize;
|
||||||
|
resultVoxel = { x: x, y: y, z: z, s: voxelSize };
|
||||||
|
highlightAt = { x: x, y: y, z: z, s: voxelSize };
|
||||||
|
|
||||||
if (whichColor == -1) {
|
// now we also want to calculate the "edge square" for the face for this voxel
|
||||||
// Copy mode - use clicked voxel color
|
if (intersection.face == "MIN_X_FACE") {
|
||||||
voxelColor = { red: intersection.voxel.red,
|
highlightAt.x = intersection.voxel.x;
|
||||||
green: intersection.voxel.green,
|
resultVoxel.x = intersection.voxel.x;
|
||||||
blue: intersection.voxel.blue };
|
if (operation == "add") {
|
||||||
} else {
|
resultVoxel.x -= voxelSize;
|
||||||
voxelColor = { red: colors[whichColor].red,
|
}
|
||||||
green: colors[whichColor].green,
|
|
||||||
blue: colors[whichColor].blue };
|
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
|
||||||
|
resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize };
|
||||||
|
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z };
|
||||||
|
resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z + voxelSize };
|
||||||
|
|
||||||
|
} else if (intersection.face == "MAX_X_FACE") {
|
||||||
|
highlightAt.x = intersection.voxel.x + intersection.voxel.s;
|
||||||
|
resultVoxel.x = intersection.voxel.x + intersection.voxel.s;
|
||||||
|
if (operation != "add") {
|
||||||
|
resultVoxel.x -= voxelSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
var guidePosition;
|
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
|
||||||
|
resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize };
|
||||||
|
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z };
|
||||||
|
resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z + voxelSize };
|
||||||
|
|
||||||
|
} else if (intersection.face == "MIN_Y_FACE") {
|
||||||
|
|
||||||
|
highlightAt.y = intersection.voxel.y;
|
||||||
|
resultVoxel.y = intersection.voxel.y;
|
||||||
|
|
||||||
if (trackAsDelete) {
|
if (operation == "add") {
|
||||||
guidePosition = { x: intersection.voxel.x,
|
resultVoxel.y -= voxelSize;
|
||||||
y: intersection.voxel.y,
|
}
|
||||||
z: intersection.voxel.z };
|
|
||||||
Overlays.editOverlay(voxelPreview, {
|
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
|
||||||
position: guidePosition,
|
resultVoxel.bottomRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z};
|
||||||
size: intersection.voxel.s,
|
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize };
|
||||||
visible: true,
|
resultVoxel.topRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z + voxelSize};
|
||||||
color: { red: 255, green: 0, blue: 0 },
|
|
||||||
solid: false,
|
|
||||||
alpha: 1
|
|
||||||
});
|
|
||||||
} else if (trackAsRecolor) {
|
|
||||||
guidePosition = { x: intersection.voxel.x - 0.001,
|
|
||||||
y: intersection.voxel.y - 0.001,
|
|
||||||
z: intersection.voxel.z - 0.001 };
|
|
||||||
|
|
||||||
Overlays.editOverlay(voxelPreview, {
|
} else if (intersection.face == "MAX_Y_FACE") {
|
||||||
position: guidePosition,
|
|
||||||
size: intersection.voxel.s + 0.002,
|
|
||||||
visible: true,
|
|
||||||
color: voxelColor,
|
|
||||||
solid: true,
|
|
||||||
alpha: 0.8
|
|
||||||
});
|
|
||||||
|
|
||||||
} else if (!isExtruding) {
|
highlightAt.y = intersection.voxel.y + intersection.voxel.s;
|
||||||
guidePosition = { x: intersection.voxel.x,
|
resultVoxel.y = intersection.voxel.y + intersection.voxel.s;
|
||||||
y: intersection.voxel.y,
|
if (operation != "add") {
|
||||||
z: intersection.voxel.z };
|
resultVoxel.y -= voxelSize;
|
||||||
|
}
|
||||||
if (intersection.face == "MIN_X_FACE") {
|
|
||||||
guidePosition.x -= intersection.voxel.s;
|
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
|
||||||
} else if (intersection.face == "MAX_X_FACE") {
|
resultVoxel.bottomRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z};
|
||||||
guidePosition.x += intersection.voxel.s;
|
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize };
|
||||||
} else if (intersection.face == "MIN_Y_FACE") {
|
resultVoxel.topRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z + voxelSize};
|
||||||
guidePosition.y -= intersection.voxel.s;
|
|
||||||
} else if (intersection.face == "MAX_Y_FACE") {
|
|
||||||
guidePosition.y += intersection.voxel.s;
|
|
||||||
} else if (intersection.face == "MIN_Z_FACE") {
|
|
||||||
guidePosition.z -= intersection.voxel.s;
|
|
||||||
} else if (intersection.face == "MAX_Z_FACE") {
|
|
||||||
guidePosition.z += intersection.voxel.s;
|
|
||||||
}
|
|
||||||
|
|
||||||
Overlays.editOverlay(voxelPreview, {
|
} else if (intersection.face == "MIN_Z_FACE") {
|
||||||
position: guidePosition,
|
|
||||||
size: intersection.voxel.s,
|
highlightAt.z = intersection.voxel.z;
|
||||||
visible: true,
|
resultVoxel.z = intersection.voxel.z;
|
||||||
color: voxelColor,
|
|
||||||
solid: true,
|
if (operation == "add") {
|
||||||
alpha: 0.7
|
resultVoxel.z -= voxelSize;
|
||||||
});
|
}
|
||||||
} else if (isExtruding) {
|
|
||||||
|
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
|
||||||
|
resultVoxel.bottomRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z};
|
||||||
|
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z };
|
||||||
|
resultVoxel.topRight = {x: highlightAt.x + voxelSize , y: highlightAt.y + voxelSize, z: highlightAt.z};
|
||||||
|
|
||||||
|
} else if (intersection.face == "MAX_Z_FACE") {
|
||||||
|
|
||||||
|
highlightAt.z = intersection.voxel.z + intersection.voxel.s;
|
||||||
|
resultVoxel.z = intersection.voxel.z + intersection.voxel.s;
|
||||||
|
if (operation != "add") {
|
||||||
|
resultVoxel.z -= voxelSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
|
||||||
|
resultVoxel.bottomRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z};
|
||||||
|
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z };
|
||||||
|
resultVoxel.topRight = {x: highlightAt.x + voxelSize , y: highlightAt.y + voxelSize, z: highlightAt.z};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVoxel;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPreviewVoxel() {
|
||||||
|
var voxelColor;
|
||||||
|
|
||||||
|
var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY);
|
||||||
|
var intersection = Voxels.findRayIntersection(pickRay);
|
||||||
|
|
||||||
|
// if the user hasn't updated the
|
||||||
|
if (!pointerVoxelScaleSet) {
|
||||||
|
calcThumbFromScale(intersection.voxel.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (whichColor == -1) {
|
||||||
|
// Copy mode - use clicked voxel color
|
||||||
|
voxelColor = { red: intersection.voxel.red,
|
||||||
|
green: intersection.voxel.green,
|
||||||
|
blue: intersection.voxel.blue };
|
||||||
|
} else {
|
||||||
|
voxelColor = { red: colors[whichColor].red,
|
||||||
|
green: colors[whichColor].green,
|
||||||
|
blue: colors[whichColor].blue };
|
||||||
|
}
|
||||||
|
|
||||||
|
var guidePosition;
|
||||||
|
|
||||||
|
if (trackAsDelete) {
|
||||||
|
guidePosition = calculateVoxelFromIntersection(intersection,"delete");
|
||||||
|
Overlays.editOverlay(voxelPreview, {
|
||||||
|
position: guidePosition,
|
||||||
|
size: guidePosition.s,
|
||||||
|
visible: true,
|
||||||
|
color: { red: 255, green: 0, blue: 0 },
|
||||||
|
solid: false,
|
||||||
|
alpha: 1
|
||||||
|
});
|
||||||
|
} else if (trackAsRecolor || trackAsEyedropper) {
|
||||||
|
guidePosition = calculateVoxelFromIntersection(intersection,"recolor");
|
||||||
|
|
||||||
|
Overlays.editOverlay(voxelPreview, {
|
||||||
|
position: guidePosition,
|
||||||
|
size: guidePosition.s + 0.002,
|
||||||
|
visible: true,
|
||||||
|
color: voxelColor,
|
||||||
|
solid: true,
|
||||||
|
alpha: 0.8
|
||||||
|
});
|
||||||
|
} else if (trackAsOrbit) {
|
||||||
|
Overlays.editOverlay(voxelPreview, { visible: false });
|
||||||
|
} else if (!isExtruding) {
|
||||||
|
guidePosition = calculateVoxelFromIntersection(intersection,"add");
|
||||||
|
|
||||||
|
Overlays.editOverlay(voxelPreview, {
|
||||||
|
position: guidePosition,
|
||||||
|
size: guidePosition.s,
|
||||||
|
visible: true,
|
||||||
|
color: voxelColor,
|
||||||
|
solid: true,
|
||||||
|
alpha: 0.7
|
||||||
|
});
|
||||||
|
} else if (isExtruding) {
|
||||||
|
Overlays.editOverlay(voxelPreview, { visible: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPreviewLines() {
|
||||||
|
|
||||||
|
var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY);
|
||||||
|
var intersection = Voxels.findRayIntersection(pickRay);
|
||||||
|
|
||||||
|
if (intersection.intersects) {
|
||||||
|
|
||||||
|
// if the user hasn't updated the
|
||||||
|
if (!pointerVoxelScaleSet) {
|
||||||
|
calcThumbFromScale(intersection.voxel.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
resultVoxel = calculateVoxelFromIntersection(intersection,"");
|
||||||
|
Overlays.editOverlay(linePreviewTop, { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true });
|
||||||
|
Overlays.editOverlay(linePreviewBottom, { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true });
|
||||||
|
Overlays.editOverlay(linePreviewLeft, { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true });
|
||||||
|
Overlays.editOverlay(linePreviewRight, { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Overlays.editOverlay(linePreviewTop, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewBottom, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewLeft, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewRight, { visible: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPreviewGuides() {
|
||||||
|
if (editToolsOn) {
|
||||||
|
if (previewAsVoxel) {
|
||||||
|
showPreviewVoxel();
|
||||||
|
|
||||||
|
// make sure alternative is hidden
|
||||||
|
Overlays.editOverlay(linePreviewTop, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewBottom, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewLeft, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewRight, { visible: false });
|
||||||
|
} else {
|
||||||
|
showPreviewLines();
|
||||||
|
|
||||||
|
// make sure alternative is hidden
|
||||||
Overlays.editOverlay(voxelPreview, { visible: false });
|
Overlays.editOverlay(voxelPreview, { visible: false });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// make sure all previews are off
|
||||||
Overlays.editOverlay(voxelPreview, { visible: false });
|
Overlays.editOverlay(voxelPreview, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewTop, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewBottom, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewLeft, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewRight, { visible: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,27 +552,58 @@ function trackMouseEvent(event) {
|
||||||
trackLastMouseY = event.y;
|
trackLastMouseY = event.y;
|
||||||
trackAsDelete = event.isControl;
|
trackAsDelete = event.isControl;
|
||||||
trackAsRecolor = event.isShifted;
|
trackAsRecolor = event.isShifted;
|
||||||
showPreviewVoxel();
|
trackAsEyedropper = event.isMeta;
|
||||||
|
trackAsOrbit = event.isAlt;
|
||||||
|
showPreviewGuides();
|
||||||
}
|
}
|
||||||
|
|
||||||
function trackKeyPressEvent(event) {
|
function trackKeyPressEvent(event) {
|
||||||
if (event.text == "CONTROL") {
|
if (event.text == "CONTROL") {
|
||||||
trackAsDelete = true;
|
trackAsDelete = true;
|
||||||
showPreviewVoxel();
|
moveTools();
|
||||||
}
|
}
|
||||||
if (event.text == "SHIFT") {
|
if (event.text == "SHIFT") {
|
||||||
trackAsRecolor = true;
|
trackAsRecolor = true;
|
||||||
|
moveTools();
|
||||||
}
|
}
|
||||||
showPreviewVoxel();
|
if (event.text == "META") {
|
||||||
|
trackAsEyedropper = true;
|
||||||
|
moveTools();
|
||||||
|
}
|
||||||
|
if (event.text == "ALT") {
|
||||||
|
trackAsOrbit = true;
|
||||||
|
moveTools();
|
||||||
|
}
|
||||||
|
showPreviewGuides();
|
||||||
}
|
}
|
||||||
|
|
||||||
function trackKeyReleaseEvent(event) {
|
function trackKeyReleaseEvent(event) {
|
||||||
|
if (event.text == "ESC") {
|
||||||
|
pointerVoxelScaleSet = false;
|
||||||
|
}
|
||||||
|
if (event.text == "-") {
|
||||||
|
thumbX -= thumbDeltaPerStep;
|
||||||
|
calcScaleFromThumb(thumbX);
|
||||||
|
}
|
||||||
|
if (event.text == "+") {
|
||||||
|
thumbX += thumbDeltaPerStep;
|
||||||
|
calcScaleFromThumb(thumbX);
|
||||||
|
}
|
||||||
if (event.text == "CONTROL") {
|
if (event.text == "CONTROL") {
|
||||||
trackAsDelete = false;
|
trackAsDelete = false;
|
||||||
showPreviewVoxel();
|
moveTools();
|
||||||
}
|
}
|
||||||
if (event.text == "SHIFT") {
|
if (event.text == "SHIFT") {
|
||||||
trackAsRecolor = false;
|
trackAsRecolor = false;
|
||||||
|
moveTools();
|
||||||
|
}
|
||||||
|
if (event.text == "META") {
|
||||||
|
trackAsEyedropper = false;
|
||||||
|
moveTools();
|
||||||
|
}
|
||||||
|
if (event.text == "ALT") {
|
||||||
|
trackAsOrbit = false;
|
||||||
|
moveTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
// on TAB release, toggle our tool state
|
// on TAB release, toggle our tool state
|
||||||
|
@ -260,7 +612,13 @@ function trackKeyReleaseEvent(event) {
|
||||||
moveTools();
|
moveTools();
|
||||||
Audio.playSound(clickSound, audioOptions);
|
Audio.playSound(clickSound, audioOptions);
|
||||||
}
|
}
|
||||||
showPreviewVoxel();
|
|
||||||
|
// on F1 toggle the preview mode between cubes and lines
|
||||||
|
if (event.text == "F1") {
|
||||||
|
previewAsVoxel = !previewAsVoxel;
|
||||||
|
}
|
||||||
|
|
||||||
|
showPreviewGuides();
|
||||||
}
|
}
|
||||||
|
|
||||||
function mousePressEvent(event) {
|
function mousePressEvent(event) {
|
||||||
|
@ -269,11 +627,30 @@ function mousePressEvent(event) {
|
||||||
if (!editToolsOn) {
|
if (!editToolsOn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clickedOnSwatch = false;
|
||||||
|
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||||
|
|
||||||
if (event.isRightButton) {
|
// If the user clicked on the thumb, handle the slider logic
|
||||||
// debugging of right button click on mac...
|
if (clickedOverlay == thumb) {
|
||||||
print(">>>> RIGHT BUTTON <<<<<");
|
isMovingSlider = true;
|
||||||
|
thumbClickOffsetX = event.x - (sliderX + thumbX); // this should be the position of the mouse relative to the thumb
|
||||||
|
return; // no further processing
|
||||||
|
} else {
|
||||||
|
// if the user clicked on one of the color swatches, update the selectedSwatch
|
||||||
|
for (s = 0; s < numColors; s++) {
|
||||||
|
if (clickedOverlay == swatches[s]) {
|
||||||
|
whichColor = s;
|
||||||
|
moveTools();
|
||||||
|
clickedOnSwatch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (clickedOnSwatch) {
|
||||||
|
return; // no further processing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
trackMouseEvent(event); // used by preview support
|
trackMouseEvent(event); // used by preview support
|
||||||
mouseX = event.x;
|
mouseX = event.x;
|
||||||
mouseY = event.y;
|
mouseY = event.y;
|
||||||
|
@ -281,6 +658,11 @@ function mousePressEvent(event) {
|
||||||
var intersection = Voxels.findRayIntersection(pickRay);
|
var intersection = Voxels.findRayIntersection(pickRay);
|
||||||
audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction);
|
audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction);
|
||||||
if (intersection.intersects) {
|
if (intersection.intersects) {
|
||||||
|
// if the user hasn't updated the
|
||||||
|
if (!pointerVoxelScaleSet) {
|
||||||
|
calcThumbFromScale(intersection.voxel.s);
|
||||||
|
}
|
||||||
|
|
||||||
if (event.isAlt) {
|
if (event.isAlt) {
|
||||||
// start orbit camera!
|
// start orbit camera!
|
||||||
var cameraPosition = Camera.getPosition();
|
var cameraPosition = Camera.getPosition();
|
||||||
|
@ -295,18 +677,27 @@ function mousePressEvent(event) {
|
||||||
orbitAzimuth = Math.atan2(orbitVector.z, orbitVector.x);
|
orbitAzimuth = Math.atan2(orbitVector.z, orbitVector.x);
|
||||||
orbitAltitude = Math.asin(orbitVector.y / Vec3.length(orbitVector));
|
orbitAltitude = Math.asin(orbitVector.y / Vec3.length(orbitVector));
|
||||||
|
|
||||||
} else if (trackAsDelete || event.isRightButton) {
|
} else if (trackAsDelete || (event.isRightButton && !trackAsEyedropper)) {
|
||||||
// Delete voxel
|
// Delete voxel
|
||||||
Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, intersection.voxel.s);
|
voxelDetails = calculateVoxelFromIntersection(intersection,"delete");
|
||||||
|
Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s);
|
||||||
Audio.playSound(deleteSound, audioOptions);
|
Audio.playSound(deleteSound, audioOptions);
|
||||||
Overlays.editOverlay(voxelPreview, { visible: false });
|
Overlays.editOverlay(voxelPreview, { visible: false });
|
||||||
|
} else if (trackAsEyedropper) {
|
||||||
|
if (whichColor != -1) {
|
||||||
|
colors[whichColor].red = intersection.voxel.red;
|
||||||
|
colors[whichColor].green = intersection.voxel.green;
|
||||||
|
colors[whichColor].blue = intersection.voxel.blue;
|
||||||
|
moveTools();
|
||||||
|
}
|
||||||
|
|
||||||
} else if (trackAsRecolor) {
|
} else if (trackAsRecolor) {
|
||||||
// Recolor Voxel
|
// Recolor Voxel
|
||||||
Voxels.setVoxel(intersection.voxel.x,
|
voxelDetails = calculateVoxelFromIntersection(intersection,"recolor");
|
||||||
intersection.voxel.y,
|
|
||||||
intersection.voxel.z,
|
// doing this erase then set will make sure we only recolor just the target voxel
|
||||||
intersection.voxel.s,
|
Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s);
|
||||||
|
Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s,
|
||||||
colors[whichColor].red, colors[whichColor].green, colors[whichColor].blue);
|
colors[whichColor].red, colors[whichColor].green, colors[whichColor].blue);
|
||||||
Audio.playSound(changeColorSound, audioOptions);
|
Audio.playSound(changeColorSound, audioOptions);
|
||||||
Overlays.editOverlay(voxelPreview, { visible: false });
|
Overlays.editOverlay(voxelPreview, { visible: false });
|
||||||
|
@ -314,43 +705,23 @@ function mousePressEvent(event) {
|
||||||
// Add voxel on face
|
// Add voxel on face
|
||||||
if (whichColor == -1) {
|
if (whichColor == -1) {
|
||||||
// Copy mode - use clicked voxel color
|
// Copy mode - use clicked voxel color
|
||||||
var newVoxel = {
|
newColor = {
|
||||||
x: intersection.voxel.x,
|
|
||||||
y: intersection.voxel.y,
|
|
||||||
z: intersection.voxel.z,
|
|
||||||
s: intersection.voxel.s,
|
|
||||||
red: intersection.voxel.red,
|
red: intersection.voxel.red,
|
||||||
green: intersection.voxel.green,
|
green: intersection.voxel.green,
|
||||||
blue: intersection.voxel.blue };
|
blue: intersection.voxel.blue };
|
||||||
} else {
|
} else {
|
||||||
var newVoxel = {
|
newColor = {
|
||||||
x: intersection.voxel.x,
|
|
||||||
y: intersection.voxel.y,
|
|
||||||
z: intersection.voxel.z,
|
|
||||||
s: intersection.voxel.s,
|
|
||||||
red: colors[whichColor].red,
|
red: colors[whichColor].red,
|
||||||
green: colors[whichColor].green,
|
green: colors[whichColor].green,
|
||||||
blue: colors[whichColor].blue };
|
blue: colors[whichColor].blue };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersection.face == "MIN_X_FACE") {
|
voxelDetails = calculateVoxelFromIntersection(intersection,"add");
|
||||||
newVoxel.x -= newVoxel.s;
|
Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s,
|
||||||
} else if (intersection.face == "MAX_X_FACE") {
|
newColor.red, newColor.green, newColor.blue);
|
||||||
newVoxel.x += newVoxel.s;
|
lastVoxelPosition = { x: voxelDetails.x, y: voxelDetails.y, z: voxelDetails.z };
|
||||||
} else if (intersection.face == "MIN_Y_FACE") {
|
lastVoxelColor = { red: newColor.red, green: newColor.green, blue: newColor.blue };
|
||||||
newVoxel.y -= newVoxel.s;
|
lastVoxelScale = voxelDetails.s;
|
||||||
} else if (intersection.face == "MAX_Y_FACE") {
|
|
||||||
newVoxel.y += newVoxel.s;
|
|
||||||
} else if (intersection.face == "MIN_Z_FACE") {
|
|
||||||
newVoxel.z -= newVoxel.s;
|
|
||||||
} else if (intersection.face == "MAX_Z_FACE") {
|
|
||||||
newVoxel.z += newVoxel.s;
|
|
||||||
}
|
|
||||||
|
|
||||||
Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue);
|
|
||||||
lastVoxelPosition = { x: newVoxel.x, y: newVoxel.y, z: newVoxel.z };
|
|
||||||
lastVoxelColor = { red: newVoxel.red, green: newVoxel.green, blue: newVoxel.blue };
|
|
||||||
lastVoxelScale = newVoxel.s;
|
|
||||||
|
|
||||||
Audio.playSound(addSound, audioOptions);
|
Audio.playSound(addSound, audioOptions);
|
||||||
Overlays.editOverlay(voxelPreview, { visible: false });
|
Overlays.editOverlay(voxelPreview, { visible: false });
|
||||||
|
@ -410,8 +781,20 @@ function keyReleaseEvent(event) {
|
||||||
key_alt = false;
|
key_alt = false;
|
||||||
key_shift = false;
|
key_shift = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function mouseMoveEvent(event) {
|
function mouseMoveEvent(event) {
|
||||||
if (isOrbiting) {
|
if (isMovingSlider) {
|
||||||
|
thumbX = (event.x - thumbClickOffsetX) - sliderX;
|
||||||
|
if (thumbX < minThumbX) {
|
||||||
|
thumbX = minThumbX;
|
||||||
|
}
|
||||||
|
if (thumbX > maxThumbX) {
|
||||||
|
thumbX = maxThumbX;
|
||||||
|
}
|
||||||
|
calcScaleFromThumb(thumbX);
|
||||||
|
|
||||||
|
} else if (isOrbiting) {
|
||||||
var cameraOrientation = Camera.getOrientation();
|
var cameraOrientation = Camera.getOrientation();
|
||||||
var origEulers = Quat.safeEulerAngles(cameraOrientation);
|
var origEulers = Quat.safeEulerAngles(cameraOrientation);
|
||||||
var newEulers = fixEulerAngles(Quat.safeEulerAngles(cameraOrientation));
|
var newEulers = fixEulerAngles(Quat.safeEulerAngles(cameraOrientation));
|
||||||
|
@ -426,8 +809,7 @@ function mouseMoveEvent(event) {
|
||||||
Camera.setPosition(orbitPosition);
|
Camera.setPosition(orbitPosition);
|
||||||
mouseX = event.x;
|
mouseX = event.x;
|
||||||
mouseY = event.y;
|
mouseY = event.y;
|
||||||
}
|
} else if (isAdding) {
|
||||||
if (isAdding) {
|
|
||||||
// Watch the drag direction to tell which way to 'extrude' this voxel
|
// Watch the drag direction to tell which way to 'extrude' this voxel
|
||||||
if (!isExtruding) {
|
if (!isExtruding) {
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
@ -476,6 +858,10 @@ function mouseReleaseEvent(event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isMovingSlider) {
|
||||||
|
isMovingSlider = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (isOrbiting) {
|
if (isOrbiting) {
|
||||||
var cameraOrientation = Camera.getOrientation();
|
var cameraOrientation = Camera.getOrientation();
|
||||||
var eulers = Quat.safeEulerAngles(cameraOrientation);
|
var eulers = Quat.safeEulerAngles(cameraOrientation);
|
||||||
|
@ -491,7 +877,8 @@ function mouseReleaseEvent(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveTools() {
|
function moveTools() {
|
||||||
swatchesX = (windowDimensions.x - swatchesWidth) / 2;
|
// move the swatches
|
||||||
|
swatchesX = (windowDimensions.x - (swatchesWidth + sliderWidth)) / 2;
|
||||||
swatchesY = windowDimensions.y - swatchHeight;
|
swatchesY = windowDimensions.y - swatchHeight;
|
||||||
|
|
||||||
// create the overlays, position them in a row, set their colors, and for the selected one, use a different source image
|
// create the overlays, position them in a row, set their colors, and for the selected one, use a different source image
|
||||||
|
@ -513,6 +900,66 @@ function moveTools() {
|
||||||
visible: editToolsOn
|
visible: editToolsOn
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// move the tools
|
||||||
|
toolsY = (windowDimensions.y - toolsHeight) / 2;
|
||||||
|
addToolColor = notSelectedColor;
|
||||||
|
deleteToolColor = notSelectedColor;
|
||||||
|
recolorToolColor = notSelectedColor;
|
||||||
|
eyedropperToolColor = notSelectedColor;
|
||||||
|
selectToolColor = notSelectedColor;
|
||||||
|
|
||||||
|
if (trackAsDelete) {
|
||||||
|
deleteToolColor = toolSelectedColor;
|
||||||
|
} else if (trackAsRecolor) {
|
||||||
|
recolorToolColor = toolSelectedColor;
|
||||||
|
} else if (trackAsEyedropper) {
|
||||||
|
eyedropperToolColor = toolSelectedColor;
|
||||||
|
} else if (trackAsOrbit) {
|
||||||
|
// nothing gets selected in this case...
|
||||||
|
} else {
|
||||||
|
addToolColor = toolSelectedColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
Overlays.editOverlay(addTool, {
|
||||||
|
x: 0, y: toolsY + (toolHeight * addToolAt), width: toolWidth, height: toolHeight,
|
||||||
|
color: addToolColor,
|
||||||
|
visible: editToolsOn
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(deleteTool, {
|
||||||
|
x: 0, y: toolsY + (toolHeight * deleteToolAt), width: toolWidth, height: toolHeight,
|
||||||
|
color: deleteToolColor,
|
||||||
|
visible: editToolsOn
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(recolorTool, {
|
||||||
|
x: 0, y: toolsY + (toolHeight * recolorToolAt), width: toolWidth, height: toolHeight,
|
||||||
|
color: recolorToolColor,
|
||||||
|
visible: editToolsOn
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(eyedropperTool, {
|
||||||
|
x: 0, y: toolsY + (toolHeight * eyedropperToolAt), width: toolWidth, height: toolHeight,
|
||||||
|
color: eyedropperToolColor,
|
||||||
|
visible: editToolsOn
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(selectTool, {
|
||||||
|
x: 0, y: toolsY + (toolHeight * selectToolAt), width: toolWidth, height: toolHeight,
|
||||||
|
color: selectToolColor,
|
||||||
|
visible: editToolsOn
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
sliderX = swatchesX + swatchesWidth;
|
||||||
|
sliderY = windowDimensions.y - sliderHeight;
|
||||||
|
Overlays.editOverlay(slider, { x: sliderX, y: sliderY, visible: editToolsOn });
|
||||||
|
|
||||||
|
// This is the thumb of our slider
|
||||||
|
thumbY = sliderY + 9;
|
||||||
|
Overlays.editOverlay(thumb, { x: sliderX + thumbX, y: thumbY, visible: editToolsOn });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -520,7 +967,6 @@ function update() {
|
||||||
var newWindowDimensions = Controller.getViewportDimensions();
|
var newWindowDimensions = Controller.getViewportDimensions();
|
||||||
if (newWindowDimensions.x != windowDimensions.x || newWindowDimensions.y != windowDimensions.y) {
|
if (newWindowDimensions.x != windowDimensions.x || newWindowDimensions.y != windowDimensions.y) {
|
||||||
windowDimensions = newWindowDimensions;
|
windowDimensions = newWindowDimensions;
|
||||||
print("window resized...");
|
|
||||||
moveTools();
|
moveTools();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -533,9 +979,18 @@ Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||||
|
|
||||||
function scriptEnding() {
|
function scriptEnding() {
|
||||||
Overlays.deleteOverlay(voxelPreview);
|
Overlays.deleteOverlay(voxelPreview);
|
||||||
|
Overlays.deleteOverlay(linePreviewTop);
|
||||||
|
Overlays.deleteOverlay(linePreviewBottom);
|
||||||
|
Overlays.deleteOverlay(linePreviewLeft);
|
||||||
|
Overlays.deleteOverlay(linePreviewRight);
|
||||||
for (s = 0; s < numColors; s++) {
|
for (s = 0; s < numColors; s++) {
|
||||||
Overlays.deleteOverlay(swatches[s]);
|
Overlays.deleteOverlay(swatches[s]);
|
||||||
}
|
}
|
||||||
|
Overlays.deleteOverlay(addTool);
|
||||||
|
Overlays.deleteOverlay(deleteTool);
|
||||||
|
Overlays.deleteOverlay(recolorTool);
|
||||||
|
Overlays.deleteOverlay(eyedropperTool);
|
||||||
|
Overlays.deleteOverlay(selectTool);
|
||||||
}
|
}
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
#include <VoxelSceneStats.h>
|
#include <VoxelSceneStats.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "ClipboardScriptingInterface.h"
|
||||||
#include "DataServerClient.h"
|
#include "DataServerClient.h"
|
||||||
#include "InterfaceVersion.h"
|
#include "InterfaceVersion.h"
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
|
@ -1699,6 +1700,10 @@ bool Application::sendVoxelsOperation(OctreeElement* element, void* extraData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::exportVoxels() {
|
void Application::exportVoxels() {
|
||||||
|
exportVoxels(_mouseVoxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::exportVoxels(const VoxelDetail& sourceVoxel) {
|
||||||
QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||||
QString suggestedName = desktopLocation.append("/voxels.svo");
|
QString suggestedName = desktopLocation.append("/voxels.svo");
|
||||||
|
|
||||||
|
@ -1706,7 +1711,7 @@ void Application::exportVoxels() {
|
||||||
tr("Sparse Voxel Octree Files (*.svo)"));
|
tr("Sparse Voxel Octree Files (*.svo)"));
|
||||||
QByteArray fileNameAscii = fileNameString.toLocal8Bit();
|
QByteArray fileNameAscii = fileNameString.toLocal8Bit();
|
||||||
const char* fileName = fileNameAscii.data();
|
const char* fileName = fileNameAscii.data();
|
||||||
VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s);
|
VoxelTreeElement* selectedNode = _voxels.getVoxelAt(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
|
||||||
if (selectedNode) {
|
if (selectedNode) {
|
||||||
VoxelTree exportTree;
|
VoxelTree exportTree;
|
||||||
_voxels.copySubTreeIntoNewTree(selectedNode, &exportTree, true);
|
_voxels.copySubTreeIntoNewTree(selectedNode, &exportTree, true);
|
||||||
|
@ -1740,11 +1745,19 @@ void Application::importVoxels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::cutVoxels() {
|
void Application::cutVoxels() {
|
||||||
copyVoxels();
|
cutVoxels(_mouseVoxel);
|
||||||
deleteVoxelUnderCursor();
|
}
|
||||||
|
|
||||||
|
void Application::cutVoxels(const VoxelDetail& sourceVoxel) {
|
||||||
|
copyVoxels(sourceVoxel);
|
||||||
|
deleteVoxelAt(sourceVoxel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::copyVoxels() {
|
void Application::copyVoxels() {
|
||||||
|
copyVoxels(_mouseVoxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::copyVoxels(const VoxelDetail& sourceVoxel) {
|
||||||
// switch to and clear the clipboard first...
|
// switch to and clear the clipboard first...
|
||||||
_sharedVoxelSystem.killLocalVoxels();
|
_sharedVoxelSystem.killLocalVoxels();
|
||||||
if (_sharedVoxelSystem.getTree() != &_clipboard) {
|
if (_sharedVoxelSystem.getTree() != &_clipboard) {
|
||||||
|
@ -1753,7 +1766,7 @@ void Application::copyVoxels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// then copy onto it if there is something to copy
|
// then copy onto it if there is something to copy
|
||||||
VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s);
|
VoxelTreeElement* selectedNode = _voxels.getVoxelAt(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
|
||||||
if (selectedNode) {
|
if (selectedNode) {
|
||||||
_voxels.copySubTreeIntoNewTree(selectedNode, &_sharedVoxelSystem, true);
|
_voxels.copySubTreeIntoNewTree(selectedNode, &_sharedVoxelSystem, true);
|
||||||
}
|
}
|
||||||
|
@ -1775,8 +1788,12 @@ void Application::pasteVoxelsToOctalCode(const unsigned char* octalCodeDestinati
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::pasteVoxels() {
|
void Application::pasteVoxels() {
|
||||||
|
pasteVoxels(_mouseVoxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::pasteVoxels(const VoxelDetail& sourceVoxel) {
|
||||||
unsigned char* calculatedOctCode = NULL;
|
unsigned char* calculatedOctCode = NULL;
|
||||||
VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s);
|
VoxelTreeElement* selectedNode = _voxels.getVoxelAt(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
|
||||||
|
|
||||||
// we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the
|
// we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the
|
||||||
// voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a
|
// voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a
|
||||||
|
@ -1785,7 +1802,7 @@ void Application::pasteVoxels() {
|
||||||
if (selectedNode) {
|
if (selectedNode) {
|
||||||
octalCodeDestination = selectedNode->getOctalCode();
|
octalCodeDestination = selectedNode->getOctalCode();
|
||||||
} else {
|
} else {
|
||||||
octalCodeDestination = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s);
|
octalCodeDestination = calculatedOctCode = pointToVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
pasteVoxelsToOctalCode(octalCodeDestination);
|
pasteVoxelsToOctalCode(octalCodeDestination);
|
||||||
|
@ -1830,12 +1847,14 @@ void Application::nudgeVoxels() {
|
||||||
// calculate nudgeVec
|
// calculate nudgeVec
|
||||||
glm::vec3 nudgeVec(_nudgeGuidePosition.x - _nudgeVoxel.x, _nudgeGuidePosition.y - _nudgeVoxel.y, _nudgeGuidePosition.z - _nudgeVoxel.z);
|
glm::vec3 nudgeVec(_nudgeGuidePosition.x - _nudgeVoxel.x, _nudgeGuidePosition.y - _nudgeVoxel.y, _nudgeGuidePosition.z - _nudgeVoxel.z);
|
||||||
|
|
||||||
VoxelTreeElement* nodeToNudge = _voxels.getVoxelAt(_nudgeVoxel.x, _nudgeVoxel.y, _nudgeVoxel.z, _nudgeVoxel.s);
|
nudgeVoxelsByVector(_nudgeVoxel, nudgeVec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (nodeToNudge) {
|
void Application::nudgeVoxelsByVector(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) {
|
||||||
_voxels.getTree()->nudgeSubTree(nodeToNudge, nudgeVec, _voxelEditSender);
|
VoxelTreeElement* nodeToNudge = _voxels.getVoxelAt(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
|
||||||
_nudgeStarted = false;
|
if (nodeToNudge) {
|
||||||
}
|
_voxels.getTree()->nudgeSubTree(nodeToNudge, nudgeVec, _voxelEditSender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3843,18 +3862,27 @@ bool Application::maybeEditVoxelUnderCursor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::deleteVoxelUnderCursor() {
|
void Application::deleteVoxelUnderCursor() {
|
||||||
if (_mouseVoxel.s != 0) {
|
deleteVoxelAt(_mouseVoxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::deleteVoxels(const VoxelDetail& voxel) {
|
||||||
|
deleteVoxelAt(voxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::deleteVoxelAt(const VoxelDetail& voxel) {
|
||||||
|
if (voxel.s != 0) {
|
||||||
// sending delete to the server is sufficient, server will send new version so we see updates soon enough
|
// sending delete to the server is sufficient, server will send new version so we see updates soon enough
|
||||||
_voxelEditSender.sendVoxelEditMessage(PacketTypeVoxelErase, _mouseVoxel);
|
_voxelEditSender.sendVoxelEditMessage(PacketTypeVoxelErase, voxel);
|
||||||
|
|
||||||
// delete it locally to see the effect immediately (and in case no voxel server is present)
|
// delete it locally to see the effect immediately (and in case no voxel server is present)
|
||||||
_voxels.deleteVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s);
|
_voxels.deleteVoxelAt(voxel.x, voxel.y, voxel.z, voxel.s);
|
||||||
|
|
||||||
}
|
}
|
||||||
// remember the position for drag detection
|
// remember the position for drag detection
|
||||||
_justEditedVoxel = true;
|
_justEditedVoxel = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Application::eyedropperVoxelUnderCursor() {
|
void Application::eyedropperVoxelUnderCursor() {
|
||||||
VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s);
|
VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s);
|
||||||
if (selectedNode && selectedNode->isColored()) {
|
if (selectedNode && selectedNode->isColored()) {
|
||||||
|
@ -4193,6 +4221,10 @@ void Application::loadScript(const QString& fileNameString) {
|
||||||
scriptEngine->registerGlobalObject("Camera", cameraScriptable);
|
scriptEngine->registerGlobalObject("Camera", cameraScriptable);
|
||||||
connect(scriptEngine, SIGNAL(finished(const QString&)), cameraScriptable, SLOT(deleteLater()));
|
connect(scriptEngine, SIGNAL(finished(const QString&)), cameraScriptable, SLOT(deleteLater()));
|
||||||
|
|
||||||
|
ClipboardScriptingInterface* clipboardScriptable = new ClipboardScriptingInterface();
|
||||||
|
scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable);
|
||||||
|
connect(scriptEngine, SIGNAL(finished(const QString&)), clipboardScriptable, SLOT(deleteLater()));
|
||||||
|
|
||||||
scriptEngine->registerGlobalObject("Overlays", &_overlays);
|
scriptEngine->registerGlobalObject("Overlays", &_overlays);
|
||||||
|
|
||||||
QThread* workerThread = new QThread(this);
|
QThread* workerThread = new QThread(this);
|
||||||
|
|
|
@ -230,13 +230,20 @@ public slots:
|
||||||
void nodeKilled(SharedNodePointer node);
|
void nodeKilled(SharedNodePointer node);
|
||||||
void packetSent(quint64 length);
|
void packetSent(quint64 length);
|
||||||
|
|
||||||
void exportVoxels();
|
|
||||||
void importVoxels();
|
|
||||||
void cutVoxels();
|
void cutVoxels();
|
||||||
void copyVoxels();
|
void copyVoxels();
|
||||||
void pasteVoxels();
|
void pasteVoxels();
|
||||||
void nudgeVoxels();
|
|
||||||
void deleteVoxels();
|
void deleteVoxels();
|
||||||
|
void exportVoxels();
|
||||||
|
void importVoxels();
|
||||||
|
void nudgeVoxels();
|
||||||
|
|
||||||
|
void cutVoxels(const VoxelDetail& sourceVoxel);
|
||||||
|
void copyVoxels(const VoxelDetail& sourceVoxel);
|
||||||
|
void pasteVoxels(const VoxelDetail& sourceVoxel);
|
||||||
|
void deleteVoxels(const VoxelDetail& sourceVoxel);
|
||||||
|
void exportVoxels(const VoxelDetail& sourceVoxel);
|
||||||
|
void nudgeVoxelsByVector(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec);
|
||||||
|
|
||||||
void setRenderVoxels(bool renderVoxels);
|
void setRenderVoxels(bool renderVoxels);
|
||||||
void doKillLocalVoxels();
|
void doKillLocalVoxels();
|
||||||
|
@ -331,6 +338,7 @@ private:
|
||||||
|
|
||||||
bool maybeEditVoxelUnderCursor();
|
bool maybeEditVoxelUnderCursor();
|
||||||
void deleteVoxelUnderCursor();
|
void deleteVoxelUnderCursor();
|
||||||
|
void deleteVoxelAt(const VoxelDetail& voxel);
|
||||||
void eyedropperVoxelUnderCursor();
|
void eyedropperVoxelUnderCursor();
|
||||||
|
|
||||||
void setMenuShortcutsEnabled(bool enabled);
|
void setMenuShortcutsEnabled(bool enabled);
|
||||||
|
|
94
interface/src/ClipboardScriptingInterface.cpp
Normal file
94
interface/src/ClipboardScriptingInterface.cpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
//
|
||||||
|
// ClipboardScriptingInterface.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "ClipboardScriptingInterface.h"
|
||||||
|
|
||||||
|
ClipboardScriptingInterface::ClipboardScriptingInterface() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::cutVoxel(const VoxelDetail& sourceVoxel) {
|
||||||
|
cutVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::cutVoxel(float x, float y, float z, float s) {
|
||||||
|
VoxelDetail sourceVoxel = { x / (float)TREE_SCALE,
|
||||||
|
y / (float)TREE_SCALE,
|
||||||
|
z / (float)TREE_SCALE,
|
||||||
|
s / (float)TREE_SCALE };
|
||||||
|
Application::getInstance()->cutVoxels(sourceVoxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::copyVoxel(const VoxelDetail& sourceVoxel) {
|
||||||
|
copyVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::copyVoxel(float x, float y, float z, float s) {
|
||||||
|
VoxelDetail sourceVoxel = { x / (float)TREE_SCALE,
|
||||||
|
y / (float)TREE_SCALE,
|
||||||
|
z / (float)TREE_SCALE,
|
||||||
|
s / (float)TREE_SCALE };
|
||||||
|
Application::getInstance()->copyVoxels(sourceVoxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::pasteVoxel(const VoxelDetail& destinationVoxel) {
|
||||||
|
pasteVoxel(destinationVoxel.x, destinationVoxel.y, destinationVoxel.z, destinationVoxel.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::pasteVoxel(float x, float y, float z, float s) {
|
||||||
|
VoxelDetail sourceVoxel = { x / (float)TREE_SCALE,
|
||||||
|
y / (float)TREE_SCALE,
|
||||||
|
z / (float)TREE_SCALE,
|
||||||
|
s / (float)TREE_SCALE };
|
||||||
|
|
||||||
|
Application::getInstance()->pasteVoxels(sourceVoxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::deleteVoxel(const VoxelDetail& sourceVoxel) {
|
||||||
|
deleteVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::deleteVoxel(float x, float y, float z, float s) {
|
||||||
|
VoxelDetail sourceVoxel = { x / (float)TREE_SCALE,
|
||||||
|
y / (float)TREE_SCALE,
|
||||||
|
z / (float)TREE_SCALE,
|
||||||
|
s / (float)TREE_SCALE };
|
||||||
|
Application::getInstance()->deleteVoxels(sourceVoxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::exportVoxel(const VoxelDetail& sourceVoxel) {
|
||||||
|
exportVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::exportVoxel(float x, float y, float z, float s) {
|
||||||
|
VoxelDetail sourceVoxel = { x / (float)TREE_SCALE,
|
||||||
|
y / (float)TREE_SCALE,
|
||||||
|
z / (float)TREE_SCALE,
|
||||||
|
s / (float)TREE_SCALE };
|
||||||
|
|
||||||
|
// TODO: should we be calling invokeMethod() in all these cases?
|
||||||
|
Application::getInstance()->exportVoxels(sourceVoxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::importVoxels() {
|
||||||
|
QMetaObject::invokeMethod(Application::getInstance(), "importVoxels");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) {
|
||||||
|
nudgeVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s, nudgeVec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardScriptingInterface::nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec) {
|
||||||
|
glm::vec3 nudgeVecInTreeSpace = nudgeVec / (float)TREE_SCALE;
|
||||||
|
VoxelDetail sourceVoxel = { x / (float)TREE_SCALE,
|
||||||
|
y / (float)TREE_SCALE,
|
||||||
|
z / (float)TREE_SCALE,
|
||||||
|
s / (float)TREE_SCALE };
|
||||||
|
|
||||||
|
Application::getInstance()->nudgeVoxelsByVector(sourceVoxel, nudgeVecInTreeSpace);
|
||||||
|
}
|
||||||
|
|
43
interface/src/ClipboardScriptingInterface.h
Normal file
43
interface/src/ClipboardScriptingInterface.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
//
|
||||||
|
// ClipboardScriptingInterface.h
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Scriptable interface for the Application clipboard
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __interface__Clipboard__
|
||||||
|
#define __interface__Clipboard__
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <VoxelDetail.h>
|
||||||
|
|
||||||
|
class ClipboardScriptingInterface : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ClipboardScriptingInterface();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void cutVoxel(const VoxelDetail& sourceVoxel);
|
||||||
|
void cutVoxel(float x, float y, float z, float s);
|
||||||
|
|
||||||
|
void copyVoxel(const VoxelDetail& sourceVoxel);
|
||||||
|
void copyVoxel(float x, float y, float z, float s);
|
||||||
|
|
||||||
|
void pasteVoxel(const VoxelDetail& destinationVoxel);
|
||||||
|
void pasteVoxel(float x, float y, float z, float s);
|
||||||
|
|
||||||
|
void deleteVoxel(const VoxelDetail& sourceVoxel);
|
||||||
|
void deleteVoxel(float x, float y, float z, float s);
|
||||||
|
|
||||||
|
void exportVoxel(const VoxelDetail& sourceVoxel);
|
||||||
|
void exportVoxel(float x, float y, float z, float s);
|
||||||
|
|
||||||
|
void importVoxels();
|
||||||
|
|
||||||
|
void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec);
|
||||||
|
void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __interface__Clipboard__
|
|
@ -104,6 +104,16 @@ KeyEvent::KeyEvent(const QKeyEvent& event) {
|
||||||
text = "HELP";
|
text = "HELP";
|
||||||
} else if (key == Qt::Key_CapsLock) {
|
} else if (key == Qt::Key_CapsLock) {
|
||||||
text = "CAPS LOCK";
|
text = "CAPS LOCK";
|
||||||
|
} else if (key >= Qt::Key_A && key <= Qt::Key_Z && (isMeta || isControl || isAlt)) {
|
||||||
|
// this little bit of hackery will fix the text character keys like a-z in cases of control/alt/meta where
|
||||||
|
// qt doesn't always give you the key characters and will sometimes give you crazy non-printable characters
|
||||||
|
const int lowerCaseAdjust = 0x20;
|
||||||
|
QString unicode;
|
||||||
|
if (isShifted) {
|
||||||
|
text = QString(QChar(key));
|
||||||
|
} else {
|
||||||
|
text = QString(QChar(key + lowerCaseAdjust));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
/// PacketTypeVoxelSet, PacketTypeVoxelSetDestructive, or PacketTypeVoxelErase. The buffer is returned to caller becomes
|
/// PacketTypeVoxelSet, PacketTypeVoxelSetDestructive, or PacketTypeVoxelErase. The buffer is returned to caller becomes
|
||||||
/// responsibility of caller and MUST be deleted by caller.
|
/// responsibility of caller and MUST be deleted by caller.
|
||||||
bool createVoxelEditMessage(PacketType command, short int sequence,
|
bool createVoxelEditMessage(PacketType command, short int sequence,
|
||||||
int voxelCount, VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut) {
|
int voxelCount, const VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut) {
|
||||||
|
|
||||||
bool success = true; // assume the best
|
bool success = true; // assume the best
|
||||||
int messageSize = MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE; // just a guess for now
|
int messageSize = MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE; // just a guess for now
|
||||||
|
@ -102,7 +102,7 @@ bool encodeVoxelEditMessageDetails(PacketType, int voxelCount, VoxelDetail* voxe
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelEditPacketSender::sendVoxelEditMessage(PacketType type, VoxelDetail& detail) {
|
void VoxelEditPacketSender::sendVoxelEditMessage(PacketType type, const VoxelDetail& detail) {
|
||||||
// allows app to disable sending if for example voxels have been disabled
|
// allows app to disable sending if for example voxels have been disabled
|
||||||
if (!_shouldSend) {
|
if (!_shouldSend) {
|
||||||
return; // bail early
|
return; // bail early
|
||||||
|
|
|
@ -19,7 +19,7 @@ class VoxelEditPacketSender : public OctreeEditPacketSender {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
/// Send voxel edit message immediately
|
/// Send voxel edit message immediately
|
||||||
void sendVoxelEditMessage(PacketType type, VoxelDetail& detail);
|
void sendVoxelEditMessage(PacketType type, const VoxelDetail& detail);
|
||||||
|
|
||||||
/// Queues a single voxel edit message. Will potentially send a pending multi-command packet. Determines which voxel-server
|
/// Queues a single voxel edit message. Will potentially send a pending multi-command packet. Determines which voxel-server
|
||||||
/// node or nodes the packet should be sent to. Can be called even before voxel servers are known, in which case up to
|
/// node or nodes the packet should be sent to. Can be called even before voxel servers are known, in which case up to
|
||||||
|
|
Loading…
Reference in a new issue