mirror of
https://github.com/JannisX11/blockbench.git
synced 2024-11-21 01:13:37 +08:00
v3.0.5
This commit is contained in:
parent
fd3085b8fa
commit
d5426e9998
@ -4,4 +4,4 @@ Blockbench is a free, modern model editor for Minecraft Java and Bedrock Edition
|
||||
Blockbench features a modern and intuitive UI, plugin support and innovative features. It is the industry standard for creating custom 3D models for the Minecraft Marketplace.
|
||||
Project and download page: [blockbench.net](https://www.blockbench.net)
|
||||
|
||||
![Interface](https://blockbench.net/wp-content/uploads/2018/10/crane.png)
|
||||
![Interface](https://blockbench.net/wp-content/uploads/2019/07/interface_skidsteer.png)
|
||||
|
@ -27,7 +27,7 @@
|
||||
<script>
|
||||
if (typeof module === 'object') {window.module = module; module = undefined;}//jQuery Fix
|
||||
const isApp = typeof require !== 'undefined';
|
||||
const appVersion = '3.0.4';
|
||||
const appVersion = '3.0.5';
|
||||
</script>
|
||||
<script src="lib/vue.min.js"></script>
|
||||
<script src="lib/vue_sortable.js"></script>
|
||||
@ -938,8 +938,8 @@
|
||||
<div class="texture_res">{{ texture.error
|
||||
? texture.getErrorMessage()
|
||||
: (Format.single_texture
|
||||
? (texture.res + ' x ' + texture.res/texture.ratio + 'px')
|
||||
: (texture.ratio == 1? texture.res + 'px': (texture.res + 'px, ' + texture.frameCount+'f'))
|
||||
? (texture.width + ' x ' + texture.height + 'px')
|
||||
: (texture.ratio == 1? texture.width + 'px': (texture.width + 'px, ' + texture.frameCount+'f'))
|
||||
)
|
||||
}}</div>
|
||||
</li>
|
||||
|
@ -23,7 +23,7 @@ class Animation {
|
||||
Merge.number(this, data, 'length')
|
||||
if (data.bones) {
|
||||
for (var key in data.bones) {
|
||||
var group = Outliner.root.findRecursive( isUUID(key) ? 'uuid' : 'name', key )
|
||||
var group = Group.all.findInArray( isUUID(key) ? 'uuid' : 'name', key )
|
||||
if (group) {
|
||||
var ba = this.getBoneAnimator(group)
|
||||
var kfs = data.bones[key]
|
||||
@ -45,7 +45,7 @@ class Animation {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
undoCopy(options) {
|
||||
getUndoCopy(options) {
|
||||
var scope = this;
|
||||
var copy = {
|
||||
uuid: this.uuid,
|
||||
@ -69,7 +69,7 @@ class Animation {
|
||||
}
|
||||
var kfs_copy = copy.bones[uuid] = []
|
||||
kfs.forEach(kf => {
|
||||
kfs_copy.push(kf.undoCopy())
|
||||
kfs_copy.push(kf.getUndoCopy())
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -99,13 +99,40 @@ class Animation {
|
||||
Animator.preview()
|
||||
return this;
|
||||
}
|
||||
createUniqueName(arr) {
|
||||
var scope = this;
|
||||
var others = Animator.animations;
|
||||
if (arr && arr.length) {
|
||||
arr.forEach(g => {
|
||||
others.safePush(g)
|
||||
})
|
||||
}
|
||||
var name = this.name.replace(/\d+$/, '');
|
||||
function check(n) {
|
||||
for (var i = 0; i < others.length; i++) {
|
||||
if (others[i] !== scope && others[i].name == n) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (check(this.name)) {
|
||||
return this.name;
|
||||
}
|
||||
for (var num = 2; num < 8e3; num++) {
|
||||
if (check(name+num)) {
|
||||
scope.name = name+num;
|
||||
return scope.name;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
rename() {
|
||||
var scope = this;
|
||||
Blockbench.textPrompt('message.rename_animation', this.name, function(name) {
|
||||
if (name && name !== scope.name) {
|
||||
Undo.initEdit({animations: [scope]})
|
||||
scope.name = name
|
||||
Undo.finishEdit('rename animation')
|
||||
Undo.initEdit({animations: [scope]});
|
||||
scope.name = name;
|
||||
scope.createUniqueName();
|
||||
Undo.finishEdit('rename animation');
|
||||
}
|
||||
})
|
||||
return this;
|
||||
@ -193,7 +220,6 @@ class Animation {
|
||||
}
|
||||
}
|
||||
Animation.prototype.menu = new Menu([
|
||||
'rename',
|
||||
{name: 'menu.animation.loop', icon: (a) => (a.loop?'check_box':'check_box_outline_blank'), click: function(animation) {
|
||||
animation.loop = !animation.loop
|
||||
}},
|
||||
@ -203,7 +229,10 @@ class Animation {
|
||||
{name: 'menu.animation.anim_time_update', icon: 'update', click: function(animation) {
|
||||
animation.editUpdateVariable()
|
||||
}},
|
||||
'delete'
|
||||
'_',
|
||||
'duplicate',
|
||||
'rename',
|
||||
'delete',
|
||||
/*
|
||||
rename
|
||||
Loop: checkbox
|
||||
@ -220,7 +249,7 @@ class BoneAnimator {
|
||||
this.animation = animation;
|
||||
}
|
||||
getGroup() {
|
||||
this.group = Outliner.root.findRecursive('uuid', this.uuid)
|
||||
this.group = Group.all.findInArray('uuid', this.uuid)
|
||||
if (!this.group) {
|
||||
console.log('no group found for '+this.uuid)
|
||||
if (this.animation && this.animation.bones[this.uuid]) {
|
||||
@ -429,7 +458,7 @@ class BoneAnimator {
|
||||
}
|
||||
}
|
||||
class Keyframe {
|
||||
constructor(data) {
|
||||
constructor(data, uuid) {
|
||||
this.type = 'keyframe'
|
||||
this.channel = 'rotation'//, 'position', 'scale'
|
||||
this.channel_index = 0;
|
||||
@ -440,7 +469,7 @@ class Keyframe {
|
||||
this.z = '0';
|
||||
this.w = '0';
|
||||
this.isQuaternion = false;
|
||||
this.uuid = guid()
|
||||
this.uuid = (uuid && isUUID(uuid)) ? uuid : guid();
|
||||
if (typeof data === 'object') {
|
||||
this.extend(data)
|
||||
if (this.channel === 'scale' && data.x == undefined && data.y == undefined && data.z == undefined) {
|
||||
@ -631,7 +660,7 @@ class Keyframe {
|
||||
this.channel_index = Animator.channel_index.indexOf(this.channel)
|
||||
return this;
|
||||
}
|
||||
undoCopy() {
|
||||
getUndoCopy() {
|
||||
var copy = {
|
||||
channel: this.channel_index,
|
||||
time: this.time,
|
||||
@ -860,7 +889,7 @@ const Animator = {
|
||||
//Bones
|
||||
for (var bone_name in a.bones) {
|
||||
var b = a.bones[bone_name]
|
||||
var group = Outliner.root.findRecursive('name', bone_name)
|
||||
var group = Group.all.findInArray('name', bone_name)
|
||||
if (group) {
|
||||
var ba = new BoneAnimator(group.uuid, animation);
|
||||
animation.bones[group.uuid] = ba;
|
||||
@ -912,7 +941,7 @@ const Animator = {
|
||||
if (!channels[kf.channel]) {
|
||||
channels[kf.channel] = {}
|
||||
}
|
||||
let timecode = trimFloatNumber(Math.round(kf.time*60)/60) + ''
|
||||
let timecode = Math.clamp(trimFloatNumber(Math.round(kf.time*60)/60), 0) + '';
|
||||
if (!timecode.includes('.')) {
|
||||
timecode = timecode + '.0'
|
||||
}
|
||||
|
194
js/blockbench.js
194
js/blockbench.js
@ -193,6 +193,47 @@ function updateNslideValues() {
|
||||
}
|
||||
}
|
||||
}
|
||||
function setProjectResolution(width, height, modify_uv) {
|
||||
let old_res = {
|
||||
x: Project.texture_width,
|
||||
y: Project.texture_height
|
||||
}
|
||||
Project.texture_width = width;
|
||||
Project.texture_height = height;
|
||||
|
||||
if (Project.texture_width / old_res.x != Project.texture_width / old_res.y) {
|
||||
modify_uv = false;
|
||||
}
|
||||
|
||||
if (modify_uv) {
|
||||
var multiplier = [
|
||||
Project.texture_width/entityMode.old_res.x,
|
||||
Project.texture_height/entityMode.old_res.y
|
||||
]
|
||||
function shiftCube(cube, axis) {
|
||||
if (Project.box_uv) {
|
||||
obj.uv_offset[axis] *= multiplier[axis];
|
||||
} else {
|
||||
for (var face in cube.faces) {
|
||||
var uv = cube.faces[face];
|
||||
uv[axis] *= multiplier[axis];
|
||||
uv[axis+2] *= multiplier[axis];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (old_res.x != Project.texture_width && Math.areMultiples(old_res.x, Project.texture_width)) {
|
||||
Cube.all.forEach(cube => shiftCube(cube, 0));
|
||||
}
|
||||
if (old_res.y != Project.texture_height && Math.areMultiples(old_res.x, Project.texture_width)) {
|
||||
Cube.all.forEach(cube => shiftCube(cube, 1));
|
||||
}
|
||||
}
|
||||
|
||||
Canvas.updateAllUVs()
|
||||
if (selected.length) {
|
||||
main_uv.loadData()
|
||||
}
|
||||
}
|
||||
|
||||
//Selections
|
||||
function updateSelection() {
|
||||
@ -469,155 +510,6 @@ const TickUpdates = {
|
||||
}
|
||||
}
|
||||
}
|
||||
const Screencam = {
|
||||
fullScreen(options, cb) {
|
||||
setTimeout(function() {
|
||||
currentwindow.capturePage(function(screenshot) {
|
||||
var dataUrl = screenshot.toDataURL()
|
||||
dataUrl = dataUrl.replace('data:image/png;base64,','')
|
||||
Jimp.read(Buffer.from(dataUrl, 'base64')).then(function(image) {
|
||||
|
||||
if (options && options.width && options.height) {
|
||||
image.contain(options.width, options.height)
|
||||
}
|
||||
|
||||
image.getBase64(Jimp.MIME_PNG, function(a, dataUrl){
|
||||
Screencam.returnScreenshot(dataUrl, cb)
|
||||
})
|
||||
});
|
||||
})
|
||||
}, 40)
|
||||
},
|
||||
returnScreenshot(dataUrl, cb) {
|
||||
if (cb) {
|
||||
cb(dataUrl)
|
||||
} else if (isApp) {
|
||||
var screenshot = nativeImage.createFromDataURL(dataUrl)
|
||||
var img = new Image()
|
||||
var is_gif = dataUrl.substr(5, 9) == 'image/gif'
|
||||
img.src = dataUrl
|
||||
|
||||
var btns = [tl('dialog.cancel'), tl('dialog.save')]
|
||||
if (!is_gif) {
|
||||
btns.push(tl('message.screenshot.clipboard'))
|
||||
}
|
||||
Blockbench.showMessageBox({
|
||||
translateKey: 'screenshot',
|
||||
icon: img,
|
||||
buttons: btns,
|
||||
confirm: 1,
|
||||
cancel: 0
|
||||
}, function(result) {
|
||||
if (result === 1) {
|
||||
electron.dialog.showSaveDialog(currentwindow, {filters: [ {name: tl('data.image'), extensions: [is_gif ? 'gif' : 'png']} ]}, function (fileName) {
|
||||
if (fileName === undefined) {
|
||||
return;
|
||||
}
|
||||
fs.writeFile(fileName, Buffer(dataUrl.split(',')[1], 'base64'), err => {})
|
||||
})
|
||||
} else if (result === 2) {
|
||||
clipboard.writeImage(screenshot)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
new Dialog({
|
||||
title: tl('message.screenshot.right_click'),
|
||||
id: 'screenie',
|
||||
lines: ['<img src="'+dataUrl+'" width="600px" class="allow_default_menu"></img>'],
|
||||
draggable: true,
|
||||
singleButton: true
|
||||
}).show()
|
||||
}
|
||||
},
|
||||
cleanCanvas(options, cb) {
|
||||
quad_previews.current.screenshot(options, cb)
|
||||
},
|
||||
createGif(options, cb) {
|
||||
/*
|
||||
var images = [];
|
||||
var preview = quad_previews.current;
|
||||
var interval = setInterval(function() {
|
||||
|
||||
var shot = preview.canvas.toDataURL()
|
||||
images.push(shot);
|
||||
|
||||
if (images.length >= options.length/1000*options.fps) {
|
||||
clearInterval(interval);
|
||||
gifshot.createGIF({
|
||||
images,
|
||||
frameDuration: 10/options.fps,
|
||||
progressCallback: cl,
|
||||
text: 'BLOCKBENCH'
|
||||
}, obj => {
|
||||
Screencam.returnScreenshot(obj.image, cb);
|
||||
})
|
||||
}
|
||||
}, 1000/options.fps)
|
||||
//Does not support transparency
|
||||
*/
|
||||
|
||||
|
||||
if (typeof options !== 'object') {
|
||||
options = {}
|
||||
}
|
||||
if (!options.length) {
|
||||
options.length = 1000
|
||||
}
|
||||
var preview = quad_previews.current;
|
||||
var interval = options.fps ? (1000/options.fps) : 100
|
||||
var gif = new GIF({
|
||||
repeat: options.repeat,
|
||||
quality: options.quality,
|
||||
transparent: 0x000000,
|
||||
})
|
||||
var frame_count = (options.length/interval)
|
||||
|
||||
if (options.turnspeed) {
|
||||
preview.controls.autoRotate = true;
|
||||
preview.controls.autoRotateSpeed = options.turnspeed;
|
||||
}
|
||||
|
||||
gif.on('finished', blob => {
|
||||
var reader = new FileReader()
|
||||
reader.onload = () => {
|
||||
if (!options.silent) {
|
||||
Blockbench.setProgress(0)
|
||||
Blockbench.setStatusBarText()
|
||||
}
|
||||
Screencam.returnScreenshot(reader.result, cb)
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
})
|
||||
if (!options.silent) {
|
||||
Blockbench.setStatusBarText(tl('status_bar.recording_gif'))
|
||||
gif.on('progress', Blockbench.setProgress)
|
||||
}
|
||||
var frames = 0;
|
||||
var loop = setInterval(() => {
|
||||
var img = new Image()
|
||||
img.src = preview.canvas.toDataURL()
|
||||
img.onload = () => {
|
||||
gif.addFrame(img, {delay: interval})
|
||||
}
|
||||
Blockbench.setProgress(interval*frames/options.length)
|
||||
frames++;
|
||||
}, interval)
|
||||
|
||||
setTimeout(() => {
|
||||
clearInterval(loop)
|
||||
if (!options.silent) {
|
||||
Blockbench.setStatusBarText(tl('status_bar.processing_gif'))
|
||||
}
|
||||
gif.render()
|
||||
if (Animator.open && Timeline.playing) {
|
||||
Timeline.pause()
|
||||
}
|
||||
if (options.turnspeed) {
|
||||
preview.controls.autoRotate = false;
|
||||
}
|
||||
}, options.length)
|
||||
}
|
||||
}
|
||||
const Clipbench = {
|
||||
elements: [],
|
||||
copy(event, cut) {
|
||||
@ -732,6 +624,9 @@ const Clipbench = {
|
||||
function iterate(obj, parent) {
|
||||
if (obj.children) {
|
||||
var copy = new Group(obj).addTo(parent).init()
|
||||
if (Format.bone_rig) {
|
||||
copy.createUniqueName();
|
||||
}
|
||||
if (obj.children && obj.children.length) {
|
||||
obj.children.forEach((child) => {
|
||||
iterate(child, copy)
|
||||
@ -823,6 +718,5 @@ const Clipbench = {
|
||||
}
|
||||
|
||||
const entityMode = {
|
||||
old_res: {},
|
||||
hardcodes: {"geometry.chicken":{"body":{"rotation":[90,0,0]}},"geometry.llama":{"chest1":{"rotation":[0,90,0]},"chest2":{"rotation":[0,90,0]},"body":{"rotation":[90,0,0]}},"geometry.cow":{"body":{"rotation":[90,0,0]}},"geometry.sheep.sheared":{"body":{"rotation":[90,0,0]}},"geometry.sheep":{"body":{"rotation":[90,0,0]}},"geometry.phantom":{"body":{"rotation":[0,0,0]},"wing0":{"rotation":[0,0,5.7]},"wingtip0":{"rotation":[0,0,5.7]},"wing1":{"rotation":[0,0,-5.7]},"wingtip1":{"rotation":[0,0,-5.7]},"head":{"rotation":[11.5,0,0]},"tail":{"rotation":[0,0,0]},"tailtip":{"rotation":[0,0,0]}},"geometry.pig":{"body":{"rotation":[90,0,0]}},"geometry.ocelot":{"body":{"rotation":[90,0,0]},"tail1":{"rotation":[90,0,0]},"tail2":{"rotation":[90,0,0]}},"geometry.cat":{"body":{"rotation":[90,0,0]},"tail1":{"rotation":[90,0,0]},"tail2":{"rotation":[90,0,0]}},"geometry.turtle":{"eggbelly":{"rotation":[90,0,0]},"body":{"rotation":[90,0,0]}},"geometry.villager.witch":{"hat2":{"rotation":[-3,0,1.5]},"hat3":{"rotation":[-6,0,3]},"hat4":{"rotation":[-12,0,6]}},"geometry.pufferfish.mid":{"spines_top_front":{"rotation":[45,0,0]},"spines_top_back":{"rotation":[-45,0,0]},"spines_bottom_front":{"rotation":[-45,0,0]},"spines_bottom_back":{"rotation":[45,0,0]},"spines_left_front":{"rotation":[0,45,0]},"spines_left_back":{"rotation":[0,-45,0]},"spines_right_front":{"rotation":[0,-45,0]},"spines_right_back":{"rotation":[0,45,0]}},"geometry.pufferfish.large":{"spines_top_front":{"rotation":[45,0,0]},"spines_top_back":{"rotation":[-45,0,0]},"spines_bottom_front":{"rotation":[-45,0,0]},"spines_bottom_back":{"rotation":[45,0,0]},"spines_left_front":{"rotation":[0,45,0]},"spines_left_back":{"rotation":[0,-45,0]},"spines_right_front":{"rotation":[0,-45,0]},"spines_right_back":{"rotation":[0,45,0]}},"geometry.tropicalfish_a":{"leftFin":{"rotation":[0,-35,0]},"rightFin":{"rotation":[0,35,0]}},"geometry.tropicalfish_b":{"leftFin":{"rotation":[0,-35,0]},"rightFin":{"rotation":[0,35,0]}}},
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ function changeImageEditor(texture, from_settings) {
|
||||
var id = $('.dialog#image_editor option:selected').attr('id')
|
||||
var path;
|
||||
switch (id) {
|
||||
case 'ps': path = 'C:\\Program Files\\Adobe\\Adobe Photoshop CC 2018\\Photoshop.exe'; break;
|
||||
case 'ps': path = 'C:\\Program Files\\Adobe\\Adobe Photoshop CC 2019\\Photoshop.exe'; break;
|
||||
case 'gimp':path = 'C:\\Program Files\\GIMP 2\\bin\\gimp-2.10.exe'; break;
|
||||
case 'pdn': path = 'C:\\Program Files\\paint.net\\PaintDotNet.exe'; break;
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ const EditSession = {
|
||||
}, result => {
|
||||
showDialog('edit_sessions');
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
EditSession.token = token;
|
||||
@ -289,7 +290,7 @@ EditSession.Client = class {
|
||||
this.conn.send(tag)
|
||||
}
|
||||
disconnect(e) {
|
||||
Blockbench.dispatchEvent('user_leaves_session', {conn: this.conn})
|
||||
Blockbench.dispatchEvent('user_leaves_session', this)
|
||||
delete EditSession.peer.connections[this.conn.peer];
|
||||
delete EditSession.clients[this.id];
|
||||
EditSession.updateClientCount();
|
||||
@ -313,7 +314,11 @@ const Chat = {
|
||||
$('input#chat_input').val('')
|
||||
}
|
||||
if (!text) return;
|
||||
Chat.processMessage({author: EditSession.username, text: text})
|
||||
Chat.processMessage({
|
||||
author: EditSession.username,
|
||||
text: text,
|
||||
sender: EditSession.peer.id
|
||||
})
|
||||
},
|
||||
addMessage(message) {
|
||||
if (!(message instanceof Chat.Message)) {
|
||||
@ -330,7 +335,11 @@ const Chat = {
|
||||
},
|
||||
processMessage(data) {
|
||||
if (!EditSession.hosting) {
|
||||
EditSession.host.send({type: 'chat_input', data: data})
|
||||
EditSession.host.send({
|
||||
type: 'chat_input',
|
||||
data,
|
||||
sender: EditSession.peer.id
|
||||
})
|
||||
return;
|
||||
}
|
||||
var message = new Chat.Message(data)
|
||||
@ -345,7 +354,8 @@ Chat.Message = class {
|
||||
constructor(data) {
|
||||
this.author = data.author||'';
|
||||
this.author = this.author.substr(0, 64)
|
||||
this.self = (this.author && this.author === EditSession.username);
|
||||
this.sender = data.sender
|
||||
this.self = data.sender == EditSession.peer.id;
|
||||
this.text = data.text.substr(0, Chat.maxlength)||'';
|
||||
|
||||
this.html = this.text.replace(/</g, '<').replace(/>/g, '>');
|
||||
|
@ -993,7 +993,7 @@ const BARS = {
|
||||
transformerMode: 'translate',
|
||||
toolbar: Blockbench.isMobile ? 'element_origin' : 'main_tools',
|
||||
alt_tool: 'rotate_tool',
|
||||
modes: ['edit'],
|
||||
modes: ['edit', 'animate'],
|
||||
keybind: new Keybind({key: 80}),
|
||||
})
|
||||
new Tool({
|
||||
@ -1106,8 +1106,6 @@ const BARS = {
|
||||
keybind: new Keybind({key: 88, ctrl: true, shift: null}),
|
||||
click: function (event) {Clipbench.copy(event, true)}
|
||||
})
|
||||
|
||||
|
||||
new Action({
|
||||
id: 'rename',
|
||||
icon: 'text_format',
|
||||
@ -1162,6 +1160,39 @@ const BARS = {
|
||||
})
|
||||
|
||||
|
||||
new Action({
|
||||
id: 'duplicate',
|
||||
icon: 'content_copy',
|
||||
category: 'edit',
|
||||
condition: () => (Animator.selected && Modes.animate) || (Modes.edit && (selected.length || Group.selected)),
|
||||
keybind: new Keybind({key: 68, ctrl: true}),
|
||||
click: function () {
|
||||
if (Modes.animate) {
|
||||
if (Animator.selected && Prop.active_panel == 'animations') {
|
||||
var copy = Animator.selected.getUndoCopy();
|
||||
var animation = new Animation(copy);
|
||||
animation.createUniqueName();
|
||||
Animator.animations.splice(Animator.animations.indexOf(Animator.selected)+1, 0, animation)
|
||||
animation.add(true).select();
|
||||
}
|
||||
} else if (Group.selected && (Group.selected.matchesSelection() || selected.length === 0)) {
|
||||
var cubes_before = elements.length;
|
||||
Undo.initEdit({outliner: true, elements: [], selection: true});
|
||||
var g = Group.selected.duplicate();
|
||||
g.select();
|
||||
Undo.finishEdit('duplicate_group', {outliner: true, elements: elements.slice().slice(cubes_before), selection: true})
|
||||
} else {
|
||||
var added_elements = [];
|
||||
Undo.initEdit({elements: added_elements, outliner: true, selection: true})
|
||||
selected.forEach(function(obj, i) {
|
||||
var copy = obj.duplicate();
|
||||
added_elements.push(copy);
|
||||
})
|
||||
BarItems.move_tool.select();
|
||||
Undo.finishEdit('duplicate')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
//Move Cube Keys
|
||||
@ -1499,10 +1530,13 @@ const BARS = {
|
||||
children: [
|
||||
'brush_mode',
|
||||
'fill_mode',
|
||||
'_',
|
||||
'slider_brush_size',
|
||||
'slider_brush_opacity',
|
||||
'slider_brush_min_opacity',
|
||||
'slider_brush_softness'
|
||||
'slider_brush_softness',
|
||||
'_',
|
||||
'painting_grid',
|
||||
]
|
||||
})
|
||||
Toolbars.vertex_snap = new Toolbar({
|
||||
|
@ -265,8 +265,8 @@ function setupInterface() {
|
||||
try {
|
||||
interface_data = JSON.parse(interface_data)
|
||||
var old_data = Interface.data
|
||||
Interface.data.left_bar = interface_data.left_bar
|
||||
Interface.data.right_bar = interface_data.right_bar
|
||||
if (interface_data.left_bar) Interface.data.left_bar = interface_data.left_bar;
|
||||
if (interface_data.right_bar) Interface.data.right_bar = interface_data.right_bar;
|
||||
for (key in Interface.Panels) {
|
||||
if (!Interface.data.left_bar.includes(key) && !Interface.data.right_bar.includes(key)) {
|
||||
if (old_data.left_bar.includes(key)) {
|
||||
|
@ -580,6 +580,7 @@ const MenuBar = {
|
||||
]},
|
||||
'_',
|
||||
'toggle_wireframe',
|
||||
'painting_grid',
|
||||
'toggle_quad_view',
|
||||
{name: 'menu.view.screenshot', id: 'screenshot', icon: 'camera_alt', children: [
|
||||
'screenshot_model',
|
||||
|
@ -66,7 +66,7 @@ var codec = new Codec('project', {
|
||||
if (Animator.animations.length) {
|
||||
model.animations = [];
|
||||
Animator.animations.forEach(a => {
|
||||
model.animations.push(a.undoCopy({bone_names: true}))
|
||||
model.animations.push(a.getUndoCopy({bone_names: true}))
|
||||
})
|
||||
}
|
||||
|
||||
@ -227,10 +227,6 @@ BARS.defineActions(function() {
|
||||
}
|
||||
})
|
||||
|
||||
if (BarItems.save_project.keybind.key == 83 && BarItems.save_project.keybind.ctrl && !BarItems.save_project.keybind.alt && !BarItems.save_project.keybind.shift) {
|
||||
//Blockbench 3.0.2 update
|
||||
BarItems.save_project.keybind.set({key: 83, ctrl: true, alt: true}).save(true)
|
||||
}
|
||||
new Action({
|
||||
id: 'save_project_as',
|
||||
icon: 'save',
|
||||
@ -241,10 +237,6 @@ BARS.defineActions(function() {
|
||||
codec.export()
|
||||
}
|
||||
})
|
||||
if (BarItems.save_project_as.keybind.key == 83 && BarItems.save_project_as.keybind.ctrl && !BarItems.save_project_as.keybind.alt && BarItems.save_project_as.keybind.shift) {
|
||||
//Blockbench 3.0.2 update
|
||||
BarItems.save_project_as.keybind.set({key: 83, ctrl: true, alt: true, shift: true}).save(true)
|
||||
}
|
||||
})
|
||||
|
||||
})()
|
||||
|
@ -132,8 +132,8 @@ function parseGeometry(data) {
|
||||
if (b.pivot) {
|
||||
group.origin[0] *= -1
|
||||
}
|
||||
group.rotation.forEach(function(br, ri) {
|
||||
group.rotation[ri] *= -1
|
||||
group.rotation.forEach(function(br, axis) {
|
||||
group.rotation[axis] *= -1
|
||||
})
|
||||
|
||||
group.mirror_uv = b.mirror === true
|
||||
@ -148,8 +148,8 @@ function parseGeometry(data) {
|
||||
rotation: s.rotation,
|
||||
origin: s.pivot
|
||||
})
|
||||
base_cube.rotation.forEach(function(br, ri) {
|
||||
base_cube.rotation[ri] *= -1
|
||||
base_cube.rotation.forEach(function(br, axis) {
|
||||
if (axis != 2) base_cube.rotation[axis] *= -1
|
||||
})
|
||||
base_cube.origin[0] *= -1;
|
||||
if (s.origin) {
|
||||
@ -168,25 +168,28 @@ function parseGeometry(data) {
|
||||
} else if (s.uv) {
|
||||
Project.box_uv = false;
|
||||
for (var key in base_cube.faces) {
|
||||
var face = base_cube.faces[key]
|
||||
if (s.uv[key]) {
|
||||
base_cube.faces[key].extend({
|
||||
face.extend({
|
||||
uv: [
|
||||
s.uv[key].uv[0] * Project.texture_width/16,
|
||||
s.uv[key].uv[1] * Project.texture_height/16,
|
||||
s.uv[key].uv[0] * (16/Project.texture_width),
|
||||
s.uv[key].uv[1] * (16/Project.texture_height),
|
||||
]
|
||||
})
|
||||
if (s.uv[key].uv_size) {
|
||||
base_cube.faces[key].uv_size = [
|
||||
s.uv[key].uv_size[0] * Project.texture_width/16,
|
||||
s.uv[key].uv_size[1] * Project.texture_height/16,
|
||||
face.uv_size = [
|
||||
s.uv[key].uv_size[0] * (16/Project.texture_width),
|
||||
s.uv[key].uv_size[1] * (16/Project.texture_height),
|
||||
]
|
||||
|
||||
} else {
|
||||
base_cube.autouv = 1;
|
||||
base_cube.mapAutoUV();
|
||||
}
|
||||
if (key == 'up') {
|
||||
face.uv = [face.uv[2], face.uv[3], face.uv[0], face.uv[1]]
|
||||
}
|
||||
} else {
|
||||
base_cube.faces[key].texture = null;
|
||||
face.texture = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,6 +241,7 @@ function parseGeometry(data) {
|
||||
if (isApp && Project.geometry_name) {
|
||||
findEntityTexture(Project.geometry_name)
|
||||
}
|
||||
updateSelection()
|
||||
EditSession.initNewModel()
|
||||
}
|
||||
|
||||
@ -291,8 +295,8 @@ var codec = new Codec('bedrock', {
|
||||
bone.pivot[0] *= -1
|
||||
if (!g.rotation.allEqual(0)) {
|
||||
bone.rotation = g.rotation.slice()
|
||||
bone.rotation.forEach(function(br, ri) {
|
||||
bone.rotation[ri] *= -1
|
||||
bone.rotation.forEach(function(br, axis) {
|
||||
bone.rotation[axis] *= -1
|
||||
})
|
||||
}
|
||||
if (g.reset) {
|
||||
@ -326,8 +330,8 @@ var codec = new Codec('bedrock', {
|
||||
cube.pivot = obj.origin.slice();
|
||||
cube.pivot[0] *= -1
|
||||
cube.rotation = obj.rotation.slice();
|
||||
cube.rotation.forEach(function(br, ri) {
|
||||
cube.rotation[ri] *= -1
|
||||
cube.rotation.forEach(function(br, axis) {
|
||||
if (axis != 2) cube.rotation[axis] *= -1
|
||||
})
|
||||
}
|
||||
|
||||
@ -351,6 +355,12 @@ var codec = new Codec('bedrock', {
|
||||
face.uv_size[1] * entitymodel.description.texture_height/16,
|
||||
]
|
||||
});
|
||||
if (key == 'up') {
|
||||
cube.uv[key].uv[0] += cube.uv[key].uv_size[0];
|
||||
cube.uv[key].uv[1] += cube.uv[key].uv_size[1];
|
||||
cube.uv[key].uv_size[0] *= -1;
|
||||
cube.uv[key].uv_size[1] *= -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +112,7 @@ function parseGeometry(data) {
|
||||
if (isApp && Project.geometry_name) {
|
||||
findEntityTexture(Project.geometry_name)
|
||||
}
|
||||
updateSelection()
|
||||
EditSession.initNewModel()
|
||||
}
|
||||
|
||||
|
17
js/io/io.js
17
js/io/io.js
@ -156,24 +156,23 @@ class ModelFormat {
|
||||
Cube.all.forEach(function(s, i) {
|
||||
//Push elements into 3x3 block box
|
||||
[0, 1, 2].forEach(function(ax) {
|
||||
var overlap = s.to[ax] - 32
|
||||
var overlap = s.to[ax] + s.inflate - 32
|
||||
if (overlap > 0) {
|
||||
//If positive site overlaps
|
||||
s.from[ax] -= overlap
|
||||
s.to[ax] -= overlap
|
||||
|
||||
overlap = 16 + s.from[ax]
|
||||
if (overlap < 0) {
|
||||
s.from[ax] = -16
|
||||
if (16 + s.from[ax] - s.inflate < 0) {
|
||||
s.from[ax] = -16 + s.inflate
|
||||
}
|
||||
} else {
|
||||
overlap = s.from[ax] + 16
|
||||
overlap = s.from[ax] - s.inflate + 16
|
||||
if (overlap < 0) {
|
||||
s.from[ax] -= overlap
|
||||
s.to[ax] -= overlap
|
||||
|
||||
if (s.to[ax] > 32) {
|
||||
s.to[ax] = 32
|
||||
if (s.to[ax] + s.inflate > 32) {
|
||||
s.to[ax] = 32 - s.inflate
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1015,10 +1014,6 @@ BARS.defineActions(function() {
|
||||
}
|
||||
}
|
||||
})
|
||||
if (BarItems.export_over.keybind.key == 69 && BarItems.export_over.keybind.ctrl) {
|
||||
//Blockbench 3.0.2 update
|
||||
BarItems.export_over.keybind.set({key: 83, ctrl: true}).save(true)
|
||||
}
|
||||
if (!isApp) {
|
||||
new Action({
|
||||
id: 'export_asset_archive',
|
||||
|
@ -33,10 +33,11 @@ var codec = new Codec('java_block', {
|
||||
if (s.shade === false) {
|
||||
element.shade = false
|
||||
}
|
||||
if (!s.rotation.equals([0, 0, 0])) {
|
||||
if (!s.rotation.allEqual(0) || !s.origin.allEqual(8)) {
|
||||
var axis = s.rotationAxis()||'y';
|
||||
element.rotation = new oneLiner({
|
||||
angle: s.rotation[getAxisNumber(s.rotationAxis())],
|
||||
axis: s.rotationAxis(),
|
||||
angle: s.rotation[getAxisNumber(axis)],
|
||||
axis,
|
||||
origin: s.origin
|
||||
})
|
||||
}
|
||||
@ -98,12 +99,12 @@ var codec = new Codec('java_block', {
|
||||
function inVd(n) {
|
||||
return n > 32 || n < -16
|
||||
}
|
||||
if (inVd(s.from[0]) ||
|
||||
inVd(s.from[1]) ||
|
||||
inVd(s.from[2]) ||
|
||||
inVd(s.to[0]) ||
|
||||
inVd(s.to[1]) ||
|
||||
inVd(s.to[2])
|
||||
if (inVd(element.from[0]) ||
|
||||
inVd(element.from[1]) ||
|
||||
inVd(element.from[2]) ||
|
||||
inVd(element.to[0]) ||
|
||||
inVd(element.to[1]) ||
|
||||
inVd(element.to[2])
|
||||
) {
|
||||
largerCubesNr++;
|
||||
}
|
||||
|
128
js/io/obj.js
128
js/io/obj.js
@ -48,106 +48,100 @@ var codec = new Codec('obj', {
|
||||
var nbNormals = 0;
|
||||
|
||||
var geometry = mesh.geometry;
|
||||
var element = Outliner.root.findRecursive('uuid', mesh.name)
|
||||
var element = elements.findInArray('uuid', mesh.name)
|
||||
|
||||
if (element === undefined) return;
|
||||
if (!element) return;
|
||||
if (element.export === false) return;
|
||||
|
||||
if ( geometry instanceof THREE.Geometry ) {
|
||||
output += 'o ' + element.name + '\n';
|
||||
|
||||
output += 'o ' + element.name + '\n';
|
||||
var vertices = geometry.vertices;
|
||||
|
||||
var vertices = geometry.vertices;
|
||||
for ( var i = 0, l = vertices.length; i < l; i ++ ) {
|
||||
|
||||
for ( var i = 0, l = vertices.length; i < l; i ++ ) {
|
||||
var vertex = vertices[ i ].clone();
|
||||
vertex.applyMatrix4( mesh.matrixWorld );
|
||||
|
||||
var vertex = vertices[ i ].clone();
|
||||
vertex.applyMatrix4( mesh.matrixWorld );
|
||||
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
|
||||
nbVertex ++;
|
||||
}
|
||||
// uvs
|
||||
var faces = geometry.faces;
|
||||
var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
|
||||
var hasVertexUvs = faces.length === faceVertexUvs.length;
|
||||
|
||||
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
|
||||
nbVertex ++;
|
||||
}
|
||||
// uvs
|
||||
var faces = geometry.faces;
|
||||
var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
|
||||
var hasVertexUvs = faces.length === faceVertexUvs.length;
|
||||
if ( hasVertexUvs ) {
|
||||
|
||||
if ( hasVertexUvs ) {
|
||||
for ( var i = 0, l = faceVertexUvs.length; i < l; i ++ ) {
|
||||
|
||||
for ( var i = 0, l = faceVertexUvs.length; i < l; i ++ ) {
|
||||
var vertexUvs = faceVertexUvs[ i ];
|
||||
|
||||
var vertexUvs = faceVertexUvs[ i ];
|
||||
for ( var j = 0, jl = vertexUvs.length; j < jl; j ++ ) {
|
||||
|
||||
for ( var j = 0, jl = vertexUvs.length; j < jl; j ++ ) {
|
||||
|
||||
var uv = vertexUvs[ j ];
|
||||
output += 'vt ' + uv.x + ' ' + uv.y + '\n';
|
||||
nbVertexUvs ++;
|
||||
}
|
||||
var uv = vertexUvs[ j ];
|
||||
output += 'vt ' + uv.x + ' ' + uv.y + '\n';
|
||||
nbVertexUvs ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normals
|
||||
// normals
|
||||
|
||||
var normalMatrixWorld = new THREE.Matrix3();
|
||||
normalMatrixWorld.getNormalMatrix( mesh.matrixWorld );
|
||||
var normalMatrixWorld = new THREE.Matrix3();
|
||||
normalMatrixWorld.getNormalMatrix( mesh.matrixWorld );
|
||||
|
||||
for ( var i = 0, l = faces.length; i < l; i ++ ) {
|
||||
for ( var i = 0, l = faces.length; i < l; i ++ ) {
|
||||
|
||||
var face = faces[ i ];
|
||||
var vertexNormals = face.vertexNormals;
|
||||
var face = faces[ i ];
|
||||
var vertexNormals = face.vertexNormals;
|
||||
|
||||
if ( vertexNormals.length === 3 ) {
|
||||
if ( vertexNormals.length === 3 ) {
|
||||
|
||||
for ( var j = 0, jl = vertexNormals.length; j < jl; j ++ ) {
|
||||
for ( var j = 0, jl = vertexNormals.length; j < jl; j ++ ) {
|
||||
|
||||
var normal = vertexNormals[ j ].clone();
|
||||
normal.applyMatrix3( normalMatrixWorld );
|
||||
|
||||
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
|
||||
|
||||
nbNormals ++;
|
||||
}
|
||||
} else {
|
||||
|
||||
var normal = face.normal.clone();
|
||||
var normal = vertexNormals[ j ].clone();
|
||||
normal.applyMatrix3( normalMatrixWorld );
|
||||
|
||||
for ( var j = 0; j < 3; j ++ ) {
|
||||
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
|
||||
|
||||
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
|
||||
nbNormals ++;
|
||||
}
|
||||
nbNormals ++;
|
||||
}
|
||||
} else {
|
||||
|
||||
var normal = face.normal.clone();
|
||||
normal.applyMatrix3( normalMatrixWorld );
|
||||
|
||||
for ( var j = 0; j < 3; j ++ ) {
|
||||
|
||||
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
|
||||
nbNormals ++;
|
||||
}
|
||||
}
|
||||
|
||||
// material
|
||||
for (var face in element.faces) {
|
||||
var tex = element.faces[face].getTexture()
|
||||
if (tex && tex.uuid && !materials[tex.id]) {
|
||||
materials[tex.id] = tex
|
||||
}
|
||||
}
|
||||
|
||||
// material
|
||||
for (var face in element.faces) {
|
||||
var tex = element.faces[face].getTexture()
|
||||
if (tex && tex.uuid && !materials[tex.id]) {
|
||||
materials[tex.id] = tex
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for ( var i = 0, j = 1, l = faces.length; i < l; i ++, j += 3 ) {
|
||||
for ( var i = 0, j = 1, l = faces.length; i < l; i ++, j += 3 ) {
|
||||
|
||||
var f_mat = getMtlFace(element, i)
|
||||
if (f_mat) {
|
||||
var f_mat = getMtlFace(element, i)
|
||||
if (f_mat) {
|
||||
|
||||
var face = faces[ i ];
|
||||
if (i % 2 === 0) {
|
||||
output += f_mat
|
||||
}
|
||||
output += 'f ';
|
||||
output += ( indexVertex + face.a + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j ) : '' ) + '/' + ( indexNormals + j ) + ' ';
|
||||
output += ( indexVertex + face.b + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 1 ) : '' ) + '/' + ( indexNormals + j + 1 ) + ' ';
|
||||
output += ( indexVertex + face.c + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 2 ) : '' ) + '/' + ( indexNormals + j + 2 ) + '\n';
|
||||
var face = faces[ i ];
|
||||
if (i % 2 === 0) {
|
||||
output += f_mat
|
||||
}
|
||||
output += 'f ';
|
||||
output += ( indexVertex + face.a + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j ) : '' ) + '/' + ( indexNormals + j ) + ' ';
|
||||
output += ( indexVertex + face.b + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 1 ) : '' ) + '/' + ( indexNormals + j + 1 ) + ' ';
|
||||
output += ( indexVertex + face.c + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 2 ) : '' ) + '/' + ( indexNormals + j + 2 ) + '\n';
|
||||
}
|
||||
} else {
|
||||
console.warn( 'THREE.OBJExporter.parseMesh(): geometry type unsupported', mesh );
|
||||
// TODO: Support only BufferGeometry and use setFromObject()
|
||||
}
|
||||
|
||||
// update index
|
||||
|
@ -193,7 +193,7 @@ class Cube extends NonGroup {
|
||||
if (!this.parent || (this.parent === 'root' && Outliner.root.indexOf(this) === -1)) {
|
||||
this.addTo('root')
|
||||
}
|
||||
if (this.visibility && (!this.mesh || !scene.children.includes(this.mesh))) {
|
||||
if (this.visibility && (!this.mesh || !this.mesh.parent)) {
|
||||
Canvas.addCube(this)
|
||||
}
|
||||
TickUpdates.outliner = true;
|
||||
@ -474,12 +474,7 @@ class Cube extends NonGroup {
|
||||
shift.sub(dq)
|
||||
shift.applyQuaternion(q.inverse())
|
||||
|
||||
this.from[0] += shift.x;
|
||||
this.from[1] += shift.y;
|
||||
this.from[2] += shift.z;
|
||||
this.to[0] += shift.x;
|
||||
this.to[1] += shift.y;
|
||||
this.to[2] += shift.z;
|
||||
this.move(shift)
|
||||
|
||||
this.origin = origin.slice();
|
||||
|
||||
@ -538,7 +533,7 @@ class Cube extends NonGroup {
|
||||
}
|
||||
mapAutoUV() {
|
||||
if (Blockbench.box_uv) return;
|
||||
var scope = this
|
||||
var scope = this;
|
||||
if (scope.autouv === 2) {
|
||||
//Relative UV
|
||||
function gt(n) {
|
||||
@ -547,6 +542,7 @@ class Cube extends NonGroup {
|
||||
var all_faces = ['north', 'south', 'west', 'east', 'up', 'down']
|
||||
all_faces.forEach(function(side) {
|
||||
var uv = scope.faces[side].uv.slice()
|
||||
var texture = scope.faces[side]
|
||||
switch (side) {
|
||||
case 'north':
|
||||
uv = [
|
||||
@ -597,9 +593,11 @@ class Cube extends NonGroup {
|
||||
];
|
||||
break;
|
||||
}
|
||||
var fr_u = 16 / Project.texture_width;
|
||||
var fr_v = 16 / Project.texture_height;
|
||||
uv.forEach(function(s, uvi) {
|
||||
s *= (uvi%2 ? fr_v : fr_u);
|
||||
uv[uvi] = limitNumber(s, 0, 16)
|
||||
uv[uvi] *= 16 / (uvi%2 ? Project.texture_height : Project.texture_width)
|
||||
})
|
||||
scope.faces[side].uv = uv
|
||||
})
|
||||
@ -615,6 +613,8 @@ class Cube extends NonGroup {
|
||||
if (rot === 90 || rot === 270) {
|
||||
size.reverse()
|
||||
}
|
||||
size[0] *= 16/Project.texture_width;
|
||||
size[1] *= 16/Project.texture_height;
|
||||
//Limit Input to 16
|
||||
size.forEach(function(s) {
|
||||
if (s > 16) {
|
||||
@ -652,12 +652,19 @@ class Cube extends NonGroup {
|
||||
Canvas.updateUV(scope)
|
||||
}
|
||||
}
|
||||
move(val, axis, absolute, move_origin) {
|
||||
move(val, axis, absolute, move_origin, no_update) {
|
||||
if (val instanceof THREE.Vector3) {
|
||||
return this.move(val.x, 0, absolute, move_origin, true)
|
||||
&& this.move(val.y, 1, absolute, move_origin, true)
|
||||
&& this.move(val.z, 2, absolute, move_origin, true);
|
||||
}
|
||||
var size = this.size(axis)
|
||||
if (!absolute) {
|
||||
val = val + this.from[axis]
|
||||
}
|
||||
val = limitToBox(limitToBox(val) + size) - size
|
||||
var in_box = val;
|
||||
val = limitToBox(limitToBox(val, -this.inflate) + size, this.inflate) - size
|
||||
in_box = Math.abs(in_box - val) < 1e-4;
|
||||
val -= this.from[axis]
|
||||
|
||||
//Move
|
||||
@ -684,11 +691,12 @@ class Cube extends NonGroup {
|
||||
if (Blockbench.globalMovement && move_origin) {
|
||||
this.origin[axis] += val
|
||||
}
|
||||
|
||||
this.mapAutoUV()
|
||||
Canvas.adaptObjectPosition(this);
|
||||
TickUpdates.selection = true;
|
||||
return this;
|
||||
if (!no_update) {
|
||||
this.mapAutoUV()
|
||||
Canvas.adaptObjectPosition(this);
|
||||
TickUpdates.selection = true;
|
||||
}
|
||||
return in_box;
|
||||
}
|
||||
scale(val, axis, negative, absolute, allow_negative) {
|
||||
if (absolute) {
|
||||
@ -700,14 +708,14 @@ class Cube extends NonGroup {
|
||||
val = Math.ceil(val);
|
||||
}
|
||||
if (!negative) {
|
||||
var pos = limitToBox(val + this.from[axis] + before);
|
||||
var pos = limitToBox(val + this.from[axis] + before, this.inflate);
|
||||
if (pos >= this.from[axis] || settings.negative_size.value || allow_negative) {
|
||||
this.to[axis] = pos;
|
||||
} else {
|
||||
this.to[axis] = this.from[axis];
|
||||
}
|
||||
} else {
|
||||
var pos = limitToBox(val + this.to[axis] - before);
|
||||
var pos = limitToBox(val + this.to[axis] - before, this.inflate);
|
||||
if (pos <= this.to[axis] || settings.negative_size.value || allow_negative) {
|
||||
this.from[axis] = pos;
|
||||
} else {
|
||||
|
@ -255,7 +255,7 @@ class OutlinerElement {
|
||||
others.safePush(g)
|
||||
})
|
||||
}
|
||||
var name = this.name.replace(/\d+$/, '');
|
||||
var name = this.name.replace(/\d+$/, '').replace(/\s+/g, '_');
|
||||
function check(n) {
|
||||
for (var i = 0; i < others.length; i++) {
|
||||
if (others[i] !== scope && others[i].name == n) return false;
|
||||
@ -265,7 +265,7 @@ class OutlinerElement {
|
||||
if (check(this.name)) {
|
||||
return this.name;
|
||||
}
|
||||
for (var num = 2; num < 2e3; num++) {
|
||||
for (var num = 2; num < 8e3; num++) {
|
||||
if (check(name+num)) {
|
||||
scope.name = name+num;
|
||||
return scope.name;
|
||||
@ -440,7 +440,8 @@ class NonGroup extends OutlinerElement {
|
||||
|
||||
//Normal
|
||||
} else {
|
||||
unselectAll()
|
||||
selected.forEachReverse(obj => obj.unselect())
|
||||
if (Group.selected) Group.selected.unselect()
|
||||
scope.selectLow()
|
||||
just_selected.push(scope)
|
||||
scope.showInOutliner()
|
||||
@ -950,31 +951,6 @@ BARS.defineActions(function() {
|
||||
}
|
||||
})
|
||||
|
||||
new Action({
|
||||
id: 'duplicate',
|
||||
icon: 'content_copy',
|
||||
category: 'edit',
|
||||
condition: () => (Modes.edit && (selected.length || Group.selected)),
|
||||
keybind: new Keybind({key: 68, ctrl: true}),
|
||||
click: function () {
|
||||
if (Group.selected && (Group.selected.matchesSelection() || selected.length === 0)) {
|
||||
var cubes_before = elements.length;
|
||||
Undo.initEdit({outliner: true, elements: [], selection: true});
|
||||
var g = Group.selected.duplicate();
|
||||
g.select();
|
||||
Undo.finishEdit('duplicate_group', {outliner: true, elements: elements.slice().slice(cubes_before), selection: true})
|
||||
} else {
|
||||
var added_elements = [];
|
||||
Undo.initEdit({elements: added_elements, outliner: true, selection: true})
|
||||
selected.forEach(function(obj, i) {
|
||||
var copy = obj.duplicate();
|
||||
added_elements.push(copy);
|
||||
})
|
||||
BarItems.move_tool.select();
|
||||
Undo.finishEdit('duplicate')
|
||||
}
|
||||
}
|
||||
})
|
||||
new Action({
|
||||
id: 'sort_outliner',
|
||||
icon: 'sort_by_alpha',
|
||||
|
@ -170,8 +170,8 @@ const Painter = {
|
||||
getCanvas(texture) {
|
||||
var c = document.createElement('canvas')
|
||||
var ctx = c.getContext('2d');
|
||||
c.width = texture.res;
|
||||
c.height = texture.img.naturalHeight;
|
||||
c.width = texture.width;
|
||||
c.height = texture.height;
|
||||
ctx.drawImage(texture.img, 0, 0)
|
||||
return c;
|
||||
},
|
||||
@ -856,7 +856,6 @@ const Painter = {
|
||||
}
|
||||
|
||||
//Drawing
|
||||
cl(templates.length)
|
||||
templates.forEach(function(t) {
|
||||
let obj = t.obj
|
||||
|
||||
@ -1052,6 +1051,23 @@ BARS.defineActions(function() {
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
new Action({
|
||||
id: 'painting_grid',
|
||||
name: tl('settings.painting_grid'),
|
||||
description: tl('settings.painting_grid.desc'),
|
||||
icon: 'check_box',
|
||||
category: 'view',
|
||||
condition: () => Modes.paint,
|
||||
linked_setting: 'painting_grid',
|
||||
click: function () {
|
||||
BarItems.painting_grid.toggleLinkedSetting()
|
||||
Cube.all.forEach(cube => {
|
||||
Canvas.buildGridBox(cube)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
new NumSlider({
|
||||
id: 'slider_brush_size',
|
||||
condition: () => (Toolbox && ['brush_tool', 'eraser'].includes(Toolbox.selected.id)),
|
||||
|
@ -81,6 +81,10 @@ const Canvas = {
|
||||
objects.push(s)
|
||||
}
|
||||
})
|
||||
for (var uuid in Canvas.meshes) {
|
||||
var mesh = Canvas.meshes[uuid];
|
||||
objects.safePush(mesh);
|
||||
}
|
||||
objects.forEach(function(s) {
|
||||
if (s.parent) {
|
||||
s.parent.remove(s)
|
||||
@ -157,13 +161,17 @@ const Canvas = {
|
||||
}
|
||||
})
|
||||
},
|
||||
updateRenderSides() {
|
||||
getRenderSide() {
|
||||
var side = Format.id === 'java_block' ? 0 : 2;
|
||||
if (display_mode) {
|
||||
if (['thirdperson_righthand', 'thirdperson_lefthand', 'head'].includes(display_slot)) {
|
||||
side = 2;
|
||||
}
|
||||
}
|
||||
return side;
|
||||
},
|
||||
updateRenderSides() {
|
||||
var side = Canvas.getRenderSide();
|
||||
textures.forEach(function(t) {
|
||||
var mat = Canvas.materials[t.uuid]
|
||||
if (mat) {
|
||||
@ -173,7 +181,6 @@ const Canvas = {
|
||||
emptyMaterials.forEach(function(mat) {
|
||||
mat.side = side
|
||||
})
|
||||
return side;
|
||||
},
|
||||
//Selection updaters
|
||||
updateSelected(arr) {
|
||||
@ -324,6 +331,7 @@ const Canvas = {
|
||||
},
|
||||
//Object handlers
|
||||
addCube(obj) {
|
||||
|
||||
//This does NOT remove old cubes
|
||||
var mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1))
|
||||
Canvas.adaptObjectFaces(obj, mesh)
|
||||
@ -661,8 +669,8 @@ const Canvas = {
|
||||
}
|
||||
if (true) {
|
||||
var tex = cube.faces.north.getTexture()
|
||||
var width = tex ? tex.res : 16
|
||||
var height = tex ? tex.res / tex.ratio : 16
|
||||
var width = tex ? tex.width : 16
|
||||
var height = tex ? tex.height : 16
|
||||
size = [
|
||||
Math.abs(width/16 * cube.faces.north.uv_size[cube.faces.north.rotation%180 ? 1 : 0]),
|
||||
Math.abs(height/16 * cube.faces.north.uv_size[cube.faces.north.rotation%180 ? 0 : 1]),
|
||||
|
@ -1442,7 +1442,7 @@ enterDisplaySettings = function() { //Enterung Display Setting Mode, changes th
|
||||
|
||||
display_area.updateMatrixWorld()
|
||||
display_base.updateMatrixWorld()
|
||||
DisplayMode.centerTransformer()
|
||||
Transformer.center()
|
||||
if (outlines.children.length) {
|
||||
outlines.children.length = 0
|
||||
Canvas.updateAllPositions()
|
||||
@ -1493,22 +1493,6 @@ function resetDisplayBase() {
|
||||
display_base.scale.z = 1;
|
||||
}
|
||||
|
||||
DisplayMode.centerTransformer = function() {
|
||||
display_scene.add(Transformer)
|
||||
Transformer.attach(display_base)
|
||||
|
||||
display_base.getWorldPosition(Transformer.position)
|
||||
|
||||
if (Toolbox.selected.transformerMode === 'translate') {
|
||||
Transformer.rotation.copy(display_area.rotation)
|
||||
} else if (Toolbox.selected.transformerMode === 'scale') {
|
||||
var q = display_base.getWorldQuaternion(new THREE.Quaternion())
|
||||
Transformer.rotation.setFromQuaternion(q)
|
||||
} else {
|
||||
Transformer.rotation.set(0, 0, 0)
|
||||
}
|
||||
Transformer.update()
|
||||
}
|
||||
DisplayMode.updateDisplayBase = function(slot) {
|
||||
if (!slot) slot = display[display_slot]
|
||||
|
||||
@ -1524,7 +1508,7 @@ DisplayMode.updateDisplayBase = function(slot) {
|
||||
display_base.scale.y = (slot.scale[1]||0.001) * (slot.mirror[1] ? -1 : 1);
|
||||
display_base.scale.z = (slot.scale[2]||0.001) * (slot.mirror[2] ? -1 : 1);
|
||||
|
||||
DisplayMode.centerTransformer()
|
||||
Transformer.center()
|
||||
}
|
||||
|
||||
|
||||
@ -1589,13 +1573,13 @@ var setDisplayArea = DisplayMode.setBase = function(x, y, z, rx, ry, rz, sx, sy,
|
||||
|
||||
display_area.updateMatrixWorld()
|
||||
|
||||
DisplayMode.centerTransformer()
|
||||
Transformer.center()
|
||||
}
|
||||
DisplayMode.groundAnimation = function() {
|
||||
display_area.rotation.y += 0.015
|
||||
ground_timer += 1
|
||||
display_area.position.y = 13.5 + Math.sin(Math.PI * (ground_timer / 100)) * Math.PI/2
|
||||
DisplayMode.centerTransformer()
|
||||
Transformer.center()
|
||||
if (ground_timer === 200) ground_timer = 0;
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ class Preview {
|
||||
var intersect = intersects[0].object
|
||||
if (intersect.isElement) {
|
||||
this.controls.hasMoved = true
|
||||
var obj = Outliner.root.findRecursive('uuid', intersects[0].object.name)
|
||||
var obj = elements.findInArray('uuid', intersects[0].object.name)
|
||||
switch (Math.floor( intersects[0].faceIndex / 2 )) {
|
||||
case 5: var face = 'north'; break;
|
||||
case 0: var face = 'east'; break;
|
||||
@ -322,7 +322,11 @@ class Preview {
|
||||
main_uv.setFace(data.face, false)
|
||||
}
|
||||
Blockbench.dispatchEvent( 'canvas_select', data )
|
||||
if (Animator.open || (!Format.rotate_cubes && Format.bone_rig && ['rotate_tool', 'pivot_tool'].includes(Toolbox.selected.id))) {
|
||||
if (Format.bone_rig && (
|
||||
Animator.open ||
|
||||
(!Format.rotate_cubes && ['rotate_tool', 'pivot_tool'].includes(Toolbox.selected.id)) ||
|
||||
event.shiftKey
|
||||
)) {
|
||||
if (data.cube.parent.type === 'group') {
|
||||
data.cube.parent.select()
|
||||
}
|
||||
@ -793,6 +797,159 @@ function openQuadView() {
|
||||
updateInterface()
|
||||
}
|
||||
|
||||
|
||||
const Screencam = {
|
||||
fullScreen(options, cb) {
|
||||
setTimeout(function() {
|
||||
currentwindow.capturePage(function(screenshot) {
|
||||
var dataUrl = screenshot.toDataURL()
|
||||
dataUrl = dataUrl.replace('data:image/png;base64,','')
|
||||
Jimp.read(Buffer.from(dataUrl, 'base64')).then(function(image) {
|
||||
|
||||
if (options && options.width && options.height) {
|
||||
image.contain(options.width, options.height)
|
||||
}
|
||||
|
||||
image.getBase64(Jimp.MIME_PNG, function(a, dataUrl){
|
||||
Screencam.returnScreenshot(dataUrl, cb)
|
||||
})
|
||||
});
|
||||
})
|
||||
}, 40)
|
||||
},
|
||||
returnScreenshot(dataUrl, cb) {
|
||||
if (cb) {
|
||||
cb(dataUrl)
|
||||
} else if (isApp) {
|
||||
var screenshot = nativeImage.createFromDataURL(dataUrl)
|
||||
var img = new Image()
|
||||
var is_gif = dataUrl.substr(5, 9) == 'image/gif'
|
||||
img.src = dataUrl
|
||||
|
||||
var btns = [tl('dialog.cancel'), tl('dialog.save')]
|
||||
if (!is_gif) {
|
||||
btns.push(tl('message.screenshot.clipboard'))
|
||||
}
|
||||
Blockbench.showMessageBox({
|
||||
translateKey: 'screenshot',
|
||||
icon: img,
|
||||
buttons: btns,
|
||||
confirm: 1,
|
||||
cancel: 0
|
||||
}, function(result) {
|
||||
if (result === 1) {
|
||||
electron.dialog.showSaveDialog(currentwindow, {filters: [ {name: tl('data.image'), extensions: [is_gif ? 'gif' : 'png']} ]}, function (fileName) {
|
||||
if (fileName === undefined) {
|
||||
return;
|
||||
}
|
||||
fs.writeFile(fileName, Buffer(dataUrl.split(',')[1], 'base64'), err => {})
|
||||
})
|
||||
} else if (result === 2) {
|
||||
clipboard.writeImage(screenshot)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
new Dialog({
|
||||
title: tl('message.screenshot.right_click'),
|
||||
id: 'screenie',
|
||||
lines: ['<img src="'+dataUrl+'" width="600px" class="allow_default_menu"></img>'],
|
||||
draggable: true,
|
||||
singleButton: true
|
||||
}).show()
|
||||
}
|
||||
},
|
||||
cleanCanvas(options, cb) {
|
||||
quad_previews.current.screenshot(options, cb)
|
||||
},
|
||||
createGif(options, cb) {
|
||||
if (typeof options !== 'object') {
|
||||
options = {}
|
||||
}
|
||||
/*
|
||||
var images = [];
|
||||
var preview = quad_previews.current;
|
||||
var interval = setInterval(function() {
|
||||
|
||||
var shot = preview.canvas.toDataURL()
|
||||
images.push(shot);
|
||||
|
||||
if (images.length >= options.length/1000*options.fps) {
|
||||
clearInterval(interval);
|
||||
gifshot.createGIF({
|
||||
images,
|
||||
frameDuration: 10/options.fps,
|
||||
progressCallback: cl,
|
||||
text: 'BLOCKBENCH'
|
||||
}, obj => {
|
||||
Screencam.returnScreenshot(obj.image, cb);
|
||||
})
|
||||
}
|
||||
}, 1000/options.fps)
|
||||
//Does not support transparency
|
||||
*/
|
||||
|
||||
if (!options.length) {
|
||||
options.length = 1000;
|
||||
}
|
||||
var preview = quad_previews.current;
|
||||
var interval = options.fps ? (1000/options.fps) : 100;
|
||||
var gif = new GIF({
|
||||
repeat: options.repeat,
|
||||
quality: options.quality,
|
||||
transparent: 0x000000,
|
||||
});
|
||||
var frame_count = (options.length/interval);
|
||||
|
||||
if (options.turnspeed) {
|
||||
preview.controls.autoRotate = true;
|
||||
preview.controls.autoRotateSpeed = options.turnspeed;
|
||||
}
|
||||
|
||||
gif.on('finished', blob => {
|
||||
var reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
if (!options.silent) {
|
||||
Blockbench.setProgress(0);
|
||||
Blockbench.setStatusBarText();
|
||||
}
|
||||
Screencam.returnScreenshot(reader.result, cb);
|
||||
}
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
if (!options.silent) {
|
||||
Blockbench.setStatusBarText(tl('status_bar.recording_gif'));
|
||||
gif.on('progress', Blockbench.setProgress);
|
||||
}
|
||||
|
||||
var frames = 0;
|
||||
var loop = setInterval(() => {
|
||||
frames++;
|
||||
var last_frame = frames >= options.length / interval;
|
||||
if (last_frame) {
|
||||
clearInterval(loop)
|
||||
if (!options.silent) {
|
||||
Blockbench.setStatusBarText(tl('status_bar.processing_gif'))
|
||||
}
|
||||
if (Animator.open && Timeline.playing) {
|
||||
Timeline.pause();
|
||||
}
|
||||
if (options.turnspeed) {
|
||||
preview.controls.autoRotate = false;
|
||||
}
|
||||
}
|
||||
var img = new Image();
|
||||
img.src = preview.canvas.toDataURL();
|
||||
img.onload = () => {
|
||||
gif.addFrame(img, {delay: interval});
|
||||
if (last_frame) {
|
||||
gif.render();
|
||||
}
|
||||
}
|
||||
Blockbench.setProgress(interval*frames/options.length);
|
||||
}, interval)
|
||||
}
|
||||
}
|
||||
|
||||
//Init/Update
|
||||
function initCanvas() {
|
||||
|
||||
@ -1187,7 +1344,7 @@ BARS.defineActions(function() {
|
||||
form: {
|
||||
length: {label: 'dialog.create_gif.length', type: 'number', value: 10, step: 0.25},
|
||||
fps: {label: 'dialog.create_gif.fps', type: 'number', value: 10},
|
||||
quality:{label: 'dialog.create_gif.compression', type: 'number', value: 4},
|
||||
quality:{label: 'dialog.create_gif.compression', type: 'number', value: 20, min: 1, max: 80},
|
||||
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},
|
||||
},
|
||||
|
@ -698,10 +698,8 @@
|
||||
this.update = function (object) {
|
||||
var scope = Transformer;
|
||||
|
||||
if (!object && Modes.id === 'display' && Toolbox.selected.transformerMode === 'rotate') {
|
||||
object = display_area;
|
||||
} else if (Modes.id == 'animate' && Group.selected && Group.selected.parent instanceof Group) {
|
||||
object = Group.selected.parent.mesh
|
||||
if (!object) {
|
||||
object = this.rotation_ref;
|
||||
}
|
||||
if (scope.elements.length == 0) {
|
||||
this.detach()
|
||||
@ -726,9 +724,16 @@
|
||||
|
||||
if (object) {
|
||||
worldRotation.setFromRotationMatrix( tempMatrix.extractRotation( object.matrixWorld ) );
|
||||
_gizmo[ _mode ].update( worldRotation, eye );
|
||||
if (Toolbox.selected.transformerMode === 'rotate') {
|
||||
_gizmo[ _mode ].update( worldRotation, eye );
|
||||
this.rotation.set(0, 0, 0);
|
||||
} else {
|
||||
object.getWorldQuaternion(this.rotation)
|
||||
}
|
||||
|
||||
} else {
|
||||
worldRotation.set(0, 0, 0);
|
||||
this.rotation.set(0, 0, 0);
|
||||
_gizmo[ _mode ].update( new THREE.Euler(), eye );
|
||||
}
|
||||
_gizmo[ _mode ].highlight( scope.axis );
|
||||
@ -786,7 +791,7 @@
|
||||
|
||||
this.updateSelection = function() {
|
||||
this.elements.empty()
|
||||
if (Modes.edit) {
|
||||
if (Modes.edit || Toolbox.selected.id == 'pivot_tool') {
|
||||
if (selected.length) {
|
||||
selected.forEach(element => {
|
||||
if (
|
||||
@ -808,7 +813,8 @@
|
||||
return this;
|
||||
}
|
||||
this.center = function() {
|
||||
if (Modes.edit) {
|
||||
delete Transformer.rotation_ref;
|
||||
if (Modes.edit || Toolbox.selected.id == 'pivot_tool') {
|
||||
if (Transformer.visible) {
|
||||
var rotation_tool = Toolbox.selected.id === 'rotate_tool' || Toolbox.selected.id === 'pivot_tool'
|
||||
var rotation_object = getRotationObject()
|
||||
@ -827,7 +833,7 @@
|
||||
return;
|
||||
}
|
||||
this.rotation_object = rotation_object;
|
||||
if (Format.bone_rig) {
|
||||
if (Format.bone_rig && !Modes.animate) {
|
||||
Canvas.updateAllBones()
|
||||
}
|
||||
//Center
|
||||
@ -840,32 +846,41 @@
|
||||
}
|
||||
|
||||
//Rotation
|
||||
Transformer.rotation.set(0, 0, 0);
|
||||
if (Toolbox.selected.transformerMode !== 'rotate') {
|
||||
if (Toolbox.selected.id == 'pivot_tool') {
|
||||
if (rotation_tool) {
|
||||
Transformer.rotation_ref = rotation_object.mesh.parent;
|
||||
|
||||
if (rotation_object.parent instanceof Group) {
|
||||
rotation_object.parent.mesh.getWorldQuaternion(this.rotation)
|
||||
}
|
||||
} else if (!Blockbench.globalMovement && Cube.selected[0] && Cube.selected[0].mesh) {
|
||||
Cube.selected[0].mesh.getWorldQuaternion(this.rotation)
|
||||
}
|
||||
} else if (Group.selected) {
|
||||
Transformer.rotation_ref = rotation_object.mesh;
|
||||
|
||||
} else if (!Blockbench.globalMovement && Cube.selected[0] && Cube.selected[0].mesh) {
|
||||
Transformer.rotation_ref = Cube.selected[0].mesh;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (Modes.display) {
|
||||
this.attach(display_base);
|
||||
DisplayMode.centerTransformer();
|
||||
|
||||
display_scene.add(Transformer)
|
||||
Transformer.attach(display_base)
|
||||
|
||||
display_base.getWorldPosition(Transformer.position)
|
||||
|
||||
if (Toolbox.selected.transformerMode === 'translate') {
|
||||
Transformer.rotation_ref = display_area;
|
||||
|
||||
} else if (Toolbox.selected.transformerMode === 'scale') {
|
||||
Transformer.rotation_ref = display_base;
|
||||
}
|
||||
Transformer.update()
|
||||
|
||||
} else if (Modes.animate && Group.selected) {
|
||||
|
||||
this.attach(Group.selected);
|
||||
Group.selected.mesh.getWorldPosition(this.position);
|
||||
if (Toolbox.selected.transformerMode == 'rotate') {
|
||||
this.rotation.set(0, 0, 0);
|
||||
if (Toolbox.selected.id == 'resize_tool') {
|
||||
Transformer.rotation_ref = Group.selected.mesh;
|
||||
} else {
|
||||
Transformer.rotation_ref = Group.selected.mesh.parent;
|
||||
}
|
||||
Transformer.update()
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -937,7 +952,7 @@
|
||||
function beforeFirstChange(event) {
|
||||
if (scope.hasChanged) return;
|
||||
|
||||
if (Modes.edit) {
|
||||
if (Modes.edit || Toolbox.selected.id == 'pivot_tool') {
|
||||
|
||||
if (Toolbox.selected.id === 'resize_tool') {
|
||||
var axisnr = getAxisNumber(scope.axis.toLowerCase().replace('n', ''))
|
||||
@ -1001,37 +1016,25 @@
|
||||
|
||||
if (Toolbox.selected.transformerMode !== 'rotate') {
|
||||
point.sub( offset );
|
||||
}
|
||||
|
||||
if (Toolbox.selected.transformerMode === 'rotate') {
|
||||
point.removeEuler(worldRotation)
|
||||
|
||||
} else {
|
||||
point.sub( worldPosition );
|
||||
point.removeEuler(worldRotation)
|
||||
var rotations = [
|
||||
Math.atan2( point.z, point.y ),
|
||||
Math.atan2( point.x, point.z ),
|
||||
Math.atan2( point.y, point.x )
|
||||
]
|
||||
var angle = Math.radToDeg( rotations[axisNumber] )
|
||||
|
||||
} else if ((!Blockbench.globalMovement || !Modes.edit) && scope.elements.length) {
|
||||
var rotation = new THREE.Quaternion()
|
||||
var i = 0;
|
||||
while (scope.elements[i]) {
|
||||
if (scope.elements[i].mesh) {
|
||||
scope.elements[0].mesh.getWorldQuaternion(rotation)
|
||||
i = Infinity;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
point.applyQuaternion(rotation.inverse())
|
||||
}
|
||||
|
||||
if (Modes.edit) {
|
||||
if (Modes.edit || Toolbox.selected.id == 'pivot_tool') {
|
||||
|
||||
if (Toolbox.selected.id === 'move_tool') {
|
||||
|
||||
var snap_factor = canvasGridSize(event.shiftKey, event.ctrlKey)
|
||||
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor// * (useBedrockFlipFix(axis) ? -1 : 1)
|
||||
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor;
|
||||
|
||||
if (previousValue === undefined) {
|
||||
previousValue = point[axis]
|
||||
@ -1046,10 +1049,10 @@
|
||||
selected.forEach(function(obj) {
|
||||
if (obj.movable && obj.scalable) {
|
||||
overlapping = overlapping || (
|
||||
obj.to[axisNumber] + difference > 32 ||
|
||||
obj.to[axisNumber] + difference < -16 ||
|
||||
obj.from[axisNumber] + difference > 32 ||
|
||||
obj.from[axisNumber] + difference < -16
|
||||
obj.to[axisNumber] + difference + obj.inflate > 32 ||
|
||||
obj.to[axisNumber] + difference + obj.inflate < -16 ||
|
||||
obj.from[axisNumber] + difference - obj.inflate > 32 ||
|
||||
obj.from[axisNumber] + difference - obj.inflate < -16
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -1074,7 +1077,7 @@
|
||||
} else if (Toolbox.selected.id === 'resize_tool') {
|
||||
//Scale
|
||||
var snap_factor = canvasGridSize(event.shiftKey, event.ctrlKey)
|
||||
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor// * (useBedrockFlipFix(axis) ? -1 : 1)
|
||||
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor;
|
||||
|
||||
|
||||
if (previousValue !== point[axis]) {
|
||||
@ -1110,7 +1113,7 @@
|
||||
} else if (Toolbox.selected.id === 'pivot_tool') {
|
||||
|
||||
var snap_factor = canvasGridSize(event.shiftKey, event.ctrlKey)
|
||||
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor// * (useBedrockFlipFix(axis) ? -1 : 1)
|
||||
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor;
|
||||
|
||||
if (previousValue === undefined) {
|
||||
previousValue = point[axis]
|
||||
@ -1121,9 +1124,13 @@
|
||||
var difference = point[axis] - previousValue
|
||||
|
||||
if (Format.bone_rig && Group.selected) {
|
||||
var origin = Group.selected.origin.slice();
|
||||
origin[axisNumber] += difference;
|
||||
Group.selected.transferOrigin(origin, true);
|
||||
if (Modes.edit) {
|
||||
var origin = Group.selected.origin.slice();
|
||||
origin[axisNumber] += difference;
|
||||
Group.selected.transferOrigin(origin, true);
|
||||
} else if (Modes.animate) {
|
||||
Group.selected.origin[axisNumber] += difference;
|
||||
}
|
||||
} else {
|
||||
var origin = Transformer.rotation_object.origin.slice()
|
||||
origin[axisNumber] += difference;
|
||||
@ -1133,7 +1140,10 @@
|
||||
}
|
||||
})
|
||||
}
|
||||
Canvas.updatePositions(true)
|
||||
Canvas.updatePositions(true);
|
||||
if (Modes.animate) {
|
||||
Animator.preview();
|
||||
}
|
||||
scope.updateSelection()
|
||||
|
||||
previousValue = point[axis]
|
||||
@ -1174,7 +1184,6 @@
|
||||
scope.keyframe.offset(axis, difference);
|
||||
scope.keyframe.select()
|
||||
|
||||
updateKeyframeSelection()
|
||||
Animator.preview()
|
||||
previousValue = value
|
||||
scope.hasChanged = true
|
||||
@ -1242,7 +1251,7 @@
|
||||
scope.orbit_controls.stopMovement()
|
||||
outlines.children.length = 0
|
||||
|
||||
if (Modes.id === 'edit') {
|
||||
if (Modes.id === 'edit' || Toolbox.selected.id == 'pivot_tool') {
|
||||
if (Toolbox.selected.id === 'resize_tool') {
|
||||
//Scale
|
||||
selected.forEach(function(obj) {
|
||||
@ -1297,27 +1306,3 @@
|
||||
THREE.TransformControls.prototype.constructor = THREE.TransformControls;
|
||||
|
||||
}() );
|
||||
|
||||
THREE.Euler.prototype.inverse = function () {
|
||||
|
||||
var q = new THREE.Quaternion();
|
||||
return function inverse() {
|
||||
|
||||
return this.setFromQuaternion( q.setFromEuler( this ).inverse() );
|
||||
|
||||
};
|
||||
|
||||
}();
|
||||
THREE.Vector3.prototype.removeEuler = function (euler) {
|
||||
|
||||
var normal = new THREE.Vector3(0, 0, 1)
|
||||
return function removeEuler(euler) {
|
||||
|
||||
this.applyAxisAngle(normal, -euler.z)
|
||||
this.applyAxisAngle(normal.set(0, 1, 0), -euler.y)
|
||||
this.applyAxisAngle(normal.set(1, 0, 0), -euler.x)
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}();
|
@ -19,7 +19,7 @@ class Texture {
|
||||
//Data
|
||||
this.ratio = 1
|
||||
this.img = 0;
|
||||
this.res = 0;
|
||||
this.width = 0;
|
||||
this.saved = true
|
||||
|
||||
this.mode = isApp ? 'link' : 'bitmap';
|
||||
@ -58,16 +58,19 @@ class Texture {
|
||||
|
||||
var mat = new THREE.MeshLambertMaterial({
|
||||
color: 0xffffff,
|
||||
side: Canvas.getRenderSide(),
|
||||
map: tex,
|
||||
transparent: settings.transparency.value,
|
||||
alphaTest: 0.2
|
||||
});
|
||||
Canvas.materials[this.uuid] = mat
|
||||
|
||||
var size_control = {};
|
||||
|
||||
this.img.onload = function() {
|
||||
if (!this.src) return;
|
||||
this.tex.needsUpdate = true;
|
||||
scope.res = img.naturalWidth;
|
||||
scope.width = img.naturalWidth;
|
||||
scope.ratio = img.naturalWidth / img.naturalHeight;
|
||||
|
||||
if (scope.isDefault) {
|
||||
@ -88,17 +91,35 @@ class Texture {
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/*
|
||||
if (Project.box_uv && textures.indexOf(scope) === 0 && !scope.keep_size) {
|
||||
|
||||
var size = {
|
||||
pw: Project.texture_width,
|
||||
ph: Project.texture_height,
|
||||
nw: img.naturalWidth,
|
||||
nh: img.naturalHeight
|
||||
}
|
||||
if (false && (scope.old_width != size.nw || scope.old_height != size.nh) && (size.pw != size.nw || size.ph != size.nh)) {
|
||||
|
||||
if (Project.box_uv && Format.single_texture && !scope.keep_size) {
|
||||
|
||||
let pw = Project.texture_width;
|
||||
let ph = Project.texture_height;
|
||||
let nw = img.naturalWidth;
|
||||
let nh = img.naturalHeight;
|
||||
|
||||
//texture is unlike project
|
||||
var unlike = (pw != nw || ph != nh);
|
||||
//Resolution of this texture has changed
|
||||
var changed = size_control.old_width && (size_control.old_width != nw || size_control.old_height != nh);
|
||||
//Resolution could be a multiple of project size
|
||||
var multi = !(
|
||||
(pw%nw || ph%nh) &&
|
||||
(nw%pw || nh%ph)
|
||||
)
|
||||
// x__ >
|
||||
// xx_ >
|
||||
// x_x >
|
||||
// xxx >
|
||||
// ___ >
|
||||
// _x_ >
|
||||
// __x >
|
||||
// _xx >
|
||||
|
||||
|
||||
if (unlike && changed) {
|
||||
Blockbench.showMessageBox({
|
||||
translateKey: 'update_res',
|
||||
icon: 'photo_size_select_small',
|
||||
@ -107,11 +128,7 @@ class Texture {
|
||||
cancel: 1
|
||||
}, function(result) {
|
||||
if (result === 0) {
|
||||
var lockUV = ( // EG. Texture Optimierung > Modulo geht nicht in allen Bereichen auf
|
||||
(size.pw%size.nw || size.ph%size.nh) &&
|
||||
(size.nw%size.pw || size.nh%size.ph)
|
||||
)
|
||||
entityMode.setResolution(img.naturalWidth, img.naturalHeight, lockUV)
|
||||
setProjectResolution(img.naturalWidth, img.naturalHeight)
|
||||
if (selected.length) {
|
||||
main_uv.loadData()
|
||||
main_uv.setGrid()
|
||||
@ -119,11 +136,13 @@ class Texture {
|
||||
}
|
||||
})
|
||||
}
|
||||
scope.old_width = img.naturalWidth
|
||||
scope.old_height = img.naturalHeight
|
||||
size_control.old_width = img.naturalWidth
|
||||
size_control.old_height = img.naturalHeight
|
||||
}
|
||||
*/
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if ($('.dialog#texture_edit:visible').length > 0 && scope.selected === true) {
|
||||
@ -153,6 +172,9 @@ class Texture {
|
||||
return 1/this.ratio
|
||||
}
|
||||
}
|
||||
get height() {
|
||||
return this.width / this.ratio;
|
||||
}
|
||||
getErrorMessage() {
|
||||
switch (this.error) {
|
||||
case 0: return ''; break;
|
||||
@ -441,6 +463,7 @@ class Texture {
|
||||
return;
|
||||
}
|
||||
var scope = this;
|
||||
this.stopWatcher();
|
||||
|
||||
fs.watchFile(scope.path, {interval: 50}, function(curr, prev) {
|
||||
if (curr.mtime !== prev.mtime) {
|
||||
|
@ -98,13 +98,14 @@ function isMovementGlobal() {
|
||||
function isInBox(val) {
|
||||
return !Format.canvas_limit || (val < 32 && val > -16)
|
||||
}
|
||||
function limitToBox(val) {
|
||||
function limitToBox(val, inflate) {
|
||||
if (typeof inflate != 'number') inflate = 0;
|
||||
if (!Format.canvas_limit) {
|
||||
return val;
|
||||
} else if (val > 32) {
|
||||
return 32;
|
||||
} else if (val < -16) {
|
||||
return -16;
|
||||
} else if (val + inflate > 32) {
|
||||
return 32 - inflate;
|
||||
} else if (val - inflate < -16) {
|
||||
return -16 + inflate;
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
@ -338,9 +339,9 @@ const Vertexsnap = {
|
||||
|
||||
for (i=0; i<3; i++) {
|
||||
if (m[i] === 1) {
|
||||
obj.to[i] += cube_pos.getComponent(i)
|
||||
obj.to[i] = limitToBox(obj.to[i] + cube_pos.getComponent(i), obj.inflate)
|
||||
} else {
|
||||
obj.from[i] += cube_pos.getComponent(i)
|
||||
obj.from[i] = limitToBox(obj.from[i] + cube_pos.getComponent(i), -obj.inflate)
|
||||
}
|
||||
}
|
||||
if (Project.box_uv && obj.visibility) {
|
||||
@ -358,12 +359,10 @@ const Vertexsnap = {
|
||||
var q = obj.mesh.getWorldQuaternion(new THREE.Quaternion()).inverse()
|
||||
cube_pos.applyQuaternion(q)
|
||||
}
|
||||
obj.from[0] += cube_pos.getComponent(0)
|
||||
obj.from[1] += cube_pos.getComponent(1)
|
||||
obj.from[2] += cube_pos.getComponent(2)
|
||||
obj.to[0] += cube_pos.getComponent(0)
|
||||
obj.to[1] += cube_pos.getComponent(1)
|
||||
obj.to[2] += cube_pos.getComponent(2)
|
||||
var in_box = obj.move(cube_pos);
|
||||
if (!in_box) {
|
||||
Blockbench.showMessageBox({translateKey: 'canvas_limit_error'})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -403,13 +402,13 @@ function scaleAll(save, size) {
|
||||
if (obj.from) {
|
||||
obj.from[i] = (obj.before.from[i] - ogn) * size;
|
||||
if (obj.from[i] + ogn > 32 || obj.from[i] + ogn < -16) overflow.push(obj);
|
||||
obj.from[i] = limitToBox(obj.from[i] + ogn);
|
||||
obj.from[i] = limitToBox(obj.from[i] + ogn, -obj.inflate);
|
||||
}
|
||||
|
||||
if (obj.to) {
|
||||
obj.to[i] = (obj.before.to[i] - ogn) * size;
|
||||
if (obj.to[i] + ogn > 32 || obj.to[i] + ogn < -16) overflow.push(obj);
|
||||
obj.to[i] = limitToBox(obj.to[i] + ogn);
|
||||
obj.to[i] = limitToBox(obj.to[i] + ogn, obj.inflate);
|
||||
}
|
||||
|
||||
if (obj.origin) {
|
||||
@ -513,8 +512,8 @@ function centerCubes(axis, update) {
|
||||
var difference = (Format.bone_rig ? 0 : 8) - average
|
||||
|
||||
selected.forEach(function(obj) {
|
||||
if (obj.movable) obj.from[axis] = limitToBox(obj.from[axis] + difference);
|
||||
if (obj.scalable) obj.to[axis] = limitToBox(obj.to[axis] + difference);
|
||||
if (obj.movable) obj.from[axis] = limitToBox(obj.from[axis] + difference, obj.inflate);
|
||||
if (obj.scalable) obj.to[axis] = limitToBox(obj.to[axis] + difference, obj.inflate);
|
||||
if (obj.origin) obj.origin[axis] += difference;
|
||||
})
|
||||
|
||||
@ -734,7 +733,7 @@ BARS.defineActions(function() {
|
||||
Undo.finishEdit('resize')
|
||||
}
|
||||
})
|
||||
//Inflage
|
||||
//Inflate
|
||||
new NumSlider({
|
||||
id: 'slider_inflate',
|
||||
condition: function() {return Cube.selected.length && Modes.edit},
|
||||
@ -836,7 +835,7 @@ BARS.defineActions(function() {
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
//Origin
|
||||
function moveOriginOnAxis(value, fixed, axis) {
|
||||
if (Group.selected) {
|
||||
var diff = value
|
||||
|
25
js/undo.js
25
js/undo.js
@ -170,7 +170,7 @@ var Undo = {
|
||||
if (aspects.animations) {
|
||||
this.animations = {}
|
||||
aspects.animations.forEach(a => {
|
||||
scope.animations[a.uuid] = a.undoCopy();
|
||||
scope.animations[a.uuid] = a.getUndoCopy();
|
||||
})
|
||||
}
|
||||
if (aspects.keyframes && Animator.selected && Animator.selected.getBoneAnimator()) {
|
||||
@ -179,7 +179,7 @@ var Undo = {
|
||||
bone: Animator.selected.getBoneAnimator().uuid
|
||||
}
|
||||
aspects.keyframes.forEach(kf => {
|
||||
scope.keyframes[kf.uuid] = kf.undoCopy()
|
||||
scope.keyframes[kf.uuid] = kf.getUndoCopy()
|
||||
})
|
||||
}
|
||||
|
||||
@ -250,7 +250,7 @@ var Undo = {
|
||||
|
||||
if (save.selection_group && !is_session) {
|
||||
Group.selected = undefined
|
||||
var sel_group = Outliner.root.findRecursive('uuid', save.selection_group)
|
||||
var sel_group = Group.all.findInArray('uuid', save.selection_group)
|
||||
if (sel_group) {
|
||||
sel_group.select()
|
||||
}
|
||||
@ -266,7 +266,7 @@ var Undo = {
|
||||
}
|
||||
|
||||
if (save.group) {
|
||||
var group = Outliner.root.findRecursive('uuid', save.group.uuid)
|
||||
var group = Group.all.findInArray('uuid', save.group.uuid)
|
||||
if (group) {
|
||||
if (is_session) {
|
||||
delete save.group.isOpen;
|
||||
@ -361,19 +361,19 @@ var Undo = {
|
||||
for (var uuid in Animator.selected.bones) {
|
||||
if (uuid === save.keyframes.bone) {
|
||||
bone = Animator.selected.bones[uuid]
|
||||
if (bone.select && Animator.open && is_session) {
|
||||
bone.select()
|
||||
if (bone.group && Animator.open && !is_session) {
|
||||
bone.group.select()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bone) {
|
||||
if (bone.uuid === save.keyframes.bone) {
|
||||
|
||||
function getKeyframe(uuid) {
|
||||
var i = 0;
|
||||
while (i < Timeline.keyframes.length) {
|
||||
if (Timeline.keyframes[i].uuid === uuid) {
|
||||
return Timeline.keyframes[i];
|
||||
while (i < bone.keyframes.length) {
|
||||
if (bone.keyframes[i].uuid === uuid) {
|
||||
return bone.keyframes[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@ -386,10 +386,9 @@ var Undo = {
|
||||
if (kf) {
|
||||
kf.extend(data)
|
||||
} else {
|
||||
kf = new Keyframe(data)
|
||||
kf = new Keyframe(data, uuid)
|
||||
kf.parent = bone;
|
||||
kf.uuid = uuid;
|
||||
Timeline.keyframes.push(kf)
|
||||
bone.keyframes.push(kf)
|
||||
added++;
|
||||
}
|
||||
}
|
||||
|
37
js/util.js
37
js/util.js
@ -18,36 +18,6 @@ function compareVersions(string1/*new*/, string2/*old*/) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function useBedrockFlipFix(axis) {
|
||||
if (Format.bone_rig === false) return false;
|
||||
if (typeof axis === 'string') {
|
||||
axis = getAxisNumber(axis)
|
||||
}
|
||||
var group;
|
||||
if (Group.selected) {
|
||||
var group = Group.selected
|
||||
} else {
|
||||
var i = 0;
|
||||
while (i < selected.length) {
|
||||
if (typeof selected[i].parent === 'object' &&
|
||||
selected[i].parent.type === 'group'
|
||||
) {
|
||||
var group = selected[i].parent
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (group) {
|
||||
var rotations = group.rotation.slice()
|
||||
rotations.splice(axis, 1)
|
||||
rotations.forEach(function(r, i) {
|
||||
rotations[i] = (r >= -90 && r <= 90)
|
||||
})
|
||||
return rotations[0] !== rotations[1]
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
const Condition = function(condition, context) {
|
||||
if (condition !== undefined && condition !== null && condition.condition !== undefined) {
|
||||
condition = condition.condition
|
||||
@ -155,6 +125,12 @@ Math.isPowerOfTwo = function(x) {
|
||||
Math.randomab = function(a, b) {
|
||||
return a + Math.random()*(b-a);
|
||||
}
|
||||
Math.areMultiples = function(n1, n2) {
|
||||
return (
|
||||
(n1/n2)%1 === 0 ||
|
||||
(n2/n1)%1 === 0
|
||||
)
|
||||
}
|
||||
function trimFloatNumber(val) {
|
||||
if (val == '') return val;
|
||||
var string = val.toFixed(4)
|
||||
@ -448,6 +424,7 @@ function pathToName(path, extension) {
|
||||
}
|
||||
}
|
||||
function pathToExtension(path) {
|
||||
if (typeof path !== 'string') return '';
|
||||
var matches = path.match(/\.\w{2,24}$/)
|
||||
if (!matches || !matches.length) return '';
|
||||
return matches[0].replace('.', '').toLowerCase()
|
||||
|
54
js/uv.js
54
js/uv.js
@ -20,7 +20,7 @@ function showUVShiftDialog() {
|
||||
id: 'uv_shift_dialog',
|
||||
fadeTime: 100,
|
||||
onConfirm: function() {
|
||||
Undo.initEdit({elements: elements, uv_only: true})
|
||||
Undo.initEdit({elements: Cube.all, uv_only: true})
|
||||
dialog.hide()
|
||||
var h = $(dialog.object).find('#shift_uv_horizontal').val()
|
||||
if (h.length > 0) {
|
||||
@ -30,7 +30,7 @@ function showUVShiftDialog() {
|
||||
add = true
|
||||
}
|
||||
h = eval(h)
|
||||
elements.forEach(function(obj) {
|
||||
Cube.all.forEach(function(obj) {
|
||||
if (add) {
|
||||
obj.uv_offset[0] += h
|
||||
} else {
|
||||
@ -46,7 +46,7 @@ function showUVShiftDialog() {
|
||||
add = true
|
||||
}
|
||||
v = eval(v)
|
||||
elements.forEach(function(obj) {
|
||||
Cube.all.forEach(function(obj) {
|
||||
if (add) {
|
||||
obj.uv_offset[1] += v
|
||||
} else {
|
||||
@ -387,8 +387,8 @@ class UVEditor {
|
||||
//Brush
|
||||
getBrushCoordinates(event, tex) {
|
||||
var scope = this;
|
||||
var multiplier = (Project.box_uv && tex) ? tex.res/Project.texture_width : 1
|
||||
var pixel_size = scope.inner_size / tex.res
|
||||
var multiplier = (Project.box_uv && tex) ? tex.width/Project.texture_width : 1
|
||||
var pixel_size = scope.inner_size / tex.width
|
||||
return {
|
||||
x: Math.floor(event.offsetX/scope.getPixelSize()*multiplier),
|
||||
y: Math.floor(event.offsetY/scope.getPixelSize()*multiplier)
|
||||
@ -450,8 +450,8 @@ class UVEditor {
|
||||
return this.inner_size/this.grid
|
||||
} else {
|
||||
return this.inner_size/ (
|
||||
(typeof this.texture === 'object' && this.texture.res)
|
||||
? this.texture.res
|
||||
(typeof this.texture === 'object' && this.texture.width)
|
||||
? this.texture.width
|
||||
: this.grid
|
||||
)
|
||||
}
|
||||
@ -543,13 +543,13 @@ class UVEditor {
|
||||
grid = BarItems.uv_grid.get()
|
||||
if (grid === 'auto') {
|
||||
if (this.texture) {
|
||||
grid = this.texture.res
|
||||
grid = this.texture.width
|
||||
} else {
|
||||
grid = 16
|
||||
}
|
||||
this.autoGrid = true
|
||||
} else if (grid === 'none') {
|
||||
grid = 1024
|
||||
grid = 2084
|
||||
} else {
|
||||
grid = parseInt(grid)
|
||||
}
|
||||
@ -731,21 +731,21 @@ class UVEditor {
|
||||
this.jquery.frame.css('background-color', 'var(--color-back)').css('background-image', 'none')
|
||||
this.texture = false;
|
||||
this.setFrameColor()
|
||||
if (this.autoGrid || Project.box_uv) {
|
||||
this.setGrid(16, false)
|
||||
}
|
||||
this.setGrid(16, false)
|
||||
} else {
|
||||
this.setFrameColor(tex.dark_box)
|
||||
var css = 'url("'+tex.source.split('\\').join('\\\\').replace(/ /g, '%20')+'")'
|
||||
this.jquery.frame.css('background-image', css)
|
||||
if (Project.box_uv) {
|
||||
this.jquery.frame.css('background-size', 'contain')
|
||||
} else {
|
||||
if (Format.id == 'java_block') {
|
||||
this.jquery.frame.css('background-size', 'cover')
|
||||
} else {
|
||||
this.jquery.frame.css('background-size', 'contain')
|
||||
}
|
||||
this.texture = tex;
|
||||
if (this.autoGrid || Project.box_uv) {
|
||||
this.setGrid(tex.res, false)
|
||||
if (this.autoGrid) {
|
||||
this.setGrid(Project.texture_width, false)
|
||||
} else {
|
||||
this.setGrid(undefined, false)
|
||||
}
|
||||
}
|
||||
if (!tex || typeof tex !== 'object') {
|
||||
@ -1027,11 +1027,13 @@ class UVEditor {
|
||||
}
|
||||
setAutoSize(event) {
|
||||
var scope = this;
|
||||
var top, left, top2, left2;
|
||||
var top2, left2;
|
||||
|
||||
this.forCubes(obj => {
|
||||
scope.getFaces(event).forEach(function(side) {
|
||||
left = top = 0;
|
||||
var face = obj.faces[side];
|
||||
face.uv[0] = Math.min(face.uv[0], face.uv[2]);
|
||||
face.uv[1] = Math.min(face.uv[1], face.uv[3]);
|
||||
if (side == 'north' || side == 'south') {
|
||||
left2 = limitNumber(obj.size('0'), 0, 16)
|
||||
top2 = limitNumber(obj.size('1'), 0, 16)
|
||||
@ -1042,10 +1044,12 @@ class UVEditor {
|
||||
left2 = limitNumber(obj.size('0'), 0, 16)
|
||||
top2 = limitNumber(obj.size('2'), 0, 16)
|
||||
}
|
||||
if (obj.faces[side].rotation % 180) {
|
||||
if (face.rotation % 180) {
|
||||
[left2, top2] = [top2, left2];
|
||||
}
|
||||
obj.faces[side].uv = [left, top, left2, top2]
|
||||
left2 *= 16 / Project.texture_width;
|
||||
top2 *= 16 / Project.texture_height;
|
||||
face.uv_size = [left2, top2];
|
||||
})
|
||||
obj.autouv = 0
|
||||
Canvas.updateUV(obj)
|
||||
@ -1109,7 +1113,7 @@ class UVEditor {
|
||||
break;
|
||||
}
|
||||
uv.forEach(function(s, uvi) {
|
||||
uv[uvi] = limitNumber(s, 0, 16)
|
||||
uv[uvi] = limitNumber(s * 16 / (uvi%2 ? Project.texture_height : Project.texture_width), 0, 16)
|
||||
})
|
||||
obj.faces[side].uv = uv
|
||||
})
|
||||
@ -1373,7 +1377,7 @@ class UVEditor {
|
||||
'uv_maximize',
|
||||
'uv_auto',
|
||||
'uv_rel_auto',
|
||||
{icon: 'rotate_90_degrees_ccw', name: 'menu.uv.mapping.rotation', children: function() {
|
||||
{icon: 'rotate_90_degrees_ccw', condition: () => Format.id == 'java_block', name: 'menu.uv.mapping.rotation', children: function() {
|
||||
var off = 'radio_button_unchecked'
|
||||
var on = 'radio_button_checked'
|
||||
return [
|
||||
@ -1789,7 +1793,7 @@ BARS.defineActions(function() {
|
||||
new BarSlider({
|
||||
id: 'uv_rotation',
|
||||
category: 'uv',
|
||||
condition: () => !Project.box_uv && Cube.selected.length,
|
||||
condition: () => !Project.box_uv && Format.id == 'java_block' && Cube.selected.length,
|
||||
min: 0, max: 270, step: 90, width: 80,
|
||||
onBefore: () => {
|
||||
Undo.initEdit({elements: Cube.selected, uv_only: true})
|
||||
@ -1812,6 +1816,8 @@ BARS.defineActions(function() {
|
||||
'16': '16x16',
|
||||
'32': '32x32',
|
||||
'64': '64x64',
|
||||
'128': '128x128',
|
||||
'256': '256x256',
|
||||
none: true,
|
||||
},
|
||||
onChange: function(slider) {
|
||||
|
@ -964,5 +964,7 @@
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Größe",
|
||||
"panel.element.origin": "Angelpunkt",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"panel.element.rotation": "Rotation",
|
||||
"message.canvas_limit_error.title": "Begrenzungsfehler",
|
||||
"message.canvas_limit_error.message": "Die Aktion konnte nicht korrekt durchgeführt werden, weil das Format das Modell auf einen Bereich von 48 Einheiten beschränkt. Verschiebe den Angelpunkt, um das zu verhindern."
|
||||
}
|
@ -98,6 +98,8 @@
|
||||
"status_bar.recording_gif":"Recording GIF",
|
||||
"status_bar.processing_gif":"Processing GIF",
|
||||
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this.",
|
||||
"message.rotation_limit.title": "Rotation Limits",
|
||||
"message.rotation_limit.message": "Rotations are limited by Minecraft to one axis and 22.5 degree increments. Rotating on a different axis will clear all rotations on the other axes. Convert the model to \"Free Model\" if you are modeling for other purposes and need free rotations.",
|
||||
"message.file_not_found.title": "File Not Found",
|
||||
|
28
lang/es.json
28
lang/es.json
@ -890,7 +890,7 @@
|
||||
"dates.yesterday": "Ayer",
|
||||
"dates.this_week": "Esta semana",
|
||||
"dates.weeks_ago": "Hace %0 semanas",
|
||||
"mode.start": "Empezar",
|
||||
"mode.start": "Inicio",
|
||||
"mode.start.new": "Nuevo",
|
||||
"mode.start.recent": "Reciente",
|
||||
"format.free": "Modelo libre",
|
||||
@ -953,16 +953,18 @@
|
||||
"web.download_app": "Descargar Aplicación",
|
||||
"uv_editor.turned": "Mapeado Girado",
|
||||
"display.reference.crossbow": "Ballesta",
|
||||
"dialog.settings.search_results": "Search Results",
|
||||
"settings.animation_snap": "Animation Snap",
|
||||
"settings.animation_snap.desc": "Snap interval for keyframes in the animation timeline in steps per second",
|
||||
"action.import_optifine_part": "Import OptiFine Part",
|
||||
"action.import_optifine_part.desc": "Import an entity part model for OptiFine",
|
||||
"data.locator": "Locator",
|
||||
"mode.start.no_recents": "No recently opened models",
|
||||
"panel.element": "Element",
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Pivot Point",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"dialog.settings.search_results": "Resultados de Búsqueda",
|
||||
"settings.animation_snap": "Imán de Animación",
|
||||
"settings.animation_snap.desc": "Intervalo del imán para frames en la timeline de la animación en pasos por segundo",
|
||||
"action.import_optifine_part": "Importar Parte de OptiFine",
|
||||
"action.import_optifine_part.desc": "Importa un modelo de parte de entidad para OptiFine",
|
||||
"data.locator": "Localizador",
|
||||
"mode.start.no_recents": "No hay modelos abiertos recientemente",
|
||||
"panel.element": "Elemento",
|
||||
"panel.element.position": "Posición",
|
||||
"panel.element.size": "Tamaño",
|
||||
"panel.element.origin": "Punto de Pivote",
|
||||
"panel.element.rotation": "Rotación",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this."
|
||||
}
|
34
lang/fr.json
34
lang/fr.json
@ -49,7 +49,7 @@
|
||||
"message.rotation_limit.title": "Limites de rotation",
|
||||
"message.rotation_limit.message": "Minecraft limite les rotations à un axe et par intervalles de 22.5 degrés. Appliquer une rotation sur un axe va supprimer la rotation des autres axes. Désactiver l'option \"Rotation restreintes\" si vous modélisez pour d'autres logiciels et avez besoin de rotations libres. ",
|
||||
"message.file_not_found.title": "Fichier non trouvé",
|
||||
"message.file_not_found.message": "Blockbench n'a pas pu trouver le fichier demandé. Assurez-vous qu'il est stocké localement et pas sur le cloud.",
|
||||
"message.file_not_found.message": "Blockbench n'a pas pu trouver le fichier demandé. Assurez-vous qu'il soit stocké localement et pas sur un cloud.",
|
||||
"message.screenshot.title": "Capture d'écran",
|
||||
"message.screenshot.message": "Capture d'écran effectuée",
|
||||
"message.screenshot.clipboard": "Presse-papier",
|
||||
@ -60,7 +60,7 @@
|
||||
"message.invalid_model.message": "Le fichier ne contient pas de données de modèle valide",
|
||||
"message.child_model_only.title": "Modèle enfant vide",
|
||||
"message.child_model_only.message": "Ce fichier a pour parent %0 et ne contient pas de model",
|
||||
"message.drag_background.title": "Positionner le fond d'écran ",
|
||||
"message.drag_background.title": "Positionner le fond d'écran",
|
||||
"message.drag_background.message": "Glissez l'écran pour changer sa position. Maintenez shift puis glissez verticalement pour changer sa taille.",
|
||||
"message.unsaved_textures.title": "Textures non sauvegardées",
|
||||
"message.unsaved_textures.message": "Votre modèle a des textures non sauvegardées. Assurez-vous de les enregistrer et de les coller dans votre pack de ressources dans le dossier approprié.",
|
||||
@ -68,7 +68,7 @@
|
||||
"message.model_clipping.message": "Votre modèle contient %0 cubes plus grands que la limite de 3x3x3 autorisée par Minecraft. Ce modèle ne fonctionnera pas dans Minecraft. Activer l'option 'Toile limité' pour empêcher cela",
|
||||
"message.loose_texture.title": "Importation texture",
|
||||
"message.loose_texture.message": "La texture importée n'est pas dans un pack de ressource. Minecraft peut seulement charger des textures dans le dossier textures d'un pack de ressources chargé.",
|
||||
"message.loose_texture.change": "Changer chemin",
|
||||
"message.loose_texture.change": "Changer le chemin",
|
||||
"message.update_res.title": "Résolution de texture",
|
||||
"message.update_res.message": "Souhaitez-vous mettre à jour la résolution du projet avec la résolution de cette texture? Cliquez sur 'Annuler' si votre texture a une résolution supérieure à la normale.",
|
||||
"message.update_res.update": "Mise à jour",
|
||||
@ -752,7 +752,7 @@
|
||||
"menu.group.material": "Mettre un matériel",
|
||||
"action.camera_reset": "Réinitialiser la caméra",
|
||||
"action.camera_reset.desc": "Réinitialiser l'angle de la caméra de la prévisualisation actuelle",
|
||||
"panel.variable_placeholders": "Espaces réservés variables",
|
||||
"panel.variable_placeholders": "Espaces réservés aux variables",
|
||||
"panel.variable_placeholders.info": "Lister les variables à prévisualiser par nom=valeur",
|
||||
"status_bar.vertex_distance": "Distance: %0",
|
||||
"dialog.create_gif.title": "Enregistrer un GIF",
|
||||
@ -893,7 +893,7 @@
|
||||
"mode.start": "Commencer",
|
||||
"mode.start.new": "Nouveau",
|
||||
"mode.start.recent": "Récent",
|
||||
"format.free": "Modèle gratuit",
|
||||
"format.free": "Modèle libre",
|
||||
"format.free.desc": "Modèle sans limites pour Unity etc.",
|
||||
"format.java_block": "Bloc/Objet Java",
|
||||
"format.java_block.desc": "Model de bloc pour Java Edition. La taille et les rotations sont limitées.",
|
||||
@ -953,16 +953,18 @@
|
||||
"web.download_app": "Télécharger l'application",
|
||||
"uv_editor.turned": "Mappage UV retournée",
|
||||
"display.reference.crossbow": "Arbalète",
|
||||
"dialog.settings.search_results": "Search Results",
|
||||
"settings.animation_snap": "Animation Snap",
|
||||
"settings.animation_snap.desc": "Snap interval for keyframes in the animation timeline in steps per second",
|
||||
"action.import_optifine_part": "Import OptiFine Part",
|
||||
"action.import_optifine_part.desc": "Import an entity part model for OptiFine",
|
||||
"data.locator": "Locator",
|
||||
"mode.start.no_recents": "No recently opened models",
|
||||
"panel.element": "Element",
|
||||
"dialog.settings.search_results": "Rechercher les résultats",
|
||||
"settings.animation_snap": "Aligner les animations",
|
||||
"settings.animation_snap.desc": "Intervalle de Snap des clés d'animation dans la ligne de temps, en pas par seconde",
|
||||
"action.import_optifine_part": "Importer une partie OptiFine",
|
||||
"action.import_optifine_part.desc": "Importer une partie d'entité pour un modèle OptiFine",
|
||||
"data.locator": "Localisateur",
|
||||
"mode.start.no_recents": "Aucun modèle ouvert récemment",
|
||||
"panel.element": "Élément",
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Pivot Point",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"panel.element.size": "Taille",
|
||||
"panel.element.origin": "Point de pivot",
|
||||
"panel.element.rotation": "Rotation",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this."
|
||||
}
|
14
lang/it.json
14
lang/it.json
@ -959,10 +959,12 @@
|
||||
"action.import_optifine_part": "Importare parte OptiFine",
|
||||
"action.import_optifine_part.desc": "Importare una parte di un modello per OptiFine",
|
||||
"data.locator": "Locator",
|
||||
"mode.start.no_recents": "No recently opened models",
|
||||
"panel.element": "Element",
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Pivot Point",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"mode.start.no_recents": "Nessun modello aperto recentemente",
|
||||
"panel.element": "Elemento",
|
||||
"panel.element.position": "Posizione",
|
||||
"panel.element.size": "Dimensione",
|
||||
"panel.element.origin": "Origine",
|
||||
"panel.element.rotation": "Rotazione",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this."
|
||||
}
|
72
lang/ja.json
72
lang/ja.json
@ -445,13 +445,13 @@
|
||||
"action.center_z.desc": "選択したキューブをZ軸の中心に合わせる",
|
||||
"action.center_all": "Center All",
|
||||
"action.center_all.desc": "キューブの中心を回転軸にする",
|
||||
"action.toggle_visibility": "Toggle Visibility",
|
||||
"action.toggle_visibility": "可視化",
|
||||
"action.toggle_visibility.desc": "選択したキューブの表示を切り替えます",
|
||||
"action.toggle_export": "Toggle Export",
|
||||
"action.toggle_export": "エキスポート",
|
||||
"action.toggle_export.desc": "選択したキューブのエクスポート設定を切り替えます",
|
||||
"action.toggle_autouv": "Toggle Auto UV",
|
||||
"action.toggle_autouv": "オートUV",
|
||||
"action.toggle_autouv.desc": "選択したキューブの自動UV設定を切り替えます",
|
||||
"action.toggle_shade": "Toggle Shading",
|
||||
"action.toggle_shade": "シェーディング",
|
||||
"action.toggle_shade.desc": "選択したキューブの偏光を切り替えます",
|
||||
"action.rename": "名前を変更",
|
||||
"action.rename.desc": "選択したキューブの名前を変更します",
|
||||
@ -498,7 +498,7 @@
|
||||
"menu.display": "Display",
|
||||
"menu.view": "View",
|
||||
"menu.file.new": "新規作成",
|
||||
"menu.file.recent": "呼び戻し",
|
||||
"menu.file.recent": "最近使ったファイル",
|
||||
"menu.file.import": "インポート",
|
||||
"menu.file.export": "エクスポート",
|
||||
"menu.transform.rotate": "回転",
|
||||
@ -792,7 +792,7 @@
|
||||
"action.open_backup_folder.desc": "Blockbenchのバックアップフォルダーを開きます",
|
||||
"switches.mirror": "ミラーUV",
|
||||
"Name of the Language you are editing, NOT English": {
|
||||
"language_name": "English"
|
||||
"language_name": "英語"
|
||||
},
|
||||
"message.plugin_reload": "%0プラグインをリロードしました",
|
||||
"settings.brightness": "輝度",
|
||||
@ -898,13 +898,13 @@
|
||||
"format.java_block": "Java block/item",
|
||||
"format.java_block.desc": "Java Editionモデリング (サイズと回転は限られています)",
|
||||
"format.bedrock": "Bedrock Model",
|
||||
"format.bedrock.desc": "統合版 モデリング",
|
||||
"format.bedrock_old": "統合版デフォルトモデル",
|
||||
"format.bedrock.desc": "統合版モデリング",
|
||||
"format.bedrock_old": "Bedrock Legacy Model",
|
||||
"format.bedrock_old.desc": "統合版-1.12 エンティティモデル",
|
||||
"format.modded_entity": "Modded Entity",
|
||||
"format.modded_entity.desc": "エンティティモデリング",
|
||||
"format.optifine_entity": "OptiFine Entity",
|
||||
"format.optifine_entity.desc": "OptiFine カスタムエンティティモデリング",
|
||||
"format.optifine_entity.desc": "OptiFineカスタムエンティティモデリング",
|
||||
"keys.mouse": "マウス %0",
|
||||
"message.cleared_blank_faces.title": "空白の面",
|
||||
"message.cleared_blank_faces.message": "%0個のテクスチャがない面を発見しました。それらをすべて削除しますか?",
|
||||
@ -927,42 +927,44 @@
|
||||
"settings.painting_grid.desc": "キューブ上にグリットを表示する",
|
||||
"action.slider_brush_min_opacity": "最小不透明度",
|
||||
"action.slider_brush_min_opacity.desc": "ブラシの最小不透明度",
|
||||
"action.convert_project": "Convert Project",
|
||||
"action.convert_project.desc": "Converts the current project to a project for another model format",
|
||||
"action.convert_project": "プロジェクトを変換",
|
||||
"action.convert_project.desc": "別のモデルフォーマットに変換します",
|
||||
"action.close_project": "プロジェクトを閉じる",
|
||||
"action.close_project.desc": "Closes the currently open project",
|
||||
"action.export_bedrock": "Export Bedrock Geometry",
|
||||
"action.export_bedrock.desc": "Export the model as a bedrock edition geometry file.",
|
||||
"action.close_project.desc": "進行中のプロジェクトを閉じます",
|
||||
"action.export_bedrock": "ジオメトリーとしてエクスポート",
|
||||
"action.export_bedrock.desc": "モデルを統合版ジオメトリーファイルとしてエクスポートします",
|
||||
"action.save_project": "プロジェクトを保存",
|
||||
"action.save_project.desc": "Saves the current model as a project file",
|
||||
"action.save_project.desc": "進行中のプロジェクトを保存します",
|
||||
"action.save_project_as": "すべてのプロジェクトを保存",
|
||||
"action.save_project_as.desc": "Saves the current model as a project file at a new location",
|
||||
"action.save_project_as.desc": "進行中のすべてのプロジェクトを保存します",
|
||||
"action.export_over": "上書き保存",
|
||||
"action.export_over.desc": "Saves the model, textures and animations by overwriting the files",
|
||||
"action.export_over.desc": "呼び出したファイルに上書きで保存します",
|
||||
"action.add_locator": "ロケータ-を追加",
|
||||
"action.add_locator.desc": "Adds a new locator to control positions of particles, leashes etc",
|
||||
"action.sidebar_left": "Textures and UV",
|
||||
"action.sidebar_left.desc": "Open the interface for UV and textures",
|
||||
"action.add_locator.desc": "パーティクルの位置を制御するための新しいロケータを追加します",
|
||||
"action.sidebar_left": "テクスチャとUV",
|
||||
"action.sidebar_left.desc": "テクスチャとUVを呼び出します",
|
||||
"action.sidebar_right": "エレメント",
|
||||
"action.sidebar_right.desc": "Open the interface to edit elements",
|
||||
"action.uv_turn_mapping": "Turn Mapping",
|
||||
"action.uv_turn_mapping.desc": "Turn the UV mapping around 90 degrees",
|
||||
"action.sidebar_right.desc": "変更したエレメントを呼び出します",
|
||||
"action.uv_turn_mapping": "ターンマッピング",
|
||||
"action.uv_turn_mapping.desc": "UVマッピングを90度回転させます",
|
||||
"action.remove_blank_faces": "空白の面を削除",
|
||||
"action.remove_blank_faces.desc": "Deletes all untextured faces of the selection",
|
||||
"menu.uv.select": "Select Cubes",
|
||||
"web.download_app": "Download App",
|
||||
"uv_editor.turned": "Turned Mapping",
|
||||
"action.remove_blank_faces.desc": "選択した面をすべて削除します",
|
||||
"menu.uv.select": "キューブを選択",
|
||||
"web.download_app": "Appをダウンロード",
|
||||
"uv_editor.turned": "ターンマッピング",
|
||||
"display.reference.crossbow": "クロスボウ",
|
||||
"dialog.settings.search_results": "Search Results",
|
||||
"settings.animation_snap": "Animation Snap",
|
||||
"settings.animation_snap.desc": "Snap interval for keyframes in the animation timeline in steps per second",
|
||||
"action.import_optifine_part": "Import OptiFine Part",
|
||||
"action.import_optifine_part.desc": "Import an entity part model for OptiFine",
|
||||
"dialog.settings.search_results": "検索",
|
||||
"settings.animation_snap": "アニメーションスナップ",
|
||||
"settings.animation_snap.desc": "アニメーションライン1ステップの間隔幅",
|
||||
"action.import_optifine_part": "OptiFineをインポート",
|
||||
"action.import_optifine_part.desc": "OptiFineエンティティモデルをインポートします",
|
||||
"data.locator": "ロケーター",
|
||||
"mode.start.no_recents": "最近開いたモデルはありません",
|
||||
"panel.element": "Element",
|
||||
"panel.element": "エレメント",
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Pivot Point",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"panel.element.origin": "Center",
|
||||
"panel.element.rotation": "Rotation",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this."
|
||||
}
|
@ -964,5 +964,7 @@
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Pivot Point",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"panel.element.rotation": "Rotation",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this."
|
||||
}
|
@ -964,5 +964,7 @@
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Pivot Point",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"panel.element.rotation": "Rotation",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this."
|
||||
}
|
@ -964,5 +964,7 @@
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Pivot Point",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"panel.element.rotation": "Rotation",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this."
|
||||
}
|
26
lang/ru.json
26
lang/ru.json
@ -25,12 +25,12 @@
|
||||
"keys.rightclick": "ПКМ",
|
||||
"keys.tab": "Tab",
|
||||
"keys.backspace": "Backspace",
|
||||
"keys.enter": "Ввод",
|
||||
"keys.enter": "Enter",
|
||||
"keys.escape": "Escape",
|
||||
"keys.function": "F%0",
|
||||
"keys.numpad": "%0 (цифр. кл.)",
|
||||
"keys.caps": "Caps Lock",
|
||||
"keys.menu": "Menu",
|
||||
"keys.menu": "Меню",
|
||||
"keys.left": "Стрелка влево",
|
||||
"keys.up": "Стрелка вверх",
|
||||
"keys.right": "Стрелка вправо",
|
||||
@ -47,7 +47,7 @@
|
||||
"keys.printscreen": "Print Screen",
|
||||
"keys.pause": "Pause",
|
||||
"message.rotation_limit.title": "Ограничение поворота",
|
||||
"message.rotation_limit.message": "Поворот ограничен до 22,5 градусов Майнкрафтом по каждой с осей. Поворот на разных осях сбросит повороты на других. Отключите функцию \"Ограничение поворота\", если вы создаете модель для других целей, где нужен свободный поворот.",
|
||||
"message.rotation_limit.message": "Поворот ограничен до 22,5 градусов Майнкрафтом по каждой из осей. Поворот на разных осях сбросит повороты на других. Отключите функцию \"Ограничение поворота\", если вы создаете модель для других целей, где нужен свободный поворот.",
|
||||
"message.file_not_found.title": "Файл не найден",
|
||||
"message.file_not_found.message": "Blockbench не может найти запрашиваемый файл. Убедитесь, что он сохранен по указанному пути, не в облаке.",
|
||||
"message.screenshot.title": "Скриншот",
|
||||
@ -147,8 +147,8 @@
|
||||
"dialog.plugins.show_less": "Показать меньше",
|
||||
"dialog.entitylist.title": "Открыть модель сущности",
|
||||
"dialog.entitylist.text": "Выберите модель, которую Вы хотите импортировать",
|
||||
"dialog.entitylist.bones": "костей",
|
||||
"dialog.entitylist.cubes": "кубов",
|
||||
"dialog.entitylist.bones": "Костей",
|
||||
"dialog.entitylist.cubes": "Кубов",
|
||||
"dialog.create_texture.title": "Создать текстуру",
|
||||
"dialog.create_texture.name": "Имя файла",
|
||||
"dialog.create_texture.folder": "Папка",
|
||||
@ -958,11 +958,13 @@
|
||||
"settings.animation_snap.desc": "Интервал привязки кадров на графике анимаций",
|
||||
"action.import_optifine_part": "Импортировать часть OptiFine",
|
||||
"action.import_optifine_part.desc": "Импортировать часть модели сущности OptiFine",
|
||||
"data.locator": "Locator",
|
||||
"mode.start.no_recents": "No recently opened models",
|
||||
"panel.element": "Element",
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Pivot Point",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"data.locator": "Маркер",
|
||||
"mode.start.no_recents": "Вы еще не открывали моделей",
|
||||
"panel.element": "Элемент",
|
||||
"panel.element.position": "Позиция",
|
||||
"panel.element.size": "Размер",
|
||||
"panel.element.origin": "Центральная точка",
|
||||
"panel.element.rotation": "Поворот",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this."
|
||||
}
|
@ -964,5 +964,7 @@
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Pivot Point",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"panel.element.rotation": "Rotation",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this."
|
||||
}
|
120
lang/zh.json
120
lang/zh.json
@ -1,20 +1,20 @@
|
||||
{
|
||||
"dialog.ok": "OK",
|
||||
"dialog.cancel": "Cancel",
|
||||
"dialog.confirm": "Confirm",
|
||||
"dialog.close": "Close",
|
||||
"dialog.import": "Import",
|
||||
"dialog.save": "Save",
|
||||
"dialog.discard": "Discard",
|
||||
"dialog.dontshowagain": "Don't Show Again",
|
||||
"dialog.ok": "好的",
|
||||
"dialog.cancel": "取消",
|
||||
"dialog.confirm": "确认",
|
||||
"dialog.close": "关闭",
|
||||
"dialog.import": "导入",
|
||||
"dialog.save": "保存",
|
||||
"dialog.discard": "弃置",
|
||||
"dialog.dontshowagain": "不再显示",
|
||||
"data.cube": "Cube",
|
||||
"data.group": "Group",
|
||||
"data.texture": "Texture",
|
||||
"data.plugin": "Plugin",
|
||||
"data.preview": "Preview",
|
||||
"data.toolbar": "Toolbar",
|
||||
"data.image": "Image",
|
||||
"keys.ctrl": "Control",
|
||||
"data.group": "组",
|
||||
"data.texture": "材质",
|
||||
"data.plugin": "插件",
|
||||
"data.preview": "预览",
|
||||
"data.toolbar": "工具栏",
|
||||
"data.image": "图片",
|
||||
"keys.ctrl": "Ctrl",
|
||||
"keys.shift": "Shift",
|
||||
"keys.alt": "Alt",
|
||||
"keys.meta": "Cmd",
|
||||
@ -47,7 +47,7 @@
|
||||
"keys.printscreen": "截屏键",
|
||||
"keys.pause": "暂停键",
|
||||
"message.rotation_limit.title": "旋转限制",
|
||||
"message.rotation_limit.message": "受 Minecarft 的限制,仅允许旋转单个轴,且旋转角度限制为22.5的倍数。在不同的轴上旋转将清除其他轴上的旋转。如果您的建模需要自由旋转,请禁用“限制旋转”选项。",
|
||||
"message.rotation_limit.message": "受 Minecarft 的限制,仅允许旋转单个轴,且旋转角度限制为22.5的倍数。在不同的轴上旋转将清除其他轴上的旋转。如果您的建模需要自由旋转,请禁用“限制旋转”选项",
|
||||
"message.file_not_found.title": "未找到文件",
|
||||
"message.file_not_found.message": "Blockbench 找不到该文件。请确保此文件为本地文件而不是云文件。",
|
||||
"message.screenshot.title": "屏幕截图",
|
||||
@ -65,7 +65,7 @@
|
||||
"message.unsaved_textures.title": "未保存的贴图",
|
||||
"message.unsaved_textures.message": "您的模型中存在未保存的贴图。请确保它们存在于资源包里正确的文件夹中。",
|
||||
"message.model_clipping.title": "模型太大了",
|
||||
"message.model_clipping.message": "您的模型包含了 %0 个大于 Minecraft 限制允许的 3x3x3 方块范围。此模型将不会被 Minecraft 成功读取。可启用 “限制工作区” 选项防止此类情况发生。",
|
||||
"message.model_clipping.message": "您的模型包含了 %0 个大于 Minecraft 限制允许的 3x3x3 方块范围。此模型将不会被 Minecraft 成功读取。可启用 “限制工作区” 选项防止此类情况发生",
|
||||
"message.loose_texture.title": "导入贴图",
|
||||
"message.loose_texture.message": "导入的贴图不在资源包中。Minecraft 只能加载资源包里 textures 文件夹中的贴图。",
|
||||
"message.loose_texture.change": "更改路径",
|
||||
@ -395,66 +395,66 @@
|
||||
"action.paste.desc": "粘贴选定的,面或显示设置",
|
||||
"action.cut": "剪切",
|
||||
"action.cut.desc": "剪切选定的,面或显示设置",
|
||||
"action.add_cube": "添加方块",
|
||||
"action.add_cube.desc": "添加一个新的方块",
|
||||
"action.add_cube": "添加立方体",
|
||||
"action.add_cube.desc": "添加一个新的立方体",
|
||||
"action.add_group": "添加组",
|
||||
"action.add_group.desc": "添加一个新的组",
|
||||
"action.outliner_toggle": "切换更多选项",
|
||||
"action.outliner_toggle.desc": "切换开关以在outliner中添加更多选项",
|
||||
"action.duplicate": "生成副本",
|
||||
"action.duplicate.desc": "复制选定的方块或组",
|
||||
"action.duplicate.desc": "复制选定的立方体或组",
|
||||
"action.delete": "删除",
|
||||
"action.delete.desc": "删除选定的方块或组",
|
||||
"action.delete.desc": "删除选定的立方体或组",
|
||||
"action.sort_outliner": "排序大纲",
|
||||
"action.sort_outliner.desc": "按字母顺序排列大纲",
|
||||
"action.local_move": "相对移动",
|
||||
"action.local_move.desc": "如果可以,将旋转的元素移动到自己的轴上",
|
||||
"action.select_window": "选择",
|
||||
"action.select_window.desc": "根据其属性搜索并选择方块",
|
||||
"action.select_window.desc": "根据其属性搜索并选择立方体",
|
||||
"action.invert_selection": "反向选择",
|
||||
"action.invert_selection.desc": "反向选择当前的方块",
|
||||
"action.invert_selection.desc": "反向选择当前的立方体",
|
||||
"action.select_all": "全选",
|
||||
"action.select_all.desc": "选择所有方块",
|
||||
"action.select_all.desc": "选择所有立方体",
|
||||
"action.collapse_groups": "折叠组",
|
||||
"action.collapse_groups.desc": "折叠所有组",
|
||||
"action.scale": "缩放",
|
||||
"action.scale.desc": "缩放选定的方块",
|
||||
"action.scale.desc": "缩放选定的立方体",
|
||||
"action.rotate_x_cw": "顺时针旋转",
|
||||
"action.rotate_x_cw.desc": "在 X 轴上将选定的方块旋转 90°",
|
||||
"action.rotate_x_cw.desc": "在 X 轴上将选定的立方体旋转 90°",
|
||||
"action.rotate_x_ccw": "逆时针旋转",
|
||||
"action.rotate_x_ccw.desc": "在 X 轴上旋转选定的方块 -90°",
|
||||
"action.rotate_x_ccw.desc": "在 X 轴上旋转选定的立方体 -90°",
|
||||
"action.rotate_y_cw": "顺时针旋转",
|
||||
"action.rotate_y_cw.desc": "在 Y 轴上将选定的方块旋转 90°",
|
||||
"action.rotate_y_cw.desc": "在 Y 轴上将选定的立方体旋转 90°",
|
||||
"action.rotate_y_ccw": "逆时针旋转",
|
||||
"action.rotate_y_ccw.desc": "在 Y 轴上将选定的方块旋转 -90°",
|
||||
"action.rotate_y_ccw.desc": "在 Y 轴上将选定的立方体旋转 -90°",
|
||||
"action.rotate_z_cw": "顺时针旋转",
|
||||
"action.rotate_z_cw.desc": "在 Z 轴上将选定的方块旋转 90°",
|
||||
"action.rotate_z_cw.desc": "在 Z 轴上将选定的立方体旋转 90°",
|
||||
"action.rotate_z_ccw": "逆时针旋转",
|
||||
"action.rotate_z_ccw.desc": "在 Y 轴上将选定的方块旋转 -90°",
|
||||
"action.rotate_z_ccw.desc": "在 Y 轴上将选定的立方体旋转 -90°",
|
||||
"action.flip_x": "X 轴翻转",
|
||||
"action.flip_x.desc": "翻转 X 轴上的选定方块",
|
||||
"action.flip_x.desc": "翻转 X 轴上的选定立方体",
|
||||
"action.flip_y": "Y 轴翻转",
|
||||
"action.flip_y.desc": "翻转 Y 轴上的选定方块",
|
||||
"action.flip_y.desc": "翻转 Y 轴上的选定立方体",
|
||||
"action.flip_z": "Z 轴翻转",
|
||||
"action.flip_z.desc": "翻转 Z 轴上的选定方块",
|
||||
"action.flip_z.desc": "翻转 Z 轴上的选定立方体",
|
||||
"action.center_x": "X 轴居中",
|
||||
"action.center_x.desc": "将所选方块居中在 X 轴上",
|
||||
"action.center_x.desc": "将所选立方体居中在 X 轴上",
|
||||
"action.center_y": "Y 轴居中",
|
||||
"action.center_y.desc": "将所选方块居中在 Y 轴上",
|
||||
"action.center_y.desc": "将所选立方体居中在 Y 轴上",
|
||||
"action.center_z": "Z 轴居中",
|
||||
"action.center_z.desc": "将所选方块居中在 Z 轴上",
|
||||
"action.center_z.desc": "将所选立方体居中在 Z 轴上",
|
||||
"action.center_all": "全部居中",
|
||||
"action.center_all.desc": "使所选方块居中",
|
||||
"action.center_all.desc": "使所选立方体居中",
|
||||
"action.toggle_visibility": "切换可见",
|
||||
"action.toggle_visibility.desc": "切换所选方块的可见",
|
||||
"action.toggle_visibility.desc": "切换所选立方体的可见",
|
||||
"action.toggle_export": "切换导出",
|
||||
"action.toggle_export.desc": "切换所选方块的导出设置",
|
||||
"action.toggle_export.desc": "切换所选立方体的导出设置",
|
||||
"action.toggle_autouv": "切换自动 UV",
|
||||
"action.toggle_autouv.desc": "切换所选方块的自动UV设置",
|
||||
"action.toggle_autouv.desc": "切换所选立方体的自动UV设置",
|
||||
"action.toggle_shade": "切换阴影",
|
||||
"action.toggle_shade.desc": "切换所选方块的阴影",
|
||||
"action.toggle_shade.desc": "切换所选立方体的阴影",
|
||||
"action.rename": "重命名",
|
||||
"action.rename.desc": "更改所选方块的名称",
|
||||
"action.rename.desc": "更改所选立方体的名称",
|
||||
"action.add_display_preset": "新建预设",
|
||||
"action.add_display_preset.desc": "添加新的显示设置预设",
|
||||
"action.fullscreen": "全屏",
|
||||
@ -486,9 +486,9 @@
|
||||
"action.origin_to_geometry": "原点到几何",
|
||||
"action.origin_to_geometry.desc": "将原点设置为几何体的中心",
|
||||
"action.rescale_toggle": "切换重新调节",
|
||||
"action.rescale_toggle.desc": "根据当前旋转重新缩放方块",
|
||||
"action.rescale_toggle.desc": "根据当前旋转重新缩放立方体",
|
||||
"action.bone_reset_toggle": "重置骨骼",
|
||||
"action.bone_reset_toggle.desc": "阻止骨骼显示父模型中的方块",
|
||||
"action.bone_reset_toggle.desc": "阻止骨骼显示父模型中的立方体",
|
||||
"action.reload": "重载 Blockbench",
|
||||
"action.reload.desc": "重载 Blockbench,这将删除所有未保存的进度",
|
||||
"menu.file": "文件",
|
||||
@ -531,7 +531,7 @@
|
||||
"menu.texture.properties": "属性",
|
||||
"menu.preview.background": "背景",
|
||||
"menu.preview.background.load": "加载",
|
||||
"menu.preview.background.position": "位置",
|
||||
"menu.preview.background.position": "立方体位置",
|
||||
"menu.preview.background.lock": "锁定视角",
|
||||
"menu.preview.background.remove": "清除",
|
||||
"menu.preview.screenshot": "截图",
|
||||
@ -601,7 +601,7 @@
|
||||
"display.reference.bow": "弓",
|
||||
"display.reference.block": "方块",
|
||||
"display.reference.frame": "物品展示框",
|
||||
"display.reference.inventory_nine": "3x3",
|
||||
"display.reference.inventory_nine": "合成台",
|
||||
"display.reference.inventory_full": "物品栏",
|
||||
"display.reference.hud": "HUD",
|
||||
"display.preset.blank_name": "请输入名称",
|
||||
@ -638,7 +638,7 @@
|
||||
"dialog.shift_uv.vertical": "垂直",
|
||||
"keybindings.reset": "重启",
|
||||
"keybindings.clear": "Empty",
|
||||
"action.cube_counter": "方块数量",
|
||||
"action.cube_counter": "立方体数量",
|
||||
"action.uv_rotation": "UV旋转",
|
||||
"action.uv_rotation.desc": "UV面的旋转",
|
||||
"action.uv_grid": "UV网格",
|
||||
@ -690,7 +690,7 @@
|
||||
"message.image_editor_missing.message": "选择图像编辑器的可执行文件",
|
||||
"message.image_editor_missing.detail": "Blockbench 无法在您的计算机上找到图像编辑器,请选择图像编辑器的可执行文件。",
|
||||
"action.update_autouv": "自动更新UV",
|
||||
"action.update_autouv.desc": "更新所选方块的自动UV映射",
|
||||
"action.update_autouv.desc": "更新所选立方体的自动UV映射",
|
||||
"category.uv": "UV",
|
||||
"status_bar.saved": "模型已保存",
|
||||
"status_bar.unsaved": "有未保存的更改",
|
||||
@ -768,7 +768,7 @@
|
||||
"message.set_background_position.title": "背景位置",
|
||||
"menu.preview.background.set_position": "设置位置",
|
||||
"dialog.toolbar_edit.hidden": "隐藏",
|
||||
"action.export_class_entity": "导出java实体(?",
|
||||
"action.export_class_entity": "导出为java实体模型",
|
||||
"action.export_class_entity.desc": "作为java class导出模型",
|
||||
"settings.seethrough_outline": "X-Ray 轮廓",
|
||||
"settings.seethrough_outline.desc": "通过对象显示轮廓",
|
||||
@ -894,15 +894,15 @@
|
||||
"mode.start.new": "新建",
|
||||
"mode.start.recent": "最近",
|
||||
"format.free": "自由模型",
|
||||
"format.free.desc": "为 Unity 等软件的无限制模型",
|
||||
"format.free.desc": "制作 Unity 等游戏制作软件的无建模限制的模型",
|
||||
"format.java_block": "Java 方块/物品",
|
||||
"format.java_block.desc": "Java 版方块模型,大小和旋转都有限制。",
|
||||
"format.java_block.desc": "Java 版方块模型,大小和旋转都有限制",
|
||||
"format.bedrock": "基岩版模型",
|
||||
"format.bedrock.desc": "适用于基岩版的模型",
|
||||
"format.bedrock_old": "旧版基岩版模型",
|
||||
"format.bedrock_old.desc": "Pre-1.12 基岩版实体模型",
|
||||
"format.modded_entity": "模组版实体",
|
||||
"format.modded_entity.desc": "为模组所适用的模型,能够直接以 .java 类文件形式导出。",
|
||||
"format.modded_entity.desc": "为模组所适用的模型,能够直接以 .java 的class文件形式导出",
|
||||
"format.optifine_entity": "OptiFine 实体",
|
||||
"format.optifine_entity.desc": "OptiFine 自定义的实体模型",
|
||||
"keys.mouse": "鼠标按键 %0",
|
||||
@ -943,7 +943,7 @@
|
||||
"action.add_locator.desc": "添加新的定位器,以控制粒子、牵引等位置",
|
||||
"action.sidebar_left": "材质和 UV",
|
||||
"action.sidebar_left.desc": "打开一个 UV 和材质的面板",
|
||||
"action.sidebar_right": "元素",
|
||||
"action.sidebar_right": "立方体元素属性",
|
||||
"action.sidebar_right.desc": "打开编辑元素的面板",
|
||||
"action.uv_turn_mapping": "转向映射",
|
||||
"action.uv_turn_mapping.desc": "将 UV 映射转 90 度",
|
||||
@ -960,9 +960,11 @@
|
||||
"action.import_optifine_part.desc": "为 OptiFine 导入一个实体部件模型",
|
||||
"data.locator": "定位器",
|
||||
"mode.start.no_recents": "最近未打开过模型文件",
|
||||
"panel.element": "Element",
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Pivot Point",
|
||||
"panel.element.rotation": "Rotation"
|
||||
"panel.element": "元素",
|
||||
"panel.element.position": "位置",
|
||||
"panel.element.size": "尺寸",
|
||||
"panel.element.origin": "旋转源点",
|
||||
"panel.element.rotation": "旋转",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the origin to prevent this."
|
||||
}
|
@ -59,6 +59,27 @@ Object.assign( THREE.Euler.prototype, {
|
||||
|
||||
}
|
||||
})
|
||||
THREE.Euler.prototype.inverse = function () {
|
||||
|
||||
var q = new THREE.Quaternion();
|
||||
return function inverse() {
|
||||
|
||||
return this.setFromQuaternion( q.setFromEuler( this ).inverse() );
|
||||
|
||||
};
|
||||
}();
|
||||
THREE.Vector3.prototype.removeEuler = function (euler) {
|
||||
|
||||
var normal = new THREE.Vector3(0, 0, 1)
|
||||
return function removeEuler(euler) {
|
||||
|
||||
this.applyAxisAngle(normal, -euler.z)
|
||||
this.applyAxisAngle(normal.set(0, 1, 0), -euler.y)
|
||||
this.applyAxisAngle(normal.set(1, 0, 0), -euler.x)
|
||||
return this;
|
||||
|
||||
};
|
||||
}();
|
||||
var GridBox = function( from, to, size, material) {
|
||||
|
||||
var vertices = [];
|
||||
@ -110,7 +131,6 @@ var GridBox = function( from, to, size, material) {
|
||||
material = material || new THREE.LineBasicMaterial( { color: gizmo_colors.grid } );
|
||||
|
||||
THREE.LineSegments.call( this, geometry, material );
|
||||
|
||||
}
|
||||
GridBox.prototype = Object.assign( Object.create( THREE.LineSegments.prototype ), {
|
||||
constructor: GridBox,
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Blockbench",
|
||||
"description": "Model editing and animation software",
|
||||
"version": "3.0.4",
|
||||
"version": "3.0.5",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "JannisX11",
|
||||
|
Loading…
Reference in New Issue
Block a user