mirror of
https://github.com/JannisX11/blockbench.git
synced 2024-11-27 04:21:46 +08:00
Reference image blueprint support
This commit is contained in:
parent
e4aeff55c2
commit
d0ffd15bac
@ -382,7 +382,7 @@ function unselectInterface(event) {
|
||||
stopRenameOutliner()
|
||||
}
|
||||
if (ReferenceImageMode.active &&
|
||||
![event.target, event.target.parentNode, event.target.parentNode?.parentNode, event.target.parentNode?.parentNode?.parentNode, event.target.parentNode?.parentNode?.parentNode?.parentNode].find(n => n && n.classList.contains('reference_image')) &&
|
||||
![event.target, event.target.parentNode, event.target.parentNode?.parentNode, event.target.parentNode?.parentNode?.parentNode, event.target.parentNode?.parentNode?.parentNode?.parentNode].find(n => n?.classList?.contains('reference_image')) &&
|
||||
!ReferenceImageMode.toolbar.node.contains(event.target) &&
|
||||
!Dialog.open &&
|
||||
!open_menu
|
||||
@ -555,6 +555,7 @@ function resizeWindow(event) {
|
||||
prev.resize()
|
||||
}
|
||||
})
|
||||
ReferenceImage.active.forEach(ref => ref.updateTransform());
|
||||
Outliner.elements.forEach(element => {
|
||||
if (element.preview_controller.updateWindowSize) {
|
||||
element.preview_controller.updateWindowSize(element);
|
||||
|
@ -72,9 +72,11 @@ THREE.OrbitControls = function ( object, preview ) {
|
||||
};
|
||||
|
||||
this.updateSceneScale = function() {
|
||||
if (scope.preview.isOrtho === true && scope.preview.camOrtho.axis) {
|
||||
scope.preview.updateBackground()
|
||||
}
|
||||
ReferenceImage.active.forEach(ref => {
|
||||
if (ref.layer == 'blueprint' && ref.attached_side == scope.preview.angle) {
|
||||
ref.updateTransform()
|
||||
}
|
||||
})
|
||||
if (Transformer.visible) Transformer.update()
|
||||
Blockbench.dispatchEvent('update_camera_position', {preview: scope.preview})
|
||||
};
|
||||
|
@ -573,7 +573,7 @@ class Preview {
|
||||
}
|
||||
|
||||
Transformer.update();
|
||||
//this.loadBackground()
|
||||
ReferenceImage.updateAll();
|
||||
return this;
|
||||
}
|
||||
setDefaultAnglePreset(preset) {
|
||||
@ -1558,7 +1558,7 @@ function openQuadView() {
|
||||
|
||||
quad_previews.enabled = true;
|
||||
|
||||
$('#preview').empty()
|
||||
$('#preview .single_canvas_wrapper').remove();
|
||||
|
||||
var wrapper1 = Interface.createElement('div', {class: 'quad_canvas_wrapper qcw_x qcw_y'}, quad_previews.one.node);
|
||||
Interface.preview.append(wrapper1)
|
||||
@ -1584,6 +1584,7 @@ function openQuadView() {
|
||||
}
|
||||
})
|
||||
updateInterface()
|
||||
ReferenceImage.updateAll();
|
||||
}
|
||||
|
||||
function editCameraPreset(preset, presets) {
|
||||
|
@ -34,6 +34,7 @@ class ReferenceImage {
|
||||
this._modify_nodes = [];
|
||||
this.defaults = data;
|
||||
|
||||
this.dark_background = false;
|
||||
this.image_is_loaded = false;
|
||||
this.auto_aspect_ratio = true;
|
||||
this.img.onload = () => {
|
||||
@ -48,6 +49,7 @@ class ReferenceImage {
|
||||
} else if (!was_image_loaded) {
|
||||
this.update();
|
||||
}
|
||||
this.updateClearMode();
|
||||
}
|
||||
this.img.onerror = () => {
|
||||
this.image_is_loaded = false;
|
||||
@ -55,15 +57,6 @@ class ReferenceImage {
|
||||
|
||||
this.extend(data);
|
||||
}
|
||||
/*get image() {
|
||||
return this._image;
|
||||
}
|
||||
set image(path) {
|
||||
this._image = path;
|
||||
if (typeof this._image == 'string') {
|
||||
this.img.src = this._image.replace(/#/g, '%23');
|
||||
}
|
||||
}*/
|
||||
get aspect_ratio() {
|
||||
if (this.img && this.img.naturalWidth && this.img.naturalHeight) {
|
||||
return this.img.naturalWidth / this.img.naturalHeight;
|
||||
@ -94,6 +87,13 @@ class ReferenceImage {
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
resolveCondition() {
|
||||
if (!Condition(this.condition)) return false;
|
||||
if (this.layer == 'blueprint') {
|
||||
return Preview.all.find(p => p.isOrtho && p.angle == this.attached_side) !== undefined;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
addAsReference(save) {
|
||||
Project.reference_images.push(this);
|
||||
this.scope = 'project';
|
||||
@ -151,7 +151,7 @@ class ReferenceImage {
|
||||
}
|
||||
update() {
|
||||
if (!Interface.preview) return this;
|
||||
let shown = Condition(this.condition);
|
||||
let shown = this.resolveCondition();
|
||||
if (!shown) {
|
||||
this.node.remove();
|
||||
return this;
|
||||
@ -177,11 +177,8 @@ class ReferenceImage {
|
||||
}
|
||||
}
|
||||
|
||||
this.updateTransform();
|
||||
|
||||
this.node.style.width = this.size[0] + 'px';
|
||||
this.node.style.height = this.size[1] + 'px';
|
||||
this.node.style.left = (Math.clamp(this.position[0], 0, this.node.parentNode.clientWidth) - this.size[0]/2) + 'px';
|
||||
this.node.style.top = (Math.clamp(this.position[1], 0, this.node.parentNode.clientHeight) - this.size[1]/2) + 'px';
|
||||
this.img.style.display = (this.visibility && this.image_is_loaded) ? 'block' : 'none';
|
||||
this.img.style.opacity = this.opacity;
|
||||
|
||||
@ -197,7 +194,7 @@ class ReferenceImage {
|
||||
|
||||
if (!this.selected && this.clear_mode) {
|
||||
let light_mode = document.body.classList.contains('light_mode');
|
||||
this.node.style.filter = light_mode ? '' : 'invert(1)';
|
||||
this.node.style.filter = (light_mode != this.dark_background ? '' : 'invert(1) ') + 'contrast(1.2)';
|
||||
this.node.style.mixBlendMode = 'lighten';
|
||||
|
||||
} else {
|
||||
@ -215,8 +212,55 @@ class ReferenceImage {
|
||||
this._modify_nodes.forEach(node => node.remove());
|
||||
this._modify_nodes.empty();
|
||||
}
|
||||
if (this.selected) {
|
||||
this.node.querySelector('div.reference_image_toolbar .tool[tool_id=flip_x]').classList.toggle('enabled', this.flip_x);
|
||||
this.node.querySelector('div.reference_image_toolbar .tool[tool_id=flip_y]').classList.toggle('enabled', this.flip_y);
|
||||
this.node.querySelector('div.reference_image_toolbar .tool[tool_id=visibility]').classList.toggle('enabled', this.visibility);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
getZoomLevel() {
|
||||
let preview = this.layer == 'blueprint' && Preview.all.find(p => p.isOrtho && p.angle == this.attached_side);
|
||||
return preview ? preview.camOrtho.zoom * 2 : 1;
|
||||
}
|
||||
updateTransform() {
|
||||
let preview = this.layer == 'blueprint' && Preview.all.find(p => p.isOrtho && p.angle == this.attached_side);
|
||||
if (preview) {
|
||||
|
||||
let zoom = this.getZoomLevel();;
|
||||
let pos_x = this.position[0];
|
||||
let pos_y = this.position[1];
|
||||
|
||||
pos_x = preview.controls.target[preview.camOrtho.backgroundHandle[0].a] * zoom * 20;
|
||||
pos_y = preview.controls.target[preview.camOrtho.backgroundHandle[1].a] * zoom * 20;
|
||||
pos_x *= preview.camOrtho.backgroundHandle[0].n === true ? 1 : -1;
|
||||
pos_y *= preview.camOrtho.backgroundHandle[1].n === true ? 1 : -1;
|
||||
pos_x += preview.width/2;
|
||||
pos_y += preview.height/2;
|
||||
|
||||
pos_x += (this.position[0] * zoom) - (this.size[0] * zoom) / 2;
|
||||
pos_y += (this.position[1] * zoom) - (this.size[1] * zoom) / 2;
|
||||
|
||||
this.node.style.width = (this.size[0] * zoom) + 'px';
|
||||
this.node.style.height = (this.size[1] * zoom) + 'px';
|
||||
this.node.style.left = pos_x + 'px';
|
||||
this.node.style.top = pos_y + 'px';
|
||||
|
||||
} else {
|
||||
this.node.style.width = this.size[0] + 'px';
|
||||
this.node.style.height = this.size[1] + 'px';
|
||||
this.node.style.left = (Math.clamp(this.position[0], 0, this.node.parentNode.clientWidth) - this.size[0]/2) + 'px';
|
||||
this.node.style.top = (Math.clamp(this.position[1], 0, this.node.parentNode.clientHeight) - this.size[1]/2) + 'px';
|
||||
}
|
||||
}
|
||||
updateClearMode() {
|
||||
if (this.clear_mode && this.image_is_loaded) {
|
||||
let average_color = getAverageRGB(this.img);
|
||||
this.dark_background = (average_color.r + average_color.g + average_color.b) < 380;
|
||||
} else {
|
||||
this.dark_background = false;
|
||||
}
|
||||
}
|
||||
detach() {
|
||||
this.node.remove();
|
||||
}
|
||||
@ -240,7 +284,7 @@ class ReferenceImage {
|
||||
(e2.clientY - e1.clientY),
|
||||
];
|
||||
this.size[0] = Math.max(original_size[0] + offset[0] * sign_x, 48);
|
||||
this.position[0] = Math.clamp(original_position[0] + offset[0] / 2, 0, this.node.parentNode.clientWidth);
|
||||
this.position[0] = original_position[0] + offset[0] / 2, 0;
|
||||
|
||||
if (!e2.ctrlOrCmd && !Pressing.overrides.ctrl) {
|
||||
//offset[0] = offset[1] * this.aspect_ratio * Math.sign(offset[1]) * Math.sign(offset[0]);
|
||||
@ -249,7 +293,12 @@ class ReferenceImage {
|
||||
}
|
||||
|
||||
this.size[1] = Math.max(original_size[1] + offset[1] * sign_y, 32);
|
||||
this.position[1] = Math.clamp(original_position[1] + offset[1] / 2, 0, this.node.parentNode.clientHeight);
|
||||
this.position[1] = original_position[1] + offset[1] / 2, 0;
|
||||
|
||||
if (this.layer !== 'blueprint') {
|
||||
this.position[0] = Math.clamp(this.position[0], 0, this.node.parentNode.clientWidth);
|
||||
this.position[1] = Math.clamp(this.position[1], 0, this.node.parentNode.clientHeight);
|
||||
}
|
||||
|
||||
this.update();
|
||||
}
|
||||
@ -310,22 +359,22 @@ class ReferenceImage {
|
||||
this._modify_nodes.push(this.toolbar);
|
||||
|
||||
// Controls
|
||||
function addButton(icon, click) {
|
||||
let node = Interface.createElement('div', {class: 'tool'}, Blockbench.getIconNode(icon));
|
||||
function addButton(id, icon, click) {
|
||||
let node = Interface.createElement('div', {class: 'tool', tool_id: id}, Blockbench.getIconNode(icon));
|
||||
self.toolbar.append(node);
|
||||
node.onclick = click;
|
||||
}
|
||||
|
||||
addButton('flip_to_front', () => {
|
||||
addButton('layer', 'flip_to_front', () => {
|
||||
// todo: layer menu
|
||||
});
|
||||
|
||||
addButton('icon-mirror_x', () => {
|
||||
addButton('flip_x', 'icon-mirror_x', () => {
|
||||
self.flip_x = !self.flip_x;
|
||||
self.update().save();
|
||||
});
|
||||
|
||||
addButton('icon-mirror_y', () => {
|
||||
addButton('flip_y', 'icon-mirror_y', () => {
|
||||
self.flip_y = !self.flip_y;
|
||||
self.update().save();
|
||||
});
|
||||
@ -350,7 +399,7 @@ class ReferenceImage {
|
||||
}
|
||||
}).toElement(this.toolbar).update();
|
||||
|
||||
addButton('visibility', () => {
|
||||
addButton('visibility', 'visibility', () => {
|
||||
self.visibility = !self.visibility;
|
||||
self.update().save();
|
||||
});
|
||||
@ -361,6 +410,7 @@ class ReferenceImage {
|
||||
convertTouchEvent(e1);
|
||||
|
||||
let original_position = this.position.slice();
|
||||
let zoom = this.getZoomLevel();
|
||||
|
||||
let move = (e2) => {
|
||||
convertTouchEvent(e2);
|
||||
@ -368,8 +418,13 @@ class ReferenceImage {
|
||||
(e2.clientX - e1.clientX),
|
||||
(e2.clientY - e1.clientY),
|
||||
];
|
||||
this.position[0] = Math.clamp(original_position[0] + offset[0], 0, this.node.parentNode.clientWidth);
|
||||
this.position[1] = Math.clamp(original_position[1] + offset[1], 0, this.node.parentNode.clientHeight);
|
||||
this.position[0] = original_position[0] + offset[0] / zoom;
|
||||
this.position[1] = original_position[1] + offset[1] / zoom;
|
||||
|
||||
if (this.layer !== 'blueprint') {
|
||||
this.position[0] = Math.clamp(this.position[0], 0, this.node.parentNode.clientWidth);
|
||||
this.position[1] = Math.clamp(this.position[1], 0, this.node.parentNode.clientHeight);
|
||||
}
|
||||
|
||||
this.update();
|
||||
}
|
||||
@ -382,19 +437,20 @@ class ReferenceImage {
|
||||
addEventListeners(document, 'mousemove touchmove', move);
|
||||
addEventListeners(document, 'mouseup touchend', stop);
|
||||
})
|
||||
this.node.addEventListener('dblclick', event => {
|
||||
this.propertiesDialog();
|
||||
})
|
||||
this._edit_events_initialized = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
projectMouseCursor(x, y) {
|
||||
if (!Condition(this.condition) || !this.visibility) return false;
|
||||
if (!this.resolveCondition() || !this.visibility) return false;
|
||||
|
||||
let rect = this.img.getBoundingClientRect();
|
||||
console.log(x, y, rect)
|
||||
if (x > rect.x && y > rect.y && x < rect.right && y < rect.bottom) {
|
||||
let lerp_x = Math.getLerp(rect.x, rect.right, x);
|
||||
let lerp_y = Math.getLerp(rect.y, rect.bottom, y);
|
||||
console.log(lerp_y)
|
||||
if (this.flip_x) lerp_x = 1 - lerp_x;
|
||||
if (this.flip_y) lerp_y = 1 - lerp_y;
|
||||
return [
|
||||
@ -430,11 +486,22 @@ class ReferenceImage {
|
||||
this.save();
|
||||
this.node.remove();
|
||||
}
|
||||
changeLayer(layer) {
|
||||
if (layer == this.layer) return;
|
||||
if (layer == 'blueprint' && Preview.selected?.angle) {
|
||||
this.attached_side = Preview.selected.angle;
|
||||
this.position.V2_set(0, 0);
|
||||
}
|
||||
this.layer = layer;
|
||||
}
|
||||
changeScope() {
|
||||
// todo
|
||||
}
|
||||
propertiesDialog() {
|
||||
new Dialog('reference_image_properties', {
|
||||
title: 'Reference Image',
|
||||
form: {
|
||||
path: {type: 'file', label: 'Image', value: this.path, extensions: ['png', 'jpg', 'jpeg']},
|
||||
source: {type: 'file', label: 'Image', condition: () => isApp && PathModule.isAbsolute(this.source), value: this.source, extensions: ['png', 'jpg', 'jpeg']},
|
||||
layer: {type: 'select', label: 'Layer', value: this.layer, options: {
|
||||
background: 'Behind Model',
|
||||
viewport: 'Above Model',
|
||||
@ -450,9 +517,14 @@ class ReferenceImage {
|
||||
rotation: {type: 'number', label: 'Rotation', value: this.rotation},
|
||||
opacity: {type: 'range', label: 'Opacity', editable_range_label: true, value: this.opacity, min: 0, max: 1}
|
||||
},
|
||||
onConfirm(result) {
|
||||
// todo: Switch Scope
|
||||
onConfirm: (result) => {
|
||||
let clear_mode_before = this.clear_mode;
|
||||
this.changeLayer(result.layer);
|
||||
this.changeScope(result.scope);
|
||||
this.extend(result);
|
||||
if (this.clear_mode != clear_mode_before) {
|
||||
this.updateClearMode();
|
||||
}
|
||||
this.update().save();
|
||||
}
|
||||
}).show();
|
||||
@ -466,14 +538,16 @@ ReferenceImage.prototype.menu = new Menu([
|
||||
*/
|
||||
{
|
||||
id: 'clear_mode',
|
||||
name: 'Clear Mode',
|
||||
icon: (ref) => ref.clear_mode,
|
||||
condition: ref => ref.layer == 'blueprint',
|
||||
click(ref) {
|
||||
ref.clear_mode = !ref.clear_mode;
|
||||
ref.updateClearMode();
|
||||
ref.update().save();
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
name: 'Layer',
|
||||
icon: 'list',
|
||||
children: (reference) => {
|
||||
@ -490,7 +564,7 @@ ReferenceImage.prototype.menu = new Menu([
|
||||
name: layers[key],
|
||||
icon: reference.layer == key ? 'radio_button_checked' : 'radio_button_unchecked',
|
||||
click() {
|
||||
reference.layer = key;
|
||||
reference.changeLayer(key);
|
||||
reference.update();
|
||||
}
|
||||
})
|
||||
@ -498,6 +572,7 @@ ReferenceImage.prototype.menu = new Menu([
|
||||
return children;
|
||||
}
|
||||
},
|
||||
'_',
|
||||
'delete',
|
||||
'_',
|
||||
{
|
||||
@ -520,7 +595,7 @@ new Property(ReferenceImage, 'number', 'rotation');
|
||||
new Property(ReferenceImage, 'number', 'opacity', {default: 1});
|
||||
new Property(ReferenceImage, 'boolean', 'visibility', {default: true});
|
||||
new Property(ReferenceImage, 'boolean', 'clear_mode');
|
||||
new Property(ReferenceImage, 'number', 'attached_side');
|
||||
new Property(ReferenceImage, 'string', 'attached_side', {default: 'north'});
|
||||
new Property(ReferenceImage, 'string', 'source');
|
||||
|
||||
ReferenceImage.selected = null;
|
||||
@ -538,7 +613,7 @@ Object.defineProperty(ReferenceImage, 'all', {
|
||||
})
|
||||
Object.defineProperty(ReferenceImage, 'active', {
|
||||
get() {
|
||||
return ReferenceImage.all.filter(ref => Condition(ref.condition));
|
||||
return ReferenceImage.all.filter(ref => ref.resolveCondition());
|
||||
}
|
||||
})
|
||||
|
||||
@ -722,7 +797,6 @@ BARS.defineActions(function() {
|
||||
window.close();
|
||||
|
||||
ReferenceImageMode.importReferences([{content: url.srcURL, name: url.altText.substring(0, 24)}]);
|
||||
confirmImage(url.srcURL, url.altText);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user