improved mouse down / move detection

This commit is contained in:
Stewart Allen 2020-03-19 18:34:03 -04:00
commit 3d59400c0b
2 changed files with 230 additions and 121 deletions

View file

@ -27,17 +27,22 @@ let gs_meta = exports;
THREE.Material.prototype.motoSetup = function() { THREE.Material.prototype.motoSetup = function() {
this.fog = false; this.fog = false;
this.transparent = false;
let hidden = this.clone(); let hidden = this.clone();
this.m_hide = hidden; hidden.visible = false;
this.m_show = this;
hidden.m_hide = hidden; hidden.m_hide = hidden;
hidden.m_show = this; hidden.m_show = this;
hidden.visible = false;
this.m_hide = hidden;
this.m_show = this;
return this; return this;
}; };
THREE.Face3.prototype.mVisible = function(show) { THREE.Face3.prototype.mVisible = function(show) {
this.onface.cube.showHideFace(this.materialIndex, show); this.onface.cube.showFace(this.materialIndex, show);
}; };
(function() { (function() {
@ -136,7 +141,7 @@ THREE.Face3.prototype.mVisible = function(show) {
}, },
// --------------- // ---------------
boxMaterial = new THREE.MeshPhongMaterial({ boxMaterial = new THREE.MeshPhongMaterial({
side:THREE.DoubleSide, side: THREE.DoubleSide,
color: 0x00ff00, color: 0x00ff00,
specular: 0x111111, specular: 0x111111,
transparent: false, transparent: false,
@ -236,12 +241,17 @@ THREE.Face3.prototype.mVisible = function(show) {
matrix = {}, matrix = {},
selected = [], // cubes selected = [], // cubes
selectable = [], // meshes selectable = [], // meshes
selectedBounds = new Bounds(); selectedBounds = new Bounds(),
cubeID = 0;
/** ****************************************************************** /** ******************************************************************
* LETS_GET_THIS_PARTY_STARTED() * LETS_GET_THIS_PARTY_STARTED()
******************************************************************* */ ******************************************************************* */
function nextID() {
return ++cubeID;
}
function metaInit() { function metaInit() {
SPACE.showSkyGrid(false); SPACE.showSkyGrid(false);
SPACE.setSkyColor(0xf8f8f8); SPACE.setSkyColor(0xf8f8f8);
@ -273,61 +283,62 @@ THREE.Face3.prototype.mVisible = function(show) {
SPACE.mouse.downSelect(function(selection, event) { SPACE.mouse.downSelect(function(selection, event) {
dragCopy = selection && event.metaKey; dragCopy = selection && event.metaKey;
return selectedFace ? [ selectedFace.cube.boxM ] : null; // let mdr = selectedFace ? [ selectedFace.cube.boxy ] : null;
let mdr = selectedFace ? selectedFace.cube.boxy.children : null;
return mdr;
}); });
SPACE.mouse.upSelect(function(selection, event) { SPACE.mouse.upSelect(function(selection, event) {
if (event) { if (!event) {
if (selection && selection.faceIndex) { return selectable;
let face = selection.face.onface, }
cube = face.cube; if (!(selection && selection.faceIndex >= 0)) {
switch (editMode) { return;
case EDIT.MARK: }
if (!cube.isSynthetic()) markFace(face); let face = selection.face.onface,
scheduleUpdateFaces(cube, face); cube = face.cube;
break; switch (editMode) {
case EDIT.SELECT: case EDIT.MARK:
let shift = event.shiftKey, if (!cube.isSynthetic()) markFace(face);
meta = event.metaKey, scheduleUpdateFaces(cube, face);
isSelected = cube.isSelected(); break;
if (shift) { case EDIT.SELECT:
selectRegion(face, true, meta ? SELECT.REGION : selectMode); let shift = event.shiftKey,
} else if (!isSelected) { meta = event.metaKey,
clearSelections(); isSelected = cube.isSelected();
selectRegion(face, true, meta ? SELECT.REGION : selectMode); if (shift) {
} selectRegion(face, true, meta ? SELECT.REGION : selectMode);
if (cube.isSelected()) { } else if (!isSelected) {
selectedFace = face; clearSelections();
scheduleUpdateFaces(cube, face); selectRegion(face, true, meta ? SELECT.REGION : selectMode);
} }
let s = face.set, rot = { x: s.tx, y: s.ty, z: s.tz }; if (cube.isSelected()) {
SPACE.alignTracking(selection.point, rot, {x:-ABS(s.ox), y:-ABS(s.oz), z:-ABS(s.oy)}); selectedFace = face;
break; scheduleUpdateFaces(cube, face);
case EDIT.ADD: }
clearSelections(); let s = face.set, rot = { x: s.tx, y: s.ty, z: s.tz };
cube.newAdjacent(face).add(); SPACE.alignTracking(selection.point, rot, {x:-ABS(s.ox), y:-ABS(s.oz), z:-ABS(s.oy)});
break; break;
case EDIT.CLONE: case EDIT.ADD:
clearSelections(); clearSelections();
cube.newAdjacent(face).add().cloneFrom(cube); cube.newAdjacent(face).add();
break; break;
case EDIT.DELETE: case EDIT.CLONE:
if (cube.isSynthetic()) return; clearSelections();
clearSelections(); cube.newAdjacent(face).add().cloneFrom(cube);
removeCube(cube); break;
break; case EDIT.DELETE:
} if (cube.isSynthetic()) return;
} else { clearSelections();
clearSelections(); removeCube(cube);
} break;
} }
return selectable;
}); });
SPACE.mouse.onDrag(function(delta, offset, end) { SPACE.mouse.onDrag(function(delta, offset, end) {
if (offset) moveSelection(offset); if (offset) moveSelection(offset);
if (end) moveComplete(); if (end) moveComplete();
return selectedFace.cube.boxM; return selectedFace.cube.boxy;
}); });
SPACE.mouse.onHover(function(selection, event) { SPACE.mouse.onHover(function(selection, event) {
@ -421,12 +432,11 @@ THREE.Face3.prototype.mVisible = function(show) {
UC.newTableRow([ UC.newTableRow([
[ [
UC.newButton('x-', function() { rotateSelection(-1, 0, 0) }), UC.newButton('x-', function() { rotateSelection(-1, 0, 0) }),
UC.newButton('x+', function() { rotateSelection( 1, 0, 0) })
],[
UC.newButton('y-', function() { rotateSelection( 0,-1, 0) }), UC.newButton('y-', function() { rotateSelection( 0,-1, 0) }),
UC.newButton('y+', function() { rotateSelection( 0, 1, 0) }) UC.newButton('z-', function() { rotateSelection( 0, 0,-1) })
],[ ],[
UC.newButton('z-', function() { rotateSelection( 0, 0,-1) }), UC.newButton('x+', function() { rotateSelection( 1, 0, 0) }),
UC.newButton('y+', function() { rotateSelection( 0, 1, 0) }),
UC.newButton('z+', function() { rotateSelection( 0, 0, 1) }) UC.newButton('z+', function() { rotateSelection( 0, 0, 1) })
] ]
]); ]);
@ -434,12 +444,11 @@ THREE.Face3.prototype.mVisible = function(show) {
UC.newTableRow([ UC.newTableRow([
[ [
UC.newButton('x-', function() { updateAnchorSelection(-1, 0, 0) }), UC.newButton('x-', function() { updateAnchorSelection(-1, 0, 0) }),
UC.newButton('x+', function() { updateAnchorSelection( 1, 0, 0) })
],[
UC.newButton('y-', function() { updateAnchorSelection( 0,-1, 0) }), UC.newButton('y-', function() { updateAnchorSelection( 0,-1, 0) }),
UC.newButton('y+', function() { updateAnchorSelection( 0, 1, 0) }) UC.newButton('z-', function() { updateAnchorSelection( 0, 0,-1) })
],[ ],[
UC.newButton('z-', function() { updateAnchorSelection( 0, 0,-1) }), UC.newButton('x+', function() { updateAnchorSelection( 1, 0, 0) }),
UC.newButton('y+', function() { updateAnchorSelection( 0, 1, 0) }),
UC.newButton('z+', function() { updateAnchorSelection( 0, 0, 1) }) UC.newButton('z+', function() { updateAnchorSelection( 0, 0, 1) })
],[ ],[
UC.newButton('center', function() { setAnchorSelection(0,0,0) }) UC.newButton('center', function() { setAnchorSelection(0,0,0) })
@ -455,6 +464,9 @@ THREE.Face3.prototype.mVisible = function(show) {
] ]
]); ]);
UC.newGroup('options');
UI.invert = UC.newBoolean('invert zoom', setZoom);
UC.newGroup('space', control); UC.newGroup('space', control);
UI.name = UC.newInput('name', {size:10}); UI.name = UC.newInput('name', {size:10});
UI.units = UC.newInput('units'); UI.units = UC.newInput('units');
@ -521,6 +533,7 @@ THREE.Face3.prototype.mVisible = function(show) {
/** and a few more settings before we're done */ /** and a few more settings before we're done */
setGridSize(gridSize); setGridSize(gridSize);
setZoom(SDB['meta-zoom'] === 'true');
setSelectMode(SDB['meta-smode'] || SELECT.REGION,true); setSelectMode(SDB['meta-smode'] || SELECT.REGION,true);
setMarkMode(SDB['meta-mmode'] || MARK.EMIT,true); setMarkMode(SDB['meta-mmode'] || MARK.EMIT,true);
setEditMode(EDIT.SELECT); setEditMode(EDIT.SELECT);
@ -533,6 +546,13 @@ THREE.Face3.prototype.mVisible = function(show) {
ctrlRight.style.display = 'block'; ctrlRight.style.display = 'block';
} }
function setZoom(value) {
if (value !== undefined) {
UI.invert.checked = value;
}
SPACE.view.setZoom(SDB['meta-zoom'] = UI.invert.checked);
}
function inputHasFocus() { function inputHasFocus() {
return DOC.activeElement && (DOC.activeElement != DOC.body); return DOC.activeElement && (DOC.activeElement != DOC.body);
} }
@ -753,8 +773,6 @@ THREE.Face3.prototype.mVisible = function(show) {
} }
setSelectMode(newSelect,true); setSelectMode(newSelect,true);
setMarkMode(newMark,true); setMarkMode(newMark,true);
// updateHighlights(selectModeButtons,editMode === EDIT.SELECT ? selectMode : null);
// updateHighlights(markTypeButtons,editMode === EDIT.MARK ? markMode : null);
scheduleUpdateFaces(); scheduleUpdateFaces();
hoverMaterial.color.setHex(color); hoverMaterial.color.setHex(color);
SPACE.update(); SPACE.update();
@ -905,28 +923,14 @@ THREE.Face3.prototype.mVisible = function(show) {
}; };
function Cube(x, y, z, synth) { function Cube(x, y, z, synth) {
this.id = nextID();
this.pos = {x:x, y:y, z:z}; this.pos = {x:x, y:y, z:z};
this.key = [x,y,z].join(','); this.key = [x,y,z].join(',');
this.synth = synth; this.synth = synth;
this.selected = false; this.selected = false;
this.materials = [
boxMaterial, boxMaterial, boxMaterial, boxMaterial, boxMaterial, boxMaterial
];
this.box = new THREE.BoxGeometry(1,1,1,1,1,1);
this.boxM = new THREE.Mesh(this.box, this.materials);
this.boxM.position.set(x, y, z);
this.boxM.cube = this;
this.mesh = null;
this.meshRotate = null;
this.group = new THREE.Object3D();
this.group.cube = this;
this.group.add(this.boxM);
this.faces = { this.faces = {
rl: this.makeFace('rl'), rl: this.makeFace('rl'),
lr: this.makeFace('lr'), lr: this.makeFace('lr'),
@ -936,19 +940,109 @@ THREE.Face3.prototype.mVisible = function(show) {
bt: this.makeFace('bt') bt: this.makeFace('bt')
}; };
let b = this.box, f, key; this.sides = [
for (let i=0; i<b.faces.length; i++) { this.side(0, this.faces.rl),
f = b.faces[i]; this.side(1, this.faces.lr),
switch (f.materialIndex) { this.side(2, this.faces.bf),
case 0: key = "rl"; break; this.side(3, this.faces.fb),
case 1: key = "lr"; break; this.side(4, this.faces.tb),
case 2: key = "bf"; break; this.side(5, this.faces.bt)
case 3: key = "fb"; break; ];
case 4: key = "tb"; break;
case 5: key = "bt"; break; this.boxy = new THREE.Object3D();
} this.boxy.add(this.sides[0]);
f.onface = this.faces[key]; this.boxy.add(this.sides[1]);
this.boxy.add(this.sides[2]);
this.boxy.add(this.sides[3]);
this.boxy.add(this.sides[4]);
this.boxy.add(this.sides[5]);
this.boxy.position.set(x, y, z);
this.boxy.cube = this;
this.mesh = null;
this.meshRotate = null;
this.group = new THREE.Object3D();
this.group.cube = this;
this.group.add(this.boxy);
}
CP.side = function(order,face) {
let P = 0.5;
let N = -0.5;
let geo = new THREE.Geometry();
switch (order) {
case 0:
geo.vertices.push(
new THREE.Vector3(P,P,N),
new THREE.Vector3(P,P,P),
new THREE.Vector3(P,N,P),
new THREE.Vector3(P,P,N),
new THREE.Vector3(P,N,N),
new THREE.Vector3(P,N,P)
);
break;
case 1:
geo.vertices.push(
new THREE.Vector3(N,P,N),
new THREE.Vector3(N,P,P),
new THREE.Vector3(N,N,P),
new THREE.Vector3(N,P,N),
new THREE.Vector3(N,N,N),
new THREE.Vector3(N,N,P)
);
break;
case 2:
geo.vertices.push(
new THREE.Vector3(P,P,N),
new THREE.Vector3(P,P,P),
new THREE.Vector3(N,P,P),
new THREE.Vector3(P,P,N),
new THREE.Vector3(N,P,N),
new THREE.Vector3(N,P,P)
);
break;
case 3:
geo.vertices.push(
new THREE.Vector3(P,N,N),
new THREE.Vector3(P,N,P),
new THREE.Vector3(N,N,P),
new THREE.Vector3(P,N,N),
new THREE.Vector3(N,N,N),
new THREE.Vector3(N,N,P)
);
break;
case 4:
geo.vertices.push(
new THREE.Vector3(P,N,P),
new THREE.Vector3(P,P,P),
new THREE.Vector3(N,P,P),
new THREE.Vector3(P,N,P),
new THREE.Vector3(N,N,P),
new THREE.Vector3(N,P,P)
);
break;
case 5:
geo.vertices.push(
new THREE.Vector3(P,N,N),
new THREE.Vector3(P,P,N),
new THREE.Vector3(N,P,N),
new THREE.Vector3(P,N,N),
new THREE.Vector3(N,N,N),
new THREE.Vector3(N,P,N)
);
break;
} }
let f1 = new THREE.Face3(0,1,2);
let f2 = new THREE.Face3(3,4,5);
f1.onface = face;
f2.onface = face;
geo.faces.push(f1);
geo.faces.push(f2);
geo.computeFaceNormals();
geo.computeVertexNormals();
let mesh = new THREE.Mesh(geo, boxMaterial);
return mesh;
} }
CP.copyMesh = function(cube) { CP.copyMesh = function(cube) {
@ -968,10 +1062,12 @@ THREE.Face3.prototype.mVisible = function(show) {
}; };
CP.setMesh = function(mesh) { CP.setMesh = function(mesh) {
if (this.mesh) this.group.remove(this.mesh); if (this.mesh) {
this.group.remove(this.mesh);
}
if (mesh) { if (mesh) {
this.group.add(mesh); this.group.add(mesh);
mesh.position.copy(this.boxM.position); mesh.position.copy(this.boxy.position);
} }
this.mesh = mesh; this.mesh = mesh;
this.meshRotate = {f:2, r:3, mx:0, my:0, mz:0, ax:0, ay:0, az:0}; this.meshRotate = {f:2, r:3, mx:0, my:0, mz:0, ax:0, ay:0, az:0};
@ -1063,11 +1159,15 @@ THREE.Face3.prototype.mVisible = function(show) {
}; };
CP.setFaceMaterial = function(index, mat) { CP.setFaceMaterial = function(index, mat) {
this.materials[index] = mat; this.sides[index].material = mat;
}; };
CP.showHideFace = function(index, show) { CP.showFace = function(index, show) {
this.materials[index].visible = show; if (show) {
this.sides[index].material = this.sides[index].material.m_show;
} else {
this.sides[index].material = this.sides[index].material.m_hide;
}
}; };
CP.canMoveTo = function(delta) { CP.canMoveTo = function(delta) {
@ -1094,7 +1194,7 @@ THREE.Face3.prototype.mVisible = function(show) {
this.group.position.set(0,0,0); this.group.position.set(0,0,0);
return this.cloneTo(npos.x, npos.y, npos.z); return this.cloneTo(npos.x, npos.y, npos.z);
} else { } else {
this.boxM.position.add(delta); this.boxy.position.add(delta);
if (this.mesh) this.mesh.position.add(delta); if (this.mesh) this.mesh.position.add(delta);
this.group.position.set(0,0,0); this.group.position.set(0,0,0);
if (!delete matrix[this.key]) throw "missing cube @ "+this.key; if (!delete matrix[this.key]) throw "missing cube @ "+this.key;
@ -1184,8 +1284,9 @@ THREE.Face3.prototype.mVisible = function(show) {
// todo: make more efficient by marking cube changes and only updating // todo: make more efficient by marking cube changes and only updating
// todo: if this cube or one if it's neighbors has been changed // todo: if this cube or one if it's neighbors has been changed
CP.updateFaces = function() { CP.updateFaces = function() {
if (this.mesh) { let mesh = this.mesh;
this.mesh.material = this.selected ? boxMaterialSelected : boxMaterial; if (mesh) {
mesh.material = this.selected ? boxMaterialSelected : boxMaterial;
} }
for (let k in this.faces) { for (let k in this.faces) {
if (!HAS(this.faces, k)) continue; if (!HAS(this.faces, k)) continue;
@ -1217,9 +1318,10 @@ THREE.Face3.prototype.mVisible = function(show) {
if (sel) { if (sel) {
mat = faceMaterialSelected; mat = faceMaterialSelected;
} }
// mark inside if adjacent to cube that has no mesh
face.inside = adj && !adjm; face.inside = adj && !adjm;
cube.setFaceMaterial(face.set.mi, mat); cube.setFaceMaterial(face.set.mi, mat);
cube.showHideFace(face.set.mi, mark || sel || !(face.inside || this.mesh)); cube.showFace(face.set.mi, !mesh && (mark || sel || !face.inside));
} }
SPACE.update(); SPACE.update();
}; };
@ -1308,7 +1410,7 @@ THREE.Face3.prototype.mVisible = function(show) {
if (!matrix[key]) { if (!matrix[key]) {
matrix[key] = cube; matrix[key] = cube;
SPACE.platform.add(cube.group); SPACE.platform.add(cube.group);
selectable.push(cube.boxM); selectable.push(cube.boxy);
scheduleUpdateFaces(); scheduleUpdateFaces();
return cube; return cube;
} }
@ -1321,7 +1423,7 @@ THREE.Face3.prototype.mVisible = function(show) {
delete matrix[key]; delete matrix[key];
SPACE.platform.remove(cube.group); SPACE.platform.remove(cube.group);
selected.remove(cube); selected.remove(cube);
selectable.remove(cube.boxM); selectable.remove(cube.boxy);
} }
if (!nosynth) removeSynthetic(); if (!nosynth) removeSynthetic();
scheduleUpdateFaces(); scheduleUpdateFaces();
@ -1715,7 +1817,9 @@ THREE.Face3.prototype.mVisible = function(show) {
function updateFaces() { function updateFaces() {
let i = 0, k; let i = 0, k;
if (updateSynthetic && enablePost) { if (updateSynthetic && enablePost) {
while (i < selectable.length) selectable[i++].cube.addSynthetic(); while (i < selectable.length) {
selectable[i++].cube.addSynthetic();
}
} }
for (k in matrix) { for (k in matrix) {
if (HAS(matrix,k)) { if (HAS(matrix,k)) {

View file

@ -19,6 +19,7 @@ var MOTO = window.moto = window.moto || {};
gridZOff = 0, gridZOff = 0,
platformZOff = 0, platformZOff = 0,
perspective = 35, perspective = 35,
refreshTimeout = null,
refreshRequested = false, refreshRequested = false,
selectRecurse = false, selectRecurse = false,
defaultKeys = true, defaultKeys = true,
@ -33,7 +34,7 @@ var MOTO = window.moto = window.moto || {};
trackcam = addLight(0, 0, 0, lightIntensity/3), trackcam = addLight(0, 0, 0, lightIntensity/3),
trackDelta = {x:0, y:0, z:0}, trackDelta = {x:0, y:0, z:0},
mouse = {x: 0, y: 0}, mouse = {x: 0, y: 0},
mouseMoved = false, mouseStart = null,
mouseDragPoint = null, mouseDragPoint = null,
mouseDragStart = null, mouseDragStart = null,
mouseDownSelect, mouseDownSelect,
@ -314,7 +315,8 @@ var MOTO = window.moto = window.moto || {};
function requestRefresh(timeout) { function requestRefresh(timeout) {
if (refreshRequested === false) { if (refreshRequested === false) {
refreshRequested = true; refreshRequested = true;
setTimeout(refresh, timeout || 10); clearTimeout(refreshTimeout);
refreshTimeout = setTimeout(refresh, timeout || 10);
} }
} }
@ -452,7 +454,9 @@ var MOTO = window.moto = window.moto || {};
} else { } else {
viewControl.enabled = false; viewControl.enabled = false;
} }
mouseMoved = false; mouseStart = {
x: (event.clientX / width()) * 2 - 1,
y: -(event.clientY / height()) * 2 + 1};
} }
function onMouseUp(event) { function onMouseUp(event) {
@ -460,26 +464,28 @@ var MOTO = window.moto = window.moto || {};
viewControl.enabled = true; viewControl.enabled = true;
viewControl.onMouseUp(event); viewControl.onMouseUp(event);
} }
if (!mouseMoved) { let mouseEnd = {
x: (event.clientX / width()) * 2 - 1,
y: -(event.clientY / height()) * 2 + 1};
// only fire on mouse move between mouseStart (down) and up
if (mouseEnd.x - mouseStart.x + mouseEnd.y - mouseStart.y === 0) {
event.preventDefault(); event.preventDefault();
if (!mouseMoved) { let refresh = false,
let refresh = false, selection = null;
selection = null; if (mouseUpSelect) selection = mouseUpSelect();
if (mouseUpSelect) selection = mouseUpSelect(); if (selection && selection.length > 0) {
if (selection && selection.length > 0) { let int = intersect(selection, selectRecurse);
let int = intersect(selection, selectRecurse); if (int.length > 0) {
if (int.length > 0) { mouseUpSelect(int[0], event);
mouseUpSelect(int[0], event); refresh = true;
refresh = true; } else {
} else { mouseUpSelect(null, event);
mouseUpSelect(null, event);
}
} }
if (!refresh && platformClickAt) {
platformClick(platformClickAt);
}
if (refresh) requestRefresh();
} }
if (!refresh && platformClickAt) {
platformClick(platformClickAt);
}
if (refresh) requestRefresh();
} else if (mouseDrag && mouseDragStart) { } else if (mouseDrag && mouseDragStart) {
mouseDrag(null,null,true); mouseDrag(null,null,true);
} }
@ -517,7 +523,6 @@ var MOTO = window.moto = window.moto || {};
requestRefresh(); requestRefresh();
} }
} }
mouseMoved = true;
mouse = { mouse = {
x: (event.clientX / width()) * 2 - 1, x: (event.clientX / width()) * 2 - 1,
y: -(event.clientY / height()) * 2 + 1}; y: -(event.clientY / height()) * 2 + 1};