2018-03-29 02:48:11 +08:00
|
|
|
//Actions
|
|
|
|
function origin2geometry() {
|
2019-02-04 04:09:35 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
Undo.initEdit({group: Group.selected})
|
2019-02-04 04:09:35 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
if (!Group.selected || Group.selected.children.length === 0) return;
|
2018-10-18 01:50:25 +08:00
|
|
|
var position = [0, 0, 0]
|
2019-07-18 00:02:07 +08:00
|
|
|
Group.selected.children.forEach(function(obj) {
|
2019-02-04 04:09:35 +08:00
|
|
|
if (obj.type === 'cube') {
|
|
|
|
position[0] += obj.from[0] + obj.size(0)/2
|
|
|
|
position[1] += obj.from[1] + obj.size(1)/2
|
|
|
|
position[2] += obj.from[2] + obj.size(2)/2
|
|
|
|
}
|
2018-10-18 01:50:25 +08:00
|
|
|
})
|
|
|
|
position.forEach(function(p, pi) {
|
2019-07-18 00:02:07 +08:00
|
|
|
position[pi] = p / Group.selected.children.length
|
2018-10-18 01:50:25 +08:00
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
Group.selected.origin = position
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
} else if (Cube.selected) {
|
|
|
|
Undo.initEdit({elements: Cube.selected})
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2019-02-04 04:09:35 +08:00
|
|
|
var center = getSelectionCenter()
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
Cube.selected.forEach(cube => {
|
2019-02-04 04:09:35 +08:00
|
|
|
cube.transferOrigin(center)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
Canvas.updatePositions()
|
|
|
|
Undo.finishEdit('origin to geometry')
|
|
|
|
}
|
|
|
|
function getSelectionCenter() {
|
|
|
|
var center = [0, 0, 0]
|
|
|
|
var i = 0;
|
|
|
|
selected.forEach(cube => {
|
|
|
|
var m = cube.mesh
|
2019-08-18 00:26:14 +08:00
|
|
|
if (m) {
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2019-02-04 04:09:35 +08:00
|
|
|
var pos = cube.getWorldCenter()
|
|
|
|
center[0] += pos.x
|
|
|
|
center[1] += pos.y
|
|
|
|
center[2] += pos.z
|
2019-07-18 00:02:07 +08:00
|
|
|
} else if (!m && cube.from) {
|
2019-08-18 00:26:14 +08:00
|
|
|
center[0] += cube.from[0]-scene.position.x;
|
|
|
|
center[1] += cube.from[1]-scene.position.y;
|
|
|
|
center[2] += cube.from[2]-scene.position.z;
|
2018-04-15 22:06:43 +08:00
|
|
|
}
|
2019-02-04 04:09:35 +08:00
|
|
|
})
|
|
|
|
for (var i = 0; i < 3; i++) {
|
|
|
|
center[i] = center[i] / selected.length
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
if (!Format.bone_rig) {
|
|
|
|
center[0] += 8;
|
|
|
|
center[1] += 8;
|
|
|
|
center[2] += 8;
|
|
|
|
}
|
2019-02-04 04:09:35 +08:00
|
|
|
return center;
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
2018-10-18 01:50:25 +08:00
|
|
|
function isMovementGlobal() {
|
2018-10-24 03:49:04 +08:00
|
|
|
if (selected.length === 0 || (!settings.local_move.value && Toolbox.selected.id !== 'resize_tool')) {
|
2018-10-18 01:50:25 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.rotate_cubes) {
|
|
|
|
if (Cube.selected.length > 1) {
|
|
|
|
if (Cube.selected[0].rotation.equals([0,0,0])) return true;
|
2018-03-29 02:48:11 +08:00
|
|
|
var i = 0;
|
2019-07-18 00:02:07 +08:00
|
|
|
while (i < Cube.selected.length) {
|
|
|
|
if (!Cube.selected[0].rotation.equals(Cube.selected[i].rotation)) {
|
2018-10-18 01:50:25 +08:00
|
|
|
return true;
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
if (Format.bone_rig) {
|
|
|
|
if (Cube.selected[0] && Cube.selected[0].parent.type === 'group') {
|
|
|
|
var ref_group = Cube.selected[0].parent
|
2018-10-18 01:50:25 +08:00
|
|
|
var i = 0;
|
2019-07-18 00:02:07 +08:00
|
|
|
while (i < Cube.selected.length) {
|
|
|
|
var obj = Cube.selected[i]
|
2018-10-18 01:50:25 +08:00
|
|
|
if (
|
|
|
|
obj.parent.type !== 'group' ||
|
|
|
|
!obj.parent.rotation.equals(ref_group.rotation)
|
|
|
|
) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true;
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
//Canvas Restriction
|
|
|
|
function isInBox(val) {
|
2019-07-18 00:02:07 +08:00
|
|
|
return !Format.canvas_limit || (val < 32 && val > -16)
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
2019-08-01 06:01:47 +08:00
|
|
|
function limitToBox(val, inflate) {
|
|
|
|
if (typeof inflate != 'number') inflate = 0;
|
2019-07-18 00:02:07 +08:00
|
|
|
if (!Format.canvas_limit) {
|
2018-10-18 01:50:25 +08:00
|
|
|
return val;
|
2019-08-01 06:01:47 +08:00
|
|
|
} else if (val + inflate > 32) {
|
|
|
|
return 32 - inflate;
|
|
|
|
} else if (val - inflate < -16) {
|
|
|
|
return -16 + inflate;
|
2018-10-18 01:50:25 +08:00
|
|
|
} else {
|
|
|
|
return val;
|
|
|
|
}
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
|
|
|
//Movement
|
2018-10-24 03:49:04 +08:00
|
|
|
function moveCubesRelative(difference, index, event) { //Multiple
|
2019-07-18 00:02:07 +08:00
|
|
|
if (!quad_previews.current || !Cube.selected.length) {
|
2018-10-24 03:49:04 +08:00
|
|
|
return;
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: Cube.selected})
|
2018-10-24 03:49:04 +08:00
|
|
|
var axes = []
|
|
|
|
// < >
|
|
|
|
// PageUpDown
|
|
|
|
// ^ v
|
|
|
|
var facing = quad_previews.current.getFacingDirection()
|
|
|
|
var height = quad_previews.current.getFacingHeight()
|
|
|
|
switch (facing) {
|
|
|
|
case 'north': axes = [0, 2, 1]; break;
|
|
|
|
case 'south': axes = [0, 2, 1]; break;
|
|
|
|
case 'west': axes = [2, 0, 1]; break;
|
|
|
|
case 'east': axes = [2, 0, 1]; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (height !== 'middle') {
|
|
|
|
if (index === 1) {
|
|
|
|
index = 2
|
|
|
|
} else if (index === 2) {
|
|
|
|
index = 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (facing === 'south' && (index === 0 || index === 1)) difference *= -1
|
|
|
|
if (facing === 'west' && index === 0) difference *= -1
|
|
|
|
if (facing === 'east' && index === 1) difference *= -1
|
|
|
|
if (index === 2 && height !== 'down') difference *= -1
|
|
|
|
if (index === 1 && height === 'up') difference *= -1
|
|
|
|
|
|
|
|
if (event) {
|
2019-08-18 00:26:14 +08:00
|
|
|
difference *= canvasGridSize(event.shiftKey, event.ctrlOrCmd);
|
2018-10-24 03:49:04 +08:00
|
|
|
}
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
Cube.selected.forEach(cube => {
|
|
|
|
cube.move(difference, axes[index])
|
2018-10-24 03:49:04 +08:00
|
|
|
})
|
|
|
|
Canvas.updatePositions()
|
|
|
|
Undo.finishEdit('move')
|
|
|
|
}
|
2018-03-29 02:48:11 +08:00
|
|
|
//Rotate
|
2018-10-18 01:50:25 +08:00
|
|
|
function rotateSelected(axis, steps) {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (!Cube.selected.length) return;
|
|
|
|
Undo.initEdit({elements: Cube.selected});
|
2018-10-18 01:50:25 +08:00
|
|
|
if (!steps) steps = 1
|
|
|
|
var origin = [8, 8, 8]
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Group.selected && Format.bone_rig) {
|
|
|
|
origin = Group.selected.origin.slice()
|
|
|
|
} else if (Format.bone_rig) {
|
2018-10-18 01:50:25 +08:00
|
|
|
origin = [0, 0, 0]
|
|
|
|
} else {
|
2019-07-18 00:02:07 +08:00
|
|
|
origin = Cube.selected[0].origin.slice()
|
2018-10-18 01:50:25 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
Cube.selected.forEach(function(obj) {
|
2018-10-18 01:50:25 +08:00
|
|
|
obj.roll(axis, steps, origin)
|
|
|
|
})
|
|
|
|
updateSelection()
|
|
|
|
Undo.finishEdit('rotate')
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
|
|
|
//Mirror
|
2018-10-18 01:50:25 +08:00
|
|
|
function mirrorSelected(axis) {
|
2019-08-18 00:26:14 +08:00
|
|
|
if (Modes.animate && Timeline.selected.length) {
|
|
|
|
|
|
|
|
Undo.initEdit({keyframes: Timeline.selected})
|
|
|
|
for (var kf of Timeline.selected) {
|
|
|
|
kf.flip(axis)
|
|
|
|
}
|
|
|
|
Undo.finishEdit('flipped keyframes');
|
|
|
|
updateKeyframeSelection();
|
|
|
|
Animator.preview();
|
|
|
|
|
|
|
|
} else if (Modes.edit && Cube.selected.length) {
|
|
|
|
Undo.initEdit({elements: Cube.selected, outliner: Format.bone_rig})
|
|
|
|
var center = 8
|
|
|
|
if (Format.bone_rig) {
|
|
|
|
center = 0
|
|
|
|
if (Group.selected && Group.selected.matchesSelection()) {
|
|
|
|
function flipGroup(group) {
|
|
|
|
if (group.type === 'group') {
|
|
|
|
for (var i = 0; i < 3; i++) {
|
|
|
|
if (i === axis) {
|
|
|
|
group.origin[i] *= -1
|
|
|
|
} else {
|
|
|
|
group.rotation[i] *= -1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (axis == 0 && group.name.includes('right')) {
|
|
|
|
group.name = group.name.replace(/right/g, 'left').replace(/2/, '');
|
|
|
|
} else if (axis == 0 && group.name.includes('left')) {
|
|
|
|
group.name = group.name.replace(/left/g, 'right').replace(/2/, '');
|
2018-12-16 23:18:20 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2018-12-16 23:18:20 +08:00
|
|
|
}
|
2019-08-18 00:26:14 +08:00
|
|
|
flipGroup(Group.selected)
|
|
|
|
Group.selected.forEachChild(flipGroup)
|
2018-12-16 23:18:20 +08:00
|
|
|
}
|
|
|
|
}
|
2019-08-18 00:26:14 +08:00
|
|
|
Cube.selected.forEach(function(obj) {
|
|
|
|
obj.flip(axis, center, false)
|
|
|
|
if (Project.box_uv && axis === 0) {
|
|
|
|
obj.shade = !obj.shade
|
|
|
|
Canvas.updateUV(obj)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
updateSelection()
|
|
|
|
Undo.finishEdit('mirror')
|
2018-10-18 01:50:25 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const Vertexsnap = {
|
|
|
|
step1: true,
|
|
|
|
vertexes: new THREE.Object3D(),
|
|
|
|
vertexed_cubes: [],
|
|
|
|
hovering: false,
|
|
|
|
addVertexes: function(cube) {
|
|
|
|
if (Vertexsnap.vertexed_cubes.includes(cube)) return;
|
|
|
|
if (cube.visibility === false) return;
|
|
|
|
|
|
|
|
$('#preview').get(0).removeEventListener("mousemove", Vertexsnap.hoverCanvas)
|
|
|
|
$('#preview').get(0).addEventListener("mousemove", Vertexsnap.hoverCanvas)
|
|
|
|
|
|
|
|
var o_vertices = cube.mesh.geometry.vertices
|
|
|
|
cube.mesh.updateMatrixWorld()
|
|
|
|
o_vertices.forEach(function(v, id) {
|
|
|
|
var outline_color = '0x'+app_colors.accent.hex.replace('#', '')
|
|
|
|
//Each vertex needs it's own material for hovering
|
|
|
|
var material = new THREE.MeshBasicMaterial({color: parseInt(outline_color)})
|
|
|
|
var mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material)
|
|
|
|
var pos = mesh.position.copy(v)
|
|
|
|
pos.applyMatrix4(cube.mesh.matrixWorld)
|
2019-07-19 23:31:22 +08:00
|
|
|
if (!Format.bone_rig) {
|
|
|
|
pos.addScalar(8)
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
mesh.rotation.copy(cube.mesh.rotation)
|
|
|
|
mesh.cube = cube
|
|
|
|
mesh.isVertex = true
|
|
|
|
mesh.vertex_id = id
|
|
|
|
Vertexsnap.vertexes.add(mesh)
|
|
|
|
})
|
|
|
|
Vertexsnap.vertexed_cubes.push(cube)
|
|
|
|
Vertexsnap.updateVertexSize()
|
|
|
|
},
|
|
|
|
removeVertexes: function() {
|
|
|
|
var i = Vertexsnap.vertexes.children.length
|
|
|
|
while (i >= 0) {
|
|
|
|
Vertexsnap.vertexes.remove(Vertexsnap.vertexes.children[i])
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
Vertexsnap.vertexed_cubes = []
|
|
|
|
$('#preview').get(0).removeEventListener("mousemove", Vertexsnap.hoverCanvas)
|
|
|
|
},
|
|
|
|
hoverCanvas: function(event) {
|
|
|
|
if (Vertexsnap.hovering) {
|
|
|
|
Vertexsnap.vertexes.children.forEach(function(v) {
|
|
|
|
if (v.type === 'Line') {
|
|
|
|
Vertexsnap.vertexes.remove(v)
|
|
|
|
} else {
|
|
|
|
v.material.color.set(parseInt('0x'+app_colors.accent.hex.replace('#', '')))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
let data = Canvas.raycast()
|
|
|
|
if (!data || !data.vertex) {
|
|
|
|
Blockbench.setStatusBarText()
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var vertex = data.vertex
|
|
|
|
vertex.material.color.g = 1
|
|
|
|
Vertexsnap.hovering = true
|
|
|
|
|
|
|
|
if (Vertexsnap.step1 === false) {
|
|
|
|
//Line
|
|
|
|
var geometry = new THREE.Geometry();
|
|
|
|
geometry.vertices.push(Vertexsnap.vertex_pos);
|
|
|
|
geometry.vertices.push(vertex.position);
|
|
|
|
var line = new THREE.Line(geometry, Vertexsnap.lineMaterial);
|
|
|
|
line.renderOrder = 900
|
|
|
|
Vertexsnap.vertexes.add(line)
|
|
|
|
//Measure
|
|
|
|
var diff = new THREE.Vector3().copy(Vertexsnap.vertex_pos)
|
|
|
|
diff.sub(vertex.position)
|
|
|
|
Blockbench.setStatusBarText(tl('status_bar.vertex_distance', [trimFloatNumber(diff.length())] ))
|
|
|
|
}
|
|
|
|
},
|
|
|
|
select: function() {
|
|
|
|
Vertexsnap.removeVertexes()
|
|
|
|
Cube.selected.forEach(function(obj) {
|
|
|
|
Vertexsnap.addVertexes(obj)
|
|
|
|
})
|
|
|
|
if (Cube.selected.length) {
|
|
|
|
$('#preview').css('cursor', (Vertexsnap.step1 ? 'copy' : 'alias'))
|
|
|
|
}
|
|
|
|
Vertexsnap.lineMaterial = Canvas.outlineMaterial.clone()
|
|
|
|
Vertexsnap.lineMaterial.depthTest = false
|
|
|
|
},
|
|
|
|
canvasClick: function(data) {
|
|
|
|
if (!data.vertex) return;
|
|
|
|
|
|
|
|
if (Vertexsnap.step1) {
|
|
|
|
Vertexsnap.step1 = false
|
|
|
|
Vertexsnap.vertex_pos = data.vertex.position
|
|
|
|
Vertexsnap.vertex_id = data.vertex.vertex_id
|
|
|
|
Vertexsnap.cubes = Cube.selected.slice()
|
|
|
|
Vertexsnap.removeVertexes()
|
|
|
|
$('#preview').css('cursor', (Vertexsnap.step1 ? 'copy' : 'alias'))
|
|
|
|
} else {
|
|
|
|
Vertexsnap.snap(data)
|
|
|
|
$('#preview').css('cursor', (Vertexsnap.step1 ? 'copy' : 'alias'))
|
|
|
|
}
|
|
|
|
Blockbench.setStatusBarText()
|
|
|
|
},
|
|
|
|
snap: function(data) {
|
|
|
|
Undo.initEdit({elements: Vertexsnap.cubes})
|
|
|
|
|
|
|
|
var global_delta = data.vertex.position
|
|
|
|
global_delta.sub(Vertexsnap.vertex_pos)
|
|
|
|
|
|
|
|
if (BarItems.vertex_snap_mode.get() === 'scale') {
|
|
|
|
//Scale
|
|
|
|
|
|
|
|
var m;
|
|
|
|
switch (Vertexsnap.vertex_id) {
|
|
|
|
case 0: m=[ 1,1,1 ]; break;
|
|
|
|
case 1: m=[ 1,1,0 ]; break;
|
|
|
|
case 2: m=[ 1,0,1 ]; break;
|
|
|
|
case 3: m=[ 1,0,0 ]; break;
|
|
|
|
case 4: m=[ 0,1,0 ]; break;
|
|
|
|
case 5: m=[ 0,1,1 ]; break;
|
|
|
|
case 6: m=[ 0,0,0 ]; break;
|
|
|
|
case 7: m=[ 0,0,1 ]; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vertexsnap.cubes.forEach(function(obj) {
|
|
|
|
var q = obj.mesh.getWorldQuaternion(new THREE.Quaternion()).inverse()
|
|
|
|
var cube_pos = new THREE.Vector3().copy(global_delta).applyQuaternion(q)
|
|
|
|
|
|
|
|
for (i=0; i<3; i++) {
|
|
|
|
if (m[i] === 1) {
|
2019-08-01 06:01:47 +08:00
|
|
|
obj.to[i] = limitToBox(obj.to[i] + cube_pos.getComponent(i), obj.inflate)
|
2019-07-18 00:02:07 +08:00
|
|
|
} else {
|
2019-08-01 06:01:47 +08:00
|
|
|
obj.from[i] = limitToBox(obj.from[i] + cube_pos.getComponent(i), -obj.inflate)
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Project.box_uv && obj.visibility) {
|
|
|
|
Canvas.updateUV(obj)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
Vertexsnap.cubes.forEach(function(obj) {
|
|
|
|
var cube_pos = new THREE.Vector3().copy(global_delta)
|
|
|
|
if (Format.rotate_cubes && !Format.bone_rig) {
|
|
|
|
obj.origin[0] += cube_pos.getComponent(0)
|
|
|
|
obj.origin[1] += cube_pos.getComponent(1)
|
|
|
|
obj.origin[2] += cube_pos.getComponent(2)
|
|
|
|
}
|
2019-08-01 06:01:47 +08:00
|
|
|
var in_box = obj.move(cube_pos);
|
|
|
|
if (!in_box) {
|
|
|
|
Blockbench.showMessageBox({translateKey: 'canvas_limit_error'})
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
})
|
|
|
|
}
|
2018-12-16 23:18:20 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
Vertexsnap.removeVertexes()
|
|
|
|
Canvas.updateAllPositions()
|
|
|
|
Undo.finishEdit('vertex snap')
|
|
|
|
Vertexsnap.step1 = true
|
|
|
|
},
|
|
|
|
updateVertexSize: function() {
|
|
|
|
Vertexsnap.vertexes.children.forEach(function(v,i) {
|
|
|
|
var scaleVector = new THREE.Vector3();
|
|
|
|
var scale = scaleVector.subVectors(v.position, Transformer.camera.position).length() / 500;
|
2019-07-26 19:33:29 +08:00
|
|
|
scale = (Math.sqrt(scale) + scale/4) * 1.2
|
2019-07-18 00:02:07 +08:00
|
|
|
v.scale.set(scale, scale, scale)
|
|
|
|
})
|
|
|
|
}
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
|
|
|
//Scale
|
|
|
|
function scaleAll(save, size) {
|
2018-10-18 01:50:25 +08:00
|
|
|
if (save === true) {
|
|
|
|
hideDialog()
|
|
|
|
}
|
|
|
|
if (size === undefined) {
|
|
|
|
size = $('#model_scale_label').val()
|
|
|
|
}
|
2019-04-08 00:53:33 +08:00
|
|
|
var origin = [
|
|
|
|
parseFloat($('#scaling_origin_x').val())||0,
|
|
|
|
parseFloat($('#scaling_origin_y').val())||0,
|
|
|
|
parseFloat($('#scaling_origin_z').val())||0,
|
|
|
|
]
|
2019-07-19 23:31:22 +08:00
|
|
|
var overflow = [];
|
2018-10-18 01:50:25 +08:00
|
|
|
selected.forEach(function(obj) {
|
|
|
|
obj.autouv = 0;
|
|
|
|
origin.forEach(function(ogn, i) {
|
|
|
|
if ($('#model_scale_'+getAxisLetter(i)+'_axis').is(':checked')) {
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
if (obj.from) {
|
|
|
|
obj.from[i] = (obj.before.from[i] - ogn) * size;
|
2019-07-19 23:31:22 +08:00
|
|
|
if (obj.from[i] + ogn > 32 || obj.from[i] + ogn < -16) overflow.push(obj);
|
2019-08-01 06:01:47 +08:00
|
|
|
obj.from[i] = limitToBox(obj.from[i] + ogn, -obj.inflate);
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
if (obj.to) {
|
|
|
|
obj.to[i] = (obj.before.to[i] - ogn) * size;
|
2019-07-19 23:31:22 +08:00
|
|
|
if (obj.to[i] + ogn > 32 || obj.to[i] + ogn < -16) overflow.push(obj);
|
2019-08-01 06:01:47 +08:00
|
|
|
obj.to[i] = limitToBox(obj.to[i] + ogn, obj.inflate);
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
if (obj.origin) {
|
|
|
|
obj.origin[i] = (obj.before.origin[i] - ogn) * size;
|
|
|
|
obj.origin[i] = obj.origin[i] + ogn;
|
|
|
|
}
|
2018-10-18 01:50:25 +08:00
|
|
|
} else {
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
if (obj.from) obj.from[i] = obj.before.from[i];
|
|
|
|
if (obj.to) obj.to[i] = obj.before.to[i];
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
if (obj.origin) obj.origin[i] = obj.before.origin[i];
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2018-10-18 01:50:25 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
if (save === true) {
|
|
|
|
delete obj.before
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Project.box_uv) {
|
2018-10-18 01:50:25 +08:00
|
|
|
Canvas.updateUV(obj)
|
|
|
|
}
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
Group.selected.forEachChild((g) => {
|
2018-12-29 19:26:02 +08:00
|
|
|
g.origin[0] = g.old_origin[0] * size
|
|
|
|
g.origin[1] = g.old_origin[1] * size
|
|
|
|
g.origin[2] = g.old_origin[2] * size
|
|
|
|
if (save === true) {
|
|
|
|
delete g.old_origin
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}, Group)
|
2018-12-29 19:26:02 +08:00
|
|
|
}
|
2019-07-19 23:31:22 +08:00
|
|
|
if (overflow.length && Format.canvas_limit) {
|
|
|
|
scaleAll.overflow = overflow;
|
2018-10-18 01:50:25 +08:00
|
|
|
$('#scaling_clipping_warning').text('Model clipping: Your model is too large for the canvas')
|
2019-02-04 04:09:35 +08:00
|
|
|
$('#scale_overflow_btn').css('display', 'inline-block')
|
2018-10-18 01:50:25 +08:00
|
|
|
} else {
|
|
|
|
$('#scaling_clipping_warning').text('')
|
2019-02-04 04:09:35 +08:00
|
|
|
$('#scale_overflow_btn').hide()
|
2018-10-18 01:50:25 +08:00
|
|
|
}
|
|
|
|
Canvas.updatePositions()
|
|
|
|
if (save === true) {
|
|
|
|
Undo.finishEdit('scale')
|
|
|
|
}
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
|
|
|
function modelScaleSync(label) {
|
2018-10-18 01:50:25 +08:00
|
|
|
if (label) {
|
|
|
|
var size = $('#model_scale_label').val()
|
|
|
|
$('#model_scale_range').val(size)
|
|
|
|
} else {
|
|
|
|
var size = $('#model_scale_range').val()
|
|
|
|
$('#model_scale_label').val(size)
|
|
|
|
}
|
|
|
|
scaleAll(false, size)
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
|
|
|
function cancelScaleAll() {
|
2018-10-18 01:50:25 +08:00
|
|
|
selected.forEach(function(obj) {
|
|
|
|
if (obj === undefined) return;
|
2019-07-18 00:02:07 +08:00
|
|
|
if (obj.from) obj.from = obj.before.from;
|
|
|
|
if (obj.to) obj.to = obj.before.to;
|
|
|
|
if (obj.origin) obj.origin = obj.before.origin;
|
2018-10-18 01:50:25 +08:00
|
|
|
delete obj.before
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Project.box_uv) {
|
|
|
|
Canvas.updateUV(obj)
|
|
|
|
}
|
2018-10-18 01:50:25 +08:00
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
Group.selected.forEachChild((g) => {
|
2018-12-29 19:26:02 +08:00
|
|
|
g.origin[0] = g.old_origin[0]
|
|
|
|
g.origin[1] = g.old_origin[1]
|
|
|
|
g.origin[2] = g.old_origin[2]
|
|
|
|
delete g.old_origin
|
2019-07-18 00:02:07 +08:00
|
|
|
}, Group)
|
2018-12-29 19:26:02 +08:00
|
|
|
}
|
2018-10-18 01:50:25 +08:00
|
|
|
Canvas.updatePositions()
|
|
|
|
hideDialog()
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
2019-02-04 04:09:35 +08:00
|
|
|
function scaleAllSelectOverflow() {
|
|
|
|
cancelScaleAll()
|
|
|
|
selected.length = 0;
|
2019-07-19 23:31:22 +08:00
|
|
|
scaleAll.overflow.forEach(obj => {
|
2019-07-18 00:02:07 +08:00
|
|
|
obj.selectLow()
|
2019-02-04 04:09:35 +08:00
|
|
|
})
|
|
|
|
updateSelection();
|
|
|
|
}
|
2018-03-29 02:48:11 +08:00
|
|
|
//Center
|
|
|
|
function centerCubesAll(axis) {
|
2018-10-18 01:50:25 +08:00
|
|
|
centerCubes(0, false)
|
|
|
|
centerCubes(1, false)
|
|
|
|
centerCubes(2, false)
|
|
|
|
Canvas.updatePositions()
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
|
|
|
function centerCubes(axis, update) {
|
2018-11-12 04:19:08 +08:00
|
|
|
if (!selected.length) return;
|
2018-10-18 01:50:25 +08:00
|
|
|
var average = 0;
|
|
|
|
selected.forEach(function(obj) {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (obj.movable) average += obj.from[axis]
|
2019-08-18 00:26:14 +08:00
|
|
|
if (obj.resizable) average += obj.to[axis]
|
2018-10-18 01:50:25 +08:00
|
|
|
})
|
|
|
|
average = average / (selected.length * 2)
|
2019-07-18 00:02:07 +08:00
|
|
|
var difference = (Format.bone_rig ? 0 : 8) - average
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2018-10-18 01:50:25 +08:00
|
|
|
selected.forEach(function(obj) {
|
2019-08-01 06:01:47 +08:00
|
|
|
if (obj.movable) obj.from[axis] = limitToBox(obj.from[axis] + difference, obj.inflate);
|
2019-08-18 00:26:14 +08:00
|
|
|
if (obj.resizable) obj.to[axis] = limitToBox(obj.to[axis] + difference, obj.inflate);
|
2019-07-18 00:02:07 +08:00
|
|
|
if (obj.origin) obj.origin[axis] += difference;
|
2018-10-18 01:50:25 +08:00
|
|
|
})
|
2018-03-29 02:48:11 +08:00
|
|
|
|
2018-10-18 01:50:25 +08:00
|
|
|
if (update !== false) {
|
|
|
|
Canvas.updatePositions()
|
|
|
|
}
|
2018-03-29 02:48:11 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
//Rotate
|
2018-12-27 21:03:04 +08:00
|
|
|
function getRotationInterval(event) {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.rotation_limit) {
|
2018-12-27 21:03:04 +08:00
|
|
|
return 22.5;
|
2019-08-18 00:26:14 +08:00
|
|
|
} else if (event.shiftKey && event.ctrlOrCmd) {
|
2018-12-27 21:03:04 +08:00
|
|
|
return 0.25;
|
|
|
|
} else if (event.shiftKey) {
|
|
|
|
return 45;
|
2019-08-18 00:26:14 +08:00
|
|
|
} else if (event.ctrlOrCmd) {
|
2018-12-27 21:03:04 +08:00
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
function getRotationObject() {
|
|
|
|
if (Format.bone_rig && Group.selected) return Group.selected;
|
|
|
|
if (Format.rotate_cubes && Cube.selected.length) return Cube.selected;
|
|
|
|
}
|
2018-12-27 21:03:04 +08:00
|
|
|
function rotateOnAxis(value, fixed, axis) {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
if (!Group.selected) return;
|
2018-12-27 21:03:04 +08:00
|
|
|
if (!fixed) {
|
2019-07-18 00:02:07 +08:00
|
|
|
value = value + Group.selected.rotation[axis]
|
2018-12-27 21:03:04 +08:00
|
|
|
}
|
|
|
|
value = Math.trimDeg(value)
|
2019-07-18 00:02:07 +08:00
|
|
|
Group.selected.rotation[axis] = value
|
2018-12-27 21:03:04 +08:00
|
|
|
Canvas.updateAllBones()
|
2019-07-18 00:02:07 +08:00
|
|
|
return
|
2018-12-27 21:03:04 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
if (!Format.rotate_cubes) return;
|
2018-12-27 21:03:04 +08:00
|
|
|
//Warning
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.rotation_limit && settings.dialog_rotation_limit.value) {
|
2018-12-27 21:03:04 +08:00
|
|
|
var i = 0;
|
2019-07-18 00:02:07 +08:00
|
|
|
while (i < Cube.selected.length) {
|
|
|
|
if (Cube.selected[i].rotation[(axis+1)%3] ||
|
|
|
|
Cube.selected[i].rotation[(axis+2)%3]
|
2018-12-27 21:03:04 +08:00
|
|
|
) {
|
|
|
|
i = Infinity
|
|
|
|
|
|
|
|
Blockbench.showMessageBox({
|
|
|
|
title: tl('message.rotation_limit.title'),
|
|
|
|
icon: 'rotate_right',
|
|
|
|
message: tl('message.rotation_limit.message'),
|
|
|
|
buttons: [tl('dialog.ok'), tl('dialog.dontshowagain')]
|
|
|
|
}, function(r) {
|
|
|
|
if (r === 1) {
|
|
|
|
settings.dialog_rotation_limit.value = false
|
2019-07-18 00:02:07 +08:00
|
|
|
Settings.save()
|
2018-12-27 21:03:04 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
return;
|
|
|
|
//Gotta stop the numslider here
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var axis_letter = getAxisLetter(axis)
|
2019-07-18 00:02:07 +08:00
|
|
|
var origin = Cube.selected[0].origin
|
|
|
|
Cube.selected.forEach(function(obj, i) {
|
2019-02-04 04:09:35 +08:00
|
|
|
if (!obj.rotation.allEqual(0)) {
|
2018-12-27 21:03:04 +08:00
|
|
|
origin = obj.origin
|
|
|
|
}
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
/*
|
2019-02-04 04:09:35 +08:00
|
|
|
if (origin.allEqual(8)) {
|
|
|
|
origin = getSelectionCenter()
|
|
|
|
origin.forEach((n, ni) => {
|
|
|
|
origin[ni] = Math.round(n*2)/2
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
}*/
|
|
|
|
Cube.selected.forEach(function(obj, i) {
|
2019-02-04 04:09:35 +08:00
|
|
|
if (obj.rotation.allEqual(0)) {
|
2018-12-29 19:26:02 +08:00
|
|
|
obj.origin = origin.slice()
|
2018-12-27 21:03:04 +08:00
|
|
|
}
|
|
|
|
var obj_val = value;
|
|
|
|
if (!fixed) {
|
|
|
|
obj_val += obj.rotation[axis]
|
|
|
|
}
|
2018-12-29 19:26:02 +08:00
|
|
|
obj_val = Math.trimDeg(obj_val)
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.rotation_limit) {
|
2018-12-27 21:03:04 +08:00
|
|
|
//Limit To 1 Axis
|
|
|
|
obj.rotation[(axis+1)%3] = 0
|
|
|
|
obj.rotation[(axis+2)%3] = 0
|
|
|
|
//Limit Angle
|
|
|
|
obj_val = Math.round(obj_val/22.5)*22.5
|
|
|
|
if (obj_val > 45 || obj_val < -45) {
|
|
|
|
|
|
|
|
let f = obj_val > 45
|
|
|
|
obj.roll(axis, f!=(axis==1) ? 1 : 3)
|
|
|
|
obj_val = f ? -22.5 : 22.5;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
obj_val = Math.trimDeg(obj_val)
|
|
|
|
}
|
|
|
|
obj.rotation[axis] = obj_val
|
|
|
|
obj.rotation_axis = axis_letter
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-11-12 04:19:08 +08:00
|
|
|
BARS.defineActions(function() {
|
|
|
|
function moveOnAxis(value, fixed, axis) {
|
|
|
|
selected.forEach(function(obj, i) {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (obj.movable) {
|
|
|
|
obj.move(value, axis, fixed)
|
2018-11-12 04:19:08 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_pos_x', {
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => (selected.length && Modes.edit),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
|
|
|
return selected[0].from[0]
|
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
|
|
|
moveOnAxis(value, fixed, 0)
|
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('move')
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_pos_y', {
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => (selected.length && Modes.edit),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
|
|
|
return selected[0].from[1]
|
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
|
|
|
moveOnAxis(value, fixed, 1)
|
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('move')
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_pos_z', {
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => (selected.length && Modes.edit),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
|
|
|
return selected[0].from[2]
|
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
|
|
|
moveOnAxis(value, fixed, 2)
|
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('move')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
|
2019-08-18 00:26:14 +08:00
|
|
|
function resizeOnAxis(value, fixed, axis) {
|
2018-11-12 04:19:08 +08:00
|
|
|
selected.forEach(function(obj, i) {
|
2019-08-18 00:26:14 +08:00
|
|
|
if (obj.resizable) {
|
|
|
|
obj.resize(value, axis, false, fixed, true)
|
2018-11-12 04:19:08 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_size_x', {
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => (Cube.selected.length && Modes.edit),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
return Cube.selected[0].to[0] - Cube.selected[0].from[0]
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
2019-08-18 00:26:14 +08:00
|
|
|
resizeOnAxis(value, fixed, 0)
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: Cube.selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('resize')
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_size_y', {
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => (Cube.selected.length && Modes.edit),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
return Cube.selected[0].to[1] - Cube.selected[0].from[1]
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
2019-08-18 00:26:14 +08:00
|
|
|
resizeOnAxis(value, fixed, 1)
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: Cube.selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('resize')
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_size_z', {
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => (Cube.selected.length && Modes.edit),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
return Cube.selected[0].to[2] - Cube.selected[0].from[2]
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
2019-08-18 00:26:14 +08:00
|
|
|
resizeOnAxis(value, fixed, 2)
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: Cube.selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('resize')
|
|
|
|
}
|
|
|
|
})
|
2019-08-01 06:01:47 +08:00
|
|
|
//Inflate
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_inflate', {
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: function() {return Cube.selected.length && Modes.edit},
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
return Cube.selected[0].inflate
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
2019-07-18 00:02:07 +08:00
|
|
|
Cube.selected.forEach(function(obj, i) {
|
2019-08-18 00:26:14 +08:00
|
|
|
var v = value
|
|
|
|
if (!fixed) {
|
|
|
|
v += obj.inflate
|
2018-11-12 04:19:08 +08:00
|
|
|
}
|
2019-08-18 00:26:14 +08:00
|
|
|
v = obj.from[0] - Math.clamp(obj.from[0]-v, -16, 32);
|
|
|
|
v = obj.from[1] - Math.clamp(obj.from[1]-v, -16, 32);
|
|
|
|
v = obj.from[2] - Math.clamp(obj.from[2]-v, -16, 32);
|
|
|
|
v = Math.clamp(obj.to[0]+v, -16, 32) - obj.to[0];
|
|
|
|
v = Math.clamp(obj.to[1]+v, -16, 32) - obj.to[1];
|
|
|
|
v = Math.clamp(obj.to[2]+v, -16, 32) - obj.to[2];
|
|
|
|
obj.inflate = v
|
2018-11-12 04:19:08 +08:00
|
|
|
})
|
|
|
|
Canvas.updatePositions()
|
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: Cube.selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('inflate')
|
|
|
|
}
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2018-12-27 21:03:04 +08:00
|
|
|
//Rotation
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_rotation_x', {
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => (Modes.edit && getRotationObject()),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
return Group.selected.rotation[0];
|
|
|
|
}
|
|
|
|
if (Format.rotate_cubes && Cube.selected[0]) {
|
|
|
|
return Cube.selected[0].rotation[0];
|
|
|
|
}
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
|
|
|
rotateOnAxis(value, fixed, 0)
|
2018-12-27 21:03:04 +08:00
|
|
|
Canvas.updatePositions()
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: Cube.selected, group: Group.selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('rotate')
|
|
|
|
},
|
|
|
|
getInterval: getRotationInterval
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_rotation_y', {
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => (Modes.edit && getRotationObject()),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
return Group.selected.rotation[1];
|
|
|
|
}
|
|
|
|
if (Format.rotate_cubes && Cube.selected[0]) {
|
|
|
|
return Cube.selected[0].rotation[1];
|
|
|
|
}
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
|
|
|
rotateOnAxis(value, fixed, 1)
|
2018-12-27 21:03:04 +08:00
|
|
|
Canvas.updatePositions()
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected, group: Group.selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('rotate')
|
|
|
|
},
|
|
|
|
getInterval: getRotationInterval
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_rotation_z', {
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => (Modes.edit && getRotationObject()),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
return Group.selected.rotation[2];
|
|
|
|
}
|
|
|
|
if (Format.rotate_cubes && Cube.selected[0]) {
|
|
|
|
return Cube.selected[0].rotation[2];
|
|
|
|
}
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
|
|
|
rotateOnAxis(value, fixed, 2)
|
2018-12-27 21:03:04 +08:00
|
|
|
Canvas.updatePositions()
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected, group: Group.selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('rotate')
|
|
|
|
},
|
|
|
|
getInterval: getRotationInterval
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
function rotateCondition() {
|
|
|
|
return (Modes.edit && (
|
|
|
|
(Format.bone_rig && Group.selected) ||
|
|
|
|
(Format.rotate_cubes && Cube.selected.length)
|
|
|
|
))
|
|
|
|
}
|
2018-11-12 04:19:08 +08:00
|
|
|
|
2019-08-01 06:01:47 +08:00
|
|
|
//Origin
|
2018-11-12 04:19:08 +08:00
|
|
|
function moveOriginOnAxis(value, fixed, axis) {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Group.selected) {
|
2018-11-12 04:19:08 +08:00
|
|
|
var diff = value
|
|
|
|
if (fixed) {
|
2019-07-18 00:02:07 +08:00
|
|
|
diff -= Group.selected.origin[axis]
|
2018-11-12 04:19:08 +08:00
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
Group.selected.origin[axis] += diff
|
2018-11-12 04:19:08 +08:00
|
|
|
Canvas.updatePositions()
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig) {
|
2019-04-08 00:53:33 +08:00
|
|
|
Canvas.updateAllBones()
|
|
|
|
}
|
2018-11-12 04:19:08 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
selected.forEach(function(obj, i) {
|
|
|
|
var diff = value
|
|
|
|
if (fixed) {
|
|
|
|
diff -= obj.origin[axis]
|
|
|
|
}
|
|
|
|
obj.origin[axis] += diff
|
|
|
|
})
|
|
|
|
Canvas.updatePositions()
|
|
|
|
}
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_origin_x', {
|
2019-07-19 23:31:22 +08:00
|
|
|
condition: () => (Modes.edit && getRotationObject()),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
return Group.selected.origin[0];
|
|
|
|
}
|
|
|
|
if (Format.rotate_cubes && Cube.selected[0]) {
|
|
|
|
return Cube.selected[0].origin[0];
|
|
|
|
}
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
|
|
|
moveOriginOnAxis(value, fixed, 0)
|
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected, group: Group.selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('origin')
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_origin_y', {
|
2019-07-19 23:31:22 +08:00
|
|
|
condition: () => (Modes.edit && getRotationObject()),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
return Group.selected.origin[1];
|
|
|
|
}
|
|
|
|
if (Format.rotate_cubes && Cube.selected[0]) {
|
|
|
|
return Cube.selected[0].origin[1];
|
|
|
|
}
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
|
|
|
moveOriginOnAxis(value, fixed, 1)
|
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected, group: Group.selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('origin')
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new NumSlider('slider_origin_z', {
|
2019-07-19 23:31:22 +08:00
|
|
|
condition: () => (Modes.edit && getRotationObject()),
|
2018-11-12 04:19:08 +08:00
|
|
|
get: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
return Group.selected.origin[2];
|
|
|
|
}
|
|
|
|
if (Format.rotate_cubes && Cube.selected[0]) {
|
|
|
|
return Cube.selected[0].origin[2];
|
|
|
|
}
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
change: function(value, fixed) {
|
|
|
|
moveOriginOnAxis(value, fixed, 2)
|
|
|
|
},
|
|
|
|
onBefore: function() {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected, group: Group.selected})
|
2018-11-12 04:19:08 +08:00
|
|
|
},
|
|
|
|
onAfter: function() {
|
|
|
|
Undo.finishEdit('origin')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('scale', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'settings_overscan',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
2018-12-03 02:37:06 +08:00
|
|
|
$('#model_scale_range, #model_scale_label').val(1)
|
|
|
|
$('#scaling_clipping_warning').text('')
|
2018-11-12 04:19:08 +08:00
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected, outliner: Format.bone_rig})
|
2018-11-12 04:19:08 +08:00
|
|
|
|
|
|
|
selected.forEach(function(obj) {
|
|
|
|
obj.before = {
|
2019-07-18 00:02:07 +08:00
|
|
|
from: obj.from ? obj.from.slice() : undefined,
|
|
|
|
to: obj.to ? obj.to.slice() : undefined,
|
|
|
|
origin: obj.origin ? obj.origin.slice() : undefined
|
2018-11-12 04:19:08 +08:00
|
|
|
}
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Format.bone_rig && Group.selected) {
|
|
|
|
Group.selected.forEachChild((g) => {
|
2018-12-29 19:26:02 +08:00
|
|
|
g.old_origin = g.origin.slice();
|
2019-07-18 00:02:07 +08:00
|
|
|
}, Group, true)
|
2018-12-29 19:26:02 +08:00
|
|
|
}
|
2018-11-12 04:19:08 +08:00
|
|
|
showDialog('scaling')
|
2019-07-18 00:02:07 +08:00
|
|
|
var v = Format.bone_rig ? 0 : 8;
|
|
|
|
var origin = Group.selected ? Group.selected.origin : [v, 0, v];
|
2019-04-08 00:53:33 +08:00
|
|
|
$('#scaling_origin_x').val(origin[0])
|
|
|
|
$('#scaling_origin_y').val(origin[1])
|
|
|
|
$('#scaling_origin_z').val(origin[2])
|
2019-02-04 04:09:35 +08:00
|
|
|
scaleAll(false, 1)
|
2018-11-12 04:19:08 +08:00
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('rotate_x_cw', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'rotate_right',
|
|
|
|
color: 'x',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
|
|
|
rotateSelected(0, 1);
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('rotate_x_ccw', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'rotate_left',
|
|
|
|
color: 'x',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
|
|
|
rotateSelected(0, 3);
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('rotate_y_cw', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'rotate_right',
|
|
|
|
color: 'y',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
|
|
|
rotateSelected(1, 1);
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('rotate_y_ccw', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'rotate_left',
|
|
|
|
color: 'y',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
|
|
|
rotateSelected(1, 3);
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('rotate_z_cw', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'rotate_right',
|
|
|
|
color: 'z',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
|
|
|
rotateSelected(2, 1);
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('rotate_z_ccw', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'rotate_left',
|
|
|
|
color: 'z',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
|
|
|
rotateSelected(2, 3);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('flip_x', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'icon-mirror_x',
|
|
|
|
color: 'x',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
2019-08-18 00:26:14 +08:00
|
|
|
mirrorSelected(0);
|
2018-11-12 04:19:08 +08:00
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('flip_y', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'icon-mirror_y',
|
|
|
|
color: 'y',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
|
|
|
mirrorSelected(1);
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('flip_z', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'icon-mirror_z',
|
|
|
|
color: 'z',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
|
|
|
mirrorSelected(2);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('center_x', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'vertical_align_center',
|
|
|
|
color: 'x',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected});
|
2018-11-12 04:19:08 +08:00
|
|
|
centerCubes(0);
|
|
|
|
Undo.finishEdit('center')
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('center_y', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'vertical_align_center',
|
|
|
|
color: 'y',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected});
|
2018-11-12 04:19:08 +08:00
|
|
|
centerCubes(1);
|
|
|
|
Undo.finishEdit('center')
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('center_z', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'vertical_align_center',
|
|
|
|
color: 'z',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected});
|
2018-11-12 04:19:08 +08:00
|
|
|
centerCubes(2);
|
|
|
|
Undo.finishEdit('center')
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('center_all', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'filter_center_focus',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: selected});
|
2018-11-12 04:19:08 +08:00
|
|
|
centerCubesAll();
|
|
|
|
Undo.finishEdit('center')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('toggle_visibility', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'visibility',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {toggleCubeProperty('visibility')}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('toggle_export', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'save',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {toggleCubeProperty('export')}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('toggle_autouv', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'fullscreen_exit',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {toggleCubeProperty('autouv')}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('toggle_shade', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'wb_sunny',
|
|
|
|
category: 'transform',
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => !Project.box_uv,
|
2019-02-04 04:09:35 +08:00
|
|
|
click: function () {toggleCubeProperty('shade')}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('toggle_mirror_uv', {
|
2019-02-04 04:09:35 +08:00
|
|
|
icon: 'icon-mirror_x',
|
|
|
|
category: 'transform',
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => Project.box_uv,
|
2018-11-12 04:19:08 +08:00
|
|
|
click: function () {toggleCubeProperty('shade')}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('update_autouv', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'brightness_auto',
|
|
|
|
category: 'transform',
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: () => !Project.box_uv,
|
2018-11-12 04:19:08 +08:00
|
|
|
click: function () {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Cube.selected.length) {
|
|
|
|
Undo.initEdit({elements: Cube.selected[0].forSelected(), selection: true})
|
|
|
|
Cube.selected[0].forSelected(function(cube) {
|
2018-11-12 04:19:08 +08:00
|
|
|
cube.mapAutoUV()
|
|
|
|
})
|
|
|
|
Undo.finishEdit('update_autouv')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('origin_to_geometry', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'filter_center_focus',
|
|
|
|
category: 'transform',
|
|
|
|
click: function () {origin2geometry()}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('rescale_toggle', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'check_box_outline_blank',
|
|
|
|
category: 'transform',
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: function() {return Format.rotation_limit && Cube.selected.length;},
|
2018-11-12 04:19:08 +08:00
|
|
|
click: function () {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({elements: Cube.selected})
|
|
|
|
var value = !Cube.selected[0].rescale
|
|
|
|
Cube.selected.forEach(function(cube) {
|
2018-11-12 04:19:08 +08:00
|
|
|
cube.rescale = value
|
|
|
|
})
|
|
|
|
Canvas.updatePositions()
|
|
|
|
updateNslideValues()
|
|
|
|
Undo.finishEdit('rescale')
|
|
|
|
}
|
|
|
|
})
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('bone_reset_toggle', {
|
2018-11-12 04:19:08 +08:00
|
|
|
icon: 'check_box_outline_blank',
|
|
|
|
category: 'transform',
|
2019-07-18 00:02:07 +08:00
|
|
|
condition: function() {return Format.bone_rig && Group.selected;},
|
2018-11-12 04:19:08 +08:00
|
|
|
click: function () {
|
2019-07-18 00:02:07 +08:00
|
|
|
Undo.initEdit({group: Group.selected})
|
|
|
|
Group.selected.reset = !Group.selected.reset
|
2018-11-12 04:19:08 +08:00
|
|
|
updateNslideValues()
|
|
|
|
Undo.finishEdit('bone_reset')
|
|
|
|
}
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2019-08-18 00:26:14 +08:00
|
|
|
new Action('remove_blank_faces', {
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: 'cancel_presentation',
|
|
|
|
category: 'filter',
|
|
|
|
condition: () => !Format.box_uv,
|
|
|
|
click: function () {
|
|
|
|
Undo.initEdit({elements: Cube.selected})
|
|
|
|
var arr = Cube.selected.slice()
|
|
|
|
var empty_cubes = [];
|
|
|
|
unselectAll()
|
|
|
|
arr.forEach(cube => {
|
|
|
|
var clear_count = 0;
|
|
|
|
for (var face in cube.faces) {
|
|
|
|
var face_tag = cube.faces[face];
|
|
|
|
if (face_tag.texture == false) {
|
|
|
|
face_tag.texture = null
|
|
|
|
clear_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (clear_count == 6) {
|
|
|
|
empty_cubes.push(cube);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
updateSelection();
|
|
|
|
if (empty_cubes.length) {
|
|
|
|
Blockbench.showMessageBox({
|
|
|
|
title: tl('message.cleared_blank_faces.title'),
|
|
|
|
icon: 'rotate_right',
|
|
|
|
message: tl('message.cleared_blank_faces.message', [empty_cubes.length]),
|
|
|
|
buttons: ['generic.remove', 'dialog.cancel']
|
|
|
|
}, function(r) {
|
|
|
|
empty_cubes.forEach(cube => {
|
|
|
|
if (r == 0) {
|
|
|
|
cube.remove();
|
|
|
|
} else {
|
|
|
|
for (var face in cube.faces) {
|
|
|
|
cube.faces[face].texture = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
updateSelection();
|
|
|
|
Canvas.updateAllFaces();
|
|
|
|
Undo.finishEdit('remove blank faces');
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
Canvas.updateAllFaces();
|
|
|
|
Undo.finishEdit('remove blank faces');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2018-11-12 04:19:08 +08:00
|
|
|
})
|