2020-07-16 15:32:59 +08:00
|
|
|
var scene,
|
|
|
|
main_preview, MediaPreview,
|
2019-07-18 00:02:07 +08:00
|
|
|
Sun, lights,
|
2019-12-16 03:04:31 +08:00
|
|
|
outlines,
|
2019-07-18 00:02:07 +08:00
|
|
|
Transformer,
|
|
|
|
canvas_scenes,
|
|
|
|
display_scene, display_area, display_base;
|
|
|
|
var framespersecond = 0;
|
|
|
|
var display_mode = false;
|
|
|
|
var doRender = false;
|
|
|
|
var quad_previews = {};
|
|
|
|
const three_grid = new THREE.Object3D();
|
|
|
|
const rot_origin = new THREE.Object3D();
|
|
|
|
var gizmo_colors = {
|
|
|
|
r: new THREE.Color(0xfd3043),
|
|
|
|
g: new THREE.Color(0x26ec45),
|
2019-08-18 00:26:14 +08:00
|
|
|
b: new THREE.Color(0x2d5ee8),
|
2019-12-16 03:04:31 +08:00
|
|
|
grid: new THREE.Color(0x495061),
|
|
|
|
wire: new THREE.Color(0x576f82),
|
2021-06-14 03:32:18 +08:00
|
|
|
solid: new THREE.Color(0xc1c1c1),
|
2019-12-16 03:04:31 +08:00
|
|
|
outline: new THREE.Color(0x3e90ff)
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
const DefaultCameraPresets = [
|
|
|
|
{
|
|
|
|
name: 'menu.preview.angle.initial',
|
2020-09-12 04:55:17 +08:00
|
|
|
id: 'initial',
|
2020-03-05 03:56:17 +08:00
|
|
|
projection: 'perspective',
|
|
|
|
position: [-40, 32, -40],
|
|
|
|
target: [0, 8, 0],
|
|
|
|
default: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'direction.top',
|
2020-09-12 04:55:17 +08:00
|
|
|
id: 'top',
|
2020-03-05 03:56:17 +08:00
|
|
|
projection: 'orthographic',
|
|
|
|
color: 'y',
|
|
|
|
position: [0, 64, 0],
|
|
|
|
target: [0, 0, 0],
|
|
|
|
zoom: 0.5,
|
2021-02-14 05:08:20 +08:00
|
|
|
locked_angle: 'top',
|
2020-03-05 03:56:17 +08:00
|
|
|
default: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'direction.bottom',
|
2020-09-12 04:55:17 +08:00
|
|
|
id: 'bottom',
|
2020-03-05 03:56:17 +08:00
|
|
|
projection: 'orthographic',
|
|
|
|
color: 'y',
|
|
|
|
position: [0, -64, 0],
|
|
|
|
target: [0, 0, 0],
|
|
|
|
zoom: 0.5,
|
2021-02-14 05:08:20 +08:00
|
|
|
locked_angle: 'bottom',
|
2020-03-05 03:56:17 +08:00
|
|
|
default: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'direction.south',
|
2020-09-12 04:55:17 +08:00
|
|
|
id: 'south',
|
2020-03-05 03:56:17 +08:00
|
|
|
projection: 'orthographic',
|
|
|
|
color: 'z',
|
|
|
|
position: [0, 0, 64],
|
|
|
|
target: [0, 0, 0],
|
|
|
|
zoom: 0.5,
|
2021-02-14 05:08:20 +08:00
|
|
|
locked_angle: 'south',
|
2020-03-05 03:56:17 +08:00
|
|
|
default: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'direction.north',
|
2020-09-12 04:55:17 +08:00
|
|
|
id: 'north',
|
2020-03-05 03:56:17 +08:00
|
|
|
projection: 'orthographic',
|
|
|
|
color: 'z',
|
|
|
|
position: [0, 0, -64],
|
|
|
|
target: [0, 0, 0],
|
|
|
|
zoom: 0.5,
|
2021-02-14 05:08:20 +08:00
|
|
|
locked_angle: 'north',
|
2020-03-05 03:56:17 +08:00
|
|
|
default: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'direction.east',
|
2020-09-12 04:55:17 +08:00
|
|
|
id: 'east',
|
2020-03-05 03:56:17 +08:00
|
|
|
projection: 'orthographic',
|
|
|
|
color: 'x',
|
|
|
|
position: [64, 0, 0],
|
|
|
|
target: [0, 0, 0],
|
|
|
|
zoom: 0.5,
|
2021-02-14 05:08:20 +08:00
|
|
|
locked_angle: 'east',
|
2020-03-05 03:56:17 +08:00
|
|
|
default: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'direction.west',
|
2020-09-12 04:55:17 +08:00
|
|
|
id: 'west',
|
2020-03-05 03:56:17 +08:00
|
|
|
projection: 'orthographic',
|
|
|
|
color: 'x',
|
|
|
|
position: [-64, 0, 0],
|
|
|
|
target: [0, 0, 0],
|
|
|
|
zoom: 0.5,
|
2021-02-14 05:08:20 +08:00
|
|
|
locked_angle: 'west',
|
2020-03-05 03:56:17 +08:00
|
|
|
default: true
|
2020-04-26 02:25:07 +08:00
|
|
|
},
|
|
|
|
{
|
2021-04-27 15:07:12 +08:00
|
|
|
name: 'camera_angle.common_isometric_right',
|
2020-09-12 04:55:17 +08:00
|
|
|
id: 'isometric_right',
|
2020-04-26 02:25:07 +08:00
|
|
|
projection: 'orthographic',
|
2021-04-27 15:07:12 +08:00
|
|
|
position: [-64, 64*0.8165+8, -64],
|
|
|
|
target: [0, 8, 0],
|
2020-04-26 02:25:07 +08:00
|
|
|
zoom: 0.5,
|
|
|
|
default: true
|
|
|
|
},
|
|
|
|
{
|
2021-04-27 15:07:12 +08:00
|
|
|
name: 'camera_angle.common_isometric_left',
|
2020-09-12 04:55:17 +08:00
|
|
|
id: 'isometric_left',
|
2020-04-26 02:25:07 +08:00
|
|
|
projection: 'orthographic',
|
2021-04-27 15:07:12 +08:00
|
|
|
position: [64, 64*0.8165+8, -64],
|
|
|
|
target: [0, 8, 0],
|
|
|
|
zoom: 0.5,
|
|
|
|
default: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'camera_angle.true_isometric_right',
|
|
|
|
id: 'isometric_right',
|
|
|
|
projection: 'orthographic',
|
|
|
|
position: [-64, 64+8, -64],
|
|
|
|
target: [0, 8, 0],
|
|
|
|
zoom: 0.5,
|
|
|
|
default: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'camera_angle.true_isometric_left',
|
|
|
|
id: 'isometric_left',
|
|
|
|
projection: 'orthographic',
|
|
|
|
position: [64, 64+8, -64],
|
|
|
|
target: [0, 8, 0],
|
2020-04-26 02:25:07 +08:00
|
|
|
zoom: 0.5,
|
|
|
|
default: true
|
2020-03-05 03:56:17 +08:00
|
|
|
}
|
|
|
|
]
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
class Preview {
|
2020-10-13 03:22:02 +08:00
|
|
|
constructor(options = 0) {
|
2019-07-18 00:02:07 +08:00
|
|
|
var scope = this;
|
2020-10-13 03:22:02 +08:00
|
|
|
if (options && options.id) {
|
|
|
|
this.id = options.id
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
//Node
|
|
|
|
this.canvas = document.createElement('canvas')
|
|
|
|
this.canvas.preview = this;
|
|
|
|
this.height = 0;
|
|
|
|
this.width = 0;
|
2020-07-16 15:32:59 +08:00
|
|
|
this.node = document.createElement('div')
|
|
|
|
this.node.className = 'preview';
|
|
|
|
this.node.appendChild(this.canvas);
|
2021-06-12 17:34:47 +08:00
|
|
|
let menu = $(`
|
|
|
|
<div class="preview_menu">
|
|
|
|
<div class="tool preview_background_menu" hidden><img src="" width="36px"></div>
|
|
|
|
<div class="tool preview_main_menu"><i class="material-icons">more_vert</i></div>
|
|
|
|
</div>`)[0];
|
2021-06-12 18:53:40 +08:00
|
|
|
menu.firstElementChild.onclick = (event) => {
|
|
|
|
let M = new Menu(this.menu.structure.find(s => s.id == 'background').children(this));
|
|
|
|
M.open(menu, this);
|
|
|
|
}
|
|
|
|
menu.lastElementChild.onclick = (event) => {
|
|
|
|
this.menu.open(menu, this);
|
|
|
|
}
|
|
|
|
BarItem.prototype.addLabel(false, {
|
|
|
|
name: tl('menu.preview.background'),
|
|
|
|
node: menu.firstElementChild
|
|
|
|
})
|
2020-07-16 15:32:59 +08:00
|
|
|
BarItem.prototype.addLabel(false, {
|
|
|
|
name: tl('data.preview'),
|
2021-06-12 18:53:40 +08:00
|
|
|
node: menu.lastElementChild
|
2020-07-16 15:32:59 +08:00
|
|
|
})
|
|
|
|
this.node.appendChild(menu)
|
2019-07-18 00:02:07 +08:00
|
|
|
//Cameras
|
|
|
|
this.isOrtho = false
|
2020-03-05 03:56:17 +08:00
|
|
|
this.angle = null;
|
2021-03-04 21:22:12 +08:00
|
|
|
this.camPers = new THREE.PerspectiveCamera(settings.fov.value, 16 / 9, settings.camera_near_plane.value||1, 30000);
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camOrtho = new THREE.OrthographicCamera(-600, 600, -400, 400, -200, 20000);
|
2019-07-18 00:02:07 +08:00
|
|
|
this.camOrtho.backgroundHandle = [{n: false, a: 'x'}, {n: false, a: 'y'}]
|
|
|
|
this.camOrtho.axis = null
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camOrtho.zoom = 0.5
|
2019-07-18 00:02:07 +08:00
|
|
|
this.camPers.preview = this.camOrtho.preview = this;
|
|
|
|
for (var i = 4; i <= 6; i++) {
|
|
|
|
this.camPers.layers.enable(i);
|
|
|
|
}
|
2021-02-20 07:02:56 +08:00
|
|
|
this.side_view_target = new THREE.Vector3();
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
//Controls
|
|
|
|
this.controls = new THREE.OrbitControls(this.camPers, this);
|
|
|
|
this.controls.minDistance = 1;
|
2019-12-16 03:04:31 +08:00
|
|
|
this.controls.maxDistance = 3960;
|
2019-07-18 00:02:07 +08:00
|
|
|
this.controls.enableKeys = false;
|
2019-12-16 03:04:31 +08:00
|
|
|
this.controls.zoomSpeed = 1.5;
|
2021-02-20 07:02:56 +08:00
|
|
|
this.controls.onUpdate(() => {
|
|
|
|
if (this.angle != null) {
|
|
|
|
if (this.camOrtho.axis != 'x') this.side_view_target.x = this.controls.target.x;
|
|
|
|
if (this.camOrtho.axis != 'y') this.side_view_target.y = this.controls.target.y;
|
|
|
|
if (this.camOrtho.axis != 'z') this.side_view_target.z = this.controls.target.z;
|
|
|
|
}
|
|
|
|
})
|
2019-12-16 03:04:31 +08:00
|
|
|
|
2020-01-24 01:53:36 +08:00
|
|
|
//Annotations
|
|
|
|
this.annotations = {};
|
|
|
|
this.updateAnnotations = function() {
|
|
|
|
for (var key in scope.annotations) {
|
|
|
|
var tag = scope.annotations[key];
|
2019-12-16 03:04:31 +08:00
|
|
|
if (tag.object.visible) {
|
2020-01-24 01:53:36 +08:00
|
|
|
var pos = tag.object.toScreenPosition(scope.camera, scope.canvas);
|
2021-01-31 19:51:10 +08:00
|
|
|
tag.node.style.setProperty('left', pos.x+'px');
|
|
|
|
tag.node.style.setProperty('top', pos.y+'px');
|
2019-12-16 03:04:31 +08:00
|
|
|
}
|
2020-01-24 01:53:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
this.controls.onUpdate(() => setTimeout(() => {
|
|
|
|
scope.updateAnnotations();
|
|
|
|
}, 6))
|
|
|
|
this.addAnnotation = function(key, tag) {
|
|
|
|
scope.annotations[key] = tag;
|
|
|
|
$(tag.node).insertBefore(scope.canvas);
|
|
|
|
scope.updateAnnotations();
|
|
|
|
}
|
|
|
|
this.removeAnnotation = function(key) {
|
|
|
|
if (scope.annotations[key]) {
|
|
|
|
$(scope.annotations[key].node).detach();
|
|
|
|
delete scope.annotations[key];
|
|
|
|
}
|
2019-12-16 03:04:31 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camPers.position.fromArray(DefaultCameraPresets[0].position)
|
|
|
|
this.controls.target.fromArray(DefaultCameraPresets[0].target);
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2021-02-04 17:09:25 +08:00
|
|
|
if (!Blockbench.isMobile) {
|
2021-03-06 02:03:19 +08:00
|
|
|
this.orbit_gizmo = new OrbitGizmo(this);
|
|
|
|
this.node.append(this.orbit_gizmo.node);
|
2021-02-04 17:09:25 +08:00
|
|
|
}
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
//Keybinds
|
|
|
|
this.controls.mouseButtons.ZOOM = undefined;
|
|
|
|
|
|
|
|
//Renderer
|
2020-04-26 02:25:07 +08:00
|
|
|
try {
|
|
|
|
this.renderer = new THREE.WebGLRenderer({
|
|
|
|
canvas: this.canvas,
|
2020-10-13 03:22:02 +08:00
|
|
|
antialias: typeof options.antialias == 'boolean' ? options.antialias : Settings.get('antialiasing'),
|
2020-04-26 02:25:07 +08:00
|
|
|
alpha: true,
|
|
|
|
preserveDrawingBuffer: true
|
|
|
|
});
|
|
|
|
} catch (err) {
|
2020-12-06 05:31:45 +08:00
|
|
|
let error_element = document.querySelector('#loading_error_detail')
|
|
|
|
error_element.innerHTML = `Error creating WebGL context. Try to update your graphics drivers.`
|
|
|
|
|
2020-04-26 02:25:07 +08:00
|
|
|
if (isApp) {
|
2020-12-06 05:31:45 +08:00
|
|
|
window.restartWithoutHardwareAcceleration = function() {
|
|
|
|
|
|
|
|
ipcRenderer.send('edit-launch-setting', {key: 'hardware_acceleration', value: false});
|
|
|
|
settings.hardware_acceleration = false;
|
|
|
|
Settings.saveLocalStorages();
|
|
|
|
|
|
|
|
electron.app.relaunch()
|
|
|
|
electron.app.quit()
|
|
|
|
}
|
|
|
|
error_element.innerHTML = error_element.innerHTML +
|
|
|
|
'\nAlternatively, try to <a href onclick="restartWithoutHardwareAcceleration()">Restart without Hardware Acceleration.</a>'
|
|
|
|
|
2020-04-26 02:25:07 +08:00
|
|
|
var {BrowserWindow} = require('electron').remote
|
|
|
|
new BrowserWindow({
|
|
|
|
icon:'icon.ico',
|
|
|
|
backgroundColor: '#ffffff',
|
|
|
|
title: 'Blockbench GPU Information',
|
|
|
|
webPreferences: {
|
|
|
|
webgl: true,
|
|
|
|
webSecurity: true,
|
|
|
|
nodeIntegration: true
|
|
|
|
}
|
|
|
|
}).loadURL('chrome://gpu')
|
|
|
|
}
|
|
|
|
throw err;
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
this.renderer.setClearColor( 0x000000, 0 )
|
|
|
|
this.renderer.setSize(500, 400);
|
|
|
|
|
|
|
|
this.loadBackground()
|
|
|
|
|
|
|
|
this.selection = {
|
2021-08-03 16:16:41 +08:00
|
|
|
box: $('<div id="selection_box" class="selection_rectangle"></div>'),
|
|
|
|
frustum: new THREE.Frustum()
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
|
2021-08-02 18:42:06 +08:00
|
|
|
this.raycaster = new THREE.Raycaster();
|
2019-07-18 00:02:07 +08:00
|
|
|
this.mouse = new THREE.Vector2();
|
2019-12-16 03:04:31 +08:00
|
|
|
addEventListeners(this.canvas, 'mousedown touchstart', function(event) { scope.click(event)}, { passive: false })
|
|
|
|
addEventListeners(this.canvas, 'mousemove touchmove', function(event) { scope.static_rclick = false}, false)
|
|
|
|
addEventListeners(this.canvas, 'mousemove', function(event) { scope.mousemove(event)}, false)
|
2020-10-26 00:37:14 +08:00
|
|
|
addEventListeners(this.canvas, 'mouseup touchend', function(event) { scope.mouseup(event)}, false)
|
2019-12-16 03:04:31 +08:00
|
|
|
addEventListeners(this.canvas, 'dblclick', function(event) {Toolbox.toggleTransforms(event)}, false)
|
|
|
|
addEventListeners(this.canvas, 'mouseenter touchstart', function(event) { scope.occupyTransformer(event)}, false)
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
Blockbench.addDragHandler('preview_'+this.id, {
|
|
|
|
extensions: ['jpg', 'jpeg', 'bmp', 'tiff', 'tif', 'gif'],
|
|
|
|
element: this.canvas,
|
|
|
|
readtype: 'image',
|
|
|
|
}, function(files) {
|
|
|
|
if (isApp) {
|
|
|
|
scope.background.image = files[0].path
|
|
|
|
} else {
|
|
|
|
scope.background.image = files[0].content
|
|
|
|
}
|
|
|
|
scope.loadBackground()
|
|
|
|
})
|
2020-07-16 15:32:59 +08:00
|
|
|
Preview.all.push(this);
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
//Render
|
2020-07-16 15:32:59 +08:00
|
|
|
resize(width, height) {
|
|
|
|
if (this.canvas.isConnected && this !== MediaPreview) {
|
|
|
|
this.height = this.node.parentElement.clientHeight;
|
|
|
|
this.width = this.node.parentElement.clientWidth;
|
|
|
|
} else if (height && width) {
|
|
|
|
this.height = height;
|
|
|
|
this.width = width;
|
|
|
|
} else {
|
|
|
|
return this;
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
if (this.isOrtho === false) {
|
|
|
|
this.camPers.aspect = this.width / this.height
|
|
|
|
this.camPers.updateProjectionMatrix();
|
|
|
|
} else {
|
|
|
|
this.camOrtho.right = this.width / 80
|
|
|
|
this.camOrtho.left = this.camOrtho.right*-1
|
|
|
|
this.camOrtho.top = this.height / 80
|
|
|
|
this.camOrtho.bottom = this.camOrtho.top*-1
|
|
|
|
this.camOrtho.updateProjectionMatrix();
|
|
|
|
}
|
|
|
|
this.renderer.setSize(this.width, this.height);
|
2020-07-16 15:32:59 +08:00
|
|
|
|
|
|
|
if (this.canvas.isConnected) {
|
|
|
|
this.renderer.setPixelRatio(window.devicePixelRatio);
|
|
|
|
this.updateBackground()
|
|
|
|
if (Transformer) {
|
|
|
|
Transformer.update()
|
|
|
|
}
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
raycast(event) {
|
2019-12-16 03:04:31 +08:00
|
|
|
convertTouchEvent(event);
|
2019-07-18 00:02:07 +08:00
|
|
|
var canvas_offset = $(this.canvas).offset()
|
2019-12-16 03:04:31 +08:00
|
|
|
this.mouse.x = ((event.clientX - canvas_offset.left) / this.width) * 2 - 1;
|
|
|
|
this.mouse.y = - ((event.clientY - canvas_offset.top) / this.height) * 2 + 1;
|
2020-03-05 03:56:17 +08:00
|
|
|
this.raycaster.setFromCamera( this.mouse, this.camera );
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
var objects = []
|
2021-07-28 23:49:09 +08:00
|
|
|
Outliner.elements.forEach(element => {
|
|
|
|
if (element.mesh.geometry && element.visibility && !element.locked) {
|
|
|
|
objects.push(element.mesh);
|
2021-09-01 05:51:59 +08:00
|
|
|
if (Modes.edit && element.selected) {
|
|
|
|
if (element.mesh.vertex_points && element.mesh.vertex_points.visible) {
|
|
|
|
objects.push(element.mesh.vertex_points);
|
|
|
|
}
|
2021-09-08 00:19:39 +08:00
|
|
|
if (element instanceof Mesh && element.mesh.outline.visible && BarItems.selection_mode.value == 'line') {
|
2021-09-01 05:51:59 +08:00
|
|
|
objects.push(element.mesh.outline);
|
|
|
|
}
|
2021-09-01 02:49:07 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
2021-09-07 18:25:41 +08:00
|
|
|
if (Vertexsnap.vertex_gizmos.children.length) {
|
|
|
|
Vertexsnap.vertex_gizmos.children.forEach(function(s) {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (s.isVertex === true) {
|
|
|
|
objects.push(s)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2020-10-11 00:31:56 +08:00
|
|
|
if (Animator.open && settings.motion_trails.value && Group.selected) {
|
|
|
|
Animator.motion_trail.children.forEach(object => {
|
|
|
|
if (object.isKeyframe === true) {
|
|
|
|
objects.push(object)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
var intersects = this.raycaster.intersectObjects( objects );
|
|
|
|
if (intersects.length > 0) {
|
2021-09-01 02:49:07 +08:00
|
|
|
let mesh_gizmo = intersects.find(intersect => intersect.object.type == 'Points' || intersect.object.type == 'LineSegments');
|
|
|
|
let intersect = mesh_gizmo || intersects[0];
|
2021-08-18 23:27:06 +08:00
|
|
|
let intersect_object = intersect.object
|
2021-08-07 18:57:27 +08:00
|
|
|
|
2021-08-18 23:27:06 +08:00
|
|
|
if (intersect_object.isElement) {
|
|
|
|
var element = OutlinerNode.uuids[intersect_object.name]
|
2021-08-07 18:57:27 +08:00
|
|
|
let face;
|
|
|
|
if (element instanceof Cube) {
|
2021-09-21 17:20:10 +08:00
|
|
|
face = intersect_object.geometry.faces[Math.floor(intersect.faceIndex / 2)];
|
2021-08-18 23:27:06 +08:00
|
|
|
} else if (element instanceof Mesh) {
|
|
|
|
let index = intersect.faceIndex;
|
|
|
|
for (let key in element.faces) {
|
|
|
|
let {vertices} = element.faces[key];
|
2021-09-16 22:52:21 +08:00
|
|
|
if (vertices.length < 3) continue;
|
2021-08-18 23:27:06 +08:00
|
|
|
|
|
|
|
if (index == 0 || (index == 1 && vertices.length == 4)) {
|
|
|
|
face = key;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (vertices.length == 3) index -= 1;
|
|
|
|
if (vertices.length == 4) index -= 2;
|
|
|
|
}
|
2021-08-07 18:57:27 +08:00
|
|
|
}
|
2020-10-03 01:13:11 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
return {
|
2021-07-28 23:49:09 +08:00
|
|
|
type: 'element',
|
2021-08-07 18:57:27 +08:00
|
|
|
event,
|
|
|
|
intersects,
|
|
|
|
face,
|
|
|
|
element
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2021-09-21 17:20:10 +08:00
|
|
|
} else if (intersect_object.isKeyframe) {
|
|
|
|
let uuid = intersect_object.keyframeUUIDs[intersect.index];
|
|
|
|
let keyframe = Timeline.keyframes.find(kf => kf.uuid == uuid);
|
|
|
|
return {
|
|
|
|
event,
|
|
|
|
type: 'keyframe',
|
|
|
|
intersects,
|
|
|
|
keyframe: keyframe
|
|
|
|
}
|
2021-08-18 23:27:06 +08:00
|
|
|
} else if (intersect_object.type == 'Points') {
|
|
|
|
var element = OutlinerNode.uuids[intersect_object.parent.parent.name];
|
2021-09-07 18:25:41 +08:00
|
|
|
let vertex = element instanceof Mesh
|
|
|
|
? Object.keys(element.vertices)[intersect.index]
|
|
|
|
: intersect_object.vertices[intersect.index];
|
2019-07-18 00:02:07 +08:00
|
|
|
return {
|
2021-08-07 18:57:27 +08:00
|
|
|
event,
|
2019-07-18 00:02:07 +08:00
|
|
|
type: 'vertex',
|
2021-08-07 18:57:27 +08:00
|
|
|
element,
|
|
|
|
intersects,
|
|
|
|
intersect,
|
2021-09-12 21:09:01 +08:00
|
|
|
vertex,
|
|
|
|
vertex_index: intersect.index,
|
2021-08-07 18:57:27 +08:00
|
|
|
}
|
2021-09-01 02:49:07 +08:00
|
|
|
} else if (intersect_object.type == 'LineSegments') {
|
|
|
|
var element = OutlinerNode.uuids[intersect_object.parent.name];
|
|
|
|
let vertices = intersect_object.vertex_order.slice(intersect.index, intersect.index+2);
|
|
|
|
return {
|
|
|
|
event,
|
|
|
|
type: 'line',
|
|
|
|
element,
|
|
|
|
intersects,
|
|
|
|
intersect,
|
|
|
|
vertices
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
render() {
|
|
|
|
this.controls.update()
|
|
|
|
this.renderer.render(
|
|
|
|
display_mode
|
|
|
|
? display_scene
|
|
|
|
: scene,
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camera
|
2019-07-18 00:02:07 +08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
//Camera
|
2019-12-16 03:04:31 +08:00
|
|
|
get camera() {
|
|
|
|
return this.isOrtho ? this.camOrtho : this.camPers;
|
|
|
|
}
|
2021-02-20 07:02:56 +08:00
|
|
|
setProjectionMode(ortho, toggle) {
|
2020-03-05 03:56:17 +08:00
|
|
|
|
|
|
|
let position = this.camera.position;
|
|
|
|
this.isOrtho = !!ortho;
|
2019-07-18 00:02:07 +08:00
|
|
|
this.resize()
|
2020-03-05 03:56:17 +08:00
|
|
|
this.controls.object = this.camera;
|
|
|
|
this.camera.position.copy(position);
|
2021-02-20 07:02:56 +08:00
|
|
|
if (toggle) {
|
|
|
|
let perspective_distance = this.camPers.position.distanceTo(this.controls.target);
|
2021-02-21 17:20:16 +08:00
|
|
|
let factor = 0.64 * devicePixelRatio * this.camPers.getFocalLength();
|
2021-02-20 07:02:56 +08:00
|
|
|
if (this.isOrtho) {
|
|
|
|
this.camera.zoom = factor / perspective_distance;
|
|
|
|
} else {
|
|
|
|
let target_distance = factor / this.camOrtho.zoom;
|
|
|
|
let cam_offset = new THREE.Vector3().copy(this.camPers.position).sub(this.controls.target);
|
|
|
|
cam_offset.multiplyScalar(target_distance / perspective_distance);
|
|
|
|
this.camPers.position.copy(cam_offset).add(this.controls.target);
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
}
|
2021-04-15 23:07:43 +08:00
|
|
|
this.setLockedAngle();
|
|
|
|
this.occupyTransformer();
|
2019-07-18 00:02:07 +08:00
|
|
|
this.controls.updateSceneScale();
|
2020-03-05 03:56:17 +08:00
|
|
|
return this;
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2020-08-17 22:48:14 +08:00
|
|
|
setFOV(fov) {
|
|
|
|
this.camPers.fov = fov;
|
|
|
|
this.camPers.updateProjectionMatrix();
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
setNormalCamera() {
|
|
|
|
//Deprecated
|
|
|
|
this.setProjectionMode(false)
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
setLockedAngle(angle) {
|
2021-02-14 05:08:20 +08:00
|
|
|
if (typeof angle === 'string' && this.isOrtho) {
|
2020-03-05 03:56:17 +08:00
|
|
|
|
|
|
|
this.angle = angle
|
|
|
|
this.controls.enableRotate = false;
|
|
|
|
|
|
|
|
switch (angle) {
|
2021-02-14 05:08:20 +08:00
|
|
|
case 'top':
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camOrtho.axis = 'y'
|
|
|
|
this.camOrtho.backgroundHandle = [{n: false, a: 'x'}, {n: false, a: 'z'}]
|
|
|
|
break;
|
2021-02-14 05:08:20 +08:00
|
|
|
case 'bottom':
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camOrtho.axis = 'y'
|
|
|
|
this.camOrtho.backgroundHandle = [{n: false, a: 'x'}, {n: true, a: 'z'}]
|
|
|
|
break;
|
2021-02-14 05:08:20 +08:00
|
|
|
case 'south':
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camOrtho.axis = 'z'
|
|
|
|
this.camOrtho.backgroundHandle = [{n: false, a: 'x'}, {n: true, a: 'y'}]
|
|
|
|
break;
|
2021-02-14 05:08:20 +08:00
|
|
|
case 'north':
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camOrtho.axis = 'z'
|
|
|
|
this.camOrtho.backgroundHandle = [{n: true, a: 'x'}, {n: true, a: 'y'}]
|
|
|
|
break;
|
2021-02-14 05:08:20 +08:00
|
|
|
case 'east':
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camOrtho.axis = 'x'
|
|
|
|
this.camOrtho.backgroundHandle = [{n: true, a: 'z'}, {n: true, a: 'y'}]
|
|
|
|
break;
|
2021-02-14 05:08:20 +08:00
|
|
|
case 'west':
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camOrtho.axis = 'x'
|
|
|
|
this.camOrtho.backgroundHandle = [{n: false, a: 'z'}, {n: true, a: 'y'}]
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this.loadBackground();
|
|
|
|
|
|
|
|
var layer = getAxisNumber(this.camOrtho.axis)+1;
|
|
|
|
this.camOrtho.layers.set(0);
|
|
|
|
this.camOrtho.layers.enable(layer);
|
|
|
|
for (var i = 1; i <= 3; i++) {
|
|
|
|
if (i != layer) {
|
|
|
|
this.camOrtho.layers.enable(i+3);
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2021-02-20 07:02:56 +08:00
|
|
|
if (this.camOrtho.axis != 'x') {
|
|
|
|
this.controls.target.x = this.camOrtho.position.x = this.side_view_target.x;
|
|
|
|
}
|
|
|
|
if (this.camOrtho.axis != 'y') {
|
|
|
|
this.controls.target.y = this.camOrtho.position.y = this.side_view_target.y;
|
|
|
|
}
|
|
|
|
if (this.camOrtho.axis != 'z') {
|
|
|
|
this.controls.target.z = this.camOrtho.position.z = this.side_view_target.z;
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.angle = null;
|
|
|
|
this.camOrtho.axis = null
|
|
|
|
this.camOrtho.layers.set(0);
|
|
|
|
this.camOrtho.layers.enable(4);
|
|
|
|
this.camOrtho.layers.enable(5);
|
|
|
|
this.camOrtho.layers.enable(6);
|
|
|
|
this.resize()
|
|
|
|
this.controls.enableRotate = true;
|
|
|
|
this.loadBackground()
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Transformer.update();
|
2020-03-05 03:56:17 +08:00
|
|
|
this.loadBackground()
|
2019-07-18 00:02:07 +08:00
|
|
|
return this;
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
loadAnglePreset(preset) {
|
|
|
|
if (!preset) return;
|
|
|
|
this.camera.position.fromArray(preset.position);
|
2020-08-15 03:40:48 +08:00
|
|
|
if (preset.target) {
|
|
|
|
this.controls.target.fromArray(preset.target);
|
|
|
|
} else if (preset.rotation) {
|
|
|
|
|
|
|
|
this.controls.target.set(0, 0, 16).applyEuler(new THREE.Euler(
|
|
|
|
Math.degToRad(preset.rotation[0]),
|
|
|
|
Math.degToRad(preset.rotation[1]),
|
|
|
|
Math.degToRad(preset.rotation[2]),
|
|
|
|
'ZYX'
|
|
|
|
));
|
2020-10-05 05:44:06 +08:00
|
|
|
this.controls.target.add(this.camera.position);
|
2020-08-15 03:40:48 +08:00
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
if (preset.projection !== 'unset') {
|
|
|
|
this.setProjectionMode(preset.projection == 'orthographic')
|
2021-02-20 07:02:56 +08:00
|
|
|
}
|
|
|
|
if (this.isOrtho && preset.zoom && !preset.locked_angle) {
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camera.zoom = preset.zoom;
|
|
|
|
this.camera.updateProjectionMatrix()
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
if (!this.isOrtho) {
|
2020-12-22 20:32:49 +08:00
|
|
|
// should be FOV and should be an option on saving
|
2020-03-05 03:56:17 +08:00
|
|
|
this.camera.setFocalLength(preset.focal_length||45);
|
|
|
|
}
|
|
|
|
this.setLockedAngle(preset.locked_angle)
|
2019-07-18 00:02:07 +08:00
|
|
|
return this;
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
newAnglePreset() {
|
|
|
|
let scope = this;
|
2020-04-26 02:25:07 +08:00
|
|
|
let position = scope.camera.position.toArray();
|
|
|
|
let target = scope.controls.target.toArray();
|
|
|
|
position.forEach((v, i) => {
|
|
|
|
position[i] = Math.round(v*100)/100
|
|
|
|
})
|
|
|
|
target.forEach((v, i) => {
|
|
|
|
target[i] = Math.round(v*100)/100
|
|
|
|
})
|
2020-03-05 03:56:17 +08:00
|
|
|
|
|
|
|
let dialog = new Dialog({
|
|
|
|
id: 'save_angle',
|
|
|
|
title: 'menu.preview.save_angle',
|
|
|
|
width: 540,
|
|
|
|
form: {
|
|
|
|
name: {label: 'generic.name'},
|
|
|
|
projection: {label: 'dialog.save_angle.projection', type: 'select', default: 'unset', options: {
|
|
|
|
unset: 'generic.unset',
|
|
|
|
perspective: 'dialog.save_angle.projection.perspective',
|
|
|
|
orthographic: 'dialog.save_angle.projection.orthographic'
|
2020-04-26 02:25:07 +08:00
|
|
|
}},
|
|
|
|
position: {label: 'dialog.save_angle.position', type: 'vector', dimensions: 3, value: position},
|
|
|
|
target: {label: 'dialog.save_angle.target', type: 'vector', dimensions: 3, value: target},
|
2020-03-05 03:56:17 +08:00
|
|
|
},
|
|
|
|
onConfirm: function(formResult) {
|
|
|
|
|
|
|
|
if (!formResult.name) return;
|
|
|
|
|
|
|
|
let preset = {
|
|
|
|
name: formResult.name,
|
|
|
|
projection: formResult.projection,
|
2020-04-26 02:25:07 +08:00
|
|
|
position: formResult.position,
|
|
|
|
target: formResult.target,
|
2020-03-05 03:56:17 +08:00
|
|
|
}
|
|
|
|
if (this.isOrtho) preset.zoom = this.camOrtho.zoom;
|
|
|
|
|
|
|
|
let presets = localStorage.getItem('camera_presets');
|
|
|
|
try {
|
|
|
|
presets = JSON.parse(presets)||[]
|
|
|
|
} catch (err) {
|
|
|
|
presets = [];
|
|
|
|
}
|
|
|
|
presets.push(preset);
|
|
|
|
localStorage.setItem('camera_presets', JSON.stringify(presets))
|
|
|
|
|
|
|
|
dialog.hide()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
dialog.show()
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
//Orientation
|
2019-07-18 00:02:07 +08:00
|
|
|
getFacingDirection() {
|
|
|
|
var vec = new THREE.Vector3()
|
|
|
|
this.controls.object.getWorldDirection(vec)
|
|
|
|
vec.applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 4).ceil()
|
|
|
|
switch (vec.x+'_'+vec.z) {
|
|
|
|
case '1_1':
|
|
|
|
return 'south'
|
|
|
|
break;
|
|
|
|
case '0_0':
|
|
|
|
return 'north'
|
|
|
|
break;
|
|
|
|
case '1_0':
|
|
|
|
return 'east'
|
|
|
|
break;
|
|
|
|
case '0_1':
|
|
|
|
return 'west'
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getFacingHeight() {
|
|
|
|
var y = this.controls.object.getWorldDirection(new THREE.Vector3()).y
|
|
|
|
if (y > 0.5) {
|
|
|
|
return 'up'
|
|
|
|
} else if (y < -0.5) {
|
|
|
|
return 'down';
|
|
|
|
} else {
|
|
|
|
return 'middle'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//Controls
|
|
|
|
click(event) {
|
2020-01-24 01:53:36 +08:00
|
|
|
event.preventDefault();
|
|
|
|
$(':focus').blur();
|
2021-03-09 04:33:56 +08:00
|
|
|
if (open_menu) open_menu.hide();
|
2020-01-24 01:53:36 +08:00
|
|
|
unselectInterface(event);
|
2019-12-16 03:04:31 +08:00
|
|
|
convertTouchEvent(event);
|
2021-03-09 04:33:56 +08:00
|
|
|
Preview.selected = this;
|
2019-12-16 03:04:31 +08:00
|
|
|
this.static_rclick = event.which === 3 || event.type == 'touchstart';
|
2021-03-09 04:33:56 +08:00
|
|
|
|
2020-01-24 01:53:36 +08:00
|
|
|
if (event.type == 'touchstart') {
|
|
|
|
this.rclick_cooldown = setTimeout(() => {
|
|
|
|
this.rclick_cooldown = true;
|
|
|
|
}, 420)
|
2021-03-09 04:33:56 +08:00
|
|
|
Transformer.dispatchPointerHover(event);
|
2020-01-24 01:53:36 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Transformer.hoverAxis !== null || (!Keybinds.extra.preview_select.keybind.isTriggered(event) && event.which !== 0)) return;
|
|
|
|
|
2019-12-16 03:04:31 +08:00
|
|
|
var data = this.raycast(event);
|
2019-07-18 00:02:07 +08:00
|
|
|
if (data) {
|
2021-08-29 15:33:48 +08:00
|
|
|
this.selection.click_target = data;
|
|
|
|
|
2021-08-22 07:25:50 +08:00
|
|
|
let select_mode = BarItems.selection_mode.value
|
|
|
|
|
2021-07-28 23:49:09 +08:00
|
|
|
if (data.element && data.element.locked) {
|
2020-04-26 02:25:07 +08:00
|
|
|
$('#preview').css('cursor', 'not-allowed')
|
|
|
|
function resetCursor() {
|
|
|
|
$('#preview').css('cursor', (Toolbox.selected.cursor ? Toolbox.selected.cursor : 'default'))
|
|
|
|
removeEventListeners(document, 'mouseup touchend', resetCursor, false)
|
|
|
|
}
|
|
|
|
addEventListeners(document, 'mouseup touchend', resetCursor, false)
|
|
|
|
|
2021-07-28 23:49:09 +08:00
|
|
|
} else if (Toolbox.selected.selectElements && Modes.selected.selectElements && data.type === 'element') {
|
2021-08-30 16:30:46 +08:00
|
|
|
if (Toolbox.selected.selectFace && data.face) {
|
2021-09-08 03:14:33 +08:00
|
|
|
if (data.element instanceof Mesh && select_mode == 'face' && (event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift)) {
|
|
|
|
UVEditor.vue.selected_faces.safePush(data.face)
|
|
|
|
} else {
|
|
|
|
UVEditor.setFace(data.face, false);
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2019-08-18 00:26:14 +08:00
|
|
|
Blockbench.dispatchEvent('canvas_select', data)
|
|
|
|
if (Modes.paint) {
|
|
|
|
event = 0;
|
|
|
|
}
|
2021-07-28 23:49:09 +08:00
|
|
|
if (data.element.parent.type === 'group' && (
|
2019-08-01 06:01:47 +08:00
|
|
|
Animator.open ||
|
2021-08-03 17:04:40 +08:00
|
|
|
event.shiftKey || Pressing.overrides.shift ||
|
2021-06-12 18:53:40 +08:00
|
|
|
(!Format.rotate_cubes && Format.bone_rig && ['rotate_tool', 'pivot_tool'].includes(Toolbox.selected.id))
|
2019-08-01 06:01:47 +08:00
|
|
|
)) {
|
2021-07-28 23:49:09 +08:00
|
|
|
data.element.parent.select().showInOutliner();
|
2021-06-12 18:53:40 +08:00
|
|
|
|
|
|
|
} else if (!Animator.open) {
|
2021-08-22 07:25:50 +08:00
|
|
|
|
|
|
|
if (data.element instanceof Mesh && select_mode == 'face') {
|
|
|
|
if (!data.element.selected) data.element.select(event);
|
|
|
|
|
2021-09-12 21:09:01 +08:00
|
|
|
let mesh = data.element;
|
|
|
|
let selected_vertices = mesh.getSelectedVertices(true);
|
|
|
|
|
|
|
|
if (event.altKey || Pressing.overrides.alt) {
|
|
|
|
|
|
|
|
let mesh = data.element;
|
|
|
|
let start_face = mesh.faces[data.face];
|
|
|
|
if (!start_face) return;
|
|
|
|
let processed_faces = [];
|
|
|
|
function selectFace(face, index) {
|
|
|
|
if (processed_faces.includes(face)) return;
|
|
|
|
processed_faces.push(face);
|
2021-09-19 19:22:29 +08:00
|
|
|
if (start_face.vertices.length == 4 && face.vertices.length != 4) return;
|
2021-09-12 21:09:01 +08:00
|
|
|
let next = face.getAdjacentFace(index);
|
|
|
|
if (next) selectFace(next.face, next.index+2);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-09-18 04:32:53 +08:00
|
|
|
let face_test = start_face.getAdjacentFace(1);
|
|
|
|
let index = (face_test && face_test.face.isSelected()) ? 2 : 1;
|
2021-09-12 21:09:01 +08:00
|
|
|
selectFace(start_face, index);
|
2021-09-19 19:22:29 +08:00
|
|
|
if (start_face.vertices.length == 4) {
|
|
|
|
processed_faces.remove(start_face);
|
|
|
|
selectFace(start_face, (index+2) % 4);
|
|
|
|
}
|
2021-09-12 21:09:01 +08:00
|
|
|
|
|
|
|
if (!(event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift)) {
|
|
|
|
selected_vertices.empty();
|
|
|
|
UVEditor.vue.selected_faces.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
processed_faces.forEach(face => {
|
|
|
|
Project.selected_vertices[data.element.uuid].safePush(...face.vertices);
|
|
|
|
let fkey = face.getFaceKey();
|
|
|
|
UVEditor.vue.selected_faces.push(fkey);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
if (!(event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift)) {
|
|
|
|
selected_vertices.empty();
|
|
|
|
UVEditor.vue.selected_faces.empty();
|
|
|
|
}
|
|
|
|
Project.selected_vertices[data.element.uuid].safePush(...data.element.faces[data.face].vertices);
|
|
|
|
UVEditor.vue.selected_faces.safePush(data.face);
|
2021-08-22 07:25:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
data.element.select(event)
|
|
|
|
}
|
|
|
|
updateSelection();
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2020-10-11 00:31:56 +08:00
|
|
|
} else if (Animator.open && data.type == 'keyframe') {
|
|
|
|
if (data.keyframe instanceof Keyframe) {
|
|
|
|
data.keyframe.select(event).callPlayhead();
|
|
|
|
updateSelection();
|
|
|
|
}
|
2021-08-07 18:57:27 +08:00
|
|
|
|
|
|
|
} else if (data.type == 'vertex') {
|
|
|
|
|
|
|
|
if (!Project.selected_vertices[data.element.uuid]) {
|
|
|
|
Project.selected_vertices[data.element.uuid] = [];
|
|
|
|
}
|
|
|
|
let list = Project.selected_vertices[data.element.uuid];
|
|
|
|
|
2021-08-09 03:53:36 +08:00
|
|
|
if (event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift) {
|
2021-08-07 18:57:27 +08:00
|
|
|
list.toggle(data.vertex);
|
|
|
|
} else {
|
|
|
|
list.replace([data.vertex]);
|
|
|
|
}
|
|
|
|
updateSelection();
|
2021-09-01 02:49:07 +08:00
|
|
|
} else if (data.type == 'line') {
|
|
|
|
|
|
|
|
if (!Project.selected_vertices[data.element.uuid]) {
|
|
|
|
Project.selected_vertices[data.element.uuid] = [];
|
|
|
|
}
|
|
|
|
let list = Project.selected_vertices[data.element.uuid];
|
|
|
|
|
|
|
|
if (event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift) {
|
|
|
|
if (list.includes(data.vertices[0]) && list.includes(data.vertices[1])) {
|
|
|
|
list.remove(...data.vertices);
|
|
|
|
} else {
|
|
|
|
list.remove(...data.vertices);
|
|
|
|
list.push(...data.vertices);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
list.replace(data.vertices);
|
|
|
|
}
|
2021-09-10 05:46:03 +08:00
|
|
|
if (event.altKey || Pressing.overrides.alt) {
|
|
|
|
|
|
|
|
let mesh = data.element;
|
|
|
|
let start_face;
|
|
|
|
for (let fkey in mesh.faces) {
|
|
|
|
let face = mesh.faces[fkey];
|
|
|
|
if (face.vertices.length < 3) continue;
|
|
|
|
let vertices = face.vertices.filter(vkey => data.vertices.includes(vkey))
|
|
|
|
if (vertices.length >= 2) {
|
|
|
|
start_face = face;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!start_face) return;
|
|
|
|
let processed_faces = [start_face];
|
|
|
|
|
|
|
|
function splitFace(face, side_vertices) {
|
|
|
|
processed_faces.push(face);
|
|
|
|
let sorted_vertices = face.getSortedVertices();
|
|
|
|
|
|
|
|
let side_index_diff = sorted_vertices.indexOf(side_vertices[0]) - sorted_vertices.indexOf(side_vertices[1]);
|
|
|
|
if (side_index_diff == -1 || side_index_diff > 2) side_vertices.reverse();
|
|
|
|
|
|
|
|
let opposite_vertices = sorted_vertices.filter(vkey => !side_vertices.includes(vkey));
|
|
|
|
let opposite_index_diff = sorted_vertices.indexOf(opposite_vertices[0]) - sorted_vertices.indexOf(opposite_vertices[1]);
|
|
|
|
if (opposite_index_diff == 1 || opposite_index_diff < -2) opposite_vertices.reverse();
|
|
|
|
|
|
|
|
list.safePush(...side_vertices);
|
|
|
|
|
|
|
|
// Find next (and previous) face
|
|
|
|
function doNextFace(index) {
|
|
|
|
for (let fkey in mesh.faces) {
|
|
|
|
let ref_face = mesh.faces[fkey];
|
|
|
|
if (ref_face.vertices.length < 3 || processed_faces.includes(ref_face)) continue;
|
|
|
|
|
|
|
|
let sorted_vertices = ref_face.getSortedVertices();
|
|
|
|
let vertices = ref_face.vertices.filter(vkey => vkey == side_vertices[index] || vkey == opposite_vertices[index]);
|
|
|
|
|
|
|
|
if (vertices.length >= 2) {
|
|
|
|
let second_vertex = sorted_vertices.find((vkey, i) => {
|
|
|
|
return vkey !== side_vertices[index]
|
|
|
|
&& vkey !== opposite_vertices[index]
|
|
|
|
&& (sorted_vertices.length == 3 || Math.abs(sorted_vertices.indexOf(side_vertices[index]) - i) !== 2);
|
|
|
|
})
|
|
|
|
splitFace(ref_face, [side_vertices[index], second_vertex]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
doNextFace(0)
|
|
|
|
doNextFace(1);
|
|
|
|
}
|
|
|
|
splitFace(start_face, data.vertices);
|
|
|
|
}
|
2021-09-01 02:49:07 +08:00
|
|
|
updateSelection();
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
if (typeof Toolbox.selected.onCanvasClick === 'function') {
|
|
|
|
Toolbox.selected.onCanvasClick(data)
|
2020-05-31 21:54:04 +08:00
|
|
|
Blockbench.dispatchEvent('canvas_click', data)
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
return true;
|
2019-12-16 03:04:31 +08:00
|
|
|
}
|
|
|
|
if (typeof Toolbox.selected.onCanvasClick === 'function') {
|
2021-03-09 03:00:54 +08:00
|
|
|
Toolbox.selected.onCanvasClick({event})
|
2019-12-16 03:04:31 +08:00
|
|
|
}
|
|
|
|
|
2021-08-03 16:16:41 +08:00
|
|
|
if ((Keybinds.extra.preview_area_select.keybind.isTriggered(event)) || this.movingBackground) {
|
2019-07-18 00:02:07 +08:00
|
|
|
this.startSelRect(event)
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2019-12-16 03:04:31 +08:00
|
|
|
mousemove(event) {
|
2020-04-26 02:25:07 +08:00
|
|
|
if (Settings.get('highlight_cubes')) {
|
|
|
|
var data = this.raycast(event);
|
2021-08-03 04:55:30 +08:00
|
|
|
updateCubeHighlights(data && data.element);
|
2020-04-26 02:25:07 +08:00
|
|
|
}
|
2019-12-16 03:04:31 +08:00
|
|
|
}
|
2020-10-26 00:37:14 +08:00
|
|
|
mouseup(event) {
|
|
|
|
this.showContextMenu(event);
|
2021-09-15 06:26:07 +08:00
|
|
|
if (settings.canvas_unselect.value && event.which != 2 && this.controls.hasMoved === false && !this.selection.activated && !Transformer.dragging && !this.selection.click_target) {
|
2020-10-26 00:37:14 +08:00
|
|
|
unselectAll();
|
|
|
|
}
|
2021-08-29 15:33:48 +08:00
|
|
|
delete this.selection.click_target;
|
2020-10-26 00:37:14 +08:00
|
|
|
return this;
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
raycastMouseCoords(x,y) {
|
|
|
|
var scope = this;
|
|
|
|
var canvas_offset = $(scope.canvas).offset()
|
|
|
|
scope.mouse.x = ((x - canvas_offset.left) / scope.width) * 2 - 1;
|
|
|
|
scope.mouse.y = - ((y - canvas_offset.top) / scope.height) * 2 + 1;
|
|
|
|
scope.raycaster.setFromCamera( scope.mouse, scope.camOrtho );
|
|
|
|
return scope.raycaster.ray.origin
|
|
|
|
}
|
2019-12-16 03:04:31 +08:00
|
|
|
occupyTransformer(event) {
|
2020-07-16 15:32:59 +08:00
|
|
|
if (this == MediaPreview || Transformer.dragging) return this;
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
Transformer.camera = this.isOrtho ? this.camOrtho : this.camPers
|
|
|
|
Transformer.orbit_controls = this.controls
|
|
|
|
Transformer.setCanvas(this.canvas)
|
|
|
|
main_preview.controls.updateSceneScale()
|
|
|
|
if (quad_previews) {
|
|
|
|
quad_previews.hovered = this;
|
|
|
|
}
|
2019-12-16 03:04:31 +08:00
|
|
|
if (event && event.type == 'touchstart') {
|
|
|
|
Transformer.simulateMouseDown(event);
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
return this;
|
|
|
|
}
|
2019-12-16 03:04:31 +08:00
|
|
|
showContextMenu(event, force) {
|
|
|
|
Prop.active_panel = 'preview';
|
2020-01-24 01:53:36 +08:00
|
|
|
if (this.static_rclick && (event.which === 3 || (event.type == 'touchend' && this.rclick_cooldown == true))) {
|
2019-12-16 03:04:31 +08:00
|
|
|
var data = this.raycast(event)
|
2021-08-29 15:33:48 +08:00
|
|
|
if (data) this.selection.click_target = data;
|
2021-07-28 23:49:09 +08:00
|
|
|
if (Toolbox.selected.selectElements && Modes.selected.selectElements && data && data.element && !Modes.animate) {
|
|
|
|
data.element.showContextMenu(event);
|
2020-10-17 01:44:58 +08:00
|
|
|
|
|
|
|
} else if (data.type == 'keyframe') {
|
|
|
|
data.keyframe.showContextMenu(event);
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
} else {
|
|
|
|
this.menu.open(event, this)
|
|
|
|
}
|
|
|
|
}
|
2020-01-24 01:53:36 +08:00
|
|
|
clearTimeout(this.rclick_cooldown);
|
|
|
|
delete this.rclick_cooldown;
|
2019-07-18 00:02:07 +08:00
|
|
|
return this;
|
|
|
|
}
|
2020-10-22 00:31:26 +08:00
|
|
|
calculateControlScale(position) {
|
|
|
|
if (this.isOrtho) {
|
|
|
|
return 0.35 / this.camera.zoom;
|
|
|
|
} else {
|
|
|
|
var scaleVector = new THREE.Vector3();
|
|
|
|
var scale = scaleVector.subVectors(position, this.camera.position).length() / 4;
|
|
|
|
scale *= this.camera.fov / this.height;
|
|
|
|
return scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
//Selection Rectangle
|
|
|
|
startSelRect(event) {
|
|
|
|
var scope = this;
|
2019-08-18 00:26:14 +08:00
|
|
|
if (Modes.edit || this.movingBackground) {
|
2019-07-18 00:02:07 +08:00
|
|
|
this.sr_move_f = function(event) { scope.moveSelRect(event)}
|
|
|
|
this.sr_stop_f = function(event) { scope.stopSelRect(event)}
|
2019-12-16 03:04:31 +08:00
|
|
|
document.addEventListener('mousemove', this.sr_move_f, false)
|
2019-07-18 00:02:07 +08:00
|
|
|
document.addEventListener('mouseup', this.sr_stop_f, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
this.selection.start_x = event.offsetX+0
|
|
|
|
this.selection.start_y = event.offsetY+0
|
|
|
|
this.selection.client_x = event.clientX+0
|
2019-12-16 03:04:31 +08:00
|
|
|
this.selection.client_y = event.clientY+0
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
if (this.movingBackground) {
|
|
|
|
this.background.before = {
|
|
|
|
x: this.background.x,
|
|
|
|
y: this.background.y,
|
|
|
|
size: this.background.size
|
|
|
|
}
|
|
|
|
return
|
|
|
|
};
|
2020-10-04 05:51:24 +08:00
|
|
|
if (!Modes.edit || event.type == 'touchstart') return;
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2020-07-16 15:32:59 +08:00
|
|
|
$(this.node).append(this.selection.box)
|
2021-08-12 04:59:48 +08:00
|
|
|
this.selection.activated = false;
|
|
|
|
this.selection.old_selected = Outliner.selected.slice();
|
2021-08-07 18:57:27 +08:00
|
|
|
this.selection.old_vertices_selected = {};
|
|
|
|
for (let uuid in Project.selected_vertices) {
|
|
|
|
this.selection.old_vertices_selected[uuid] = Project.selected_vertices[uuid].slice();
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
this.moveSelRect(event)
|
|
|
|
}
|
|
|
|
moveSelRect(event) {
|
|
|
|
var scope = this;
|
|
|
|
|
|
|
|
if (this.movingBackground) {
|
2021-08-03 17:04:40 +08:00
|
|
|
if (event.shiftKey || Pressing.overrides.shift) {
|
2019-07-18 00:02:07 +08:00
|
|
|
this.background.size = limitNumber( this.background.before.size + (event.offsetY - this.selection.start_y), 0, 10e3)
|
|
|
|
} else {
|
2021-02-28 19:51:15 +08:00
|
|
|
this.background.x = this.background.before.x + (event.offsetX - this.selection.start_x);
|
|
|
|
this.background.y = this.background.before.y + (event.offsetY - this.selection.start_y);
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
this.updateBackground()
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Overlay
|
|
|
|
var c = getRectangle(
|
2019-12-16 03:04:31 +08:00
|
|
|
Math.clamp(this.selection.start_x, -2, this.width),
|
|
|
|
Math.clamp(this.selection.start_y, -2, this.height),
|
|
|
|
Math.clamp(this.selection.start_x + (event.clientX - this.selection.client_x), -2, this.width),
|
|
|
|
Math.clamp(this.selection.start_y + (event.clientY - this.selection.client_y), -2, this.height),
|
2019-07-18 00:02:07 +08:00
|
|
|
)
|
|
|
|
this.selection.box.css('left', c.ax+'px')
|
|
|
|
this.selection.box.css('top', c.ay+'px')
|
|
|
|
|
|
|
|
this.selection.box.css('width', c.x+'px')
|
|
|
|
this.selection.box.css('height',c.y+'px')
|
|
|
|
|
|
|
|
if (c.x + c.y > 40) {
|
|
|
|
this.selection.activated = true
|
|
|
|
}
|
|
|
|
|
|
|
|
//Select
|
|
|
|
if (!this.selection.activated) return;
|
2021-09-01 22:23:36 +08:00
|
|
|
|
|
|
|
let vector = new THREE.Vector3();
|
|
|
|
let rect_start = [c.ax, c.ay];
|
|
|
|
let rect_end = [c.bx, c.by];
|
|
|
|
let extend_selection = (event.shiftKey || event.ctrlOrCmd || Pressing.overrides.ctrl || Pressing.overrides.shift)
|
|
|
|
let selection_mode = BarItems.selection_mode.value;
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2021-09-01 22:23:36 +08:00
|
|
|
let widthHalf = 0.5 * scope.canvas.width / window.devicePixelRatio;
|
|
|
|
let heightHalf = 0.5 * scope.canvas.height / window.devicePixelRatio;
|
2021-08-03 16:16:41 +08:00
|
|
|
|
2021-09-01 22:23:36 +08:00
|
|
|
function projectPoint(vector) {
|
|
|
|
vector.project(scope.camera);
|
|
|
|
return [
|
|
|
|
( vector.x * widthHalf ) + widthHalf,
|
|
|
|
-( vector.y * heightHalf ) + heightHalf
|
|
|
|
]
|
2021-08-03 16:16:41 +08:00
|
|
|
}
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
unselectAll()
|
2021-08-07 02:41:45 +08:00
|
|
|
Outliner.elements.forEach((element) => {
|
2021-08-03 16:16:41 +08:00
|
|
|
let isSelected;
|
2021-09-08 15:55:06 +08:00
|
|
|
if (extend_selection && scope.selection.old_selected.includes(element) && (element instanceof Mesh == false || selection_mode == 'object')) {
|
2021-08-03 16:16:41 +08:00
|
|
|
isSelected = true
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2021-08-03 16:16:41 +08:00
|
|
|
} else if (element.visibility) {
|
|
|
|
if (element.mesh && element.mesh.geometry) {
|
2021-09-01 22:23:36 +08:00
|
|
|
let {mesh} = element;
|
|
|
|
|
|
|
|
if (element instanceof Mesh && (selection_mode == 'object' || scope.selection.old_selected.includes(element))) {
|
|
|
|
|
|
|
|
let selected_vertices;
|
|
|
|
if (selection_mode != 'object') {
|
|
|
|
isSelected = true;
|
|
|
|
if (!Project.selected_vertices[element.uuid]) {
|
|
|
|
selected_vertices = Project.selected_vertices[element.uuid] = [];
|
|
|
|
} else {
|
|
|
|
selected_vertices = Project.selected_vertices[element.uuid];
|
|
|
|
}
|
|
|
|
if (!extend_selection) selected_vertices.empty();
|
|
|
|
}
|
2021-08-03 16:16:41 +08:00
|
|
|
|
2021-09-01 22:23:36 +08:00
|
|
|
let vertex_points = {};
|
|
|
|
for (let vkey in element.vertices) {
|
|
|
|
let point = projectPoint( mesh.localToWorld(vector.fromArray(element.vertices[vkey])) );
|
|
|
|
vertex_points[vkey] = point;
|
|
|
|
}
|
|
|
|
if (selection_mode == 'vertex') {
|
|
|
|
for (let vkey in element.vertices) {
|
|
|
|
let point = vertex_points[vkey];
|
2021-09-08 15:55:06 +08:00
|
|
|
if (
|
|
|
|
(extend_selection && this.selection.old_vertices_selected[element.uuid] && this.selection.old_vertices_selected[element.uuid].includes(vkey)) ||
|
|
|
|
pointInRectangle(point, rect_start, rect_end)
|
|
|
|
) {
|
2021-09-01 22:23:36 +08:00
|
|
|
selected_vertices.safePush(vkey);
|
|
|
|
}
|
|
|
|
}
|
2021-08-07 18:57:27 +08:00
|
|
|
|
2021-09-08 00:19:39 +08:00
|
|
|
} else if (selection_mode == 'line') {
|
|
|
|
for (let fkey in element.faces) {
|
|
|
|
let face = element.faces[fkey];
|
|
|
|
let vertices = face.getSortedVertices();
|
|
|
|
for (let i = 0; i < vertices.length; i++) {
|
|
|
|
let vkey = vertices[i];
|
|
|
|
let vkey2 = vertices[i+1]||vertices[0];
|
|
|
|
let p1 = vertex_points[vkey];
|
|
|
|
let p2 = vertex_points[vkey2];
|
|
|
|
if (lineIntersectsReactangle(p1, p2, rect_start, rect_end)) {
|
|
|
|
selected_vertices.safePush(vkey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-07 18:57:27 +08:00
|
|
|
} else {
|
2021-09-01 22:23:36 +08:00
|
|
|
for (let fkey in element.faces) {
|
|
|
|
let face = element.faces[fkey];
|
|
|
|
let vertices = face.getSortedVertices();
|
|
|
|
let face_intersects;
|
|
|
|
for (let i = 0; i < vertices.length; i++) {
|
|
|
|
let vkey = vertices[i];
|
|
|
|
let vkey2 = vertices[i+1]||vertices[0];
|
|
|
|
let p1 = vertex_points[vkey];
|
|
|
|
let p2 = vertex_points[vkey2];
|
|
|
|
if (lineIntersectsReactangle(p1, p2, rect_start, rect_end)) {
|
|
|
|
face_intersects = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (face_intersects && selection_mode == 'object') {
|
|
|
|
if (face_intersects) {
|
|
|
|
isSelected = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (face_intersects) {
|
|
|
|
selected_vertices.safePush(...face.vertices);
|
|
|
|
UVEditor.vue.selected_faces.safePush(fkey);
|
|
|
|
} else {
|
|
|
|
UVEditor.vue.selected_faces.remove(fkey);
|
|
|
|
}
|
|
|
|
}
|
2021-08-07 18:57:27 +08:00
|
|
|
}
|
|
|
|
}
|
2021-09-01 22:23:36 +08:00
|
|
|
|
|
|
|
} else if (element instanceof Cube) {
|
|
|
|
let vertices = [
|
|
|
|
[element.from[0] - element.inflate, element.from[1] - element.inflate, element.from[2] - element.inflate],
|
|
|
|
[element.from[0] - element.inflate, element.from[1] - element.inflate, element.to[2] + element.inflate],
|
|
|
|
[element.from[0] - element.inflate, element.to[1] + element.inflate, element.to[2] + element.inflate],
|
|
|
|
[element.from[0] - element.inflate, element.to[1] + element.inflate, element.from[2] - element.inflate],
|
|
|
|
[element.to[0] + element.inflate, element.from[1] - element.inflate, element.from[2] - element.inflate],
|
|
|
|
[element.to[0] + element.inflate, element.from[1] - element.inflate, element.to[2] + element.inflate],
|
|
|
|
[element.to[0] + element.inflate, element.to[1] + element.inflate, element.to[2] + element.inflate],
|
|
|
|
[element.to[0] + element.inflate, element.to[1] + element.inflate, element.from[2] - element.inflate],
|
|
|
|
].map(coords => {
|
2021-09-07 18:25:41 +08:00
|
|
|
coords.V3_subtract(element.origin);
|
2021-09-01 22:23:36 +08:00
|
|
|
vector.fromArray(coords);
|
|
|
|
mesh.localToWorld(vector);
|
|
|
|
return projectPoint(vector);
|
|
|
|
})
|
|
|
|
isSelected = lineIntersectsReactangle(vertices[0], vertices[1], rect_start, rect_end)
|
|
|
|
|| lineIntersectsReactangle(vertices[1], vertices[2], rect_start, rect_end)
|
|
|
|
|| lineIntersectsReactangle(vertices[2], vertices[3], rect_start, rect_end)
|
|
|
|
|| lineIntersectsReactangle(vertices[3], vertices[0], rect_start, rect_end)
|
|
|
|
|
|
|
|
|| lineIntersectsReactangle(vertices[4], vertices[5], rect_start, rect_end)
|
|
|
|
|| lineIntersectsReactangle(vertices[5], vertices[6], rect_start, rect_end)
|
|
|
|
|| lineIntersectsReactangle(vertices[6], vertices[7], rect_start, rect_end)
|
|
|
|
|| lineIntersectsReactangle(vertices[7], vertices[4], rect_start, rect_end)
|
|
|
|
|
|
|
|
|| lineIntersectsReactangle(vertices[0], vertices[4], rect_start, rect_end)
|
|
|
|
|| lineIntersectsReactangle(vertices[1], vertices[5], rect_start, rect_end)
|
|
|
|
|| lineIntersectsReactangle(vertices[2], vertices[6], rect_start, rect_end)
|
|
|
|
|| lineIntersectsReactangle(vertices[3], vertices[7], rect_start, rect_end)
|
2021-08-07 18:57:27 +08:00
|
|
|
}
|
2021-09-01 22:23:36 +08:00
|
|
|
|
|
|
|
} else if (element.mesh) {
|
|
|
|
|
|
|
|
element.mesh.getWorldPosition(vector);
|
|
|
|
isSelected = pointInRectangle(projectPoint(vector), rect_start, rect_end);
|
2021-08-07 18:57:27 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2021-09-01 22:23:36 +08:00
|
|
|
if (isSelected) {
|
|
|
|
element.selectLow();
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
})
|
2020-03-05 03:56:17 +08:00
|
|
|
TickUpdates.selection = true;
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
stopSelRect(event) {
|
2019-12-16 03:04:31 +08:00
|
|
|
document.removeEventListener('mousemove', this.sr_move_f)
|
2019-07-18 00:02:07 +08:00
|
|
|
document.removeEventListener('mouseup', this.sr_stop_f)
|
|
|
|
if (this.movingBackground) {
|
|
|
|
delete this.background.before
|
|
|
|
return
|
|
|
|
};
|
|
|
|
this.selection.box.detach()
|
|
|
|
this.selection.activated = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Backgrounds
|
|
|
|
getBackground() {
|
|
|
|
if (display_mode) {
|
|
|
|
var id = displayReferenceObjects.active.id
|
|
|
|
if (id == 'monitor' ||id == 'bow') {
|
|
|
|
this.background = canvas_scenes.monitor
|
|
|
|
} else if (['inventory_nine', 'inventory_full', 'hud'].includes(id)) {
|
|
|
|
this.background = canvas_scenes[id]
|
|
|
|
} else {
|
|
|
|
this.background = canvas_scenes.normal
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
} else if (this.angle !== null) {
|
2021-02-14 05:08:20 +08:00
|
|
|
this.background = canvas_scenes['ortho_'+this.angle]
|
2019-12-16 03:04:31 +08:00
|
|
|
} else {
|
2019-07-18 00:02:07 +08:00
|
|
|
this.background = canvas_scenes.normal
|
|
|
|
}
|
|
|
|
return this.background
|
|
|
|
}
|
|
|
|
loadBackground() {
|
|
|
|
this.getBackground()
|
|
|
|
if (this.background && this.background.image) {
|
2021-06-12 17:34:47 +08:00
|
|
|
let background_image = `url("${this.background.image.replace(/\\/g, '/').replace(/#/g, '%23')}")`;
|
|
|
|
this.canvas.style.setProperty('background-image', background_image)
|
|
|
|
this.node.querySelector('.preview_background_menu').style.setProperty('background-image', background_image);
|
|
|
|
this.node.querySelector('.preview_background_menu').style.display = 'block';
|
2019-07-18 00:02:07 +08:00
|
|
|
} else {
|
2021-01-31 19:51:10 +08:00
|
|
|
this.canvas.style.setProperty('background-image', 'none')
|
2021-06-12 17:34:47 +08:00
|
|
|
this.node.querySelector('.preview_background_menu').style.display = 'none';
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
this.updateBackground()
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
updateBackground() {
|
|
|
|
if (!this.background) return;
|
|
|
|
var bg = this.background
|
2020-03-05 03:56:17 +08:00
|
|
|
var zoom = (this.angle !== null && bg.lock === true) ? this.camOrtho.zoom : 1
|
2019-07-18 00:02:07 +08:00
|
|
|
var pos_x = 0;
|
|
|
|
var pos_y = 0;
|
2020-03-05 03:56:17 +08:00
|
|
|
if (this.angle !== null && bg.lock !== false) {
|
2019-07-18 00:02:07 +08:00
|
|
|
pos_x = this.camOrtho.backgroundHandle[0].n === true ? 1 : -1
|
|
|
|
pos_x *= this.controls.target[this.camOrtho.backgroundHandle[0].a] * zoom * 40
|
|
|
|
pos_y = this.camOrtho.backgroundHandle[1].n === true ? 1 : -1
|
|
|
|
pos_y *= this.controls.target[this.camOrtho.backgroundHandle[1].a] * zoom * 40
|
|
|
|
}
|
|
|
|
pos_x += (bg.x * zoom) + this.width/2 - ( bg.size * zoom) / 2
|
|
|
|
pos_y += (bg.y * zoom) + this.height/2 -((bg.size / bg.ratio||1) * zoom) / 2
|
|
|
|
|
2021-01-31 19:51:10 +08:00
|
|
|
this.canvas.style.setProperty('background-position-x', pos_x + 'px')
|
|
|
|
this.canvas.style.setProperty('background-position-y', pos_y + 'px')
|
|
|
|
this.canvas.style.setProperty('background-size', bg.size * zoom +'px')
|
2019-07-18 00:02:07 +08:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
clearBackground() {
|
|
|
|
this.loadBackground()
|
|
|
|
this.background.image = false
|
|
|
|
this.background.size = limitNumber(this.background.size, 100, 2400)
|
|
|
|
this.background.x = limitNumber(this.background.x, 0, this.width-30)
|
|
|
|
this.background.y = limitNumber(this.background.y, 0, this.height-30)
|
|
|
|
this.loadBackground()
|
2020-09-21 23:01:26 +08:00
|
|
|
Settings.saveLocalStorages()
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
restoreBackground() {
|
|
|
|
this.loadBackground()
|
|
|
|
if (this.background && this.background.defaults) {
|
|
|
|
this.background.image = this.background.defaults.image || false;
|
|
|
|
this.background.size = this.background.defaults.size || 1000
|
|
|
|
this.background.x = this.background.defaults.x || 0
|
|
|
|
this.background.y = this.background.defaults.y || 0
|
|
|
|
}
|
|
|
|
this.loadBackground()
|
|
|
|
Settings.saveLocalStorages()
|
2019-07-18 00:02:07 +08:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
startMovingBackground() {
|
2019-12-16 03:04:31 +08:00
|
|
|
if (this.movingBackground) {
|
|
|
|
this.stopMovingBackground()
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
this.movingBackground = true;
|
|
|
|
this.controls.enabled_before = this.controls.enabled
|
|
|
|
this.controls.enabled = false
|
2020-09-21 23:01:26 +08:00
|
|
|
|
2021-03-21 03:55:57 +08:00
|
|
|
this.position_toast = Blockbench.showToastNotification({
|
2021-02-28 19:51:15 +08:00
|
|
|
text: 'message.drag_background',
|
|
|
|
icon: 'open_with',
|
|
|
|
click: () => {
|
|
|
|
this.stopMovingBackground();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
stopMovingBackground() {
|
|
|
|
this.movingBackground = false;
|
|
|
|
this.controls.enabled = this.controls.enabled_before
|
|
|
|
delete this.controls.enabled_before
|
2021-03-21 03:55:57 +08:00
|
|
|
if (this.position_toast) {
|
|
|
|
this.position_toast.delete();
|
|
|
|
delete this.position_toast;
|
|
|
|
}
|
2020-09-21 23:01:26 +08:00
|
|
|
Settings.saveLocalStorages()
|
|
|
|
return this;
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
backgroundPositionDialog() {
|
|
|
|
var scope = this;
|
2019-12-16 03:04:31 +08:00
|
|
|
if (this.movingBackground) {
|
|
|
|
this.stopMovingBackground()
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
var dialog = new Dialog({
|
|
|
|
id: 'background_position',
|
|
|
|
title: tl('message.set_background_position.title'),
|
|
|
|
lines: [
|
|
|
|
`<div class="dialog_bar">
|
|
|
|
<input type="number" class="dark_bordered" value="${scope.background.x}" id="background_pos_x">
|
|
|
|
<input type="number" class="dark_bordered" value="${scope.background.y}" id="background_pos_y">
|
|
|
|
<input type="number" class="dark_bordered" value="${scope.background.size}" id="background_size">
|
|
|
|
</div>`
|
|
|
|
],
|
|
|
|
onConfirm: function() {
|
|
|
|
var coords = [
|
|
|
|
parseFloat( $(dialog.object).find('#background_pos_x').val() ),
|
|
|
|
parseFloat( $(dialog.object).find('#background_pos_y').val() ),
|
|
|
|
parseFloat( $(dialog.object).find('#background_size').val() )
|
|
|
|
]
|
|
|
|
dialog.hide()
|
|
|
|
if (!scope.background) return;
|
|
|
|
|
|
|
|
if (!isNaN(coords[0])) { scope.background.x = coords[0] }
|
|
|
|
if (!isNaN(coords[1])) { scope.background.y = coords[1] }
|
|
|
|
if (!isNaN(coords[2])) { scope.background.size = coords[2] }
|
|
|
|
|
|
|
|
scope.updateBackground()
|
2020-09-21 23:01:26 +08:00
|
|
|
Settings.saveLocalStorages()
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
dialog.show()
|
|
|
|
}
|
|
|
|
//Misc
|
|
|
|
screenshot(options, cb) {
|
|
|
|
var scope = this;
|
2019-12-16 03:04:31 +08:00
|
|
|
if (!options) options = 0;
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2019-09-04 15:52:21 +08:00
|
|
|
Canvas.withoutGizmos(function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2019-09-04 15:52:21 +08:00
|
|
|
scope.render()
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2019-12-23 00:33:55 +08:00
|
|
|
if (options.crop == false && !options.width && !options.height) {
|
2020-07-16 15:32:59 +08:00
|
|
|
var dataUrl = scope.canvas.toDataURL()
|
2019-12-23 00:33:55 +08:00
|
|
|
Screencam.returnScreenshot(dataUrl, cb)
|
2020-07-16 15:32:59 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.crop !== false && !(display_mode && display_slot === 'gui') && !options.width && !options.height) {
|
|
|
|
let frame = new CanvasFrame(scope.canvas);
|
|
|
|
frame.autoCrop()
|
|
|
|
Screencam.returnScreenshot(frame.canvas.toDataURL(), cb)
|
|
|
|
return;
|
2019-12-23 00:33:55 +08:00
|
|
|
}
|
|
|
|
|
2020-08-05 22:40:55 +08:00
|
|
|
var dataUrl = scope.canvas.toDataURL()
|
2019-09-04 15:52:21 +08:00
|
|
|
dataUrl = dataUrl.replace('data:image/png;base64,','')
|
|
|
|
Jimp.read(Buffer.from(dataUrl, 'base64')).then(function(image) {
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2019-12-23 00:33:55 +08:00
|
|
|
if (display_mode && display_slot === 'gui' && options.crop !== false) {
|
2019-09-04 15:52:21 +08:00
|
|
|
var zoom = display_preview.camOrtho.zoom * devicePixelRatio
|
|
|
|
var resolution = 256 * zoom;
|
|
|
|
|
|
|
|
var start_x = display_preview.width *devicePixelRatio/2 - display_preview.controls.target.x*zoom*40 - resolution/2;
|
|
|
|
var start_y = display_preview.height*devicePixelRatio/2 + display_preview.controls.target.y*zoom*40 - resolution/2;
|
|
|
|
|
|
|
|
image.crop(start_x, start_y, resolution, resolution)
|
|
|
|
} else {
|
2019-12-16 03:04:31 +08:00
|
|
|
if (options.crop !== false) {
|
|
|
|
image.autocrop([0, false])
|
|
|
|
}
|
2019-09-04 15:52:21 +08:00
|
|
|
if (options && options.width && options.height) {
|
|
|
|
image.contain(options.width, options.height)
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
|
2019-09-04 15:52:21 +08:00
|
|
|
image.getBase64(Jimp.MIME_PNG, function(a, dataUrl){
|
|
|
|
Screencam.returnScreenshot(dataUrl, cb)
|
|
|
|
})
|
|
|
|
});
|
2019-07-18 00:02:07 +08:00
|
|
|
})
|
2019-09-04 15:52:21 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
fullscreen() {
|
|
|
|
if (quad_previews.current) {
|
|
|
|
quad_previews.current.controls.stopMovement()
|
|
|
|
}
|
2020-10-11 00:31:56 +08:00
|
|
|
Preview.selected = this;
|
2019-07-18 00:02:07 +08:00
|
|
|
quad_previews.enabled = false;
|
|
|
|
$('#preview').empty()
|
|
|
|
|
|
|
|
var wrapper = $('<div class="single_canvas_wrapper"></div>')
|
2020-07-16 15:32:59 +08:00
|
|
|
wrapper.append(this.node)
|
2019-07-18 00:02:07 +08:00
|
|
|
$('#preview').append(wrapper)
|
|
|
|
|
2020-07-16 15:32:59 +08:00
|
|
|
Preview.all.forEach(function(prev) {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (prev.canvas.isConnected) {
|
|
|
|
prev.resize()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
if (Interface.data) {
|
|
|
|
updateInterfacePanels()
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
toggleFullscreen() {
|
|
|
|
if (quad_previews.enabled) {
|
|
|
|
this.fullscreen()
|
|
|
|
} else {
|
|
|
|
openQuadView()
|
|
|
|
}
|
|
|
|
}
|
2020-11-28 06:23:16 +08:00
|
|
|
delete() {
|
|
|
|
this.renderer.dispose();
|
|
|
|
this.canvas.remove();
|
|
|
|
this.node.remove();
|
|
|
|
Blockbench.removeDragHandler('preview_'+this.id)
|
|
|
|
if (Preview.selected == this) {
|
|
|
|
Preview.selected = Preview.all.find(preview => preview.canvas.isConnected);
|
|
|
|
}
|
|
|
|
Preview.all.remove(this);
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
Preview.prototype.menu = new Menu([
|
2020-03-05 03:56:17 +08:00
|
|
|
'screenshot_model',
|
2019-07-18 00:02:07 +08:00
|
|
|
{icon: 'icon-player', name: 'settings.display_skin', condition: () => (display_mode && displayReferenceObjects.active.id === 'player'), click: function() {
|
|
|
|
changeDisplaySkin()
|
|
|
|
}},
|
2020-03-05 03:56:17 +08:00
|
|
|
'preview_checkerboard',
|
2021-06-12 17:34:47 +08:00
|
|
|
{id: 'background', icon: 'wallpaper', name: 'menu.preview.background', children(preview) {
|
2019-07-18 00:02:07 +08:00
|
|
|
var has_background = !!preview.background.image
|
2021-06-12 18:53:40 +08:00
|
|
|
function applyBackground(image) {
|
|
|
|
if (!preview.background.image) {
|
|
|
|
preview.background.save_in_project = null;
|
|
|
|
}
|
|
|
|
preview.background.image = image;
|
|
|
|
preview.loadBackground();
|
|
|
|
Settings.saveLocalStorages();
|
2021-06-23 05:48:28 +08:00
|
|
|
preview.startMovingBackground();
|
2021-06-12 18:53:40 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
return [
|
|
|
|
{icon: 'folder', name: 'menu.preview.background.load', click: function(preview) {
|
|
|
|
Blockbench.import({
|
2020-04-26 02:25:07 +08:00
|
|
|
resource_id: 'preview_background',
|
2019-07-18 00:02:07 +08:00
|
|
|
extensions: ['png', 'jpg', 'jpeg', 'bmp', 'tiff', 'tif', 'gif'],
|
|
|
|
type: 'Image',
|
|
|
|
readtype: 'image'
|
|
|
|
}, function(files) {
|
|
|
|
if (files) {
|
2021-06-12 18:53:40 +08:00
|
|
|
applyBackground(isApp ? files[0].path : files[0].content);
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
}, 'image', false)
|
|
|
|
}},
|
2021-01-17 06:37:58 +08:00
|
|
|
{icon: 'fa-clipboard', name: 'menu.preview.background.clipboard', click: function(preview) {
|
|
|
|
if (isApp) {
|
|
|
|
var image = clipboard.readImage().toDataURL();
|
2021-06-12 22:41:10 +08:00
|
|
|
if (image.length > 32) applyBackground(image);
|
2021-01-17 06:37:58 +08:00
|
|
|
} else {
|
|
|
|
navigator.clipboard.read().then(content => {
|
|
|
|
if (content && content[0] && content[0].types.includes('image/png')) {
|
|
|
|
content[0].getType('image/png').then(blob => {
|
|
|
|
let url = URL.createObjectURL(blob);
|
2021-06-12 22:41:10 +08:00
|
|
|
if (image.length > 32) applyBackground(url);
|
2021-01-17 06:37:58 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
2020-01-24 01:53:36 +08:00
|
|
|
}
|
|
|
|
}},
|
2019-07-18 00:02:07 +08:00
|
|
|
{icon: 'photo_size_select_large', name: 'menu.preview.background.position', condition: has_background, click: function(preview) {
|
|
|
|
preview.startMovingBackground()
|
|
|
|
}},
|
|
|
|
{icon: 'photo_size_select_large', name: 'menu.preview.background.set_position', condition: has_background, click: function(preview) {
|
|
|
|
preview.backgroundPositionDialog()
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
name: 'menu.preview.background.lock',
|
2020-03-05 03:56:17 +08:00
|
|
|
condition: (has_background && preview.background.lock !== null && preview.angle !== null),
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: preview.background.lock?'check_box':'check_box_outline_blank',
|
|
|
|
click: function(preview) {
|
|
|
|
preview.background.lock = !preview.background.lock
|
|
|
|
preview.updateBackground()
|
|
|
|
}},
|
2020-03-05 03:56:17 +08:00
|
|
|
{icon: 'clear', name: 'generic.remove', condition: has_background, click: function(preview) {
|
2019-07-18 00:02:07 +08:00
|
|
|
preview.clearBackground()
|
2020-09-21 23:01:26 +08:00
|
|
|
}},
|
|
|
|
{icon: 'restore', name: 'generic.restore', condition: (preview) => (preview.background && preview.background.defaults.image), click: function(preview) {
|
|
|
|
// ToDo: condition, save local storage, name and icon
|
|
|
|
preview.restoreBackground()
|
2019-07-18 00:02:07 +08:00
|
|
|
}}
|
|
|
|
]
|
|
|
|
}},
|
2020-03-05 03:56:17 +08:00
|
|
|
'_',
|
2020-07-16 15:32:59 +08:00
|
|
|
'focus_on_selection',
|
2020-03-05 03:56:17 +08:00
|
|
|
{icon: 'add_a_photo', name: 'menu.preview.save_angle', condition(preview) {return !preview.movingBackground && !Modes.display}, click(preview) {
|
|
|
|
preview.newAnglePreset()
|
|
|
|
}},
|
2021-06-12 17:34:47 +08:00
|
|
|
{id: 'angle', icon: 'videocam', name: 'menu.preview.angle', condition(preview) {return !preview.movingBackground && !Modes.display}, children: function(preview) {
|
2020-03-05 03:56:17 +08:00
|
|
|
var children = [
|
2019-07-18 00:02:07 +08:00
|
|
|
]
|
2020-03-05 03:56:17 +08:00
|
|
|
let presets = localStorage.getItem('camera_presets')
|
2021-04-27 23:22:54 +08:00
|
|
|
presets = (presets && autoParseJSON(presets, false)) || [];
|
2020-03-05 03:56:17 +08:00
|
|
|
let all_presets = [...DefaultCameraPresets, ...presets];
|
|
|
|
|
|
|
|
all_presets.forEach(preset => {
|
2021-02-14 05:08:20 +08:00
|
|
|
let icon = typeof preset.locked_angle ? 'videocam' : (preset.locked_angle == preview.angle ? 'radio_button_checked' : 'radio_button_unchecked');
|
2020-03-05 03:56:17 +08:00
|
|
|
children.push({
|
|
|
|
name: preset.name,
|
|
|
|
color: preset.color,
|
|
|
|
id: preset.name,
|
|
|
|
icon,
|
|
|
|
click: preset.default ? () => {
|
|
|
|
preview.loadAnglePreset(preset)
|
|
|
|
} : null,
|
|
|
|
children: !preset.default && [
|
|
|
|
{icon: 'check_circle', name: 'menu.preview.angle.load', click() {
|
|
|
|
preview.loadAnglePreset(preset)
|
|
|
|
}},
|
2021-04-27 23:22:54 +08:00
|
|
|
{icon: 'edit', name: 'menu.preview.angle.edit', click() {
|
|
|
|
editCameraPreset(preset, presets);
|
|
|
|
}},
|
2020-03-05 03:56:17 +08:00
|
|
|
{icon: 'delete', name: 'generic.delete', click() {
|
2021-04-27 23:22:54 +08:00
|
|
|
presets.remove(preset);
|
|
|
|
localStorage.setItem('camera_presets', JSON.stringify(presets));
|
2020-03-05 03:56:17 +08:00
|
|
|
}}
|
|
|
|
]
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
return children;
|
2019-07-18 00:02:07 +08:00
|
|
|
}},
|
2020-03-05 03:56:17 +08:00
|
|
|
{icon: (preview) => (preview.isOrtho ? 'check_box' : 'check_box_outline_blank'), name: 'menu.preview.orthographic', click: function(preview) {
|
2021-02-20 07:02:56 +08:00
|
|
|
preview.setProjectionMode(!preview.isOrtho, true);
|
2020-03-05 03:56:17 +08:00
|
|
|
}},
|
|
|
|
'_',
|
2021-06-16 01:05:24 +08:00
|
|
|
{icon: 'grid_view', name: 'menu.preview.quadview', condition: function(preview) {return !quad_previews.enabled && !preview.movingBackground && !Modes.display && !Animator.open}, click: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
openQuadView()
|
|
|
|
}},
|
2020-03-05 03:56:17 +08:00
|
|
|
{icon: 'web_asset', name: 'menu.preview.maximize', condition: function(preview) {return quad_previews.enabled && !preview.movingBackground && !Modes.display}, click: function(preview) {
|
2019-07-18 00:02:07 +08:00
|
|
|
preview.fullscreen()
|
|
|
|
}},
|
|
|
|
{icon: 'cancel', color: 'x', name: 'menu.preview.stop_drag', condition: function(preview) {return preview.movingBackground;}, click: function(preview) {
|
|
|
|
preview.stopMovingBackground()
|
|
|
|
}}
|
|
|
|
])
|
|
|
|
|
2020-07-16 15:32:59 +08:00
|
|
|
Preview.all = [];
|
|
|
|
|
2021-08-07 18:57:27 +08:00
|
|
|
Blockbench.on('update_camera_position', e => {
|
|
|
|
let scale = Preview.selected.calculateControlScale(new THREE.Vector3(0, 0, 0));
|
|
|
|
Preview.all.forEach(preview => {
|
2021-09-07 18:25:41 +08:00
|
|
|
if (preview.canvas.isConnected) {
|
2021-09-16 06:49:57 +08:00
|
|
|
preview.raycaster.params.Points.threshold = scale * 0.8;
|
|
|
|
preview.raycaster.params.Line.threshold = scale * 0.42;
|
2021-08-07 18:57:27 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
function openQuadView() {
|
|
|
|
quad_previews.enabled = true;
|
|
|
|
|
|
|
|
$('#preview').empty()
|
|
|
|
|
|
|
|
var wrapper1 = $('<div class="quad_canvas_wrapper qcw_x qcw_y"></div>')
|
2020-07-16 15:32:59 +08:00
|
|
|
wrapper1.append(quad_previews.one.node)
|
2019-07-18 00:02:07 +08:00
|
|
|
$('#preview').append(wrapper1)
|
|
|
|
|
|
|
|
var wrapper2 = $('<div class="quad_canvas_wrapper qcw_y"></div>')
|
2020-07-16 15:32:59 +08:00
|
|
|
wrapper2.append(quad_previews.two.node)
|
2019-07-18 00:02:07 +08:00
|
|
|
$('#preview').append(wrapper2)
|
|
|
|
|
|
|
|
var wrapper3 = $('<div class="quad_canvas_wrapper qcw_x"></div>')
|
2020-07-16 15:32:59 +08:00
|
|
|
wrapper3.append(quad_previews.three.node)
|
2019-07-18 00:02:07 +08:00
|
|
|
$('#preview').append(wrapper3)
|
|
|
|
|
|
|
|
var wrapper4 = $('<div class="quad_canvas_wrapper"></div>')
|
2020-07-16 15:32:59 +08:00
|
|
|
wrapper4.append(quad_previews.four.node)
|
2019-07-18 00:02:07 +08:00
|
|
|
$('#preview').append(wrapper4)
|
|
|
|
|
|
|
|
updateInterface()
|
|
|
|
}
|
|
|
|
|
2021-04-27 23:22:54 +08:00
|
|
|
function editCameraPreset(preset, presets) {
|
|
|
|
let {name, projection, position, target, zoom} = preset;
|
|
|
|
|
|
|
|
let dialog = new Dialog({
|
|
|
|
id: 'edit_angle',
|
|
|
|
title: 'menu.preview.angle.edit',
|
|
|
|
form: {
|
|
|
|
name: {label: 'generic.name', value: name},
|
|
|
|
projection: {label: 'dialog.save_angle.projection', type: 'select', value: projection, options: {
|
|
|
|
unset: 'generic.unset',
|
|
|
|
perspective: 'dialog.save_angle.projection.perspective',
|
|
|
|
orthographic: 'dialog.save_angle.projection.orthographic'
|
|
|
|
}},
|
|
|
|
position: {label: 'dialog.save_angle.position', type: 'vector', dimensions: 3, value: position},
|
|
|
|
target: {label: 'dialog.save_angle.target', type: 'vector', dimensions: 3, value: target},
|
|
|
|
zoom: {label: 'dialog.save_angle.zoom', type: 'number', value: zoom||1, condition: result => (result.projection == 'orthographic')},
|
|
|
|
},
|
|
|
|
onConfirm: function(result) {
|
|
|
|
|
|
|
|
if (!result.name) return;
|
|
|
|
|
|
|
|
preset.name = result.name;
|
|
|
|
preset.projection = result.projection;
|
|
|
|
preset.position = result.position;
|
|
|
|
preset.target = result.target;
|
|
|
|
if (result.projection == 'orthographic') preset.zoom = result.zoom;
|
|
|
|
|
|
|
|
localStorage.setItem('camera_presets', JSON.stringify(presets))
|
|
|
|
dialog.hide()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
dialog.show();
|
|
|
|
}
|
|
|
|
|
2019-08-01 06:01:47 +08:00
|
|
|
|
2021-03-06 02:03:19 +08:00
|
|
|
class OrbitGizmo {
|
2021-02-04 17:09:25 +08:00
|
|
|
constructor(preview, options = {}) {
|
|
|
|
let scope = this;
|
|
|
|
this.preview = preview;
|
|
|
|
this.node = document.createElement('div');
|
2021-03-06 02:03:19 +08:00
|
|
|
this.node.classList.add('orbit_gizmo');
|
2021-02-04 17:09:25 +08:00
|
|
|
|
|
|
|
let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
|
|
this.node.append(svg);
|
|
|
|
this.lines = {
|
|
|
|
x: document.createElementNS('http://www.w3.org/2000/svg', 'path'),
|
|
|
|
y: document.createElementNS('http://www.w3.org/2000/svg', 'path'),
|
|
|
|
z: document.createElementNS('http://www.w3.org/2000/svg', 'path'),
|
|
|
|
}
|
|
|
|
for (let axis in this.lines) {
|
|
|
|
this.lines[axis].setAttribute('axis', axis);
|
|
|
|
svg.append(this.lines[axis]);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.sides = {
|
2021-02-14 05:08:20 +08:00
|
|
|
top: {opposite: 'bottom', axis: 'y', sign: 1, label: 'Y'},
|
|
|
|
bottom: {opposite: 'top', axis: 'y', sign: -1},
|
|
|
|
east: {opposite: 'west', axis: 'x', sign: 1, label: 'X'},
|
|
|
|
west: {opposite: 'east', axis: 'x', sign: -1},
|
|
|
|
south: {opposite: 'north', axis: 'z', sign: 1, label: 'Z'},
|
|
|
|
north: {opposite: 'south', axis: 'z', sign: -1},
|
2021-02-04 17:09:25 +08:00
|
|
|
}
|
|
|
|
for (let key in this.sides) {
|
|
|
|
let side = this.sides[key];
|
|
|
|
side.node = document.createElement('div');
|
2021-03-06 02:03:19 +08:00
|
|
|
side.node.classList.add('orbit_gizmo_side');
|
2021-02-04 17:09:25 +08:00
|
|
|
side.node.setAttribute('axis', side.axis);
|
2021-02-28 23:16:37 +08:00
|
|
|
side.node.title = tl(`direction.${key}`);
|
2021-02-04 17:09:25 +08:00
|
|
|
if (side.label) side.node.innerText = side.label;
|
|
|
|
|
|
|
|
side.node.addEventListener('click', e => {
|
2021-02-28 22:57:55 +08:00
|
|
|
if (!this.preview.controls.enabled) return;
|
2021-02-14 05:08:20 +08:00
|
|
|
let preset_key = key == this.preview.angle ? side.opposite : key;
|
|
|
|
let preset = DefaultCameraPresets.find(p => p.id == preset_key);
|
2021-02-04 17:09:25 +08:00
|
|
|
this.preview.loadAnglePreset(preset);
|
|
|
|
})
|
|
|
|
this.node.append(side.node);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Interact
|
|
|
|
addEventListeners(this.node, 'mousedown touchstart', e1 => {
|
2021-03-08 19:57:31 +08:00
|
|
|
if ((!scope.preview.controls.enableRotate && scope.preview.angle == null) || !scope.preview.controls.enabled || (scope.preview.force_locked_angle && scope.preview.locked_angle !== null)) return;
|
2021-02-04 17:09:25 +08:00
|
|
|
convertTouchEvent(e1);
|
|
|
|
let last_event = e1;
|
2021-02-09 06:31:20 +08:00
|
|
|
let move_calls = 0;
|
2021-02-04 17:09:25 +08:00
|
|
|
|
2021-04-16 00:24:16 +08:00
|
|
|
let started = false;
|
|
|
|
function start() {
|
|
|
|
started = true;
|
2021-02-05 00:20:01 +08:00
|
|
|
scope.node.classList.add('mouse_active');
|
2021-03-09 04:33:56 +08:00
|
|
|
if (!e1.touches && last_event == e1 && scope.node.requestPointerLock) scope.node.requestPointerLock();
|
2021-02-05 00:20:01 +08:00
|
|
|
if (scope.preview.angle != null) {
|
2021-02-20 07:02:56 +08:00
|
|
|
scope.preview.setProjectionMode(false, true);
|
2021-02-05 00:20:01 +08:00
|
|
|
}
|
2021-04-16 00:24:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
function move(e2) {
|
|
|
|
convertTouchEvent(e2);
|
|
|
|
if (!started && Math.pow(e2.clientX - e1.clientX, 2) + Math.pow(e2.clientY - e1.clientY, 2) > 12) {
|
|
|
|
start()
|
|
|
|
}
|
|
|
|
if (started) {
|
|
|
|
let limit = move_calls <= 2 ? 1 : 32;
|
|
|
|
scope.preview.controls.rotateLeft((e1.touches ? (e2.clientX - last_event.clientX) : Math.clamp(e2.movementX, -limit, limit)) / 40);
|
|
|
|
scope.preview.controls.rotateUp((e1.touches ? (e2.clientY - last_event.clientY) : Math.clamp(e2.movementY, -limit, limit)) / 40);
|
|
|
|
last_event = e2;
|
|
|
|
move_calls++;
|
|
|
|
}
|
2021-02-04 17:09:25 +08:00
|
|
|
}
|
|
|
|
function off(e2) {
|
2021-03-09 04:33:56 +08:00
|
|
|
if (document.exitPointerLock) document.exitPointerLock()
|
2021-02-04 17:09:25 +08:00
|
|
|
removeEventListeners(document, 'mousemove touchmove', move);
|
|
|
|
removeEventListeners(document, 'mouseup touchend', off);
|
|
|
|
scope.node.classList.remove('mouse_active');
|
|
|
|
}
|
|
|
|
addEventListeners(document, 'mouseup touchend', off);
|
2021-03-09 04:33:56 +08:00
|
|
|
addEventListeners(document, 'mousemove touchmove', move);
|
2021-02-04 17:09:25 +08:00
|
|
|
})
|
|
|
|
this.node.addEventListener('dblclick', e => {
|
2021-02-20 07:02:56 +08:00
|
|
|
if (e.target != this.node) return;
|
|
|
|
this.preview.setProjectionMode(!this.preview.isOrtho, true);
|
2021-02-04 17:09:25 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
this.preview.controls.onUpdate(e => this.update(e));
|
|
|
|
|
|
|
|
this.update();
|
|
|
|
}
|
|
|
|
update() {
|
|
|
|
let background = 'background';
|
|
|
|
let x = this.preview.controls.getPolarAngle();
|
|
|
|
let y = this.preview.controls.getAzimuthalAngle();
|
|
|
|
let mid = 40;
|
|
|
|
let rad = 28;
|
|
|
|
let scale = 0.16;
|
|
|
|
let offset = {
|
|
|
|
x: [Math.cos(y), Math.cos(x)*Math.sin(y), Math.sin(y)],
|
|
|
|
y: [0, -Math.sin(x), Math.cos(x)],
|
|
|
|
z: [-Math.sin(y), Math.cos(x)*Math.cos(y), Math.cos(y)],
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let key in this.sides) {
|
|
|
|
let side = this.sides[key];
|
|
|
|
let vec = offset[side.axis];
|
|
|
|
side.node.style.left = `${mid + side.sign * rad * vec[0]}px`;
|
|
|
|
side.node.style.top = `${mid + side.sign * rad * vec[1]}px`;
|
|
|
|
side.node.style.setProperty('transform', `scale(${1 + scale * side.sign * vec[2]})`);
|
|
|
|
side.node.classList.toggle(background, vec[2] * side.sign < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let axis in this.lines) {
|
|
|
|
let vec = offset[axis];
|
|
|
|
this.lines[axis].setAttribute('d', `M${mid} ${mid} L${mid + rad*vec[0]} ${mid + rad*vec[1]}`)
|
|
|
|
}
|
|
|
|
}
|
2021-03-08 19:57:31 +08:00
|
|
|
hide() {
|
|
|
|
this.node.style.display = 'none';
|
|
|
|
}
|
|
|
|
unhide() {
|
|
|
|
this.node.style.display = 'block';
|
|
|
|
}
|
2021-02-04 17:09:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-08-01 06:01:47 +08:00
|
|
|
const Screencam = {
|
2019-12-16 03:04:31 +08:00
|
|
|
recording_timelapse: false,
|
2019-08-01 06:01:47 +08:00
|
|
|
fullScreen(options, cb) {
|
|
|
|
setTimeout(function() {
|
2020-03-05 03:56:17 +08:00
|
|
|
currentwindow.capturePage().then(function(screenshot) {
|
2019-08-01 06:01:47 +08:00
|
|
|
var dataUrl = screenshot.toDataURL()
|
2020-03-05 03:56:17 +08:00
|
|
|
|
|
|
|
if (!(options && options.width && options.height)) {
|
|
|
|
Screencam.returnScreenshot(dataUrl, cb)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-01 06:01:47 +08:00
|
|
|
dataUrl = dataUrl.replace('data:image/png;base64,','')
|
|
|
|
Jimp.read(Buffer.from(dataUrl, 'base64')).then(function(image) {
|
|
|
|
|
2020-03-05 03:56:17 +08:00
|
|
|
image.contain(options.width, options.height)
|
2019-08-01 06:01:47 +08:00
|
|
|
|
|
|
|
image.getBase64(Jimp.MIME_PNG, function(a, dataUrl){
|
|
|
|
Screencam.returnScreenshot(dataUrl, cb)
|
|
|
|
})
|
|
|
|
});
|
|
|
|
})
|
|
|
|
}, 40)
|
|
|
|
},
|
2021-07-20 19:14:08 +08:00
|
|
|
async returnScreenshot(dataUrl, cb) {
|
|
|
|
|
2019-08-01 06:01:47 +08:00
|
|
|
if (cb) {
|
2021-07-20 19:14:08 +08:00
|
|
|
cb(dataUrl);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let img = new Image()
|
|
|
|
let is_gif = dataUrl.substr(5, 9) == 'image/gif'
|
|
|
|
img.src = dataUrl
|
|
|
|
img.className = 'allow_default_menu checkerboard';
|
|
|
|
await new Promise((resolve, reject) => {
|
|
|
|
img.onload = resolve;
|
|
|
|
img.onerror = reject;
|
|
|
|
})
|
|
|
|
|
|
|
|
let center = document.createElement('center');
|
|
|
|
center.innerHTML = `<div>${img.naturalWidth} x ${img.naturalHeight}px, ${is_gif ? 'GIF' : 'PNG'}</div>`;
|
|
|
|
center.appendChild(img);
|
|
|
|
|
|
|
|
let buttons = [tl('dialog.save'), tl('dialog.cancel')]
|
|
|
|
if (!is_gif) {
|
|
|
|
buttons.splice(0, 0, tl('message.screenshot.clipboard'))
|
|
|
|
}
|
|
|
|
let dialog = new Dialog({
|
|
|
|
title: 'message.screenshot.title',
|
|
|
|
id: 'screenshot',
|
|
|
|
width: img.naturalWidth + 50,
|
|
|
|
lines: [
|
|
|
|
center
|
|
|
|
],
|
|
|
|
buttons,
|
|
|
|
onButton(result) {
|
|
|
|
|
|
|
|
if (result === 0 && buttons.length == 3) {
|
|
|
|
if (navigator.clipboard && navigator.clipboard.write) {
|
|
|
|
fetch(dataUrl).then(async data => {
|
|
|
|
const blob = await data.blob();
|
|
|
|
await navigator.clipboard.write([
|
|
|
|
new ClipboardItem({
|
|
|
|
[blob.type]: blob
|
|
|
|
})
|
|
|
|
]);
|
2020-04-26 02:25:07 +08:00
|
|
|
})
|
|
|
|
} else {
|
2021-07-20 19:14:08 +08:00
|
|
|
Blockbench.showQuickMessage('message.screenshot.right_click');
|
|
|
|
return false;
|
2020-04-26 02:25:07 +08:00
|
|
|
}
|
2021-07-20 19:14:08 +08:00
|
|
|
} else if (result === buttons.length-2) {
|
|
|
|
Blockbench.export({
|
|
|
|
resource_id: 'screenshot',
|
|
|
|
extensions: [is_gif ? 'gif' : 'png'],
|
|
|
|
type: tl('data.image'),
|
|
|
|
savetype: is_gif ? 'binary' : 'image',
|
|
|
|
name: Project.name.replace(/\.geo$/, ''),
|
|
|
|
content: is_gif ? Buffer(dataUrl.split(',')[1], 'base64') : dataUrl,
|
|
|
|
})
|
2019-08-01 06:01:47 +08:00
|
|
|
}
|
2021-07-20 19:14:08 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
dialog.show();
|
2019-08-01 06:01:47 +08:00
|
|
|
},
|
|
|
|
cleanCanvas(options, cb) {
|
|
|
|
quad_previews.current.screenshot(options, cb)
|
|
|
|
},
|
|
|
|
createGif(options, cb) {
|
2020-03-05 03:56:17 +08:00
|
|
|
if (typeof options !== 'object') options = {}
|
|
|
|
if (!options.length_mode) options.length_mode = 'seconds';
|
|
|
|
if (!options.length) options.length = 1;
|
|
|
|
|
2019-08-01 06:01:47 +08:00
|
|
|
var preview = quad_previews.current;
|
2020-09-15 20:21:04 +08:00
|
|
|
var animation = Animation.selected;
|
2019-08-01 06:01:47 +08:00
|
|
|
var interval = options.fps ? (1000/options.fps) : 100;
|
2020-03-05 03:56:17 +08:00
|
|
|
var frames = 0;
|
|
|
|
const gif = new GIF({
|
2019-08-01 06:01:47 +08:00
|
|
|
repeat: options.repeat,
|
|
|
|
quality: options.quality,
|
2021-05-18 04:29:55 +08:00
|
|
|
background: options.background ? options.background : {r: 30, g: 0, b: 255},
|
|
|
|
transparent: options.background ? undefined : 0x1e01ff,
|
2019-08-01 06:01:47 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
if (options.turnspeed) {
|
|
|
|
preview.controls.autoRotate = true;
|
|
|
|
preview.controls.autoRotateSpeed = options.turnspeed;
|
2020-03-05 03:56:17 +08:00
|
|
|
preview.controls.autoRotateProgress = 0;
|
|
|
|
} else if (options.length_mode == 'turntable') {
|
|
|
|
options.length_mode = 'seconds'
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.play && animation) {
|
|
|
|
Timeline.time = 0;
|
|
|
|
Timeline.start()
|
|
|
|
if (!animation.length) options.length_mode = 'seconds';
|
|
|
|
} else if (options.length_mode == 'animation') {
|
|
|
|
options.length_mode = 'seconds'
|
2019-08-01 06:01:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.silent) {
|
|
|
|
Blockbench.setStatusBarText(tl('status_bar.recording_gif'));
|
|
|
|
gif.on('progress', Blockbench.setProgress);
|
|
|
|
}
|
|
|
|
|
2020-03-05 03:56:17 +08:00
|
|
|
function getProgress() {
|
|
|
|
switch (options.length_mode) {
|
|
|
|
case 'seconds': return interval*frames/(options.length*1000); break;
|
|
|
|
case 'frames': return frames/options.length; break;
|
|
|
|
case 'turntable': return Math.abs(preview.controls.autoRotateProgress) / (2*Math.PI); break;
|
|
|
|
case 'animation': return Timeline.time / (animation.length-(interval/1000)); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-06 03:04:16 +08:00
|
|
|
let recording = true;
|
2019-08-01 06:01:47 +08:00
|
|
|
var loop = setInterval(() => {
|
|
|
|
frames++;
|
2019-09-04 15:52:21 +08:00
|
|
|
Canvas.withoutGizmos(function() {
|
|
|
|
var img = new Image();
|
|
|
|
preview.render();
|
|
|
|
img.src = preview.canvas.toDataURL();
|
|
|
|
img.onload = () => {
|
|
|
|
gif.addFrame(img, {delay: interval});
|
2019-08-01 06:01:47 +08:00
|
|
|
}
|
2019-09-04 15:52:21 +08:00
|
|
|
})
|
2020-03-05 03:56:17 +08:00
|
|
|
Blockbench.setProgress(getProgress());
|
2020-09-30 23:29:13 +08:00
|
|
|
if (getProgress() >= 1) {
|
2021-05-06 03:04:16 +08:00
|
|
|
endRecording(true)
|
2020-09-30 23:29:13 +08:00
|
|
|
return;
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
|
2019-08-01 06:01:47 +08:00
|
|
|
}, interval)
|
2019-12-16 03:04:31 +08:00
|
|
|
|
2021-05-06 03:04:16 +08:00
|
|
|
function endRecording(render) {
|
|
|
|
recording = false;
|
2019-12-16 03:04:31 +08:00
|
|
|
clearInterval(loop)
|
2021-05-06 03:04:16 +08:00
|
|
|
if (render) {
|
|
|
|
gif.render();
|
|
|
|
if (!options.silent) {
|
|
|
|
Blockbench.setStatusBarText(tl('status_bar.processing_gif'))
|
|
|
|
}
|
2019-12-16 03:04:31 +08:00
|
|
|
}
|
|
|
|
if (Animator.open && Timeline.playing) {
|
|
|
|
Timeline.pause();
|
|
|
|
}
|
|
|
|
if (options.turnspeed) {
|
|
|
|
preview.controls.autoRotate = false;
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
}
|
2019-12-16 03:04:31 +08:00
|
|
|
|
2021-05-06 03:04:16 +08:00
|
|
|
let toast = Blockbench.showToastNotification({
|
|
|
|
text: 'message.recording_gif',
|
|
|
|
icon: 'local_movies',
|
|
|
|
click() {
|
|
|
|
if (recording) {
|
|
|
|
endRecording(false);
|
|
|
|
} else {
|
|
|
|
gif.abort();
|
|
|
|
}
|
|
|
|
Blockbench.setStatusBarText();
|
|
|
|
Blockbench.setProgress(0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2019-12-16 03:04:31 +08:00
|
|
|
gif.on('finished', blob => {
|
|
|
|
var reader = new FileReader();
|
|
|
|
reader.onload = () => {
|
|
|
|
if (!options.silent) {
|
2021-05-06 03:04:16 +08:00
|
|
|
Blockbench.setProgress();
|
2019-12-16 03:04:31 +08:00
|
|
|
Blockbench.setStatusBarText();
|
|
|
|
}
|
|
|
|
Screencam.returnScreenshot(reader.result, cb);
|
|
|
|
}
|
|
|
|
reader.readAsDataURL(blob);
|
2021-05-06 03:04:16 +08:00
|
|
|
toast.delete();
|
2019-12-16 03:04:31 +08:00
|
|
|
});
|
2021-05-06 03:04:16 +08:00
|
|
|
|
2019-12-16 03:04:31 +08:00
|
|
|
},
|
|
|
|
recordTimelapse(options) {
|
|
|
|
if (!options.destination) return;
|
|
|
|
|
2019-12-18 00:44:27 +08:00
|
|
|
function getFileName(num) {
|
|
|
|
return `${Project.name||'model'}_${num.toDigitString(4)}.png`;
|
|
|
|
}
|
|
|
|
var index = 0;
|
|
|
|
try {
|
|
|
|
var list = fs.readdirSync(options.destination);
|
|
|
|
while (list.includes(getFileName(index+1))) {
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
console.log('Unable to analyze past timelapse recording', err)
|
|
|
|
}
|
|
|
|
|
2019-12-16 03:04:31 +08:00
|
|
|
Prop.recording = true;
|
|
|
|
BarItems.timelapse.setIcon('pause');
|
|
|
|
Blockbench.showQuickMessage('message.timelapse_start');
|
|
|
|
|
|
|
|
function saveImage(image) {
|
2019-12-18 00:44:27 +08:00
|
|
|
var path = `${options.destination}${osfs}${getFileName(index)}`;
|
2019-12-16 03:04:31 +08:00
|
|
|
fs.writeFile(path, image, (e, b) => {});
|
|
|
|
|
|
|
|
}
|
|
|
|
if (options.source === 'locked') {
|
|
|
|
var view_pos = new THREE.Vector3().copy(quad_previews.current.camera.position);
|
|
|
|
var view_tar = new THREE.Vector3().copy(quad_previews.current.controls.target);
|
|
|
|
}
|
|
|
|
Screencam.timelapse_loop = setInterval(function() {
|
|
|
|
index++;
|
|
|
|
|
|
|
|
if (!isApp || options.source === 'preview' || options.source === 'locked') {
|
|
|
|
var scope = quad_previews.current;
|
|
|
|
if (options.source === 'locked') {
|
|
|
|
var old_pos = new THREE.Vector3().copy(scope.camera.position);
|
|
|
|
var old_tar = new THREE.Vector3().copy(scope.controls.target);
|
|
|
|
scope.camera.position.copy(view_pos);
|
|
|
|
scope.controls.target.copy(view_tar);
|
|
|
|
}
|
|
|
|
|
|
|
|
Canvas.withoutGizmos(function() {
|
|
|
|
|
|
|
|
scope.render();
|
|
|
|
var dataUrl = scope.canvas.toDataURL();
|
|
|
|
saveImage(nativeImage.createFromDataURL(dataUrl).toPNG());
|
|
|
|
|
|
|
|
if (options.source === 'locked') {
|
|
|
|
scope.camera.position.copy(old_pos);
|
|
|
|
scope.controls.target.copy(old_tar);
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
currentwindow.capturePage((image) => {
|
|
|
|
saveImage(image.toPNG());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
}, options.interval*1000);
|
|
|
|
},
|
|
|
|
stopTimelapse() {
|
|
|
|
if (Prop.recording) {
|
|
|
|
Prop.recording = false;
|
|
|
|
clearInterval(Screencam.timelapse_loop);
|
|
|
|
BarItems.timelapse.setIcon('timelapse');
|
|
|
|
Blockbench.showQuickMessage('message.timelapse_stop');
|
|
|
|
}
|
2019-08-01 06:01:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-27 23:57:17 +08:00
|
|
|
window.addEventListener("gamepadconnected", function(event) {
|
2021-04-15 22:20:23 +08:00
|
|
|
if (event.gamepad.id.includes('SpaceMouse') || event.gamepad.id.includes('SpaceNavigator')) {
|
2021-01-27 23:57:17 +08:00
|
|
|
|
|
|
|
let interval = setInterval(() => {
|
|
|
|
let gamepad = navigator.getGamepads()[event.gamepad.index];
|
|
|
|
let preview = Preview.selected;
|
|
|
|
if (!document.hasFocus() || !preview || !gamepad || !gamepad.axes || gamepad.axes.allEqual(0) || gamepad.axes.find(v => isNaN(v)) != undefined) return;
|
|
|
|
|
|
|
|
let offset = new THREE.Vector3(
|
|
|
|
gamepad.axes[0],
|
|
|
|
-gamepad.axes[2],
|
|
|
|
gamepad.axes[1],
|
|
|
|
)
|
2021-01-30 22:18:45 +08:00
|
|
|
offset.multiplyScalar(3);
|
2021-01-27 23:57:17 +08:00
|
|
|
offset.applyQuaternion(preview.camera.quaternion);
|
|
|
|
|
|
|
|
preview.controls.target.add(offset);
|
|
|
|
preview.camera.position.add(offset);
|
|
|
|
|
|
|
|
let camera_diff = new THREE.Vector3().copy(preview.controls.target).sub(preview.camera.position);
|
|
|
|
let axes = [
|
|
|
|
gamepad.axes[3] / -40,
|
|
|
|
gamepad.axes[5] / -40,
|
|
|
|
];
|
|
|
|
camera_diff.applyAxisAngle(THREE.NormalY, axes[1]);
|
|
|
|
let tilt_axis = new THREE.Vector3().copy(camera_diff).normalize();
|
|
|
|
tilt_axis.applyAxisAngle(THREE.NormalY, Math.PI/2);
|
|
|
|
tilt_axis.y = 0;
|
|
|
|
camera_diff.applyAxisAngle(tilt_axis, axes[0]);
|
|
|
|
|
|
|
|
preview.controls.target.copy(camera_diff).add(preview.camera.position);
|
|
|
|
|
2021-01-30 22:18:45 +08:00
|
|
|
main_preview.controls.updateSceneScale();
|
|
|
|
|
2021-01-27 23:57:17 +08:00
|
|
|
}, 16)
|
|
|
|
|
|
|
|
window.addEventListener("gamepadconnected", function(event2) {
|
|
|
|
if (event2.gamepad.id == event.gamepad.id && event2.gamepad.index == event.gamepad.index) {
|
|
|
|
clearInterval(interval);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-06-12 18:53:40 +08:00
|
|
|
class PreviewBackground {
|
|
|
|
constructor(data = {}) {
|
|
|
|
this.name = data.name ? tl(data.name) : ''
|
2021-06-29 05:01:08 +08:00
|
|
|
this._image = data.image||false
|
2021-06-12 18:53:40 +08:00
|
|
|
this.size = data.size||1000
|
|
|
|
this.x = data.x||0
|
|
|
|
this.y = data.y||0
|
|
|
|
this.lock = data.lock||false
|
|
|
|
this.save_in_project = false;
|
|
|
|
this.defaults = Object.assign({}, this);
|
2021-06-29 05:01:08 +08:00
|
|
|
this.defaults.image = this.image;
|
2021-06-12 22:41:10 +08:00
|
|
|
this.imgtag = new Image();
|
|
|
|
}
|
|
|
|
get image() {
|
|
|
|
return this._image;
|
|
|
|
}
|
|
|
|
set image(path) {
|
|
|
|
this._image = path;
|
|
|
|
if (typeof this._image == 'string') {
|
|
|
|
this.imgtag.src = this._image.replace(/#/g, '%23');
|
|
|
|
}
|
2021-06-12 18:53:40 +08:00
|
|
|
}
|
|
|
|
getSaveCopy() {
|
2021-06-12 22:41:10 +08:00
|
|
|
let dataUrl;
|
|
|
|
|
|
|
|
if (isApp && this.image && this.image.substr(0, 5) != 'data:') {
|
|
|
|
let canvas = document.createElement('canvas');
|
|
|
|
canvas.width = this.imgtag.naturalWidth;
|
|
|
|
canvas.height = this.imgtag.naturalHeight;
|
|
|
|
let ctx = canvas.getContext('2d');
|
|
|
|
ctx.drawImage(this.imgtag, 0, 0);
|
|
|
|
dataUrl = canvas.toDataURL('image/png');
|
|
|
|
}
|
|
|
|
|
2021-06-12 18:53:40 +08:00
|
|
|
return {
|
|
|
|
name: this.name,
|
2021-06-12 22:41:10 +08:00
|
|
|
image: dataUrl || this.image,
|
2021-06-12 18:53:40 +08:00
|
|
|
size: this.size,
|
|
|
|
x: this.x,
|
|
|
|
y: this.y,
|
|
|
|
lock: this.lock
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
//Init/Update
|
|
|
|
function initCanvas() {
|
|
|
|
|
|
|
|
//Objects
|
2021-01-26 05:53:55 +08:00
|
|
|
scene = Canvas.scene = new THREE.Scene();
|
2019-07-18 00:02:07 +08:00
|
|
|
display_scene = new THREE.Scene();
|
|
|
|
display_area = new THREE.Object3D();
|
|
|
|
display_base = new THREE.Object3D();
|
|
|
|
|
|
|
|
display_scene.add(display_area)
|
|
|
|
display_area.add(display_base)
|
|
|
|
|
|
|
|
scene.name = 'scene'
|
|
|
|
display_base.name = 'display_base'
|
|
|
|
display_area.name = 'display_area'
|
|
|
|
display_scene.name = 'display_scene'
|
|
|
|
|
|
|
|
|
2021-09-07 18:25:41 +08:00
|
|
|
scene.add(Vertexsnap.vertex_gizmos)
|
|
|
|
Vertexsnap.vertex_gizmos.name = 'vertex_handles'
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2021-07-26 23:07:51 +08:00
|
|
|
Canvas.outlines = new THREE.Object3D();
|
|
|
|
Canvas.outlines.name = 'outline_group'
|
|
|
|
scene.add(Canvas.outlines)
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
|
|
|
|
canvas_scenes = {
|
2021-06-12 18:53:40 +08:00
|
|
|
normal: new PreviewBackground({name: 'menu.preview.perspective.normal', lock: null}),
|
|
|
|
ortho_top: new PreviewBackground({name: 'direction.top', lock: true}),
|
|
|
|
ortho_bottom: new PreviewBackground({name: 'direction.bottom', lock: true}),
|
|
|
|
ortho_south: new PreviewBackground({name: 'direction.south', lock: true}),
|
|
|
|
ortho_north: new PreviewBackground({name: 'direction.north', lock: true}),
|
|
|
|
ortho_east: new PreviewBackground({name: 'direction.east', lock: true}),
|
|
|
|
ortho_west: new PreviewBackground({name: 'direction.west', lock: true}),
|
|
|
|
|
|
|
|
monitor: new PreviewBackground({name: 'display.reference.monitor' }),
|
|
|
|
|
|
|
|
inventory_nine: new PreviewBackground({name: 'display.reference.inventory_nine', image: './assets/inventory_nine.png', x: 0, y: -525, size: 1051, lock: true}),
|
|
|
|
inventory_full: new PreviewBackground({name: 'display.reference.inventory_full', image: './assets/inventory_full.png', x: 0, y: -1740, size: 2781, lock: true}),
|
|
|
|
hud: new PreviewBackground({name: 'display.reference.hud', image: './assets/hud.png', x: -224, y: -447.5, size: 3391, lock: true}),
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
if (localStorage.getItem('canvas_scenes')) {
|
|
|
|
var stored_canvas_scenes = undefined;
|
|
|
|
try {
|
|
|
|
stored_canvas_scenes = JSON.parse(localStorage.getItem('canvas_scenes'))
|
|
|
|
} catch (err) {}
|
|
|
|
|
|
|
|
if (stored_canvas_scenes) {
|
|
|
|
for (var key in canvas_scenes) {
|
|
|
|
if (stored_canvas_scenes.hasOwnProperty(key)) {
|
|
|
|
|
|
|
|
let store = stored_canvas_scenes[key]
|
|
|
|
let real = canvas_scenes[key]
|
|
|
|
|
2021-06-12 18:53:40 +08:00
|
|
|
if (store.save_in_project) continue;
|
|
|
|
if (store.save_in_project == null) {real.save_in_project = false}
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
if (store.image !== undefined) {real.image = store.image}
|
|
|
|
if (store.size !== undefined) {real.size = store.size}
|
|
|
|
if (store.x !== undefined) {real.x = store.x}
|
|
|
|
if (store.y !== undefined) {real.y = store.y}
|
|
|
|
if (store.lock !== undefined) {real.lock = store.lock}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
active_scene = canvas_scenes.normal
|
|
|
|
|
2020-07-16 15:32:59 +08:00
|
|
|
MediaPreview = new Preview({id: 'media'})
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
main_preview = new Preview({id: 'main'}).fullscreen()
|
|
|
|
|
|
|
|
//TransformControls
|
|
|
|
Transformer = new THREE.TransformControls(main_preview.camPers, main_preview.canvas)
|
|
|
|
Transformer.setSize(0.5)
|
|
|
|
scene.add(Transformer)
|
|
|
|
main_preview.occupyTransformer()
|
|
|
|
|
|
|
|
quad_previews = {
|
2020-10-11 00:31:56 +08:00
|
|
|
get current() {return Preview.selected},
|
|
|
|
set current(p) {Preview.selected = p},
|
|
|
|
|
2020-03-05 03:56:17 +08:00
|
|
|
one: new Preview({id: 'one'}).loadAnglePreset(DefaultCameraPresets[1]),
|
2019-07-18 00:02:07 +08:00
|
|
|
two: main_preview,
|
2020-03-05 03:56:17 +08:00
|
|
|
three: new Preview({id: 'three'}).loadAnglePreset(DefaultCameraPresets[3]),
|
|
|
|
four: new Preview({id: 'four'}).loadAnglePreset(DefaultCameraPresets[5]),
|
2020-10-30 22:54:33 +08:00
|
|
|
get current() {
|
|
|
|
return Preview.selected;
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
|
2021-09-13 04:41:10 +08:00
|
|
|
Canvas.setup();
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
resizeWindow()
|
|
|
|
}
|
|
|
|
function animate() {
|
|
|
|
requestAnimationFrame( animate );
|
2021-02-26 05:18:34 +08:00
|
|
|
if (!settings.background_rendering.value && !document.hasFocus() && !document.querySelector('#preview:hover')) return;
|
2021-01-28 02:44:30 +08:00
|
|
|
TickUpdates.Run();
|
|
|
|
|
|
|
|
if (Animator.open && Timeline.playing) {
|
|
|
|
Timeline.loop();
|
|
|
|
}
|
2020-10-07 03:23:13 +08:00
|
|
|
if (quad_previews.current) {
|
2021-05-24 21:59:45 +08:00
|
|
|
WinterskyScene.updateFacingRotation(quad_previews.current.camera);
|
2020-10-07 03:23:13 +08:00
|
|
|
}
|
2020-07-16 15:32:59 +08:00
|
|
|
Preview.all.forEach(function(prev) {
|
|
|
|
if (prev.canvas.isConnected) {
|
|
|
|
prev.render()
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
})
|
|
|
|
framespersecond++;
|
|
|
|
if (display_mode === true && ground_animation === true && !Transformer.hoverAxis) {
|
|
|
|
DisplayMode.groundAnimation()
|
|
|
|
}
|
2021-08-20 20:42:50 +08:00
|
|
|
Blockbench.dispatchEvent('render_frame');
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
|
2020-07-16 15:32:59 +08:00
|
|
|
function updateShading() {
|
|
|
|
Canvas.updateLayeredTextures();
|
2019-07-18 00:02:07 +08:00
|
|
|
scene.remove(lights)
|
|
|
|
display_scene.remove(lights)
|
2020-07-16 15:32:59 +08:00
|
|
|
Sun.intensity = settings.brightness.value/50;
|
2019-07-18 00:02:07 +08:00
|
|
|
if (settings.shading.value === true) {
|
2020-07-16 15:32:59 +08:00
|
|
|
Sun.intensity *= 0.5;
|
|
|
|
let parent = display_mode ? display_scene : scene;
|
|
|
|
parent.add(lights);
|
|
|
|
lights.position.copy(parent.position).multiplyScalar(-1);
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2021-06-13 18:24:42 +08:00
|
|
|
Texture.all.forEach(tex => {
|
|
|
|
let material = tex.getMaterial();
|
|
|
|
material.uniforms.SHADE.value = settings.shading.value;
|
|
|
|
material.uniforms.BRIGHTNESS.value = settings.brightness.value / 50;
|
|
|
|
})
|
2021-09-16 06:49:57 +08:00
|
|
|
Canvas.emptyMaterials.forEach(material => {
|
|
|
|
material.uniforms.SHADE.value = settings.shading.value;
|
|
|
|
material.uniforms.BRIGHTNESS.value = settings.brightness.value / 50;
|
|
|
|
})
|
2021-06-13 18:24:42 +08:00
|
|
|
Canvas.solidMaterial.uniforms.SHADE.value = settings.shading.value;
|
|
|
|
Canvas.solidMaterial.uniforms.BRIGHTNESS.value = settings.brightness.value / 50;
|
2021-09-16 06:49:57 +08:00
|
|
|
Canvas.normalHelperMaterial.uniforms.SHADE.value = settings.shading.value;
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2019-12-18 00:44:27 +08:00
|
|
|
function updateCubeHighlights(hover_cube, force_off) {
|
2021-08-02 18:42:06 +08:00
|
|
|
Outliner.elements.forEach(element => {
|
2021-09-13 04:41:10 +08:00
|
|
|
if (element.visibility && element.mesh.geometry && element.preview_controller.updateHighlight) {
|
|
|
|
element.preview_controller.updateHighlight(element, hover_cube, force_off);
|
2019-12-18 00:44:27 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
//Helpers
|
|
|
|
function buildGrid() {
|
|
|
|
three_grid.children.length = 0;
|
|
|
|
if (Canvas.side_grids) {
|
|
|
|
Canvas.side_grids.x.children.length = 0;
|
|
|
|
Canvas.side_grids.z.children.length = 0;
|
|
|
|
}
|
|
|
|
if (Modes.display && settings.display_grid.value === false) return;
|
|
|
|
|
|
|
|
three_grid.name = 'grid_group'
|
2019-12-16 03:04:31 +08:00
|
|
|
gizmo_colors.grid.set(parseInt('0x'+CustomTheme.data.colors.grid.replace('#', ''), 16));
|
2019-07-18 00:02:07 +08:00
|
|
|
var material;
|
|
|
|
|
2019-12-16 03:04:31 +08:00
|
|
|
Canvas.northMarkMaterial.color = gizmo_colors.grid
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
function setupAxisLine(origin, length, axis) {
|
|
|
|
var color = 'rgb'[getAxisNumber(axis)]
|
|
|
|
var material = new THREE.LineBasicMaterial({color: gizmo_colors[color]});
|
2021-01-28 02:25:12 +08:00
|
|
|
var dest = new THREE.Vector3().copy(origin);
|
|
|
|
dest[axis] += length;
|
|
|
|
let points = [
|
|
|
|
origin,
|
|
|
|
dest
|
|
|
|
];
|
|
|
|
let geometry = new THREE.BufferGeometry().setFromPoints(points)
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2021-01-28 02:25:12 +08:00
|
|
|
//geometry.vertices.push(origin)
|
|
|
|
//geometry.vertices.push(dest)
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2021-01-28 02:25:12 +08:00
|
|
|
var line = new THREE.Line(geometry, material);
|
2019-07-18 00:02:07 +08:00
|
|
|
line.name = 'axis_line_'+axis;
|
|
|
|
three_grid.add(line)
|
|
|
|
}
|
|
|
|
//Axis Lines
|
2020-06-01 00:43:41 +08:00
|
|
|
if (settings.base_grid.value) {
|
2019-12-16 03:04:31 +08:00
|
|
|
var length = Format.centered_grid
|
2019-07-18 00:02:07 +08:00
|
|
|
? (settings.full_grid.value ? 24 : 8)
|
|
|
|
: 16
|
2021-02-10 04:21:57 +08:00
|
|
|
setupAxisLine(new THREE.Vector3( 0, 0.01, 0), length, 'x')
|
|
|
|
setupAxisLine(new THREE.Vector3( 0, 0.01, 0), length, 'z')
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
var side_grid = new THREE.Object3D()
|
|
|
|
|
|
|
|
if (settings.full_grid.value === true) {
|
|
|
|
//Grid
|
2020-04-26 02:25:07 +08:00
|
|
|
let size = settings.large_grid_size.value*16;
|
|
|
|
var grid = new THREE.GridHelper(size, size/canvasGridSize(), gizmo_colors.grid)
|
2019-12-16 03:04:31 +08:00
|
|
|
if (Format.centered_grid) {
|
2019-07-18 00:02:07 +08:00
|
|
|
grid.position.set(0,0,0)
|
|
|
|
} else {
|
|
|
|
grid.position.set(8,0,8)
|
|
|
|
}
|
|
|
|
grid.name = 'grid'
|
|
|
|
three_grid.add(grid)
|
|
|
|
side_grid.add(grid.clone())
|
|
|
|
|
|
|
|
//North
|
|
|
|
geometry = new THREE.PlaneGeometry(5, 5)
|
2019-12-16 03:04:31 +08:00
|
|
|
var north_mark = new THREE.Mesh(geometry, Canvas.northMarkMaterial)
|
|
|
|
if (Format.centered_grid) {
|
2020-04-26 02:25:07 +08:00
|
|
|
north_mark.position.set(0,0, -3 - size/2)
|
2019-07-18 00:02:07 +08:00
|
|
|
} else {
|
2020-04-26 02:25:07 +08:00
|
|
|
north_mark.position.set(8, 0, 5 - size/2)
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
north_mark.rotation.x = Math.PI / -2
|
|
|
|
three_grid.add(north_mark)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (settings.large_grid.value === true) {
|
|
|
|
//Grid
|
2020-04-26 02:25:07 +08:00
|
|
|
let size = settings.large_grid_size.value
|
|
|
|
var grid = new THREE.GridHelper(size*16, size, gizmo_colors.grid)
|
2019-12-16 03:04:31 +08:00
|
|
|
if (Format.centered_grid) {
|
2019-07-18 00:02:07 +08:00
|
|
|
grid.position.set(0,0,0)
|
|
|
|
} else {
|
|
|
|
grid.position.set(8,0,8)
|
|
|
|
}
|
|
|
|
grid.name = 'grid'
|
|
|
|
three_grid.add(grid)
|
|
|
|
side_grid.add(grid.clone())
|
|
|
|
}
|
|
|
|
|
|
|
|
if (settings.base_grid.value === true) {
|
|
|
|
//Grid
|
2019-12-16 03:04:31 +08:00
|
|
|
var grid = new THREE.GridHelper(16, 16/canvasGridSize(), gizmo_colors.grid)
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2019-12-16 03:04:31 +08:00
|
|
|
if (Format.centered_grid) {
|
2019-07-18 00:02:07 +08:00
|
|
|
grid.position.set(0,0,0)
|
|
|
|
} else {
|
|
|
|
grid.position.set(8,0,8)
|
|
|
|
}
|
|
|
|
grid.name = 'grid'
|
|
|
|
three_grid.add(grid)
|
|
|
|
side_grid.add(grid.clone())
|
|
|
|
|
|
|
|
//North
|
|
|
|
geometry = new THREE.PlaneGeometry(2.4, 2.4)
|
2019-12-16 03:04:31 +08:00
|
|
|
var north_mark = new THREE.Mesh(geometry, Canvas.northMarkMaterial)
|
|
|
|
if (Format.centered_grid) {
|
2019-07-18 00:02:07 +08:00
|
|
|
north_mark.position.set(0,0,-9.5)
|
|
|
|
} else {
|
|
|
|
north_mark.position.set(8,0,-1.5)
|
|
|
|
}
|
|
|
|
north_mark.rotation.x = Math.PI / -2
|
|
|
|
three_grid.add(north_mark)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (settings.large_box.value === true) {
|
|
|
|
var geometry_box = new THREE.EdgesGeometry(new THREE.BoxBufferGeometry(48, 48, 48));
|
|
|
|
|
|
|
|
var line_material = new THREE.LineBasicMaterial({color: gizmo_colors.grid});
|
|
|
|
var large_box = new THREE.LineSegments( geometry_box, line_material);
|
2019-12-16 03:04:31 +08:00
|
|
|
if (Format.centered_grid) {
|
2019-07-18 00:02:07 +08:00
|
|
|
large_box.position.set(0,8,0)
|
|
|
|
} else {
|
|
|
|
large_box.position.set(8,8,8)
|
|
|
|
}
|
|
|
|
large_box.name = 'grid'
|
|
|
|
three_grid.add(large_box)
|
|
|
|
}
|
|
|
|
scene.add(three_grid)
|
|
|
|
|
|
|
|
Canvas.side_grids = {
|
|
|
|
x: side_grid,
|
|
|
|
z: side_grid.clone()
|
|
|
|
}
|
2020-03-11 05:19:17 +08:00
|
|
|
three_grid.add(Canvas.side_grids.x)
|
2019-07-18 00:02:07 +08:00
|
|
|
Canvas.side_grids.x.name = 'side_grid_x'
|
|
|
|
Canvas.side_grids.x.visible = !Modes.display;
|
|
|
|
Canvas.side_grids.x.rotation.z = Math.PI/2;
|
2019-12-16 03:04:31 +08:00
|
|
|
Canvas.side_grids.x.position.y = Format.centered_grid ? 8 : 0;
|
2020-07-16 15:32:59 +08:00
|
|
|
Canvas.side_grids.z.position.z = 0
|
2019-07-18 00:02:07 +08:00
|
|
|
Canvas.side_grids.x.children.forEach(el => {
|
|
|
|
el.layers.set(1)
|
|
|
|
});
|
|
|
|
|
2020-03-11 05:19:17 +08:00
|
|
|
three_grid.add(Canvas.side_grids.z)
|
2020-03-05 03:56:17 +08:00
|
|
|
Canvas.side_grids.z.name = 'side_grid_z'
|
2019-07-18 00:02:07 +08:00
|
|
|
Canvas.side_grids.z.visible = !Modes.display;
|
|
|
|
Canvas.side_grids.z.rotation.z = Math.PI/2;
|
2020-03-05 03:56:17 +08:00
|
|
|
Canvas.side_grids.z.rotation.y = Math.PI/2
|
2019-12-16 03:04:31 +08:00
|
|
|
Canvas.side_grids.z.position.y = Format.centered_grid ? 8 : 0;
|
2020-07-16 15:32:59 +08:00
|
|
|
Canvas.side_grids.z.position.z = 0
|
2019-07-18 00:02:07 +08:00
|
|
|
Canvas.side_grids.z.children.forEach(el => {
|
|
|
|
el.layers.set(3)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
BARS.defineActions(function() {
|
2021-05-07 21:57:24 +08:00
|
|
|
new BarSelect('view_mode', {
|
2019-07-18 00:02:07 +08:00
|
|
|
category: 'view',
|
2021-02-20 18:58:53 +08:00
|
|
|
keybind: new Keybind({key: 'z'}),
|
2021-09-10 17:51:34 +08:00
|
|
|
condition: () => Project && Toolbox && Toolbox.selected && (!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.length > 1),
|
2021-05-07 21:57:24 +08:00
|
|
|
value: 'textured',
|
|
|
|
options: {
|
|
|
|
textured: {name: true, condition: () => (!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.includes('textured'))},
|
|
|
|
solid: {name: true, condition: () => (!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.includes('solid'))},
|
|
|
|
wireframe: {name: true, condition: () => (!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.includes('wireframe'))},
|
2021-09-16 06:49:57 +08:00
|
|
|
normal: {name: true, condition: () => ((!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.includes('normal')) && Mesh.all.length)},
|
2021-05-07 21:57:24 +08:00
|
|
|
},
|
|
|
|
onChange() {
|
2021-09-10 17:51:34 +08:00
|
|
|
Project.view_mode = this.value;
|
2021-05-07 21:57:24 +08:00
|
|
|
Canvas.updateAllFaces();
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Modes.id === 'animate') {
|
2021-05-07 21:57:24 +08:00
|
|
|
Animator.preview();
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2021-05-07 21:57:24 +08:00
|
|
|
//Blockbench.showQuickMessage(tl('action.view_mode') + ': ' + tl('action.view_mode.' + this.value));
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
2021-01-23 19:22:05 +08:00
|
|
|
new Toggle('preview_checkerboard', {
|
|
|
|
icon: 'fas.fa-chess-board',
|
2019-12-16 03:04:31 +08:00
|
|
|
category: 'view',
|
2020-03-05 03:56:17 +08:00
|
|
|
linked_setting: 'preview_checkerboard',
|
2021-02-20 18:58:53 +08:00
|
|
|
keybind: new Keybind({key: 't'})
|
2020-03-05 03:56:17 +08:00
|
|
|
})
|
2021-01-23 19:22:05 +08:00
|
|
|
new Toggle('uv_checkerboard', {
|
|
|
|
icon: 'fas.fa-chess-board',
|
2020-03-05 03:56:17 +08:00
|
|
|
category: 'view',
|
2021-01-23 19:22:05 +08:00
|
|
|
linked_setting: 'uv_checkerboard'
|
2020-03-05 03:56:17 +08:00
|
|
|
})
|
2021-01-23 19:22:05 +08:00
|
|
|
new Toggle('toggle_shading', {
|
2020-03-05 03:56:17 +08:00
|
|
|
name: tl('settings.shading'),
|
|
|
|
description: tl('settings.shading.desc'),
|
2021-01-23 19:22:05 +08:00
|
|
|
icon: 'wb_sunny',
|
2020-03-05 03:56:17 +08:00
|
|
|
category: 'view',
|
2021-01-23 19:22:05 +08:00
|
|
|
linked_setting: 'shading'
|
2019-12-16 03:04:31 +08:00
|
|
|
})
|
2021-01-23 19:22:05 +08:00
|
|
|
new Toggle('toggle_motion_trails', {
|
2020-10-10 21:17:43 +08:00
|
|
|
name: tl('settings.motion_trails'),
|
|
|
|
description: tl('settings.motion_trails.desc'),
|
2021-01-23 19:22:05 +08:00
|
|
|
icon: 'gesture',
|
2020-10-10 21:17:43 +08:00
|
|
|
category: 'view',
|
2021-05-07 21:57:24 +08:00
|
|
|
linked_setting: 'motion_trails',
|
|
|
|
condition: {modes: ['animate']}
|
2020-10-10 21:17:43 +08:00
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('screenshot_model', {
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'fa-cubes',
|
|
|
|
category: 'view',
|
2021-02-20 18:58:53 +08:00
|
|
|
keybind: new Keybind({key: 'p', ctrl: true}),
|
2020-10-30 22:54:33 +08:00
|
|
|
click: function () {Preview.selected.screenshot()}
|
2019-07-18 00:02:07 +08:00
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('record_model_gif', {
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'local_movies',
|
|
|
|
category: 'view',
|
|
|
|
click: function () {
|
|
|
|
new Dialog({
|
|
|
|
id: 'create_gif',
|
|
|
|
title: tl('dialog.create_gif.title'),
|
|
|
|
draggable: true,
|
|
|
|
form: {
|
2020-03-05 03:56:17 +08:00
|
|
|
length_mode: {label: 'dialog.create_gif.length_mode', type: 'select', default: 'seconds', options: {
|
|
|
|
seconds: 'dialog.create_gif.length_mode.seconds',
|
|
|
|
frames: 'dialog.create_gif.length_mode.frames',
|
|
|
|
animation: 'dialog.create_gif.length_mode.animation',
|
|
|
|
turntable: 'dialog.create_gif.length_mode.turntable',
|
|
|
|
}},
|
2019-07-18 00:02:07 +08:00
|
|
|
length: {label: 'dialog.create_gif.length', type: 'number', value: 10, step: 0.25},
|
|
|
|
fps: {label: 'dialog.create_gif.fps', type: 'number', value: 10},
|
2019-08-01 06:01:47 +08:00
|
|
|
quality:{label: 'dialog.create_gif.compression', type: 'number', value: 20, min: 1, max: 80},
|
2021-05-18 04:29:55 +08:00
|
|
|
color: {label: 'dialog.create_gif.color', type: 'color', value: '#00000000'},
|
2019-07-18 00:02:07 +08:00
|
|
|
turn: {label: 'dialog.create_gif.turn', type: 'number', value: 0, min: -10, max: 10},
|
|
|
|
play: {label: 'dialog.create_gif.play', type: 'checkbox', condition: Animator.open},
|
|
|
|
},
|
|
|
|
onConfirm: function(formData) {
|
2021-05-18 04:29:55 +08:00
|
|
|
let background = formData.color.toHex8String() != '#00000000' ? formData.color.toHexString() : undefined;
|
2019-07-18 00:02:07 +08:00
|
|
|
Screencam.createGif({
|
2020-03-05 03:56:17 +08:00
|
|
|
length_mode: formData.length_mode,
|
|
|
|
length: limitNumber(formData.length, 0.1, 24000),
|
2019-07-18 00:02:07 +08:00
|
|
|
fps: limitNumber(formData.fps, 0.5, 30),
|
|
|
|
quality: limitNumber(formData.quality, 0, 30),
|
2021-05-18 04:29:55 +08:00
|
|
|
background,
|
2020-03-05 03:56:17 +08:00
|
|
|
play: formData.play,
|
2019-07-18 00:02:07 +08:00
|
|
|
turnspeed: formData.turn,
|
|
|
|
}, Screencam.returnScreenshot)
|
|
|
|
this.hide()
|
|
|
|
}
|
|
|
|
}).show()
|
|
|
|
}
|
|
|
|
})
|
2019-12-16 03:04:31 +08:00
|
|
|
new Action('timelapse', {
|
|
|
|
icon: 'timelapse',
|
|
|
|
category: 'view',
|
|
|
|
condition: isApp,
|
|
|
|
click: function () {
|
|
|
|
if (!Prop.recording) {
|
|
|
|
new Dialog({
|
|
|
|
id: 'timelapse',
|
|
|
|
title: tl('action.timelapse'),
|
|
|
|
draggable: true,
|
|
|
|
form: {
|
|
|
|
interval: {label: 'dialog.timelapse.interval', type: 'number', value: 10, step: 0.25},
|
|
|
|
source: {label: 'dialog.timelapse.source', type: 'select', value: 'preview', options: {
|
|
|
|
preview: 'data.preview',
|
|
|
|
locked: 'dialog.timelapse.source.locked',
|
|
|
|
interface: 'dialog.timelapse.source.interface',
|
|
|
|
}, condition: isApp},
|
|
|
|
destination: {label: 'dialog.timelapse.destination', type: 'folder', value: ''},
|
|
|
|
},
|
|
|
|
onConfirm: function(formData) {
|
|
|
|
Screencam.recordTimelapse(formData);
|
|
|
|
this.hide()
|
|
|
|
}
|
|
|
|
}).show();
|
|
|
|
} else {
|
|
|
|
Screencam.stopTimelapse();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('screenshot_app', {
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'icon-bb_interface',
|
|
|
|
category: 'view',
|
|
|
|
condition: isApp,
|
|
|
|
click: function () {Screencam.fullScreen()}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('toggle_quad_view', {
|
2021-06-16 01:05:24 +08:00
|
|
|
icon: 'grid_view',
|
2019-07-18 00:02:07 +08:00
|
|
|
category: 'view',
|
2019-08-18 00:26:14 +08:00
|
|
|
condition: () => !Modes.display,
|
2019-07-18 00:02:07 +08:00
|
|
|
keybind: new Keybind({key: 9}),
|
|
|
|
click: function () {
|
|
|
|
main_preview.toggleFullscreen()
|
|
|
|
}
|
|
|
|
})
|
2020-07-16 15:32:59 +08:00
|
|
|
new Action('focus_on_selection', {
|
|
|
|
icon: 'center_focus_weak',
|
|
|
|
category: 'view',
|
|
|
|
condition: () => !Modes.display,
|
|
|
|
click: function () {
|
2021-09-15 06:26:07 +08:00
|
|
|
if (Prop.active_panel == 'uv') {
|
|
|
|
UVEditor.focusOnSelection()
|
2021-04-10 19:16:05 +08:00
|
|
|
|
2021-09-15 06:26:07 +08:00
|
|
|
} else {
|
|
|
|
let preview = quad_previews.current;
|
|
|
|
let center = new THREE.Vector3().fromArray(getSelectionCenter());
|
|
|
|
center.add(scene.position);
|
2021-04-10 19:16:05 +08:00
|
|
|
|
2021-09-15 06:26:07 +08:00
|
|
|
let difference = new THREE.Vector3().copy(preview.controls.target).sub(center);
|
|
|
|
difference.divideScalar(6)
|
2021-04-10 19:16:05 +08:00
|
|
|
|
2021-09-15 06:26:07 +08:00
|
|
|
let i = 0;
|
|
|
|
let interval = setInterval(() => {
|
|
|
|
preview.controls.target.sub(difference);
|
2021-04-10 19:16:05 +08:00
|
|
|
|
2021-09-15 06:26:07 +08:00
|
|
|
if (preview.angle != null) {
|
|
|
|
preview.camera.position.sub(difference);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
if (i == 6) clearInterval(interval);
|
2021-04-10 19:16:05 +08:00
|
|
|
|
2021-09-15 06:26:07 +08:00
|
|
|
}, 16.66)
|
|
|
|
}
|
2020-07-16 15:32:59 +08:00
|
|
|
}
|
|
|
|
})
|
2020-03-05 03:56:17 +08:00
|
|
|
|
|
|
|
new Action('toggle_camera_projection', {
|
|
|
|
icon: 'switch_video',
|
2019-07-18 00:02:07 +08:00
|
|
|
category: 'view',
|
2020-03-05 03:56:17 +08:00
|
|
|
condition: _ => (!preview.movingBackground || !Modes.display),
|
|
|
|
keybind: new Keybind({key: 101}),
|
2019-07-18 00:02:07 +08:00
|
|
|
click: function () {
|
2021-02-20 07:02:56 +08:00
|
|
|
quad_previews.current.setProjectionMode(!quad_previews.current.isOrtho, true);
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
2020-03-05 03:56:17 +08:00
|
|
|
new Action('camera_initial', {
|
|
|
|
name: tl('action.load_camera_angle', tl('menu.preview.angle.initial')),
|
|
|
|
description: tl('action.load_camera_angle.desc', tl('menu.preview.angle.initial')),
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'videocam',
|
2020-03-05 03:56:17 +08:00
|
|
|
color: 'y',
|
2019-07-18 00:02:07 +08:00
|
|
|
category: 'view',
|
2019-07-19 23:31:22 +08:00
|
|
|
condition: _ => !Modes.display,
|
2020-03-05 03:56:17 +08:00
|
|
|
keybind: new Keybind({key: 97}),
|
2019-07-18 00:02:07 +08:00
|
|
|
click: function () {
|
2020-03-05 03:56:17 +08:00
|
|
|
quad_previews.current.loadAnglePreset(DefaultCameraPresets[0])
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('camera_top', {
|
2020-03-05 03:56:17 +08:00
|
|
|
name: tl('action.load_camera_angle', tl('direction.top')),
|
|
|
|
description: tl('action.load_camera_angle.desc', tl('direction.top')),
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'videocam',
|
|
|
|
color: 'y',
|
|
|
|
category: 'view',
|
2019-07-19 23:31:22 +08:00
|
|
|
condition: _ => !Modes.display,
|
2019-07-18 00:02:07 +08:00
|
|
|
keybind: new Keybind({key: 104}),
|
|
|
|
click: function () {
|
2020-03-05 03:56:17 +08:00
|
|
|
quad_previews.current.loadAnglePreset(DefaultCameraPresets[1])
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('camera_bottom', {
|
2020-03-05 03:56:17 +08:00
|
|
|
name: tl('action.load_camera_angle', tl('direction.bottom')),
|
|
|
|
description: tl('action.load_camera_angle.desc', tl('direction.bottom')),
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'videocam',
|
|
|
|
color: 'y',
|
|
|
|
category: 'view',
|
2019-07-19 23:31:22 +08:00
|
|
|
condition: _ => !Modes.display,
|
2019-07-18 00:02:07 +08:00
|
|
|
keybind: new Keybind({key: 98}),
|
|
|
|
click: function () {
|
2020-03-05 03:56:17 +08:00
|
|
|
quad_previews.current.loadAnglePreset(DefaultCameraPresets[2])
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('camera_south', {
|
2020-03-05 03:56:17 +08:00
|
|
|
name: tl('action.load_camera_angle', tl('direction.south')),
|
|
|
|
description: tl('action.load_camera_angle.desc', tl('direction.south')),
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'videocam',
|
|
|
|
color: 'z',
|
|
|
|
category: 'view',
|
2019-07-19 23:31:22 +08:00
|
|
|
condition: _ => !Modes.display,
|
2019-07-18 00:02:07 +08:00
|
|
|
keybind: new Keybind({key: 100}),
|
|
|
|
click: function () {
|
2020-03-05 03:56:17 +08:00
|
|
|
quad_previews.current.loadAnglePreset(DefaultCameraPresets[3])
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('camera_north', {
|
2020-03-05 03:56:17 +08:00
|
|
|
name: tl('action.load_camera_angle', tl('direction.north')),
|
|
|
|
description: tl('action.load_camera_angle.desc', tl('direction.north')),
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'videocam',
|
|
|
|
color: 'z',
|
|
|
|
category: 'view',
|
2019-07-19 23:31:22 +08:00
|
|
|
condition: _ => !Modes.display,
|
2019-07-18 00:02:07 +08:00
|
|
|
keybind: new Keybind({key: 102}),
|
|
|
|
click: function () {
|
2020-03-05 03:56:17 +08:00
|
|
|
quad_previews.current.loadAnglePreset(DefaultCameraPresets[4])
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('camera_east', {
|
2020-03-05 03:56:17 +08:00
|
|
|
name: tl('action.load_camera_angle', tl('direction.east')),
|
|
|
|
description: tl('action.load_camera_angle.desc', tl('direction.east')),
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'videocam',
|
|
|
|
color: 'x',
|
|
|
|
category: 'view',
|
2019-07-19 23:31:22 +08:00
|
|
|
condition: _ => !Modes.display,
|
2019-07-18 00:02:07 +08:00
|
|
|
keybind: new Keybind({key: 103}),
|
|
|
|
click: function () {
|
2020-03-05 03:56:17 +08:00
|
|
|
quad_previews.current.loadAnglePreset(DefaultCameraPresets[5])
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('camera_west', {
|
2020-03-05 03:56:17 +08:00
|
|
|
name: tl('action.load_camera_angle', tl('direction.west')),
|
|
|
|
description: tl('action.load_camera_angle.desc', tl('direction.west')),
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'videocam',
|
|
|
|
color: 'x',
|
|
|
|
category: 'view',
|
2019-07-19 23:31:22 +08:00
|
|
|
condition: _ => !Modes.display,
|
2019-07-18 00:02:07 +08:00
|
|
|
keybind: new Keybind({key: 105}),
|
|
|
|
click: function () {
|
2020-03-05 03:56:17 +08:00
|
|
|
quad_previews.current.loadAnglePreset(DefaultCameraPresets[6])
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|