This commit is contained in:
JannisX11 2019-08-01 00:01:47 +02:00
parent fd3085b8fa
commit d5426e9998
41 changed files with 842 additions and 699 deletions

View File

@ -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. 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) 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)

View File

@ -27,7 +27,7 @@
<script> <script>
if (typeof module === 'object') {window.module = module; module = undefined;}//jQuery Fix if (typeof module === 'object') {window.module = module; module = undefined;}//jQuery Fix
const isApp = typeof require !== 'undefined'; const isApp = typeof require !== 'undefined';
const appVersion = '3.0.4'; const appVersion = '3.0.5';
</script> </script>
<script src="lib/vue.min.js"></script> <script src="lib/vue.min.js"></script>
<script src="lib/vue_sortable.js"></script> <script src="lib/vue_sortable.js"></script>
@ -938,8 +938,8 @@
<div class="texture_res">{{ texture.error <div class="texture_res">{{ texture.error
? texture.getErrorMessage() ? texture.getErrorMessage()
: (Format.single_texture : (Format.single_texture
? (texture.res + ' x ' + texture.res/texture.ratio + 'px') ? (texture.width + ' x ' + texture.height + 'px')
: (texture.ratio == 1? texture.res + 'px': (texture.res + 'px, ' + texture.frameCount+'f')) : (texture.ratio == 1? texture.width + 'px': (texture.width + 'px, ' + texture.frameCount+'f'))
) )
}}</div> }}</div>
</li> </li>

View File

@ -23,7 +23,7 @@ class Animation {
Merge.number(this, data, 'length') Merge.number(this, data, 'length')
if (data.bones) { if (data.bones) {
for (var key in 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) { if (group) {
var ba = this.getBoneAnimator(group) var ba = this.getBoneAnimator(group)
var kfs = data.bones[key] var kfs = data.bones[key]
@ -45,7 +45,7 @@ class Animation {
} }
return this; return this;
} }
undoCopy(options) { getUndoCopy(options) {
var scope = this; var scope = this;
var copy = { var copy = {
uuid: this.uuid, uuid: this.uuid,
@ -69,7 +69,7 @@ class Animation {
} }
var kfs_copy = copy.bones[uuid] = [] var kfs_copy = copy.bones[uuid] = []
kfs.forEach(kf => { kfs.forEach(kf => {
kfs_copy.push(kf.undoCopy()) kfs_copy.push(kf.getUndoCopy())
}) })
} }
} }
@ -99,13 +99,40 @@ class Animation {
Animator.preview() Animator.preview()
return this; 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() { rename() {
var scope = this; var scope = this;
Blockbench.textPrompt('message.rename_animation', this.name, function(name) { Blockbench.textPrompt('message.rename_animation', this.name, function(name) {
if (name && name !== scope.name) { if (name && name !== scope.name) {
Undo.initEdit({animations: [scope]}) Undo.initEdit({animations: [scope]});
scope.name = name scope.name = name;
Undo.finishEdit('rename animation') scope.createUniqueName();
Undo.finishEdit('rename animation');
} }
}) })
return this; return this;
@ -193,7 +220,6 @@ class Animation {
} }
} }
Animation.prototype.menu = new Menu([ Animation.prototype.menu = new Menu([
'rename',
{name: 'menu.animation.loop', icon: (a) => (a.loop?'check_box':'check_box_outline_blank'), click: function(animation) { {name: 'menu.animation.loop', icon: (a) => (a.loop?'check_box':'check_box_outline_blank'), click: function(animation) {
animation.loop = !animation.loop animation.loop = !animation.loop
}}, }},
@ -203,7 +229,10 @@ class Animation {
{name: 'menu.animation.anim_time_update', icon: 'update', click: function(animation) { {name: 'menu.animation.anim_time_update', icon: 'update', click: function(animation) {
animation.editUpdateVariable() animation.editUpdateVariable()
}}, }},
'delete' '_',
'duplicate',
'rename',
'delete',
/* /*
rename rename
Loop: checkbox Loop: checkbox
@ -220,7 +249,7 @@ class BoneAnimator {
this.animation = animation; this.animation = animation;
} }
getGroup() { getGroup() {
this.group = Outliner.root.findRecursive('uuid', this.uuid) this.group = Group.all.findInArray('uuid', this.uuid)
if (!this.group) { if (!this.group) {
console.log('no group found for '+this.uuid) console.log('no group found for '+this.uuid)
if (this.animation && this.animation.bones[this.uuid]) { if (this.animation && this.animation.bones[this.uuid]) {
@ -429,7 +458,7 @@ class BoneAnimator {
} }
} }
class Keyframe { class Keyframe {
constructor(data) { constructor(data, uuid) {
this.type = 'keyframe' this.type = 'keyframe'
this.channel = 'rotation'//, 'position', 'scale' this.channel = 'rotation'//, 'position', 'scale'
this.channel_index = 0; this.channel_index = 0;
@ -440,7 +469,7 @@ class Keyframe {
this.z = '0'; this.z = '0';
this.w = '0'; this.w = '0';
this.isQuaternion = false; this.isQuaternion = false;
this.uuid = guid() this.uuid = (uuid && isUUID(uuid)) ? uuid : guid();
if (typeof data === 'object') { if (typeof data === 'object') {
this.extend(data) this.extend(data)
if (this.channel === 'scale' && data.x == undefined && data.y == undefined && data.z == undefined) { 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) this.channel_index = Animator.channel_index.indexOf(this.channel)
return this; return this;
} }
undoCopy() { getUndoCopy() {
var copy = { var copy = {
channel: this.channel_index, channel: this.channel_index,
time: this.time, time: this.time,
@ -860,7 +889,7 @@ const Animator = {
//Bones //Bones
for (var bone_name in a.bones) { for (var bone_name in a.bones) {
var b = a.bones[bone_name] var b = a.bones[bone_name]
var group = Outliner.root.findRecursive('name', bone_name) var group = Group.all.findInArray('name', bone_name)
if (group) { if (group) {
var ba = new BoneAnimator(group.uuid, animation); var ba = new BoneAnimator(group.uuid, animation);
animation.bones[group.uuid] = ba; animation.bones[group.uuid] = ba;
@ -912,7 +941,7 @@ const Animator = {
if (!channels[kf.channel]) { if (!channels[kf.channel]) {
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('.')) { if (!timecode.includes('.')) {
timecode = timecode + '.0' timecode = timecode + '.0'
} }

View File

@ -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 //Selections
function updateSelection() { 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 = { const Clipbench = {
elements: [], elements: [],
copy(event, cut) { copy(event, cut) {
@ -732,6 +624,9 @@ const Clipbench = {
function iterate(obj, parent) { function iterate(obj, parent) {
if (obj.children) { if (obj.children) {
var copy = new Group(obj).addTo(parent).init() var copy = new Group(obj).addTo(parent).init()
if (Format.bone_rig) {
copy.createUniqueName();
}
if (obj.children && obj.children.length) { if (obj.children && obj.children.length) {
obj.children.forEach((child) => { obj.children.forEach((child) => {
iterate(child, copy) iterate(child, copy)
@ -823,6 +718,5 @@ const Clipbench = {
} }
const entityMode = { 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]}}}, 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]}}},
} }

View File

@ -211,7 +211,7 @@ function changeImageEditor(texture, from_settings) {
var id = $('.dialog#image_editor option:selected').attr('id') var id = $('.dialog#image_editor option:selected').attr('id')
var path; var path;
switch (id) { 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 'gimp':path = 'C:\\Program Files\\GIMP 2\\bin\\gimp-2.10.exe'; break;
case 'pdn': path = 'C:\\Program Files\\paint.net\\PaintDotNet.exe'; break; case 'pdn': path = 'C:\\Program Files\\paint.net\\PaintDotNet.exe'; break;
} }

View File

@ -69,6 +69,7 @@ const EditSession = {
}, result => { }, result => {
showDialog('edit_sessions'); showDialog('edit_sessions');
}) })
return;
} }
EditSession.token = token; EditSession.token = token;
@ -289,7 +290,7 @@ EditSession.Client = class {
this.conn.send(tag) this.conn.send(tag)
} }
disconnect(e) { 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.peer.connections[this.conn.peer];
delete EditSession.clients[this.id]; delete EditSession.clients[this.id];
EditSession.updateClientCount(); EditSession.updateClientCount();
@ -313,7 +314,11 @@ const Chat = {
$('input#chat_input').val('') $('input#chat_input').val('')
} }
if (!text) return; if (!text) return;
Chat.processMessage({author: EditSession.username, text: text}) Chat.processMessage({
author: EditSession.username,
text: text,
sender: EditSession.peer.id
})
}, },
addMessage(message) { addMessage(message) {
if (!(message instanceof Chat.Message)) { if (!(message instanceof Chat.Message)) {
@ -330,7 +335,11 @@ const Chat = {
}, },
processMessage(data) { processMessage(data) {
if (!EditSession.hosting) { if (!EditSession.hosting) {
EditSession.host.send({type: 'chat_input', data: data}) EditSession.host.send({
type: 'chat_input',
data,
sender: EditSession.peer.id
})
return; return;
} }
var message = new Chat.Message(data) var message = new Chat.Message(data)
@ -345,7 +354,8 @@ Chat.Message = class {
constructor(data) { constructor(data) {
this.author = data.author||''; this.author = data.author||'';
this.author = this.author.substr(0, 64) 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.text = data.text.substr(0, Chat.maxlength)||'';
this.html = this.text.replace(/</g, '&lt;').replace(/>/g, '&gt;'); this.html = this.text.replace(/</g, '&lt;').replace(/>/g, '&gt;');

View File

@ -993,7 +993,7 @@ const BARS = {
transformerMode: 'translate', transformerMode: 'translate',
toolbar: Blockbench.isMobile ? 'element_origin' : 'main_tools', toolbar: Blockbench.isMobile ? 'element_origin' : 'main_tools',
alt_tool: 'rotate_tool', alt_tool: 'rotate_tool',
modes: ['edit'], modes: ['edit', 'animate'],
keybind: new Keybind({key: 80}), keybind: new Keybind({key: 80}),
}) })
new Tool({ new Tool({
@ -1106,8 +1106,6 @@ const BARS = {
keybind: new Keybind({key: 88, ctrl: true, shift: null}), keybind: new Keybind({key: 88, ctrl: true, shift: null}),
click: function (event) {Clipbench.copy(event, true)} click: function (event) {Clipbench.copy(event, true)}
}) })
new Action({ new Action({
id: 'rename', id: 'rename',
icon: 'text_format', 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 //Move Cube Keys
@ -1499,10 +1530,13 @@ const BARS = {
children: [ children: [
'brush_mode', 'brush_mode',
'fill_mode', 'fill_mode',
'_',
'slider_brush_size', 'slider_brush_size',
'slider_brush_opacity', 'slider_brush_opacity',
'slider_brush_min_opacity', 'slider_brush_min_opacity',
'slider_brush_softness' 'slider_brush_softness',
'_',
'painting_grid',
] ]
}) })
Toolbars.vertex_snap = new Toolbar({ Toolbars.vertex_snap = new Toolbar({

View File

@ -265,8 +265,8 @@ function setupInterface() {
try { try {
interface_data = JSON.parse(interface_data) interface_data = JSON.parse(interface_data)
var old_data = Interface.data var old_data = Interface.data
Interface.data.left_bar = interface_data.left_bar if (interface_data.left_bar) Interface.data.left_bar = interface_data.left_bar;
Interface.data.right_bar = interface_data.right_bar if (interface_data.right_bar) Interface.data.right_bar = interface_data.right_bar;
for (key in Interface.Panels) { for (key in Interface.Panels) {
if (!Interface.data.left_bar.includes(key) && !Interface.data.right_bar.includes(key)) { if (!Interface.data.left_bar.includes(key) && !Interface.data.right_bar.includes(key)) {
if (old_data.left_bar.includes(key)) { if (old_data.left_bar.includes(key)) {

View File

@ -580,6 +580,7 @@ const MenuBar = {
]}, ]},
'_', '_',
'toggle_wireframe', 'toggle_wireframe',
'painting_grid',
'toggle_quad_view', 'toggle_quad_view',
{name: 'menu.view.screenshot', id: 'screenshot', icon: 'camera_alt', children: [ {name: 'menu.view.screenshot', id: 'screenshot', icon: 'camera_alt', children: [
'screenshot_model', 'screenshot_model',

View File

@ -66,7 +66,7 @@ var codec = new Codec('project', {
if (Animator.animations.length) { if (Animator.animations.length) {
model.animations = []; model.animations = [];
Animator.animations.forEach(a => { 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({ new Action({
id: 'save_project_as', id: 'save_project_as',
icon: 'save', icon: 'save',
@ -241,10 +237,6 @@ BARS.defineActions(function() {
codec.export() 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)
}
}) })
})() })()

View File

@ -132,8 +132,8 @@ function parseGeometry(data) {
if (b.pivot) { if (b.pivot) {
group.origin[0] *= -1 group.origin[0] *= -1
} }
group.rotation.forEach(function(br, ri) { group.rotation.forEach(function(br, axis) {
group.rotation[ri] *= -1 group.rotation[axis] *= -1
}) })
group.mirror_uv = b.mirror === true group.mirror_uv = b.mirror === true
@ -148,8 +148,8 @@ function parseGeometry(data) {
rotation: s.rotation, rotation: s.rotation,
origin: s.pivot origin: s.pivot
}) })
base_cube.rotation.forEach(function(br, ri) { base_cube.rotation.forEach(function(br, axis) {
base_cube.rotation[ri] *= -1 if (axis != 2) base_cube.rotation[axis] *= -1
}) })
base_cube.origin[0] *= -1; base_cube.origin[0] *= -1;
if (s.origin) { if (s.origin) {
@ -168,25 +168,28 @@ function parseGeometry(data) {
} else if (s.uv) { } else if (s.uv) {
Project.box_uv = false; Project.box_uv = false;
for (var key in base_cube.faces) { for (var key in base_cube.faces) {
var face = base_cube.faces[key]
if (s.uv[key]) { if (s.uv[key]) {
base_cube.faces[key].extend({ face.extend({
uv: [ uv: [
s.uv[key].uv[0] * Project.texture_width/16, s.uv[key].uv[0] * (16/Project.texture_width),
s.uv[key].uv[1] * Project.texture_height/16, s.uv[key].uv[1] * (16/Project.texture_height),
] ]
}) })
if (s.uv[key].uv_size) { if (s.uv[key].uv_size) {
base_cube.faces[key].uv_size = [ face.uv_size = [
s.uv[key].uv_size[0] * Project.texture_width/16, s.uv[key].uv_size[0] * (16/Project.texture_width),
s.uv[key].uv_size[1] * Project.texture_height/16, s.uv[key].uv_size[1] * (16/Project.texture_height),
] ]
} else { } else {
base_cube.autouv = 1; base_cube.autouv = 1;
base_cube.mapAutoUV(); base_cube.mapAutoUV();
} }
if (key == 'up') {
face.uv = [face.uv[2], face.uv[3], face.uv[0], face.uv[1]]
}
} else { } else {
base_cube.faces[key].texture = null; face.texture = null;
} }
} }
@ -238,6 +241,7 @@ function parseGeometry(data) {
if (isApp && Project.geometry_name) { if (isApp && Project.geometry_name) {
findEntityTexture(Project.geometry_name) findEntityTexture(Project.geometry_name)
} }
updateSelection()
EditSession.initNewModel() EditSession.initNewModel()
} }
@ -291,8 +295,8 @@ var codec = new Codec('bedrock', {
bone.pivot[0] *= -1 bone.pivot[0] *= -1
if (!g.rotation.allEqual(0)) { if (!g.rotation.allEqual(0)) {
bone.rotation = g.rotation.slice() bone.rotation = g.rotation.slice()
bone.rotation.forEach(function(br, ri) { bone.rotation.forEach(function(br, axis) {
bone.rotation[ri] *= -1 bone.rotation[axis] *= -1
}) })
} }
if (g.reset) { if (g.reset) {
@ -326,8 +330,8 @@ var codec = new Codec('bedrock', {
cube.pivot = obj.origin.slice(); cube.pivot = obj.origin.slice();
cube.pivot[0] *= -1 cube.pivot[0] *= -1
cube.rotation = obj.rotation.slice(); cube.rotation = obj.rotation.slice();
cube.rotation.forEach(function(br, ri) { cube.rotation.forEach(function(br, axis) {
cube.rotation[ri] *= -1 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, 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;
}
} }
} }
} }

View File

@ -112,6 +112,7 @@ function parseGeometry(data) {
if (isApp && Project.geometry_name) { if (isApp && Project.geometry_name) {
findEntityTexture(Project.geometry_name) findEntityTexture(Project.geometry_name)
} }
updateSelection()
EditSession.initNewModel() EditSession.initNewModel()
} }

View File

@ -156,24 +156,23 @@ class ModelFormat {
Cube.all.forEach(function(s, i) { Cube.all.forEach(function(s, i) {
//Push elements into 3x3 block box //Push elements into 3x3 block box
[0, 1, 2].forEach(function(ax) { [0, 1, 2].forEach(function(ax) {
var overlap = s.to[ax] - 32 var overlap = s.to[ax] + s.inflate - 32
if (overlap > 0) { if (overlap > 0) {
//If positive site overlaps //If positive site overlaps
s.from[ax] -= overlap s.from[ax] -= overlap
s.to[ax] -= overlap s.to[ax] -= overlap
overlap = 16 + s.from[ax] if (16 + s.from[ax] - s.inflate < 0) {
if (overlap < 0) { s.from[ax] = -16 + s.inflate
s.from[ax] = -16
} }
} else { } else {
overlap = s.from[ax] + 16 overlap = s.from[ax] - s.inflate + 16
if (overlap < 0) { if (overlap < 0) {
s.from[ax] -= overlap s.from[ax] -= overlap
s.to[ax] -= overlap s.to[ax] -= overlap
if (s.to[ax] > 32) { if (s.to[ax] + s.inflate > 32) {
s.to[ax] = 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) { if (!isApp) {
new Action({ new Action({
id: 'export_asset_archive', id: 'export_asset_archive',

View File

@ -33,10 +33,11 @@ var codec = new Codec('java_block', {
if (s.shade === false) { if (s.shade === false) {
element.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({ element.rotation = new oneLiner({
angle: s.rotation[getAxisNumber(s.rotationAxis())], angle: s.rotation[getAxisNumber(axis)],
axis: s.rotationAxis(), axis,
origin: s.origin origin: s.origin
}) })
} }
@ -98,12 +99,12 @@ var codec = new Codec('java_block', {
function inVd(n) { function inVd(n) {
return n > 32 || n < -16 return n > 32 || n < -16
} }
if (inVd(s.from[0]) || if (inVd(element.from[0]) ||
inVd(s.from[1]) || inVd(element.from[1]) ||
inVd(s.from[2]) || inVd(element.from[2]) ||
inVd(s.to[0]) || inVd(element.to[0]) ||
inVd(s.to[1]) || inVd(element.to[1]) ||
inVd(s.to[2]) inVd(element.to[2])
) { ) {
largerCubesNr++; largerCubesNr++;
} }

View File

@ -48,13 +48,11 @@ var codec = new Codec('obj', {
var nbNormals = 0; var nbNormals = 0;
var geometry = mesh.geometry; 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 (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;
@ -145,10 +143,6 @@ var codec = new Codec('obj', {
output += ( indexVertex + face.c + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 2 ) : '' ) + '/' + ( indexNormals + j + 2 ) + '\n'; 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 // update index
indexVertex += nbVertex; indexVertex += nbVertex;

View File

@ -193,7 +193,7 @@ class Cube extends NonGroup {
if (!this.parent || (this.parent === 'root' && Outliner.root.indexOf(this) === -1)) { if (!this.parent || (this.parent === 'root' && Outliner.root.indexOf(this) === -1)) {
this.addTo('root') this.addTo('root')
} }
if (this.visibility && (!this.mesh || !scene.children.includes(this.mesh))) { if (this.visibility && (!this.mesh || !this.mesh.parent)) {
Canvas.addCube(this) Canvas.addCube(this)
} }
TickUpdates.outliner = true; TickUpdates.outliner = true;
@ -474,12 +474,7 @@ class Cube extends NonGroup {
shift.sub(dq) shift.sub(dq)
shift.applyQuaternion(q.inverse()) shift.applyQuaternion(q.inverse())
this.from[0] += shift.x; this.move(shift)
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.origin = origin.slice(); this.origin = origin.slice();
@ -538,7 +533,7 @@ class Cube extends NonGroup {
} }
mapAutoUV() { mapAutoUV() {
if (Blockbench.box_uv) return; if (Blockbench.box_uv) return;
var scope = this var scope = this;
if (scope.autouv === 2) { if (scope.autouv === 2) {
//Relative UV //Relative UV
function gt(n) { function gt(n) {
@ -547,6 +542,7 @@ class Cube extends NonGroup {
var all_faces = ['north', 'south', 'west', 'east', 'up', 'down'] var all_faces = ['north', 'south', 'west', 'east', 'up', 'down']
all_faces.forEach(function(side) { all_faces.forEach(function(side) {
var uv = scope.faces[side].uv.slice() var uv = scope.faces[side].uv.slice()
var texture = scope.faces[side]
switch (side) { switch (side) {
case 'north': case 'north':
uv = [ uv = [
@ -597,9 +593,11 @@ class Cube extends NonGroup {
]; ];
break; break;
} }
var fr_u = 16 / Project.texture_width;
var fr_v = 16 / Project.texture_height;
uv.forEach(function(s, uvi) { uv.forEach(function(s, uvi) {
s *= (uvi%2 ? fr_v : fr_u);
uv[uvi] = limitNumber(s, 0, 16) uv[uvi] = limitNumber(s, 0, 16)
uv[uvi] *= 16 / (uvi%2 ? Project.texture_height : Project.texture_width)
}) })
scope.faces[side].uv = uv scope.faces[side].uv = uv
}) })
@ -615,6 +613,8 @@ class Cube extends NonGroup {
if (rot === 90 || rot === 270) { if (rot === 90 || rot === 270) {
size.reverse() size.reverse()
} }
size[0] *= 16/Project.texture_width;
size[1] *= 16/Project.texture_height;
//Limit Input to 16 //Limit Input to 16
size.forEach(function(s) { size.forEach(function(s) {
if (s > 16) { if (s > 16) {
@ -652,12 +652,19 @@ class Cube extends NonGroup {
Canvas.updateUV(scope) 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) var size = this.size(axis)
if (!absolute) { if (!absolute) {
val = val + this.from[axis] 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] val -= this.from[axis]
//Move //Move
@ -684,11 +691,12 @@ class Cube extends NonGroup {
if (Blockbench.globalMovement && move_origin) { if (Blockbench.globalMovement && move_origin) {
this.origin[axis] += val this.origin[axis] += val
} }
if (!no_update) {
this.mapAutoUV() this.mapAutoUV()
Canvas.adaptObjectPosition(this); Canvas.adaptObjectPosition(this);
TickUpdates.selection = true; TickUpdates.selection = true;
return this; }
return in_box;
} }
scale(val, axis, negative, absolute, allow_negative) { scale(val, axis, negative, absolute, allow_negative) {
if (absolute) { if (absolute) {
@ -700,14 +708,14 @@ class Cube extends NonGroup {
val = Math.ceil(val); val = Math.ceil(val);
} }
if (!negative) { 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) { if (pos >= this.from[axis] || settings.negative_size.value || allow_negative) {
this.to[axis] = pos; this.to[axis] = pos;
} else { } else {
this.to[axis] = this.from[axis]; this.to[axis] = this.from[axis];
} }
} else { } 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) { if (pos <= this.to[axis] || settings.negative_size.value || allow_negative) {
this.from[axis] = pos; this.from[axis] = pos;
} else { } else {

View File

@ -255,7 +255,7 @@ class OutlinerElement {
others.safePush(g) others.safePush(g)
}) })
} }
var name = this.name.replace(/\d+$/, ''); var name = this.name.replace(/\d+$/, '').replace(/\s+/g, '_');
function check(n) { function check(n) {
for (var i = 0; i < others.length; i++) { for (var i = 0; i < others.length; i++) {
if (others[i] !== scope && others[i].name == n) return false; if (others[i] !== scope && others[i].name == n) return false;
@ -265,7 +265,7 @@ class OutlinerElement {
if (check(this.name)) { if (check(this.name)) {
return this.name; return this.name;
} }
for (var num = 2; num < 2e3; num++) { for (var num = 2; num < 8e3; num++) {
if (check(name+num)) { if (check(name+num)) {
scope.name = name+num; scope.name = name+num;
return scope.name; return scope.name;
@ -440,7 +440,8 @@ class NonGroup extends OutlinerElement {
//Normal //Normal
} else { } else {
unselectAll() selected.forEachReverse(obj => obj.unselect())
if (Group.selected) Group.selected.unselect()
scope.selectLow() scope.selectLow()
just_selected.push(scope) just_selected.push(scope)
scope.showInOutliner() 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({ new Action({
id: 'sort_outliner', id: 'sort_outliner',
icon: 'sort_by_alpha', icon: 'sort_by_alpha',

View File

@ -170,8 +170,8 @@ const Painter = {
getCanvas(texture) { getCanvas(texture) {
var c = document.createElement('canvas') var c = document.createElement('canvas')
var ctx = c.getContext('2d'); var ctx = c.getContext('2d');
c.width = texture.res; c.width = texture.width;
c.height = texture.img.naturalHeight; c.height = texture.height;
ctx.drawImage(texture.img, 0, 0) ctx.drawImage(texture.img, 0, 0)
return c; return c;
}, },
@ -856,7 +856,6 @@ const Painter = {
} }
//Drawing //Drawing
cl(templates.length)
templates.forEach(function(t) { templates.forEach(function(t) {
let obj = t.obj 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({ new NumSlider({
id: 'slider_brush_size', id: 'slider_brush_size',
condition: () => (Toolbox && ['brush_tool', 'eraser'].includes(Toolbox.selected.id)), condition: () => (Toolbox && ['brush_tool', 'eraser'].includes(Toolbox.selected.id)),

View File

@ -81,6 +81,10 @@ const Canvas = {
objects.push(s) objects.push(s)
} }
}) })
for (var uuid in Canvas.meshes) {
var mesh = Canvas.meshes[uuid];
objects.safePush(mesh);
}
objects.forEach(function(s) { objects.forEach(function(s) {
if (s.parent) { if (s.parent) {
s.parent.remove(s) s.parent.remove(s)
@ -157,13 +161,17 @@ const Canvas = {
} }
}) })
}, },
updateRenderSides() { getRenderSide() {
var side = Format.id === 'java_block' ? 0 : 2; var side = Format.id === 'java_block' ? 0 : 2;
if (display_mode) { if (display_mode) {
if (['thirdperson_righthand', 'thirdperson_lefthand', 'head'].includes(display_slot)) { if (['thirdperson_righthand', 'thirdperson_lefthand', 'head'].includes(display_slot)) {
side = 2; side = 2;
} }
} }
return side;
},
updateRenderSides() {
var side = Canvas.getRenderSide();
textures.forEach(function(t) { textures.forEach(function(t) {
var mat = Canvas.materials[t.uuid] var mat = Canvas.materials[t.uuid]
if (mat) { if (mat) {
@ -173,7 +181,6 @@ const Canvas = {
emptyMaterials.forEach(function(mat) { emptyMaterials.forEach(function(mat) {
mat.side = side mat.side = side
}) })
return side;
}, },
//Selection updaters //Selection updaters
updateSelected(arr) { updateSelected(arr) {
@ -324,6 +331,7 @@ const Canvas = {
}, },
//Object handlers //Object handlers
addCube(obj) { addCube(obj) {
//This does NOT remove old cubes //This does NOT remove old cubes
var mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1)) var mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1))
Canvas.adaptObjectFaces(obj, mesh) Canvas.adaptObjectFaces(obj, mesh)
@ -661,8 +669,8 @@ const Canvas = {
} }
if (true) { if (true) {
var tex = cube.faces.north.getTexture() var tex = cube.faces.north.getTexture()
var width = tex ? tex.res : 16 var width = tex ? tex.width : 16
var height = tex ? tex.res / tex.ratio : 16 var height = tex ? tex.height : 16
size = [ size = [
Math.abs(width/16 * cube.faces.north.uv_size[cube.faces.north.rotation%180 ? 1 : 0]), 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]), Math.abs(height/16 * cube.faces.north.uv_size[cube.faces.north.rotation%180 ? 0 : 1]),

View File

@ -1442,7 +1442,7 @@ enterDisplaySettings = function() { //Enterung Display Setting Mode, changes th
display_area.updateMatrixWorld() display_area.updateMatrixWorld()
display_base.updateMatrixWorld() display_base.updateMatrixWorld()
DisplayMode.centerTransformer() Transformer.center()
if (outlines.children.length) { if (outlines.children.length) {
outlines.children.length = 0 outlines.children.length = 0
Canvas.updateAllPositions() Canvas.updateAllPositions()
@ -1493,22 +1493,6 @@ function resetDisplayBase() {
display_base.scale.z = 1; 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) { DisplayMode.updateDisplayBase = function(slot) {
if (!slot) slot = display[display_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.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); 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() display_area.updateMatrixWorld()
DisplayMode.centerTransformer() Transformer.center()
} }
DisplayMode.groundAnimation = function() { DisplayMode.groundAnimation = function() {
display_area.rotation.y += 0.015 display_area.rotation.y += 0.015
ground_timer += 1 ground_timer += 1
display_area.position.y = 13.5 + Math.sin(Math.PI * (ground_timer / 100)) * Math.PI/2 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; if (ground_timer === 200) ground_timer = 0;
} }

View File

@ -144,7 +144,7 @@ class Preview {
var intersect = intersects[0].object var intersect = intersects[0].object
if (intersect.isElement) { if (intersect.isElement) {
this.controls.hasMoved = true 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 )) { switch (Math.floor( intersects[0].faceIndex / 2 )) {
case 5: var face = 'north'; break; case 5: var face = 'north'; break;
case 0: var face = 'east'; break; case 0: var face = 'east'; break;
@ -322,7 +322,11 @@ class Preview {
main_uv.setFace(data.face, false) main_uv.setFace(data.face, false)
} }
Blockbench.dispatchEvent( 'canvas_select', data ) 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') { if (data.cube.parent.type === 'group') {
data.cube.parent.select() data.cube.parent.select()
} }
@ -793,6 +797,159 @@ function openQuadView() {
updateInterface() 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 //Init/Update
function initCanvas() { function initCanvas() {
@ -1187,7 +1344,7 @@ BARS.defineActions(function() {
form: { form: {
length: {label: 'dialog.create_gif.length', type: 'number', value: 10, step: 0.25}, length: {label: 'dialog.create_gif.length', type: 'number', value: 10, step: 0.25},
fps: {label: 'dialog.create_gif.fps', type: 'number', value: 10}, 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}, 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}, play: {label: 'dialog.create_gif.play', type: 'checkbox', condition: Animator.open},
}, },

View File

@ -698,10 +698,8 @@
this.update = function (object) { this.update = function (object) {
var scope = Transformer; var scope = Transformer;
if (!object && Modes.id === 'display' && Toolbox.selected.transformerMode === 'rotate') { if (!object) {
object = display_area; object = this.rotation_ref;
} else if (Modes.id == 'animate' && Group.selected && Group.selected.parent instanceof Group) {
object = Group.selected.parent.mesh
} }
if (scope.elements.length == 0) { if (scope.elements.length == 0) {
this.detach() this.detach()
@ -726,9 +724,16 @@
if (object) { if (object) {
worldRotation.setFromRotationMatrix( tempMatrix.extractRotation( object.matrixWorld ) ); worldRotation.setFromRotationMatrix( tempMatrix.extractRotation( object.matrixWorld ) );
if (Toolbox.selected.transformerMode === 'rotate') {
_gizmo[ _mode ].update( worldRotation, eye ); _gizmo[ _mode ].update( worldRotation, eye );
this.rotation.set(0, 0, 0);
} else {
object.getWorldQuaternion(this.rotation)
}
} else { } else {
worldRotation.set(0, 0, 0);
this.rotation.set(0, 0, 0);
_gizmo[ _mode ].update( new THREE.Euler(), eye ); _gizmo[ _mode ].update( new THREE.Euler(), eye );
} }
_gizmo[ _mode ].highlight( scope.axis ); _gizmo[ _mode ].highlight( scope.axis );
@ -786,7 +791,7 @@
this.updateSelection = function() { this.updateSelection = function() {
this.elements.empty() this.elements.empty()
if (Modes.edit) { if (Modes.edit || Toolbox.selected.id == 'pivot_tool') {
if (selected.length) { if (selected.length) {
selected.forEach(element => { selected.forEach(element => {
if ( if (
@ -808,7 +813,8 @@
return this; return this;
} }
this.center = function() { this.center = function() {
if (Modes.edit) { delete Transformer.rotation_ref;
if (Modes.edit || Toolbox.selected.id == 'pivot_tool') {
if (Transformer.visible) { if (Transformer.visible) {
var rotation_tool = Toolbox.selected.id === 'rotate_tool' || Toolbox.selected.id === 'pivot_tool' var rotation_tool = Toolbox.selected.id === 'rotate_tool' || Toolbox.selected.id === 'pivot_tool'
var rotation_object = getRotationObject() var rotation_object = getRotationObject()
@ -827,7 +833,7 @@
return; return;
} }
this.rotation_object = rotation_object; this.rotation_object = rotation_object;
if (Format.bone_rig) { if (Format.bone_rig && !Modes.animate) {
Canvas.updateAllBones() Canvas.updateAllBones()
} }
//Center //Center
@ -840,32 +846,41 @@
} }
//Rotation //Rotation
Transformer.rotation.set(0, 0, 0); if (rotation_tool) {
if (Toolbox.selected.transformerMode !== 'rotate') { Transformer.rotation_ref = rotation_object.mesh.parent;
if (Toolbox.selected.id == 'pivot_tool') {
} else if (Group.selected) {
Transformer.rotation_ref = rotation_object.mesh;
if (rotation_object.parent instanceof Group) {
rotation_object.parent.mesh.getWorldQuaternion(this.rotation)
}
} else if (!Blockbench.globalMovement && Cube.selected[0] && Cube.selected[0].mesh) { } else if (!Blockbench.globalMovement && Cube.selected[0] && Cube.selected[0].mesh) {
Cube.selected[0].mesh.getWorldQuaternion(this.rotation) Transformer.rotation_ref = Cube.selected[0].mesh;
}
} }
} }
} else if (Modes.display) { } 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) { } else if (Modes.animate && Group.selected) {
this.attach(Group.selected); this.attach(Group.selected);
Group.selected.mesh.getWorldPosition(this.position); Group.selected.mesh.getWorldPosition(this.position);
if (Toolbox.selected.transformerMode == 'rotate') { if (Toolbox.selected.id == 'resize_tool') {
this.rotation.set(0, 0, 0); Transformer.rotation_ref = Group.selected.mesh;
} else {
Transformer.rotation_ref = Group.selected.mesh.parent;
} }
Transformer.update()
return;
} }
} }
@ -937,7 +952,7 @@
function beforeFirstChange(event) { function beforeFirstChange(event) {
if (scope.hasChanged) return; if (scope.hasChanged) return;
if (Modes.edit) { if (Modes.edit || Toolbox.selected.id == 'pivot_tool') {
if (Toolbox.selected.id === 'resize_tool') { if (Toolbox.selected.id === 'resize_tool') {
var axisnr = getAxisNumber(scope.axis.toLowerCase().replace('n', '')) var axisnr = getAxisNumber(scope.axis.toLowerCase().replace('n', ''))
@ -1001,37 +1016,25 @@
if (Toolbox.selected.transformerMode !== 'rotate') { if (Toolbox.selected.transformerMode !== 'rotate') {
point.sub( offset ); point.sub( offset );
} point.removeEuler(worldRotation)
if (Toolbox.selected.transformerMode === 'rotate') {
} else {
point.sub( worldPosition ); point.sub( worldPosition );
point.removeEuler(worldRotation)
var rotations = [ var rotations = [
Math.atan2( point.z, point.y ), Math.atan2( point.z, point.y ),
Math.atan2( point.x, point.z ), Math.atan2( point.x, point.z ),
Math.atan2( point.y, point.x ) Math.atan2( point.y, point.x )
] ]
var angle = Math.radToDeg( rotations[axisNumber] ) 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') { if (Toolbox.selected.id === 'move_tool') {
var snap_factor = canvasGridSize(event.shiftKey, event.ctrlKey) 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) { if (previousValue === undefined) {
previousValue = point[axis] previousValue = point[axis]
@ -1046,10 +1049,10 @@
selected.forEach(function(obj) { selected.forEach(function(obj) {
if (obj.movable && obj.scalable) { if (obj.movable && obj.scalable) {
overlapping = overlapping || ( overlapping = overlapping || (
obj.to[axisNumber] + difference > 32 || obj.to[axisNumber] + difference + obj.inflate > 32 ||
obj.to[axisNumber] + difference < -16 || obj.to[axisNumber] + difference + obj.inflate < -16 ||
obj.from[axisNumber] + difference > 32 || obj.from[axisNumber] + difference - obj.inflate > 32 ||
obj.from[axisNumber] + difference < -16 obj.from[axisNumber] + difference - obj.inflate < -16
) )
} }
}) })
@ -1074,7 +1077,7 @@
} else if (Toolbox.selected.id === 'resize_tool') { } else if (Toolbox.selected.id === 'resize_tool') {
//Scale //Scale
var snap_factor = canvasGridSize(event.shiftKey, event.ctrlKey) 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]) { if (previousValue !== point[axis]) {
@ -1110,7 +1113,7 @@
} else if (Toolbox.selected.id === 'pivot_tool') { } else if (Toolbox.selected.id === 'pivot_tool') {
var snap_factor = canvasGridSize(event.shiftKey, event.ctrlKey) 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) { if (previousValue === undefined) {
previousValue = point[axis] previousValue = point[axis]
@ -1121,9 +1124,13 @@
var difference = point[axis] - previousValue var difference = point[axis] - previousValue
if (Format.bone_rig && Group.selected) { if (Format.bone_rig && Group.selected) {
if (Modes.edit) {
var origin = Group.selected.origin.slice(); var origin = Group.selected.origin.slice();
origin[axisNumber] += difference; origin[axisNumber] += difference;
Group.selected.transferOrigin(origin, true); Group.selected.transferOrigin(origin, true);
} else if (Modes.animate) {
Group.selected.origin[axisNumber] += difference;
}
} else { } else {
var origin = Transformer.rotation_object.origin.slice() var origin = Transformer.rotation_object.origin.slice()
origin[axisNumber] += difference; origin[axisNumber] += difference;
@ -1133,7 +1140,10 @@
} }
}) })
} }
Canvas.updatePositions(true) Canvas.updatePositions(true);
if (Modes.animate) {
Animator.preview();
}
scope.updateSelection() scope.updateSelection()
previousValue = point[axis] previousValue = point[axis]
@ -1174,7 +1184,6 @@
scope.keyframe.offset(axis, difference); scope.keyframe.offset(axis, difference);
scope.keyframe.select() scope.keyframe.select()
updateKeyframeSelection()
Animator.preview() Animator.preview()
previousValue = value previousValue = value
scope.hasChanged = true scope.hasChanged = true
@ -1242,7 +1251,7 @@
scope.orbit_controls.stopMovement() scope.orbit_controls.stopMovement()
outlines.children.length = 0 outlines.children.length = 0
if (Modes.id === 'edit') { if (Modes.id === 'edit' || Toolbox.selected.id == 'pivot_tool') {
if (Toolbox.selected.id === 'resize_tool') { if (Toolbox.selected.id === 'resize_tool') {
//Scale //Scale
selected.forEach(function(obj) { selected.forEach(function(obj) {
@ -1297,27 +1306,3 @@
THREE.TransformControls.prototype.constructor = THREE.TransformControls; 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;
};
}();

View File

@ -19,7 +19,7 @@ class Texture {
//Data //Data
this.ratio = 1 this.ratio = 1
this.img = 0; this.img = 0;
this.res = 0; this.width = 0;
this.saved = true this.saved = true
this.mode = isApp ? 'link' : 'bitmap'; this.mode = isApp ? 'link' : 'bitmap';
@ -58,16 +58,19 @@ class Texture {
var mat = new THREE.MeshLambertMaterial({ var mat = new THREE.MeshLambertMaterial({
color: 0xffffff, color: 0xffffff,
side: Canvas.getRenderSide(),
map: tex, map: tex,
transparent: settings.transparency.value, transparent: settings.transparency.value,
alphaTest: 0.2 alphaTest: 0.2
}); });
Canvas.materials[this.uuid] = mat Canvas.materials[this.uuid] = mat
var size_control = {};
this.img.onload = function() { this.img.onload = function() {
if (!this.src) return; if (!this.src) return;
this.tex.needsUpdate = true; this.tex.needsUpdate = true;
scope.res = img.naturalWidth; scope.width = img.naturalWidth;
scope.ratio = img.naturalWidth / img.naturalHeight; scope.ratio = img.naturalWidth / img.naturalHeight;
if (scope.isDefault) { 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, if (Project.box_uv && Format.single_texture && !scope.keep_size) {
ph: Project.texture_height,
nw: img.naturalWidth, let pw = Project.texture_width;
nh: img.naturalHeight let ph = Project.texture_height;
} let nw = img.naturalWidth;
if (false && (scope.old_width != size.nw || scope.old_height != size.nh) && (size.pw != size.nw || size.ph != size.nh)) { 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({ Blockbench.showMessageBox({
translateKey: 'update_res', translateKey: 'update_res',
icon: 'photo_size_select_small', icon: 'photo_size_select_small',
@ -107,11 +128,7 @@ class Texture {
cancel: 1 cancel: 1
}, function(result) { }, function(result) {
if (result === 0) { if (result === 0) {
var lockUV = ( // EG. Texture Optimierung > Modulo geht nicht in allen Bereichen auf setProjectResolution(img.naturalWidth, img.naturalHeight)
(size.pw%size.nw || size.ph%size.nh) &&
(size.nw%size.pw || size.nh%size.ph)
)
entityMode.setResolution(img.naturalWidth, img.naturalHeight, lockUV)
if (selected.length) { if (selected.length) {
main_uv.loadData() main_uv.loadData()
main_uv.setGrid() main_uv.setGrid()
@ -119,11 +136,13 @@ class Texture {
} }
}) })
} }
scope.old_width = img.naturalWidth size_control.old_width = img.naturalWidth
scope.old_height = img.naturalHeight size_control.old_height = img.naturalHeight
} }
*/
//--------------------------------------------------------------------------
if ($('.dialog#texture_edit:visible').length > 0 && scope.selected === true) { if ($('.dialog#texture_edit:visible').length > 0 && scope.selected === true) {
@ -153,6 +172,9 @@ class Texture {
return 1/this.ratio return 1/this.ratio
} }
} }
get height() {
return this.width / this.ratio;
}
getErrorMessage() { getErrorMessage() {
switch (this.error) { switch (this.error) {
case 0: return ''; break; case 0: return ''; break;
@ -441,6 +463,7 @@ class Texture {
return; return;
} }
var scope = this; var scope = this;
this.stopWatcher();
fs.watchFile(scope.path, {interval: 50}, function(curr, prev) { fs.watchFile(scope.path, {interval: 50}, function(curr, prev) {
if (curr.mtime !== prev.mtime) { if (curr.mtime !== prev.mtime) {

View File

@ -98,13 +98,14 @@ function isMovementGlobal() {
function isInBox(val) { function isInBox(val) {
return !Format.canvas_limit || (val < 32 && val > -16) 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) { if (!Format.canvas_limit) {
return val; return val;
} else if (val > 32) { } else if (val + inflate > 32) {
return 32; return 32 - inflate;
} else if (val < -16) { } else if (val - inflate < -16) {
return -16; return -16 + inflate;
} else { } else {
return val; return val;
} }
@ -338,9 +339,9 @@ const Vertexsnap = {
for (i=0; i<3; i++) { for (i=0; i<3; i++) {
if (m[i] === 1) { 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 { } 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) { if (Project.box_uv && obj.visibility) {
@ -358,12 +359,10 @@ const Vertexsnap = {
var q = obj.mesh.getWorldQuaternion(new THREE.Quaternion()).inverse() var q = obj.mesh.getWorldQuaternion(new THREE.Quaternion()).inverse()
cube_pos.applyQuaternion(q) cube_pos.applyQuaternion(q)
} }
obj.from[0] += cube_pos.getComponent(0) var in_box = obj.move(cube_pos);
obj.from[1] += cube_pos.getComponent(1) if (!in_box) {
obj.from[2] += cube_pos.getComponent(2) Blockbench.showMessageBox({translateKey: 'canvas_limit_error'})
obj.to[0] += cube_pos.getComponent(0) }
obj.to[1] += cube_pos.getComponent(1)
obj.to[2] += cube_pos.getComponent(2)
}) })
} }
@ -403,13 +402,13 @@ function scaleAll(save, size) {
if (obj.from) { if (obj.from) {
obj.from[i] = (obj.before.from[i] - ogn) * size; obj.from[i] = (obj.before.from[i] - ogn) * size;
if (obj.from[i] + ogn > 32 || obj.from[i] + ogn < -16) overflow.push(obj); 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) { if (obj.to) {
obj.to[i] = (obj.before.to[i] - ogn) * size; obj.to[i] = (obj.before.to[i] - ogn) * size;
if (obj.to[i] + ogn > 32 || obj.to[i] + ogn < -16) overflow.push(obj); 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) { if (obj.origin) {
@ -513,8 +512,8 @@ function centerCubes(axis, update) {
var difference = (Format.bone_rig ? 0 : 8) - average var difference = (Format.bone_rig ? 0 : 8) - average
selected.forEach(function(obj) { selected.forEach(function(obj) {
if (obj.movable) obj.from[axis] = limitToBox(obj.from[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); if (obj.scalable) obj.to[axis] = limitToBox(obj.to[axis] + difference, obj.inflate);
if (obj.origin) obj.origin[axis] += difference; if (obj.origin) obj.origin[axis] += difference;
}) })
@ -734,7 +733,7 @@ BARS.defineActions(function() {
Undo.finishEdit('resize') Undo.finishEdit('resize')
} }
}) })
//Inflage //Inflate
new NumSlider({ new NumSlider({
id: 'slider_inflate', id: 'slider_inflate',
condition: function() {return Cube.selected.length && Modes.edit}, condition: function() {return Cube.selected.length && Modes.edit},
@ -836,7 +835,7 @@ BARS.defineActions(function() {
)) ))
} }
//Origin
function moveOriginOnAxis(value, fixed, axis) { function moveOriginOnAxis(value, fixed, axis) {
if (Group.selected) { if (Group.selected) {
var diff = value var diff = value

View File

@ -170,7 +170,7 @@ var Undo = {
if (aspects.animations) { if (aspects.animations) {
this.animations = {} this.animations = {}
aspects.animations.forEach(a => { aspects.animations.forEach(a => {
scope.animations[a.uuid] = a.undoCopy(); scope.animations[a.uuid] = a.getUndoCopy();
}) })
} }
if (aspects.keyframes && Animator.selected && Animator.selected.getBoneAnimator()) { if (aspects.keyframes && Animator.selected && Animator.selected.getBoneAnimator()) {
@ -179,7 +179,7 @@ var Undo = {
bone: Animator.selected.getBoneAnimator().uuid bone: Animator.selected.getBoneAnimator().uuid
} }
aspects.keyframes.forEach(kf => { 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) { if (save.selection_group && !is_session) {
Group.selected = undefined 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) { if (sel_group) {
sel_group.select() sel_group.select()
} }
@ -266,7 +266,7 @@ var Undo = {
} }
if (save.group) { if (save.group) {
var group = Outliner.root.findRecursive('uuid', save.group.uuid) var group = Group.all.findInArray('uuid', save.group.uuid)
if (group) { if (group) {
if (is_session) { if (is_session) {
delete save.group.isOpen; delete save.group.isOpen;
@ -361,19 +361,19 @@ var Undo = {
for (var uuid in Animator.selected.bones) { for (var uuid in Animator.selected.bones) {
if (uuid === save.keyframes.bone) { if (uuid === save.keyframes.bone) {
bone = Animator.selected.bones[uuid] bone = Animator.selected.bones[uuid]
if (bone.select && Animator.open && is_session) { if (bone.group && Animator.open && !is_session) {
bone.select() bone.group.select()
} }
} }
} }
} }
if (bone) { if (bone.uuid === save.keyframes.bone) {
function getKeyframe(uuid) { function getKeyframe(uuid) {
var i = 0; var i = 0;
while (i < Timeline.keyframes.length) { while (i < bone.keyframes.length) {
if (Timeline.keyframes[i].uuid === uuid) { if (bone.keyframes[i].uuid === uuid) {
return Timeline.keyframes[i]; return bone.keyframes[i];
} }
i++; i++;
} }
@ -386,10 +386,9 @@ var Undo = {
if (kf) { if (kf) {
kf.extend(data) kf.extend(data)
} else { } else {
kf = new Keyframe(data) kf = new Keyframe(data, uuid)
kf.parent = bone; kf.parent = bone;
kf.uuid = uuid; bone.keyframes.push(kf)
Timeline.keyframes.push(kf)
added++; added++;
} }
} }

View File

@ -18,36 +18,6 @@ function compareVersions(string1/*new*/, string2/*old*/) {
} }
return false; 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) { const Condition = function(condition, context) {
if (condition !== undefined && condition !== null && condition.condition !== undefined) { if (condition !== undefined && condition !== null && condition.condition !== undefined) {
condition = condition.condition condition = condition.condition
@ -155,6 +125,12 @@ Math.isPowerOfTwo = function(x) {
Math.randomab = function(a, b) { Math.randomab = function(a, b) {
return a + Math.random()*(b-a); return a + Math.random()*(b-a);
} }
Math.areMultiples = function(n1, n2) {
return (
(n1/n2)%1 === 0 ||
(n2/n1)%1 === 0
)
}
function trimFloatNumber(val) { function trimFloatNumber(val) {
if (val == '') return val; if (val == '') return val;
var string = val.toFixed(4) var string = val.toFixed(4)
@ -448,6 +424,7 @@ function pathToName(path, extension) {
} }
} }
function pathToExtension(path) { function pathToExtension(path) {
if (typeof path !== 'string') return '';
var matches = path.match(/\.\w{2,24}$/) var matches = path.match(/\.\w{2,24}$/)
if (!matches || !matches.length) return ''; if (!matches || !matches.length) return '';
return matches[0].replace('.', '').toLowerCase() return matches[0].replace('.', '').toLowerCase()

View File

@ -20,7 +20,7 @@ function showUVShiftDialog() {
id: 'uv_shift_dialog', id: 'uv_shift_dialog',
fadeTime: 100, fadeTime: 100,
onConfirm: function() { onConfirm: function() {
Undo.initEdit({elements: elements, uv_only: true}) Undo.initEdit({elements: Cube.all, uv_only: true})
dialog.hide() dialog.hide()
var h = $(dialog.object).find('#shift_uv_horizontal').val() var h = $(dialog.object).find('#shift_uv_horizontal').val()
if (h.length > 0) { if (h.length > 0) {
@ -30,7 +30,7 @@ function showUVShiftDialog() {
add = true add = true
} }
h = eval(h) h = eval(h)
elements.forEach(function(obj) { Cube.all.forEach(function(obj) {
if (add) { if (add) {
obj.uv_offset[0] += h obj.uv_offset[0] += h
} else { } else {
@ -46,7 +46,7 @@ function showUVShiftDialog() {
add = true add = true
} }
v = eval(v) v = eval(v)
elements.forEach(function(obj) { Cube.all.forEach(function(obj) {
if (add) { if (add) {
obj.uv_offset[1] += v obj.uv_offset[1] += v
} else { } else {
@ -387,8 +387,8 @@ class UVEditor {
//Brush //Brush
getBrushCoordinates(event, tex) { getBrushCoordinates(event, tex) {
var scope = this; var scope = this;
var multiplier = (Project.box_uv && tex) ? tex.res/Project.texture_width : 1 var multiplier = (Project.box_uv && tex) ? tex.width/Project.texture_width : 1
var pixel_size = scope.inner_size / tex.res var pixel_size = scope.inner_size / tex.width
return { return {
x: Math.floor(event.offsetX/scope.getPixelSize()*multiplier), x: Math.floor(event.offsetX/scope.getPixelSize()*multiplier),
y: Math.floor(event.offsetY/scope.getPixelSize()*multiplier) y: Math.floor(event.offsetY/scope.getPixelSize()*multiplier)
@ -450,8 +450,8 @@ class UVEditor {
return this.inner_size/this.grid return this.inner_size/this.grid
} else { } else {
return this.inner_size/ ( return this.inner_size/ (
(typeof this.texture === 'object' && this.texture.res) (typeof this.texture === 'object' && this.texture.width)
? this.texture.res ? this.texture.width
: this.grid : this.grid
) )
} }
@ -543,13 +543,13 @@ class UVEditor {
grid = BarItems.uv_grid.get() grid = BarItems.uv_grid.get()
if (grid === 'auto') { if (grid === 'auto') {
if (this.texture) { if (this.texture) {
grid = this.texture.res grid = this.texture.width
} else { } else {
grid = 16 grid = 16
} }
this.autoGrid = true this.autoGrid = true
} else if (grid === 'none') { } else if (grid === 'none') {
grid = 1024 grid = 2084
} else { } else {
grid = parseInt(grid) grid = parseInt(grid)
} }
@ -731,21 +731,21 @@ class UVEditor {
this.jquery.frame.css('background-color', 'var(--color-back)').css('background-image', 'none') this.jquery.frame.css('background-color', 'var(--color-back)').css('background-image', 'none')
this.texture = false; this.texture = false;
this.setFrameColor() this.setFrameColor()
if (this.autoGrid || Project.box_uv) {
this.setGrid(16, false) this.setGrid(16, false)
}
} else { } else {
this.setFrameColor(tex.dark_box) this.setFrameColor(tex.dark_box)
var css = 'url("'+tex.source.split('\\').join('\\\\').replace(/ /g, '%20')+'")' var css = 'url("'+tex.source.split('\\').join('\\\\').replace(/ /g, '%20')+'")'
this.jquery.frame.css('background-image', css) this.jquery.frame.css('background-image', css)
if (Project.box_uv) { if (Format.id == 'java_block') {
this.jquery.frame.css('background-size', 'contain')
} else {
this.jquery.frame.css('background-size', 'cover') this.jquery.frame.css('background-size', 'cover')
} else {
this.jquery.frame.css('background-size', 'contain')
} }
this.texture = tex; this.texture = tex;
if (this.autoGrid || Project.box_uv) { if (this.autoGrid) {
this.setGrid(tex.res, false) this.setGrid(Project.texture_width, false)
} else {
this.setGrid(undefined, false)
} }
} }
if (!tex || typeof tex !== 'object') { if (!tex || typeof tex !== 'object') {
@ -1027,11 +1027,13 @@ class UVEditor {
} }
setAutoSize(event) { setAutoSize(event) {
var scope = this; var scope = this;
var top, left, top2, left2; var top2, left2;
this.forCubes(obj => { this.forCubes(obj => {
scope.getFaces(event).forEach(function(side) { 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') { if (side == 'north' || side == 'south') {
left2 = limitNumber(obj.size('0'), 0, 16) left2 = limitNumber(obj.size('0'), 0, 16)
top2 = limitNumber(obj.size('1'), 0, 16) top2 = limitNumber(obj.size('1'), 0, 16)
@ -1042,10 +1044,12 @@ class UVEditor {
left2 = limitNumber(obj.size('0'), 0, 16) left2 = limitNumber(obj.size('0'), 0, 16)
top2 = limitNumber(obj.size('2'), 0, 16) top2 = limitNumber(obj.size('2'), 0, 16)
} }
if (obj.faces[side].rotation % 180) { if (face.rotation % 180) {
[left2, top2] = [top2, left2]; [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 obj.autouv = 0
Canvas.updateUV(obj) Canvas.updateUV(obj)
@ -1109,7 +1113,7 @@ class UVEditor {
break; break;
} }
uv.forEach(function(s, uvi) { 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 obj.faces[side].uv = uv
}) })
@ -1373,7 +1377,7 @@ class UVEditor {
'uv_maximize', 'uv_maximize',
'uv_auto', 'uv_auto',
'uv_rel_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 off = 'radio_button_unchecked'
var on = 'radio_button_checked' var on = 'radio_button_checked'
return [ return [
@ -1789,7 +1793,7 @@ BARS.defineActions(function() {
new BarSlider({ new BarSlider({
id: 'uv_rotation', id: 'uv_rotation',
category: 'uv', 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, min: 0, max: 270, step: 90, width: 80,
onBefore: () => { onBefore: () => {
Undo.initEdit({elements: Cube.selected, uv_only: true}) Undo.initEdit({elements: Cube.selected, uv_only: true})
@ -1812,6 +1816,8 @@ BARS.defineActions(function() {
'16': '16x16', '16': '16x16',
'32': '32x32', '32': '32x32',
'64': '64x64', '64': '64x64',
'128': '128x128',
'256': '256x256',
none: true, none: true,
}, },
onChange: function(slider) { onChange: function(slider) {

View File

@ -964,5 +964,7 @@
"panel.element.position": "Position", "panel.element.position": "Position",
"panel.element.size": "Größe", "panel.element.size": "Größe",
"panel.element.origin": "Angelpunkt", "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."
} }

View File

@ -98,6 +98,8 @@
"status_bar.recording_gif":"Recording GIF", "status_bar.recording_gif":"Recording GIF",
"status_bar.processing_gif":"Processing 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.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.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", "message.file_not_found.title": "File Not Found",

View File

@ -890,7 +890,7 @@
"dates.yesterday": "Ayer", "dates.yesterday": "Ayer",
"dates.this_week": "Esta semana", "dates.this_week": "Esta semana",
"dates.weeks_ago": "Hace %0 semanas", "dates.weeks_ago": "Hace %0 semanas",
"mode.start": "Empezar", "mode.start": "Inicio",
"mode.start.new": "Nuevo", "mode.start.new": "Nuevo",
"mode.start.recent": "Reciente", "mode.start.recent": "Reciente",
"format.free": "Modelo libre", "format.free": "Modelo libre",
@ -953,16 +953,18 @@
"web.download_app": "Descargar Aplicación", "web.download_app": "Descargar Aplicación",
"uv_editor.turned": "Mapeado Girado", "uv_editor.turned": "Mapeado Girado",
"display.reference.crossbow": "Ballesta", "display.reference.crossbow": "Ballesta",
"dialog.settings.search_results": "Search Results", "dialog.settings.search_results": "Resultados de Búsqueda",
"settings.animation_snap": "Animation Snap", "settings.animation_snap": "Imán de Animación",
"settings.animation_snap.desc": "Snap interval for keyframes in the animation timeline in steps per second", "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": "Import OptiFine Part", "action.import_optifine_part": "Importar Parte de OptiFine",
"action.import_optifine_part.desc": "Import an entity part model for OptiFine", "action.import_optifine_part.desc": "Importa un modelo de parte de entidad para OptiFine",
"data.locator": "Locator", "data.locator": "Localizador",
"mode.start.no_recents": "No recently opened models", "mode.start.no_recents": "No hay modelos abiertos recientemente",
"panel.element": "Element", "panel.element": "Elemento",
"panel.element.position": "Position", "panel.element.position": "Posición",
"panel.element.size": "Size", "panel.element.size": "Tamaño",
"panel.element.origin": "Pivot Point", "panel.element.origin": "Punto de Pivote",
"panel.element.rotation": "Rotation" "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."
} }

View File

@ -49,7 +49,7 @@
"message.rotation_limit.title": "Limites de rotation", "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.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.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.title": "Capture d'écran",
"message.screenshot.message": "Capture d'écran effectuée", "message.screenshot.message": "Capture d'écran effectuée",
"message.screenshot.clipboard": "Presse-papier", "message.screenshot.clipboard": "Presse-papier",
@ -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.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.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.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.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.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", "message.update_res.update": "Mise à jour",
@ -752,7 +752,7 @@
"menu.group.material": "Mettre un matériel", "menu.group.material": "Mettre un matériel",
"action.camera_reset": "Réinitialiser la caméra", "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", "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", "panel.variable_placeholders.info": "Lister les variables à prévisualiser par nom=valeur",
"status_bar.vertex_distance": "Distance: %0", "status_bar.vertex_distance": "Distance: %0",
"dialog.create_gif.title": "Enregistrer un GIF", "dialog.create_gif.title": "Enregistrer un GIF",
@ -893,7 +893,7 @@
"mode.start": "Commencer", "mode.start": "Commencer",
"mode.start.new": "Nouveau", "mode.start.new": "Nouveau",
"mode.start.recent": "Récent", "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.free.desc": "Modèle sans limites pour Unity etc.",
"format.java_block": "Bloc/Objet Java", "format.java_block": "Bloc/Objet Java",
"format.java_block.desc": "Model de bloc pour Java Edition. La taille et les rotations sont limitées.", "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", "web.download_app": "Télécharger l'application",
"uv_editor.turned": "Mappage UV retournée", "uv_editor.turned": "Mappage UV retournée",
"display.reference.crossbow": "Arbalète", "display.reference.crossbow": "Arbalète",
"dialog.settings.search_results": "Search Results", "dialog.settings.search_results": "Rechercher les résultats",
"settings.animation_snap": "Animation Snap", "settings.animation_snap": "Aligner les animations",
"settings.animation_snap.desc": "Snap interval for keyframes in the animation timeline in steps per second", "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": "Import OptiFine Part", "action.import_optifine_part": "Importer une partie OptiFine",
"action.import_optifine_part.desc": "Import an entity part model for OptiFine", "action.import_optifine_part.desc": "Importer une partie d'entité pour un modèle OptiFine",
"data.locator": "Locator", "data.locator": "Localisateur",
"mode.start.no_recents": "No recently opened models", "mode.start.no_recents": "Aucun modèle ouvert récemment",
"panel.element": "Element", "panel.element": "Élément",
"panel.element.position": "Position", "panel.element.position": "Position",
"panel.element.size": "Size", "panel.element.size": "Taille",
"panel.element.origin": "Pivot Point", "panel.element.origin": "Point de pivot",
"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."
} }

View File

@ -959,10 +959,12 @@
"action.import_optifine_part": "Importare parte OptiFine", "action.import_optifine_part": "Importare parte OptiFine",
"action.import_optifine_part.desc": "Importare una parte di un modello per OptiFine", "action.import_optifine_part.desc": "Importare una parte di un modello per OptiFine",
"data.locator": "Locator", "data.locator": "Locator",
"mode.start.no_recents": "No recently opened models", "mode.start.no_recents": "Nessun modello aperto recentemente",
"panel.element": "Element", "panel.element": "Elemento",
"panel.element.position": "Position", "panel.element.position": "Posizione",
"panel.element.size": "Size", "panel.element.size": "Dimensione",
"panel.element.origin": "Pivot Point", "panel.element.origin": "Origine",
"panel.element.rotation": "Rotation" "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."
} }

View File

@ -445,13 +445,13 @@
"action.center_z.desc": "選択したキューブをZ軸の中心に合わせる", "action.center_z.desc": "選択したキューブをZ軸の中心に合わせる",
"action.center_all": "Center All", "action.center_all": "Center All",
"action.center_all.desc": "キューブの中心を回転軸にする", "action.center_all.desc": "キューブの中心を回転軸にする",
"action.toggle_visibility": "Toggle Visibility", "action.toggle_visibility": "可視化",
"action.toggle_visibility.desc": "選択したキューブの表示を切り替えます", "action.toggle_visibility.desc": "選択したキューブの表示を切り替えます",
"action.toggle_export": "Toggle Export", "action.toggle_export": "エキスポート",
"action.toggle_export.desc": "選択したキューブのエクスポート設定を切り替えます", "action.toggle_export.desc": "選択したキューブのエクスポート設定を切り替えます",
"action.toggle_autouv": "Toggle Auto UV", "action.toggle_autouv": "オートUV",
"action.toggle_autouv.desc": "選択したキューブの自動UV設定を切り替えます", "action.toggle_autouv.desc": "選択したキューブの自動UV設定を切り替えます",
"action.toggle_shade": "Toggle Shading", "action.toggle_shade": "シェーディング",
"action.toggle_shade.desc": "選択したキューブの偏光を切り替えます", "action.toggle_shade.desc": "選択したキューブの偏光を切り替えます",
"action.rename": "名前を変更", "action.rename": "名前を変更",
"action.rename.desc": "選択したキューブの名前を変更します", "action.rename.desc": "選択したキューブの名前を変更します",
@ -498,7 +498,7 @@
"menu.display": "Display", "menu.display": "Display",
"menu.view": "View", "menu.view": "View",
"menu.file.new": "新規作成", "menu.file.new": "新規作成",
"menu.file.recent": "呼び戻し", "menu.file.recent": "最近使ったファイル",
"menu.file.import": "インポート", "menu.file.import": "インポート",
"menu.file.export": "エクスポート", "menu.file.export": "エクスポート",
"menu.transform.rotate": "回転", "menu.transform.rotate": "回転",
@ -792,7 +792,7 @@
"action.open_backup_folder.desc": "Blockbenchのバックアップフォルダーを開きます", "action.open_backup_folder.desc": "Blockbenchのバックアップフォルダーを開きます",
"switches.mirror": "ミラーUV", "switches.mirror": "ミラーUV",
"Name of the Language you are editing, NOT English": { "Name of the Language you are editing, NOT English": {
"language_name": "English" "language_name": "英語"
}, },
"message.plugin_reload": "%0プラグインをリロードしました", "message.plugin_reload": "%0プラグインをリロードしました",
"settings.brightness": "輝度", "settings.brightness": "輝度",
@ -899,7 +899,7 @@
"format.java_block.desc": "Java Editionモデリング (サイズと回転は限られています)", "format.java_block.desc": "Java Editionモデリング (サイズと回転は限られています)",
"format.bedrock": "Bedrock Model", "format.bedrock": "Bedrock Model",
"format.bedrock.desc": "統合版モデリング", "format.bedrock.desc": "統合版モデリング",
"format.bedrock_old": "統合版デフォルトモデル", "format.bedrock_old": "Bedrock Legacy Model",
"format.bedrock_old.desc": "統合版-1.12 エンティティモデル", "format.bedrock_old.desc": "統合版-1.12 エンティティモデル",
"format.modded_entity": "Modded Entity", "format.modded_entity": "Modded Entity",
"format.modded_entity.desc": "エンティティモデリング", "format.modded_entity.desc": "エンティティモデリング",
@ -927,42 +927,44 @@
"settings.painting_grid.desc": "キューブ上にグリットを表示する", "settings.painting_grid.desc": "キューブ上にグリットを表示する",
"action.slider_brush_min_opacity": "最小不透明度", "action.slider_brush_min_opacity": "最小不透明度",
"action.slider_brush_min_opacity.desc": "ブラシの最小不透明度", "action.slider_brush_min_opacity.desc": "ブラシの最小不透明度",
"action.convert_project": "Convert Project", "action.convert_project": "プロジェクトを変換",
"action.convert_project.desc": "Converts the current project to a project for another model format", "action.convert_project.desc": "別のモデルフォーマットに変換します",
"action.close_project": "プロジェクトを閉じる", "action.close_project": "プロジェクトを閉じる",
"action.close_project.desc": "Closes the currently open project", "action.close_project.desc": "進行中のプロジェクトを閉じます",
"action.export_bedrock": "Export Bedrock Geometry", "action.export_bedrock": "ジオメトリーとしてエクスポート",
"action.export_bedrock.desc": "Export the model as a bedrock edition geometry file.", "action.export_bedrock.desc": "モデルを統合版ジオメトリーファイルとしてエクスポートします",
"action.save_project": "プロジェクトを保存", "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": "すべてのプロジェクトを保存",
"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": "上書き保存",
"action.export_over.desc": "Saves the model, textures and animations by overwriting the files", "action.export_over.desc": "呼び出したファイルに上書きで保存します",
"action.add_locator": "ロケータ-を追加", "action.add_locator": "ロケータ-を追加",
"action.add_locator.desc": "Adds a new locator to control positions of particles, leashes etc", "action.add_locator.desc": "パーティクルの位置を制御するための新しいロケータを追加します",
"action.sidebar_left": "Textures and UV", "action.sidebar_left": "テクスチャとUV",
"action.sidebar_left.desc": "Open the interface for UV and textures", "action.sidebar_left.desc": "テクスチャとUVを呼び出します",
"action.sidebar_right": "エレメント", "action.sidebar_right": "エレメント",
"action.sidebar_right.desc": "Open the interface to edit elements", "action.sidebar_right.desc": "変更したエレメントを呼び出します",
"action.uv_turn_mapping": "Turn Mapping", "action.uv_turn_mapping": "ターンマッピング",
"action.uv_turn_mapping.desc": "Turn the UV mapping around 90 degrees", "action.uv_turn_mapping.desc": "UVマッピングを90度回転させます",
"action.remove_blank_faces": "空白の面を削除", "action.remove_blank_faces": "空白の面を削除",
"action.remove_blank_faces.desc": "Deletes all untextured faces of the selection", "action.remove_blank_faces.desc": "選択した面をすべて削除します",
"menu.uv.select": "Select Cubes", "menu.uv.select": "キューブを選択",
"web.download_app": "Download App", "web.download_app": "Appをダウンロード",
"uv_editor.turned": "Turned Mapping", "uv_editor.turned": "ターンマッピング",
"display.reference.crossbow": "クロスボウ", "display.reference.crossbow": "クロスボウ",
"dialog.settings.search_results": "Search Results", "dialog.settings.search_results": "検索",
"settings.animation_snap": "Animation Snap", "settings.animation_snap": "アニメーションスナップ",
"settings.animation_snap.desc": "Snap interval for keyframes in the animation timeline in steps per second", "settings.animation_snap.desc": "アニメーションライン1ステップの間隔幅",
"action.import_optifine_part": "Import OptiFine Part", "action.import_optifine_part": "OptiFineをインポート",
"action.import_optifine_part.desc": "Import an entity part model for OptiFine", "action.import_optifine_part.desc": "OptiFineエンティティモデルをインポートします",
"data.locator": "ロケーター", "data.locator": "ロケーター",
"mode.start.no_recents": "最近開いたモデルはありません", "mode.start.no_recents": "最近開いたモデルはありません",
"panel.element": "Element", "panel.element": "エレメント",
"panel.element.position": "Position", "panel.element.position": "Position",
"panel.element.size": "Size", "panel.element.size": "Size",
"panel.element.origin": "Pivot Point", "panel.element.origin": "Center",
"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."
} }

View File

@ -964,5 +964,7 @@
"panel.element.position": "Position", "panel.element.position": "Position",
"panel.element.size": "Size", "panel.element.size": "Size",
"panel.element.origin": "Pivot Point", "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."
} }

View File

@ -964,5 +964,7 @@
"panel.element.position": "Position", "panel.element.position": "Position",
"panel.element.size": "Size", "panel.element.size": "Size",
"panel.element.origin": "Pivot Point", "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."
} }

View File

@ -964,5 +964,7 @@
"panel.element.position": "Position", "panel.element.position": "Position",
"panel.element.size": "Size", "panel.element.size": "Size",
"panel.element.origin": "Pivot Point", "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."
} }

View File

@ -25,12 +25,12 @@
"keys.rightclick": "ПКМ", "keys.rightclick": "ПКМ",
"keys.tab": "Tab", "keys.tab": "Tab",
"keys.backspace": "Backspace", "keys.backspace": "Backspace",
"keys.enter": "Ввод", "keys.enter": "Enter",
"keys.escape": "Escape", "keys.escape": "Escape",
"keys.function": "F%0", "keys.function": "F%0",
"keys.numpad": "%0 (цифр. кл.)", "keys.numpad": "%0 (цифр. кл.)",
"keys.caps": "Caps Lock", "keys.caps": "Caps Lock",
"keys.menu": "Menu", "keys.menu": "Меню",
"keys.left": "Стрелка влево", "keys.left": "Стрелка влево",
"keys.up": "Стрелка вверх", "keys.up": "Стрелка вверх",
"keys.right": "Стрелка вправо", "keys.right": "Стрелка вправо",
@ -47,7 +47,7 @@
"keys.printscreen": "Print Screen", "keys.printscreen": "Print Screen",
"keys.pause": "Pause", "keys.pause": "Pause",
"message.rotation_limit.title": "Ограничение поворота", "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.title": "Файл не найден",
"message.file_not_found.message": "Blockbench не может найти запрашиваемый файл. Убедитесь, что он сохранен по указанному пути, не в облаке.", "message.file_not_found.message": "Blockbench не может найти запрашиваемый файл. Убедитесь, что он сохранен по указанному пути, не в облаке.",
"message.screenshot.title": "Скриншот", "message.screenshot.title": "Скриншот",
@ -147,8 +147,8 @@
"dialog.plugins.show_less": "Показать меньше", "dialog.plugins.show_less": "Показать меньше",
"dialog.entitylist.title": "Открыть модель сущности", "dialog.entitylist.title": "Открыть модель сущности",
"dialog.entitylist.text": "Выберите модель, которую Вы хотите импортировать", "dialog.entitylist.text": "Выберите модель, которую Вы хотите импортировать",
"dialog.entitylist.bones": "костей", "dialog.entitylist.bones": "Костей",
"dialog.entitylist.cubes": "кубов", "dialog.entitylist.cubes": "Кубов",
"dialog.create_texture.title": "Создать текстуру", "dialog.create_texture.title": "Создать текстуру",
"dialog.create_texture.name": "Имя файла", "dialog.create_texture.name": "Имя файла",
"dialog.create_texture.folder": "Папка", "dialog.create_texture.folder": "Папка",
@ -958,11 +958,13 @@
"settings.animation_snap.desc": "Интервал привязки кадров на графике анимаций", "settings.animation_snap.desc": "Интервал привязки кадров на графике анимаций",
"action.import_optifine_part": "Импортировать часть OptiFine", "action.import_optifine_part": "Импортировать часть OptiFine",
"action.import_optifine_part.desc": "Импортировать часть модели сущности OptiFine", "action.import_optifine_part.desc": "Импортировать часть модели сущности OptiFine",
"data.locator": "Locator", "data.locator": "Маркер",
"mode.start.no_recents": "No recently opened models", "mode.start.no_recents": "Вы еще не открывали моделей",
"panel.element": "Element", "panel.element": "Элемент",
"panel.element.position": "Position", "panel.element.position": "Позиция",
"panel.element.size": "Size", "panel.element.size": "Размер",
"panel.element.origin": "Pivot Point", "panel.element.origin": "Центральная точка",
"panel.element.rotation": "Rotation" "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."
} }

View File

@ -964,5 +964,7 @@
"panel.element.position": "Position", "panel.element.position": "Position",
"panel.element.size": "Size", "panel.element.size": "Size",
"panel.element.origin": "Pivot Point", "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."
} }

View File

@ -1,20 +1,20 @@
{ {
"dialog.ok": "OK", "dialog.ok": "好的",
"dialog.cancel": "Cancel", "dialog.cancel": "取消",
"dialog.confirm": "Confirm", "dialog.confirm": "确认",
"dialog.close": "Close", "dialog.close": "关闭",
"dialog.import": "Import", "dialog.import": "导入",
"dialog.save": "Save", "dialog.save": "保存",
"dialog.discard": "Discard", "dialog.discard": "弃置",
"dialog.dontshowagain": "Don't Show Again", "dialog.dontshowagain": "不再显示",
"data.cube": "Cube", "data.cube": "Cube",
"data.group": "Group", "data.group": "",
"data.texture": "Texture", "data.texture": "材质",
"data.plugin": "Plugin", "data.plugin": "插件",
"data.preview": "Preview", "data.preview": "预览",
"data.toolbar": "Toolbar", "data.toolbar": "工具栏",
"data.image": "Image", "data.image": "图片",
"keys.ctrl": "Control", "keys.ctrl": "Ctrl",
"keys.shift": "Shift", "keys.shift": "Shift",
"keys.alt": "Alt", "keys.alt": "Alt",
"keys.meta": "Cmd", "keys.meta": "Cmd",
@ -47,7 +47,7 @@
"keys.printscreen": "截屏键", "keys.printscreen": "截屏键",
"keys.pause": "暂停键", "keys.pause": "暂停键",
"message.rotation_limit.title": "旋转限制", "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.title": "未找到文件",
"message.file_not_found.message": "Blockbench 找不到该文件。请确保此文件为本地文件而不是云文件。", "message.file_not_found.message": "Blockbench 找不到该文件。请确保此文件为本地文件而不是云文件。",
"message.screenshot.title": "屏幕截图", "message.screenshot.title": "屏幕截图",
@ -65,7 +65,7 @@
"message.unsaved_textures.title": "未保存的贴图", "message.unsaved_textures.title": "未保存的贴图",
"message.unsaved_textures.message": "您的模型中存在未保存的贴图。请确保它们存在于资源包里正确的文件夹中。", "message.unsaved_textures.message": "您的模型中存在未保存的贴图。请确保它们存在于资源包里正确的文件夹中。",
"message.model_clipping.title": "模型太大了", "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.title": "导入贴图",
"message.loose_texture.message": "导入的贴图不在资源包中。Minecraft 只能加载资源包里 textures 文件夹中的贴图。", "message.loose_texture.message": "导入的贴图不在资源包中。Minecraft 只能加载资源包里 textures 文件夹中的贴图。",
"message.loose_texture.change": "更改路径", "message.loose_texture.change": "更改路径",
@ -395,66 +395,66 @@
"action.paste.desc": "粘贴选定的,面或显示设置", "action.paste.desc": "粘贴选定的,面或显示设置",
"action.cut": "剪切", "action.cut": "剪切",
"action.cut.desc": "剪切选定的,面或显示设置", "action.cut.desc": "剪切选定的,面或显示设置",
"action.add_cube": "添加方块", "action.add_cube": "添加立方体",
"action.add_cube.desc": "添加一个新的方块", "action.add_cube.desc": "添加一个新的立方体",
"action.add_group": "添加组", "action.add_group": "添加组",
"action.add_group.desc": "添加一个新的组", "action.add_group.desc": "添加一个新的组",
"action.outliner_toggle": "切换更多选项", "action.outliner_toggle": "切换更多选项",
"action.outliner_toggle.desc": "切换开关以在outliner中添加更多选项", "action.outliner_toggle.desc": "切换开关以在outliner中添加更多选项",
"action.duplicate": "生成副本", "action.duplicate": "生成副本",
"action.duplicate.desc": "复制选定的方块或组", "action.duplicate.desc": "复制选定的立方体或组",
"action.delete": "删除", "action.delete": "删除",
"action.delete.desc": "删除选定的方块或组", "action.delete.desc": "删除选定的立方体或组",
"action.sort_outliner": "排序大纲", "action.sort_outliner": "排序大纲",
"action.sort_outliner.desc": "按字母顺序排列大纲", "action.sort_outliner.desc": "按字母顺序排列大纲",
"action.local_move": "相对移动", "action.local_move": "相对移动",
"action.local_move.desc": "如果可以,将旋转的元素移动到自己的轴上", "action.local_move.desc": "如果可以,将旋转的元素移动到自己的轴上",
"action.select_window": "选择", "action.select_window": "选择",
"action.select_window.desc": "根据其属性搜索并选择方块", "action.select_window.desc": "根据其属性搜索并选择立方体",
"action.invert_selection": "反向选择", "action.invert_selection": "反向选择",
"action.invert_selection.desc": "反向选择当前的方块", "action.invert_selection.desc": "反向选择当前的立方体",
"action.select_all": "全选", "action.select_all": "全选",
"action.select_all.desc": "选择所有方块", "action.select_all.desc": "选择所有立方体",
"action.collapse_groups": "折叠组", "action.collapse_groups": "折叠组",
"action.collapse_groups.desc": "折叠所有组", "action.collapse_groups.desc": "折叠所有组",
"action.scale": "缩放", "action.scale": "缩放",
"action.scale.desc": "缩放选定的方块", "action.scale.desc": "缩放选定的立方体",
"action.rotate_x_cw": "顺时针旋转", "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": "逆时针旋转",
"action.rotate_x_ccw.desc": "在 X 轴上旋转选定的方块 -90°", "action.rotate_x_ccw.desc": "在 X 轴上旋转选定的立方体 -90°",
"action.rotate_y_cw": "顺时针旋转", "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": "逆时针旋转",
"action.rotate_y_ccw.desc": "在 Y 轴上将选定的方块旋转 -90°", "action.rotate_y_ccw.desc": "在 Y 轴上将选定的立方体旋转 -90°",
"action.rotate_z_cw": "顺时针旋转", "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": "逆时针旋转",
"action.rotate_z_ccw.desc": "在 Y 轴上将选定的方块旋转 -90°", "action.rotate_z_ccw.desc": "在 Y 轴上将选定的立方体旋转 -90°",
"action.flip_x": "X 轴翻转", "action.flip_x": "X 轴翻转",
"action.flip_x.desc": "翻转 X 轴上的选定方块", "action.flip_x.desc": "翻转 X 轴上的选定立方体",
"action.flip_y": "Y 轴翻转", "action.flip_y": "Y 轴翻转",
"action.flip_y.desc": "翻转 Y 轴上的选定方块", "action.flip_y.desc": "翻转 Y 轴上的选定立方体",
"action.flip_z": "Z 轴翻转", "action.flip_z": "Z 轴翻转",
"action.flip_z.desc": "翻转 Z 轴上的选定方块", "action.flip_z.desc": "翻转 Z 轴上的选定立方体",
"action.center_x": "X 轴居中", "action.center_x": "X 轴居中",
"action.center_x.desc": "将所选方块居中在 X 轴上", "action.center_x.desc": "将所选立方体居中在 X 轴上",
"action.center_y": "Y 轴居中", "action.center_y": "Y 轴居中",
"action.center_y.desc": "将所选方块居中在 Y 轴上", "action.center_y.desc": "将所选立方体居中在 Y 轴上",
"action.center_z": "Z 轴居中", "action.center_z": "Z 轴居中",
"action.center_z.desc": "将所选方块居中在 Z 轴上", "action.center_z.desc": "将所选立方体居中在 Z 轴上",
"action.center_all": "全部居中", "action.center_all": "全部居中",
"action.center_all.desc": "使所选方块居中", "action.center_all.desc": "使所选立方体居中",
"action.toggle_visibility": "切换可见", "action.toggle_visibility": "切换可见",
"action.toggle_visibility.desc": "切换所选方块的可见", "action.toggle_visibility.desc": "切换所选立方体的可见",
"action.toggle_export": "切换导出", "action.toggle_export": "切换导出",
"action.toggle_export.desc": "切换所选方块的导出设置", "action.toggle_export.desc": "切换所选立方体的导出设置",
"action.toggle_autouv": "切换自动 UV", "action.toggle_autouv": "切换自动 UV",
"action.toggle_autouv.desc": "切换所选方块的自动UV设置", "action.toggle_autouv.desc": "切换所选立方体的自动UV设置",
"action.toggle_shade": "切换阴影", "action.toggle_shade": "切换阴影",
"action.toggle_shade.desc": "切换所选方块的阴影", "action.toggle_shade.desc": "切换所选立方体的阴影",
"action.rename": "重命名", "action.rename": "重命名",
"action.rename.desc": "更改所选方块的名称", "action.rename.desc": "更改所选立方体的名称",
"action.add_display_preset": "新建预设", "action.add_display_preset": "新建预设",
"action.add_display_preset.desc": "添加新的显示设置预设", "action.add_display_preset.desc": "添加新的显示设置预设",
"action.fullscreen": "全屏", "action.fullscreen": "全屏",
@ -486,9 +486,9 @@
"action.origin_to_geometry": "原点到几何", "action.origin_to_geometry": "原点到几何",
"action.origin_to_geometry.desc": "将原点设置为几何体的中心", "action.origin_to_geometry.desc": "将原点设置为几何体的中心",
"action.rescale_toggle": "切换重新调节", "action.rescale_toggle": "切换重新调节",
"action.rescale_toggle.desc": "根据当前旋转重新缩放方块", "action.rescale_toggle.desc": "根据当前旋转重新缩放立方体",
"action.bone_reset_toggle": "重置骨骼", "action.bone_reset_toggle": "重置骨骼",
"action.bone_reset_toggle.desc": "阻止骨骼显示父模型中的方块", "action.bone_reset_toggle.desc": "阻止骨骼显示父模型中的立方体",
"action.reload": "重载 Blockbench", "action.reload": "重载 Blockbench",
"action.reload.desc": "重载 Blockbench这将删除所有未保存的进度", "action.reload.desc": "重载 Blockbench这将删除所有未保存的进度",
"menu.file": "文件", "menu.file": "文件",
@ -531,7 +531,7 @@
"menu.texture.properties": "属性", "menu.texture.properties": "属性",
"menu.preview.background": "背景", "menu.preview.background": "背景",
"menu.preview.background.load": "加载", "menu.preview.background.load": "加载",
"menu.preview.background.position": "位置", "menu.preview.background.position": "立方体位置",
"menu.preview.background.lock": "锁定视角", "menu.preview.background.lock": "锁定视角",
"menu.preview.background.remove": "清除", "menu.preview.background.remove": "清除",
"menu.preview.screenshot": "截图", "menu.preview.screenshot": "截图",
@ -601,7 +601,7 @@
"display.reference.bow": "弓", "display.reference.bow": "弓",
"display.reference.block": "方块", "display.reference.block": "方块",
"display.reference.frame": "物品展示框", "display.reference.frame": "物品展示框",
"display.reference.inventory_nine": "3x3", "display.reference.inventory_nine": "合成台",
"display.reference.inventory_full": "物品栏", "display.reference.inventory_full": "物品栏",
"display.reference.hud": "HUD", "display.reference.hud": "HUD",
"display.preset.blank_name": "请输入名称", "display.preset.blank_name": "请输入名称",
@ -638,7 +638,7 @@
"dialog.shift_uv.vertical": "垂直", "dialog.shift_uv.vertical": "垂直",
"keybindings.reset": "重启", "keybindings.reset": "重启",
"keybindings.clear": "Empty", "keybindings.clear": "Empty",
"action.cube_counter": "方块数量", "action.cube_counter": "立方体数量",
"action.uv_rotation": "UV旋转", "action.uv_rotation": "UV旋转",
"action.uv_rotation.desc": "UV面的旋转", "action.uv_rotation.desc": "UV面的旋转",
"action.uv_grid": "UV网格", "action.uv_grid": "UV网格",
@ -690,7 +690,7 @@
"message.image_editor_missing.message": "选择图像编辑器的可执行文件", "message.image_editor_missing.message": "选择图像编辑器的可执行文件",
"message.image_editor_missing.detail": "Blockbench 无法在您的计算机上找到图像编辑器,请选择图像编辑器的可执行文件。", "message.image_editor_missing.detail": "Blockbench 无法在您的计算机上找到图像编辑器,请选择图像编辑器的可执行文件。",
"action.update_autouv": "自动更新UV", "action.update_autouv": "自动更新UV",
"action.update_autouv.desc": "更新所选方块的自动UV映射", "action.update_autouv.desc": "更新所选立方体的自动UV映射",
"category.uv": "UV", "category.uv": "UV",
"status_bar.saved": "模型已保存", "status_bar.saved": "模型已保存",
"status_bar.unsaved": "有未保存的更改", "status_bar.unsaved": "有未保存的更改",
@ -768,7 +768,7 @@
"message.set_background_position.title": "背景位置", "message.set_background_position.title": "背景位置",
"menu.preview.background.set_position": "设置位置", "menu.preview.background.set_position": "设置位置",
"dialog.toolbar_edit.hidden": "隐藏", "dialog.toolbar_edit.hidden": "隐藏",
"action.export_class_entity": "导出java实体", "action.export_class_entity": "导出为java实体模型",
"action.export_class_entity.desc": "作为java class导出模型", "action.export_class_entity.desc": "作为java class导出模型",
"settings.seethrough_outline": "X-Ray 轮廓", "settings.seethrough_outline": "X-Ray 轮廓",
"settings.seethrough_outline.desc": "通过对象显示轮廓", "settings.seethrough_outline.desc": "通过对象显示轮廓",
@ -894,15 +894,15 @@
"mode.start.new": "新建", "mode.start.new": "新建",
"mode.start.recent": "最近", "mode.start.recent": "最近",
"format.free": "自由模型", "format.free": "自由模型",
"format.free.desc": "为 Unity 等软件的无限制模型", "format.free.desc": "制作 Unity 等游戏制作软件的无建模限制的模型",
"format.java_block": "Java 方块/物品", "format.java_block": "Java 方块/物品",
"format.java_block.desc": "Java 版方块模型,大小和旋转都有限制。", "format.java_block.desc": "Java 版方块模型,大小和旋转都有限制",
"format.bedrock": "基岩版模型", "format.bedrock": "基岩版模型",
"format.bedrock.desc": "适用于基岩版的模型", "format.bedrock.desc": "适用于基岩版的模型",
"format.bedrock_old": "旧版基岩版模型", "format.bedrock_old": "旧版基岩版模型",
"format.bedrock_old.desc": "Pre-1.12 基岩版实体模型", "format.bedrock_old.desc": "Pre-1.12 基岩版实体模型",
"format.modded_entity": "模组版实体", "format.modded_entity": "模组版实体",
"format.modded_entity.desc": "为模组所适用的模型,能够直接以 .java 类文件形式导出。", "format.modded_entity.desc": "为模组所适用的模型,能够直接以 .java 的class文件形式导出",
"format.optifine_entity": "OptiFine 实体", "format.optifine_entity": "OptiFine 实体",
"format.optifine_entity.desc": "OptiFine 自定义的实体模型", "format.optifine_entity.desc": "OptiFine 自定义的实体模型",
"keys.mouse": "鼠标按键 %0", "keys.mouse": "鼠标按键 %0",
@ -943,7 +943,7 @@
"action.add_locator.desc": "添加新的定位器,以控制粒子、牵引等位置", "action.add_locator.desc": "添加新的定位器,以控制粒子、牵引等位置",
"action.sidebar_left": "材质和 UV", "action.sidebar_left": "材质和 UV",
"action.sidebar_left.desc": "打开一个 UV 和材质的面板", "action.sidebar_left.desc": "打开一个 UV 和材质的面板",
"action.sidebar_right": "元素", "action.sidebar_right": "立方体元素属性",
"action.sidebar_right.desc": "打开编辑元素的面板", "action.sidebar_right.desc": "打开编辑元素的面板",
"action.uv_turn_mapping": "转向映射", "action.uv_turn_mapping": "转向映射",
"action.uv_turn_mapping.desc": "将 UV 映射转 90 度", "action.uv_turn_mapping.desc": "将 UV 映射转 90 度",
@ -960,9 +960,11 @@
"action.import_optifine_part.desc": "为 OptiFine 导入一个实体部件模型", "action.import_optifine_part.desc": "为 OptiFine 导入一个实体部件模型",
"data.locator": "定位器", "data.locator": "定位器",
"mode.start.no_recents": "最近未打开过模型文件", "mode.start.no_recents": "最近未打开过模型文件",
"panel.element": "Element", "panel.element": "元素",
"panel.element.position": "Position", "panel.element.position": "位置",
"panel.element.size": "Size", "panel.element.size": "尺寸",
"panel.element.origin": "Pivot Point", "panel.element.origin": "旋转源点",
"panel.element.rotation": "Rotation" "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."
} }

View File

@ -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 GridBox = function( from, to, size, material) {
var vertices = []; var vertices = [];
@ -110,7 +131,6 @@ var GridBox = function( from, to, size, material) {
material = material || new THREE.LineBasicMaterial( { color: gizmo_colors.grid } ); material = material || new THREE.LineBasicMaterial( { color: gizmo_colors.grid } );
THREE.LineSegments.call( this, geometry, material ); THREE.LineSegments.call( this, geometry, material );
} }
GridBox.prototype = Object.assign( Object.create( THREE.LineSegments.prototype ), { GridBox.prototype = Object.assign( Object.create( THREE.LineSegments.prototype ), {
constructor: GridBox, constructor: GridBox,

View File

@ -1,7 +1,7 @@
{ {
"name": "Blockbench", "name": "Blockbench",
"description": "Model editing and animation software", "description": "Model editing and animation software",
"version": "3.0.4", "version": "3.0.5",
"license": "MIT", "license": "MIT",
"author": { "author": {
"name": "JannisX11", "name": "JannisX11",