mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-03-19 17:01:55 +08:00
v3.1.1
This commit is contained in:
parent
e2e7b70905
commit
fd62f66ef5
@ -276,7 +276,7 @@
|
||||
}
|
||||
#keybindlist {
|
||||
max-height: 600px;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 25px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
#keybindlist > li {
|
||||
@ -643,6 +643,9 @@
|
||||
#uv_dialog h2.dialog_handle.entity_mode_only {
|
||||
margin: 0;
|
||||
}
|
||||
#uv_dialog_all .UVEditor .uv_transform_info {
|
||||
top: 30px;
|
||||
}
|
||||
|
||||
/*Action Control*/
|
||||
#action_selector {
|
||||
|
@ -170,13 +170,18 @@
|
||||
z-index: 101;
|
||||
min-width: 100px;
|
||||
max-width: 200px;
|
||||
background-color: var(--color-ui);
|
||||
color: var(--color-light);
|
||||
background-color: var(--color-bright_ui);
|
||||
color: var(--color-text_acc);
|
||||
box-shadow: 0 0 2px black;
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
top: 40px;
|
||||
left: 60px;
|
||||
right: 0px;
|
||||
left: 0px;
|
||||
pointer-events: none;
|
||||
}
|
||||
#uv_dialog_all .uv_message_box {
|
||||
top: 60px;
|
||||
}
|
||||
.selection_rectangle {
|
||||
position: absolute;
|
||||
@ -488,8 +493,10 @@
|
||||
padding: 24px;
|
||||
max-height: 600px;
|
||||
}
|
||||
#start_screen section right {
|
||||
#start_screen section right > ul {
|
||||
max-height: 465px;
|
||||
overflow-y: auto;
|
||||
padding-right: 5px;
|
||||
}
|
||||
#start_screen left {
|
||||
flex-grow: 0;
|
||||
|
@ -581,7 +581,7 @@
|
||||
<a class="open-in-browser" href="https://bgrins.github.io/spectrum">Spectrum</a>,
|
||||
<a class="open-in-browser" href="https://github.com/jnordberg/gif.js">gif.js</a>,
|
||||
<a class="open-in-browser" href="https://stuk.github.io/jszip/">JSZip</a>,
|
||||
<a class="open-in-browser" href="https://github.com/rotemdan/lzutf8.js">LZ-UTF8</a>
|
||||
<a class="open-in-browser" href="https://github.com/rotemdan/lzutf8.js">LZ-UTF8</a>,
|
||||
<a class="open-in-browser" href="https://github.com/markedjs/marked">Marked</a>
|
||||
</p>
|
||||
</div>
|
||||
@ -854,10 +854,7 @@
|
||||
<div class="texture_name">{{ texture.name }}</div>
|
||||
<div class="texture_res">{{ texture.error
|
||||
? texture.getErrorMessage()
|
||||
: (Format.single_texture
|
||||
? (texture.width + ' x ' + texture.height + 'px')
|
||||
: (texture.ratio == 1? texture.width + 'px': (texture.width + 'px, ' + texture.frameCount+'f'))
|
||||
)
|
||||
: texture.width + ' x ' + texture.height + 'px'
|
||||
}}</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -611,10 +611,8 @@ class Keyframe {
|
||||
}
|
||||
extend(data) {
|
||||
Merge.number(this, data, 'time')
|
||||
cl('0' , data)
|
||||
|
||||
if (this.transform) {
|
||||
cl('1' , this)
|
||||
if (data.values != undefined) {
|
||||
if (typeof data.values == 'number' || typeof data.values == 'string') {
|
||||
data.x = data.y = data.z = data.values;
|
||||
@ -632,7 +630,6 @@ class Keyframe {
|
||||
Merge.string(this, data, 'w')
|
||||
Merge.boolean(this, data, 'isQuaternion')
|
||||
} else {
|
||||
cl('2' , data)
|
||||
if (data.values) {
|
||||
data.effect = data.values.effect;
|
||||
data.locator = data.values.locator;
|
||||
@ -784,7 +781,7 @@ class Keyframe {
|
||||
if (kf.channel != scope.channel) select_tool = false;
|
||||
})
|
||||
this.selected = true
|
||||
updateKeyframeSelection()
|
||||
TickUpdates.keyframe_selection = true;
|
||||
if (select_tool) {
|
||||
switch (this.channel) {
|
||||
case 'rotation': BarItems.rotate_tool.select(); break;
|
||||
@ -960,6 +957,76 @@ function findBedrockAnimation() {
|
||||
}
|
||||
}
|
||||
|
||||
Clipbench.setKeyframes = function() {
|
||||
|
||||
var keyframes = Timeline.selected;
|
||||
|
||||
Clipbench.keyframes = []
|
||||
if (!keyframes || keyframes.length === 0) {
|
||||
return;
|
||||
}
|
||||
var first = keyframes[0];
|
||||
var single_animator;
|
||||
keyframes.forEach(function(kf) {
|
||||
if (kf.time < first.time) {
|
||||
first = kf
|
||||
}
|
||||
if (single_animator && single_animator !== kf.animator.uuid) {
|
||||
single_animator = false;
|
||||
} else if (single_animator == undefined) {
|
||||
single_animator = kf.animator.uuid;
|
||||
}
|
||||
})
|
||||
|
||||
keyframes.forEach(function(kf) {
|
||||
var copy = kf.getUndoCopy();
|
||||
copy.time_offset = kf.time - first.time;
|
||||
if (single_animator != false) {
|
||||
delete copy.animator;
|
||||
}
|
||||
Clipbench.keyframes.push(copy)
|
||||
})
|
||||
if (isApp) {
|
||||
clipboard.writeHTML(JSON.stringify({type: 'keyframes', content: Clipbench.keyframes}))
|
||||
}
|
||||
}
|
||||
Clipbench.pasteKeyframes = function() {
|
||||
if (isApp) {
|
||||
var raw = clipboard.readHTML()
|
||||
try {
|
||||
var data = JSON.parse(raw)
|
||||
if (data.type === 'keyframes' && data.content) {
|
||||
Clipbench.keyframes = data.content
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
if (Clipbench.keyframes && Clipbench.keyframes.length) {
|
||||
|
||||
if (!Animator.selected) return;
|
||||
var keyframes = [];
|
||||
Undo.initEdit({keyframes});
|
||||
Clipbench.keyframes.forEach(function(data, i) {
|
||||
|
||||
if (data.animator) {
|
||||
var animator = Animator.selected.animators[data.animator];
|
||||
if (animator && !Timeline.animators.includes(animator)) {
|
||||
animator.select();
|
||||
}
|
||||
} else {
|
||||
var animator = Timeline.selected_animator;
|
||||
}
|
||||
if (animator) {
|
||||
var kf = animator.createKeyframe(data, Timeline.time + data.time_offset, data.channel)
|
||||
keyframes.push(kf);
|
||||
kf.select(i ? {ctrlOrCmd: true} : null)
|
||||
}
|
||||
|
||||
})
|
||||
Animator.preview()
|
||||
Undo.finishEdit('paste keyframes');
|
||||
}
|
||||
}
|
||||
|
||||
const Animator = {
|
||||
possible_channels: {rotation: true, position: true, scale: true, sound: true, particle: true},
|
||||
open: false,
|
||||
@ -1553,7 +1620,7 @@ const Timeline = {
|
||||
}
|
||||
kf.selected = false
|
||||
})
|
||||
updateKeyframeSelection()
|
||||
TickUpdates.keyframe_selection = true;
|
||||
},
|
||||
start() {
|
||||
if (!Animator.selected) return;
|
||||
@ -1716,12 +1783,16 @@ BARS.defineActions(function() {
|
||||
if (m_index > 3) {
|
||||
path = path.substr(0, m_index) + osfs + 'animations' + osfs + pathToName(ModelMeta.export_path, true)
|
||||
}
|
||||
path.replace(/\.geo\./, 'animation')
|
||||
if (path.match(/\.geo\.json$/)) {
|
||||
path = path.replace(/\.geo\.json$/, '.animation.json')
|
||||
} else {
|
||||
path = path.replace(/\.json$/, '.animation.json')
|
||||
}
|
||||
}
|
||||
Blockbench.export({
|
||||
type: 'JSON Animation',
|
||||
extensions: ['json'],
|
||||
name: Project.geometry_name||'animation',
|
||||
name: (Project.geometry_name||'model')+'.animation',
|
||||
startpath: path,
|
||||
content: content,
|
||||
}, (real_path) => {
|
||||
|
@ -164,7 +164,8 @@ const Blockbench = {
|
||||
|
||||
jq_dialog.addClass('draggable')
|
||||
jq_dialog.draggable({
|
||||
handle: ".dialog_handle"
|
||||
handle: ".dialog_handle",
|
||||
containment: '#page_wrapper'
|
||||
})
|
||||
var x = ($(window).width()-540)/2
|
||||
jq_dialog.css('left', x+'px')
|
||||
@ -250,6 +251,7 @@ const Blockbench = {
|
||||
currentwindow,
|
||||
{
|
||||
title: options.title ? options.title : '',
|
||||
dontAddToRecent: true,
|
||||
filters: [{
|
||||
name: options.type ? options.type : options.extensions[0],
|
||||
extensions: options.extensions
|
||||
@ -423,6 +425,7 @@ const Blockbench = {
|
||||
}
|
||||
} else {
|
||||
ElecDialogs.showSaveDialog(currentwindow, {
|
||||
dontAddToRecent: true,
|
||||
filters: [ {
|
||||
name: options.type,
|
||||
extensions: options.extensions
|
||||
|
@ -52,6 +52,13 @@ const mouse_pos = {x:0,y:0}
|
||||
const sort_collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
|
||||
|
||||
$.ajaxSetup({ cache: false });
|
||||
(function() {
|
||||
var last_welcome = localStorage.getItem('welcomed_version');
|
||||
if (!last_welcome || last_welcome.replace(/.\d+$/, '') != appVersion.replace(/.\d+$/, '')) {
|
||||
Blockbench.addFlag('after_update');
|
||||
}
|
||||
localStorage.setItem('welcomed_version', appVersion);
|
||||
})();
|
||||
|
||||
|
||||
function initializeApp() {
|
||||
@ -81,11 +88,6 @@ function initializeApp() {
|
||||
} else {
|
||||
$('.web_only').remove()
|
||||
}
|
||||
var last_welcome = localStorage.getItem('welcomed_version');
|
||||
if (!last_welcome || last_welcome.replace(/.\d+$/, '') != appVersion.replace(/.\d+$/, '')) {
|
||||
Blockbench.addFlag('after_update')
|
||||
localStorage.setItem('welcomed_version', appVersion)
|
||||
}
|
||||
BARS.setupActions()
|
||||
BARS.setupToolbars()
|
||||
BARS.setupVue()
|
||||
@ -524,6 +526,10 @@ const TickUpdates = {
|
||||
delete TickUpdates.keyframes;
|
||||
Vue.nextTick(Timeline.update)
|
||||
}
|
||||
if (TickUpdates.keyframe_selection) {
|
||||
delete TickUpdates.keyframe_selection;
|
||||
Vue.nextTick(updateKeyframeSelection)
|
||||
}
|
||||
}
|
||||
}
|
||||
const Clipbench = {
|
||||
@ -542,7 +548,7 @@ const Clipbench = {
|
||||
|
||||
} else if (Animator.open) {
|
||||
if (Timeline.selected.length) {
|
||||
Clipbench.setKeyframes(Timeline.selected)
|
||||
Clipbench.setKeyframes()
|
||||
if (cut) {
|
||||
BarItems.delete.trigger()
|
||||
}
|
||||
@ -577,44 +583,11 @@ const Clipbench = {
|
||||
} else if (display_mode) {
|
||||
DisplayMode.paste()
|
||||
} else if (Animator.open) {
|
||||
//
|
||||
if (isApp) {
|
||||
var raw = clipboard.readHTML()
|
||||
try {
|
||||
var data = JSON.parse(raw)
|
||||
if (data.type === 'keyframes' && data.content) {
|
||||
Clipbench.keyframes = data.content
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
if (Clipbench.keyframes && Clipbench.keyframes.length) {
|
||||
|
||||
if (!Animator.selected) return;
|
||||
var animator = Timeline.selected_animator
|
||||
if (animator) {
|
||||
var keyframes = [];
|
||||
Undo.initEdit({keyframes});
|
||||
Clipbench.keyframes.forEach(function(data, i) {
|
||||
|
||||
var kf = animator.createKeyframe(data, Timeline.time + data.time_offset, data.channel)
|
||||
keyframes.push(kf);
|
||||
kf.select(i ? {ctrlOrCmd: true} : null)
|
||||
})
|
||||
Animator.preview()
|
||||
Undo.finishEdit('paste keyframes');
|
||||
}
|
||||
}
|
||||
Clipbench.pasteKeyframes()
|
||||
} else if (p == 'uv' || p == 'preview') {
|
||||
main_uv.paste(event)
|
||||
} else if (p == 'textures' && isApp) {
|
||||
var img = clipboard.readImage()
|
||||
if (img) {
|
||||
var dataUrl = img.toDataURL()
|
||||
var texture = new Texture({name: 'pasted', folder: 'block' }).fromDataURL(dataUrl).fillParticle().add(true)
|
||||
setTimeout(function() {
|
||||
texture.openMenu()
|
||||
},40)
|
||||
}
|
||||
Clipbench.pasteTextures();
|
||||
} else if (p == 'outliner') {
|
||||
|
||||
Undo.initEdit({outliner: true, elements: [], selection: true});
|
||||
@ -669,17 +642,6 @@ const Clipbench = {
|
||||
Undo.finishEdit('paste', {outliner: true, elements: selected, selection: true});
|
||||
}
|
||||
},
|
||||
setTexture(texture) {
|
||||
//Sets the raw image of the texture
|
||||
if (!isApp) return;
|
||||
|
||||
if (texture.mode === 'bitmap') {
|
||||
var img = nativeImage.createFromDataURL(texture.source)
|
||||
} else {
|
||||
var img = nativeImage.createFromPath(texture.source.split('?')[0])
|
||||
}
|
||||
clipboard.writeImage(img)
|
||||
},
|
||||
setGroup(group) {
|
||||
if (!group) {
|
||||
Clipbench.group = undefined
|
||||
@ -702,27 +664,6 @@ const Clipbench = {
|
||||
clipboard.writeHTML(JSON.stringify({type: 'elements', content: Clipbench.elements}))
|
||||
}
|
||||
},
|
||||
setKeyframes(keyframes) {
|
||||
Clipbench.keyframes = []
|
||||
if (!keyframes || keyframes.length === 0) {
|
||||
return;
|
||||
}
|
||||
var first = keyframes[0];
|
||||
keyframes.forEach(function(kf) {
|
||||
if (kf.time < first.time) {
|
||||
first = kf
|
||||
}
|
||||
})
|
||||
keyframes.forEach(function(kf) {
|
||||
var copy = kf.getUndoCopy();
|
||||
copy.time_offset = kf.time - first.time;
|
||||
delete copy.animator;
|
||||
Clipbench.keyframes.push(copy)
|
||||
})
|
||||
if (isApp) {
|
||||
clipboard.writeHTML(JSON.stringify({type: 'keyframes', content: Clipbench.keyframes}))
|
||||
}
|
||||
},
|
||||
setText(text) {
|
||||
if (isApp) {
|
||||
clipboard.writeText(text)
|
||||
|
@ -119,6 +119,7 @@ function addRecentProject(data) {
|
||||
icon: data.icon,
|
||||
day: new Date().dayOfYear()
|
||||
})
|
||||
app.addRecentDocument(data.path)
|
||||
if (recent_projects.length > Math.clamp(settings.recent_projects.value, 0, 256)) {
|
||||
recent_projects.pop()
|
||||
}
|
||||
|
@ -1760,7 +1760,7 @@ window.changeDisplaySkin = function() {
|
||||
settings.display_skin.value = 'username:'+text
|
||||
updateDisplaySkin()
|
||||
})
|
||||
} else {
|
||||
} else if (result < buttons.length-1) {
|
||||
settings.display_skin.value = false
|
||||
updateDisplaySkin()
|
||||
}
|
||||
|
@ -1351,7 +1351,7 @@ const BARS = {
|
||||
//
|
||||
Toolbars = {}
|
||||
var stored = localStorage.getItem('toolbars')
|
||||
if (stored && localStorage.getItem('welcomed_version') == appVersion) {
|
||||
if (stored && !Blockbench.hasFlag('after_update')) {
|
||||
stored = JSON.parse(stored)
|
||||
if (typeof stored === 'object') {
|
||||
BARS.stored = stored
|
||||
|
@ -202,7 +202,8 @@ function Dialog(settings) {
|
||||
if (this.draggable !== false) {
|
||||
jq_dialog.addClass('draggable')
|
||||
jq_dialog.draggable({
|
||||
handle: ".dialog_handle"
|
||||
handle: ".dialog_handle",
|
||||
containment: '#page_wrapper'
|
||||
})
|
||||
var x = Math.clamp(($(window).width()-540)/2, 0, 2000)
|
||||
jq_dialog.css('left', x+'px')
|
||||
|
@ -115,7 +115,7 @@ class ResizeLine {
|
||||
this.node = jq.get(0)
|
||||
jq.draggable({
|
||||
axis: this.horizontal ? 'y' : 'y',
|
||||
containment: 'document',
|
||||
containment: '#page_wrapper',
|
||||
revert: true,
|
||||
start: function(e, u) {
|
||||
scope.before = data.get()
|
||||
@ -721,7 +721,7 @@ function showDialog(dialog) {
|
||||
if (obj.hasClass('draggable')) {
|
||||
obj.draggable({
|
||||
handle: ".dialog_handle",
|
||||
containment: 'body'
|
||||
containment: '#page_wrapper'
|
||||
})
|
||||
var x = ($(window).width()-obj.outerWidth()) / 2;
|
||||
var top = ($(window).height() - obj.outerHeight()) / 2;
|
||||
|
@ -36,11 +36,9 @@ var codec = new Codec('project', {
|
||||
model.parent = Project.parent;
|
||||
model.ambientocclusion = Project.ambientocclusion
|
||||
}
|
||||
if (Project.box_uv) {
|
||||
model.resolution = {
|
||||
width: Project.texture_width || 16,
|
||||
height: Project.texture_height || 16,
|
||||
}
|
||||
model.resolution = {
|
||||
width: Project.texture_width || 16,
|
||||
height: Project.texture_height || 16,
|
||||
}
|
||||
if (options.flag) {
|
||||
model.flag = options.flag;
|
||||
|
@ -56,6 +56,7 @@ function findEntityTexture(mob, return_path) {
|
||||
'tropicalfish_b': 'fish/tropical_b',
|
||||
'panda': 'panda/panda',
|
||||
'fishing_hook': 'fishhook',
|
||||
'ravager': 'illager/ravager',
|
||||
}
|
||||
mob = mob.split(':')[0].replace(/^geometry\./, '')
|
||||
var path = textures[mob]
|
||||
|
13
js/io/io.js
13
js/io/io.js
@ -74,6 +74,9 @@ class ModelFormat {
|
||||
}
|
||||
var center = Format.bone_rig ? 8 : 0;
|
||||
previews.forEach(preview => {
|
||||
if (preview.isOrtho) {
|
||||
preview.setOrthographicCamera(preview.angle);
|
||||
}
|
||||
preview.camOrtho.position.y += center - preview.controls.target.y;
|
||||
preview.controls.target.set(0, center, 0);
|
||||
})
|
||||
@ -251,11 +254,11 @@ class Codec {
|
||||
export() {
|
||||
var scope = this;
|
||||
Blockbench.export({
|
||||
type: this.name,
|
||||
extensions: [this.extension],
|
||||
name: this.fileName(),
|
||||
startpath: this.startPath(),
|
||||
content: this.compile(),
|
||||
type: scope.name,
|
||||
extensions: [scope.extension],
|
||||
name: scope.fileName(),
|
||||
startpath: scope.startPath(),
|
||||
content: scope.compile(),
|
||||
custom_writer: isApp ? (a, b) => scope.write(a, b) : null,
|
||||
}, path => scope.afterDownload(path))
|
||||
}
|
||||
|
@ -209,7 +209,20 @@ var codec = new Codec('modded_entity', {
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
export() {
|
||||
var scope = this;
|
||||
|
||||
Blockbench.showMessageBox({translateKey: 'no_format_import'}, function() {
|
||||
Blockbench.export({
|
||||
type: scope.name,
|
||||
extensions: [scope.extension],
|
||||
name: scope.fileName(),
|
||||
startpath: scope.startPath(),
|
||||
content: scope.compile(),
|
||||
custom_writer: isApp ? (a, b) => scope.write(a, b) : null,
|
||||
}, path => scope.afterDownload(path))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -77,6 +77,7 @@ var part_codec = new Codec('optifine_part', {
|
||||
parse(model, path, add) {
|
||||
Project.box_uv = false;
|
||||
var new_cubes = [];
|
||||
var box_uv_changed = false;
|
||||
var import_group = add ? new Group({
|
||||
name: pathToName(path)
|
||||
}).init() : 'root';
|
||||
@ -118,7 +119,7 @@ var part_codec = new Codec('optifine_part', {
|
||||
-submodel.rotate[1],
|
||||
submodel.rotate[2],
|
||||
]
|
||||
base_cube = new Cube({
|
||||
var base_cube = new Cube({
|
||||
from: [
|
||||
-cs[0]-cs[3],
|
||||
-cs[1]-cs[4],
|
||||
@ -133,8 +134,15 @@ var part_codec = new Codec('optifine_part', {
|
||||
rotation,
|
||||
origin
|
||||
})
|
||||
if (box.uvNorth) {
|
||||
if (!add) Project.box_uv = false;
|
||||
if (box.textureOffset) {
|
||||
if (!add && !box_uv_changed) Project.box_uv = true;
|
||||
box_uv_changed = true;
|
||||
base_cube.extend({
|
||||
uv_offset: box.textureOffset
|
||||
})
|
||||
} else {
|
||||
if (!add && !box_uv_changed) Project.box_uv = false;
|
||||
box_uv_changed = true;
|
||||
base_cube.extend({
|
||||
faces: {
|
||||
north: {uv: convertUVCoords(box.uvNorth)},
|
||||
@ -145,11 +153,6 @@ var part_codec = new Codec('optifine_part', {
|
||||
down: {uv: convertUVCoords(box.uvDown)},
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if (!add) Project.box_uv = true;
|
||||
base_cube.extend({
|
||||
uv_offset: box.textureOffset
|
||||
})
|
||||
}
|
||||
|
||||
if (submodel.translate) {
|
||||
|
@ -497,11 +497,11 @@ class Cube extends NonGroup {
|
||||
pos.y -= this.origin[1]
|
||||
pos.z -= this.origin[2]
|
||||
|
||||
var r = m.getWorldQuaternion(new THREE.Quaternion())
|
||||
pos.applyQuaternion(r)
|
||||
|
||||
pos.add(m.getWorldPosition(new THREE.Vector3()))
|
||||
|
||||
if (m) {
|
||||
var r = m.getWorldQuaternion(new THREE.Quaternion())
|
||||
pos.applyQuaternion(r)
|
||||
pos.add(m.getWorldPosition(new THREE.Vector3()))
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
setColor(index) {
|
||||
@ -657,34 +657,23 @@ class Cube extends NonGroup {
|
||||
Canvas.updateUV(scope)
|
||||
}
|
||||
}
|
||||
move(val, axis, absolute, opts, no_update) {
|
||||
if (!opts) opts = 0;
|
||||
if (val instanceof THREE.Vector3) {
|
||||
return this.move(val.x, 0, absolute, opts, true)
|
||||
&& this.move(val.y, 1, absolute, opts, true)
|
||||
&& this.move(val.z, 2, absolute, opts, true);
|
||||
}
|
||||
var size = this.size(axis)
|
||||
if (!absolute) {
|
||||
val = val + this.from[axis]
|
||||
}
|
||||
move(val, axis, move_origin) {
|
||||
|
||||
var size = this.size(axis);
|
||||
val+= this.from[axis];
|
||||
var in_box = val;
|
||||
val = limitToBox(limitToBox(val, -this.inflate) + size, this.inflate) - size
|
||||
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
|
||||
if (opts.applyRot) {
|
||||
var m = new THREE.Vector3()
|
||||
m[getAxisLetter(axis)] = val
|
||||
}
|
||||
if (Blockbench.globalMovement && Format.bone_rig && !opts) {
|
||||
var m = new THREE.Vector3()
|
||||
m[getAxisLetter(axis)] = val
|
||||
if (Blockbench.globalMovement && Format.bone_rig && !move_origin) {
|
||||
var m = new THREE.Vector3();
|
||||
m[getAxisLetter(axis)] = val;
|
||||
|
||||
var rotation = new THREE.Quaternion()
|
||||
this.mesh.getWorldQuaternion(rotation)
|
||||
m.applyQuaternion(rotation.inverse())
|
||||
var rotation = new THREE.Quaternion();
|
||||
this.mesh.getWorldQuaternion(rotation);
|
||||
m.applyQuaternion(rotation.inverse());
|
||||
|
||||
this.from[0] += m.x;
|
||||
this.from[1] += m.y;
|
||||
@ -698,14 +687,12 @@ class Cube extends NonGroup {
|
||||
this.from[axis] += val;
|
||||
}
|
||||
//Origin
|
||||
if (Blockbench.globalMovement && opts) {
|
||||
this.origin[axis] += val
|
||||
}
|
||||
if (!no_update) {
|
||||
this.mapAutoUV()
|
||||
Canvas.adaptObjectPosition(this);
|
||||
TickUpdates.selection = true;
|
||||
if (Blockbench.globalMovement && move_origin) {
|
||||
this.origin[axis] += val;
|
||||
}
|
||||
this.mapAutoUV()
|
||||
Canvas.adaptObjectPosition(this);
|
||||
TickUpdates.selection = true;
|
||||
return in_box;
|
||||
}
|
||||
moveVector(arr, axis) {
|
||||
@ -719,21 +706,17 @@ class Cube extends NonGroup {
|
||||
var scope = this;
|
||||
var in_box = true;
|
||||
arr.forEach((val, i) => {
|
||||
cl('-------------------' + val);
|
||||
|
||||
var size = scope.size(i);
|
||||
val += scope.from[i];
|
||||
cl(val)
|
||||
|
||||
var val_before = val;
|
||||
val = limitToBox(limitToBox(val, -scope.inflate) + size, scope.inflate) - size
|
||||
if (Math.abs(val_before - val) >= 1e-4) in_box = false;
|
||||
cl(val)
|
||||
val -= scope.from[i]
|
||||
|
||||
scope.from[i] += val;
|
||||
scope.to[i] += val;
|
||||
cl(val)
|
||||
})
|
||||
this.mapAutoUV()
|
||||
Canvas.adaptObjectPosition(this);
|
||||
|
@ -415,6 +415,7 @@ class Group extends OutlinerElement {
|
||||
Outliner.buttons.shading,
|
||||
Outliner.buttons.autouv
|
||||
];
|
||||
Group.prototype.needsUniqueName = () => Format.bone_rig;
|
||||
Group.prototype.menu = new Menu([
|
||||
'copy',
|
||||
'paste',
|
||||
@ -484,7 +485,7 @@ function addGroup() {
|
||||
if (Format.bone_rig) {
|
||||
base_group.createUniqueName()
|
||||
}
|
||||
if (add_group instanceof NonGroup) {
|
||||
if (add_group instanceof NonGroup && selected.length > 1) {
|
||||
selected.forEach(function(s, i) {
|
||||
s.addTo(base_group)
|
||||
})
|
||||
|
@ -46,23 +46,28 @@ class Locator extends NonGroup {
|
||||
return this;
|
||||
}
|
||||
getWorldCenter() {
|
||||
var m = this.parent ? this.parent.mesh : scene;
|
||||
var pos = new THREE.Vector3(
|
||||
this.from[0],
|
||||
this.from[1],
|
||||
this.from[2]
|
||||
)
|
||||
var pos = this.parent.mesh.getWorldPosition(new THREE.Vector3());
|
||||
var q = this.parent.mesh.getWorldQuaternion(new THREE.Quaternion());
|
||||
|
||||
var r = m.getWorldQuaternion(new THREE.Quaternion())
|
||||
pos.applyQuaternion(r)
|
||||
var offset = new THREE.Vector3().fromArray(this.from).applyQuaternion(q);
|
||||
var offset2 = new THREE.Vector3().fromArray(this.parent.origin).applyQuaternion(q);
|
||||
|
||||
pos.add(m.getWorldPosition(new THREE.Vector3()))
|
||||
|
||||
pos.add(offset).sub(offset2);
|
||||
return pos;
|
||||
}
|
||||
move(val, axis, absolute) {
|
||||
if (absolute) {
|
||||
this.from[axis] = val
|
||||
move(val, axis) {
|
||||
|
||||
if (Blockbench.globalMovement) {
|
||||
var m = new THREE.Vector3();
|
||||
m[getAxisLetter(axis)] = val;
|
||||
|
||||
var rotation = new THREE.Quaternion();
|
||||
this.parent.mesh.getWorldQuaternion(rotation);
|
||||
m.applyQuaternion(rotation.inverse());
|
||||
|
||||
this.from[0] += m.x;
|
||||
this.from[1] += m.y;
|
||||
this.from[2] += m.z;
|
||||
} else {
|
||||
this.from[axis] += val
|
||||
}
|
||||
@ -79,6 +84,7 @@ Locator.prototype.buttons = [
|
||||
Outliner.buttons.remove,
|
||||
Outliner.buttons.export
|
||||
];
|
||||
Locator.prototype.needsUniqueName = true;
|
||||
Locator.prototype.menu = new Menu([
|
||||
'copy',
|
||||
'rename',
|
||||
@ -93,9 +99,11 @@ BARS.defineActions(function() {
|
||||
category: 'edit',
|
||||
condition: () => {return Format.locators && Modes.edit},
|
||||
click: function () {
|
||||
var elements = []
|
||||
Undo.initEdit({elements, outliner: true});
|
||||
elements.push(new Locator().addTo(Group.selected||selected[0]).init().select());
|
||||
var objs = []
|
||||
Undo.initEdit({elements: objs, outliner: true});
|
||||
objs.push(
|
||||
new Locator().addTo(Group.selected||selected[0]).init().select().createUniqueName()
|
||||
);
|
||||
Undo.finishEdit('add locator');
|
||||
}
|
||||
})
|
||||
|
@ -237,7 +237,7 @@ class OutlinerElement {
|
||||
}
|
||||
scope.name = name
|
||||
delete scope.old_name
|
||||
if (Format.bone_rig && scope instanceof Group) {
|
||||
if (Condition(scope.needsUniqueName)) {
|
||||
scope.createUniqueName()
|
||||
}
|
||||
Undo.finishEdit('rename')
|
||||
@ -394,7 +394,7 @@ class NonGroup extends OutlinerElement {
|
||||
}
|
||||
select(event, isOutlinerClick) {
|
||||
var scope = this;
|
||||
if (scope === undefined) return false;
|
||||
if (scope === undefined || Modes.animate) return false;
|
||||
//Shiftv
|
||||
var just_selected = []
|
||||
if (event && event.shiftKey === true && scope.getParentArray().includes(selected[selected.length-1]) && !Modes.paint && isOutlinerClick) {
|
||||
|
@ -86,15 +86,15 @@ const Painter = {
|
||||
Painter.current.face = data.face;
|
||||
Painter.current.cube = data.cube;
|
||||
var texture = data.cube.faces[data.face].getTexture()
|
||||
if (!texture) {
|
||||
if (!texture || (texture.error && texture.error !== 2)) {
|
||||
Blockbench.showQuickMessage('message.untextured')
|
||||
return;
|
||||
}
|
||||
if (texture) {
|
||||
var x = Math.floor( data.intersects[0].uv.x * texture.img.naturalWidth )
|
||||
var y = Math.floor( (1-data.intersects[0].uv.y) * texture.img.naturalHeight )
|
||||
Painter.startBrush(texture, x, y, data.cube.faces[data.face].uv, event)
|
||||
}
|
||||
if (Toolbox.selected.id !== 'color_picker' && texture) {
|
||||
var x = Math.floor( data.intersects[0].uv.x * texture.img.naturalWidth )
|
||||
var y = Math.floor( (1-data.intersects[0].uv.y) * texture.img.naturalHeight )
|
||||
Painter.startBrush(texture, x, y, data.cube.faces[data.face].uv, event)
|
||||
|
||||
if (Toolbox.selected.id !== 'color_picker') {
|
||||
document.addEventListener('mousemove', Painter.moveBrushCanvas, false );
|
||||
document.addEventListener('mouseup', Painter.stopBrushCanvas, false );
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
|
||||
//Display
|
||||
function getRescalingFactor(angle) {
|
||||
switch (Math.abs(angle)) {
|
||||
case 0:
|
||||
@ -73,6 +72,42 @@ const Canvas = {
|
||||
var canvas = $('canvas.preview:hover').get(0)
|
||||
if (canvas) return canvas.preview
|
||||
},
|
||||
withoutGizmos(cb) {
|
||||
|
||||
function editVis(edit) {
|
||||
edit(three_grid)
|
||||
edit(Canvas.side_grids.x)
|
||||
edit(Canvas.side_grids.z)
|
||||
edit(Transformer)
|
||||
edit(outlines)
|
||||
edit(rot_origin)
|
||||
edit(Vertexsnap.vertexes)
|
||||
Cube.selected.forEach(function(obj) {
|
||||
var m = obj.mesh
|
||||
if (m && m.outline) {
|
||||
edit(m.outline)
|
||||
}
|
||||
})
|
||||
}
|
||||
editVis(obj => {
|
||||
obj.was_visible = obj.visible
|
||||
obj.visible = false
|
||||
})
|
||||
var ground_anim_before = ground_animation
|
||||
if (display_mode && ground_animation) {
|
||||
ground_animation = false
|
||||
}
|
||||
|
||||
cb()
|
||||
|
||||
editVis(obj => {
|
||||
obj.visible = obj.was_visible
|
||||
delete obj.was_visible
|
||||
})
|
||||
if (display_mode && ground_anim_before) {
|
||||
ground_animation = ground_anim_before
|
||||
}
|
||||
},
|
||||
//Main updaters
|
||||
clear() {
|
||||
var objects = []
|
||||
@ -335,7 +370,6 @@ const Canvas = {
|
||||
},
|
||||
//Object handlers
|
||||
addCube(obj) {
|
||||
|
||||
//This does NOT remove old cubes
|
||||
var mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1))
|
||||
Canvas.adaptObjectFaces(obj, mesh)
|
||||
@ -345,11 +379,13 @@ const Canvas = {
|
||||
mesh.type = 'cube';
|
||||
mesh.isElement = true;
|
||||
//scene.add(mesh)
|
||||
Canvas.meshes[obj.uuid] = mesh
|
||||
Canvas.meshes[obj.uuid] = mesh;
|
||||
if (Prop.wireframe === false) {
|
||||
Canvas.updateUV(obj)
|
||||
Canvas.updateUV(obj);
|
||||
} else {
|
||||
mesh.visible = false;
|
||||
}
|
||||
Canvas.buildOutline(obj)
|
||||
Canvas.buildOutline(obj);
|
||||
},
|
||||
adaptObjectPosition(cube, mesh, parent) {
|
||||
if (!mesh || mesh > 0) mesh = cube.mesh
|
||||
|
@ -33,10 +33,10 @@ class Preview {
|
||||
//Cameras
|
||||
this.isOrtho = false
|
||||
this.camPers = new THREE.PerspectiveCamera(45, 16 / 9, 1, 3000)
|
||||
this.camOrtho = new THREE.OrthographicCamera(-600, 600, -400, 400, 1, 100)
|
||||
this.camOrtho = new THREE.OrthographicCamera(-600, 600, -400, 400, 0.5, 200);
|
||||
this.camOrtho.backgroundHandle = [{n: false, a: 'x'}, {n: false, a: 'y'}]
|
||||
this.camOrtho.axis = null
|
||||
this.camOrtho.zoom = 0.5
|
||||
this.camOrtho.zoom = 0.4
|
||||
this.camPers.preview = this.camOrtho.preview = this;
|
||||
for (var i = 4; i <= 6; i++) {
|
||||
this.camPers.layers.enable(i);
|
||||
@ -45,7 +45,7 @@ class Preview {
|
||||
//Controls
|
||||
this.controls = new THREE.OrbitControls(this.camPers, this);
|
||||
this.controls.minDistance = 1;
|
||||
this.controls.maxDistance = 320;
|
||||
this.controls.maxDistance = 512;
|
||||
this.controls.enableKeys = false;
|
||||
this.controls.zoomSpeed = 1.5
|
||||
|
||||
@ -269,7 +269,7 @@ class Preview {
|
||||
return this;
|
||||
}
|
||||
resetCamera(init) {
|
||||
var dis = 24
|
||||
var dis = 40;
|
||||
this.controls.target.set(0, 8+scene.position.y, 0);
|
||||
this.camPers.position.set(-dis, dis*0.8, -dis)
|
||||
if (!init) {
|
||||
@ -816,6 +816,7 @@ const Screencam = {
|
||||
cancel: 0
|
||||
}, function(result) {
|
||||
if (result === 1) {
|
||||
Blockbench.export()
|
||||
ElecDialogs.showSaveDialog(currentwindow, {filters: [ {name: tl('data.image'), extensions: [is_gif ? 'gif' : 'png']} ]}, function (fileName) {
|
||||
if (fileName === undefined) {
|
||||
return;
|
||||
@ -1297,7 +1298,7 @@ BARS.defineActions(function() {
|
||||
condition: () => Toolbox && Toolbox.selected && Toolbox.selected.allowWireframe,
|
||||
click: function () {
|
||||
Prop.wireframe = !Prop.wireframe
|
||||
Canvas.updateAll()
|
||||
Canvas.updateAllFaces()
|
||||
if (Modes.id === 'animate') {
|
||||
Animator.preview()
|
||||
}
|
||||
|
@ -859,6 +859,9 @@
|
||||
|
||||
} else if (Group.selected && !Blockbench.globalMovement) {
|
||||
Transformer.rotation_ref = rotation_object.mesh;
|
||||
|
||||
} else if (Group.selected && Blockbench.globalMovement && Group.selected.parent && Format.bone_rig) {
|
||||
Transformer.rotation_ref = Group.selected.parent.mesh;
|
||||
|
||||
} else if (!Blockbench.globalMovement && Cube.selected[0] && Cube.selected[0].mesh) {
|
||||
Transformer.rotation_ref = Cube.selected[0].mesh;
|
||||
@ -1081,7 +1084,7 @@
|
||||
}
|
||||
selected.forEach(function(obj, i) {
|
||||
if (obj.movable) {
|
||||
obj.move(difference, axisNumber, false , _has_groups||!Format.bone_rig)
|
||||
obj.move(difference, axisNumber , _has_groups||!Format.bone_rig)
|
||||
}
|
||||
})
|
||||
scope.updateSelection()
|
||||
|
@ -179,7 +179,7 @@ class Texture {
|
||||
switch (this.error) {
|
||||
case 0: return ''; break;
|
||||
case 1: return tl('texture.error.file'); break;
|
||||
case 1: return tl('texture.error.invalid'); break;
|
||||
//case 1: return tl('texture.error.invalid'); break;
|
||||
case 2: return tl('texture.error.ratio'); break;
|
||||
case 3: return tl('texture.error.parent'); break;
|
||||
}
|
||||
@ -957,6 +957,28 @@ function getTexturesById(id) {
|
||||
id = id.replace('#', '');
|
||||
return $.grep(textures, function(e) {return e.id == id});
|
||||
}
|
||||
Clipbench.setTextures = function(texture) {
|
||||
//Sets the raw image of the texture
|
||||
if (!isApp) return;
|
||||
|
||||
if (texture.mode === 'bitmap') {
|
||||
var img = nativeImage.createFromDataURL(texture.source)
|
||||
} else {
|
||||
var img = nativeImage.createFromPath(texture.source.split('?')[0])
|
||||
}
|
||||
clipboard.writeImage(img)
|
||||
}
|
||||
Clipbench.pasteTextures = function() {
|
||||
if (!isApp) return;
|
||||
var img = clipboard.readImage()
|
||||
if (img) {
|
||||
var dataUrl = img.toDataURL()
|
||||
var texture = new Texture({name: 'pasted', folder: 'block' }).fromDataURL(dataUrl).fillParticle().add(true)
|
||||
setTimeout(function() {
|
||||
texture.openMenu()
|
||||
}, 40)
|
||||
}
|
||||
}
|
||||
|
||||
TextureAnimator = {
|
||||
isPlaying: false,
|
||||
|
@ -46,14 +46,6 @@ function getSelectionCenter() {
|
||||
center[0] += pos.x
|
||||
center[1] += pos.y
|
||||
center[2] += pos.z
|
||||
/*
|
||||
center[0] += pos.x
|
||||
center[1] += pos.y
|
||||
center[2] += pos.z
|
||||
center[0] -= obj.from[0]//-scene.position.x;
|
||||
center[1] -= obj.from[1]//-scene.position.y;
|
||||
center[2] -= obj.from[2]//-scene.position.z;
|
||||
*/
|
||||
}
|
||||
})
|
||||
for (var i = 0; i < 3; i++) {
|
||||
@ -70,7 +62,6 @@ function isMovementGlobal() {
|
||||
if (selected.length === 0 || (!settings.local_move.value && Toolbox.selected.id !== 'resize_tool')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Format.rotate_cubes) {
|
||||
if (Cube.selected.length > 1) {
|
||||
if (Cube.selected[0].rotation.equals([0,0,0])) return true;
|
||||
@ -82,7 +73,13 @@ function isMovementGlobal() {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return Format.bone_rig && Group.selected;
|
||||
/*
|
||||
if (!Format.bone_rig || !Group.selected) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}*/
|
||||
}
|
||||
if (Format.bone_rig) {
|
||||
if (Cube.selected[0] && Cube.selected[0].parent.type === 'group') {
|
||||
@ -371,10 +368,19 @@ const Vertexsnap = {
|
||||
} else {
|
||||
Vertexsnap.cubes.forEach(function(obj) {
|
||||
var cube_pos = new THREE.Vector3().copy(global_delta)
|
||||
if (Format.rotate_cubes && !Blockbench.globalMovement) {
|
||||
obj.origin[0] += cube_pos.getComponent(0)
|
||||
obj.origin[1] += cube_pos.getComponent(1)
|
||||
obj.origin[2] += cube_pos.getComponent(2)
|
||||
|
||||
if (Format.bone_rig && obj.parent instanceof Group && obj.mesh.parent) {
|
||||
var q = obj.mesh.parent.getWorldQuaternion(new THREE.Quaternion()).inverse();
|
||||
cube_pos.applyQuaternion(q);
|
||||
}
|
||||
|
||||
if (Format.rotate_cubes) {
|
||||
obj.origin[0] += cube_pos.getComponent(0);
|
||||
obj.origin[1] += cube_pos.getComponent(1);
|
||||
obj.origin[2] += cube_pos.getComponent(2);
|
||||
} else {
|
||||
var q = obj.mesh.getWorldQuaternion(new THREE.Quaternion()).inverse();
|
||||
cube_pos.applyQuaternion(q);
|
||||
}
|
||||
var in_box = obj.moveVector(cube_pos.toArray());
|
||||
if (!in_box && Format.canvas_limit) {
|
||||
@ -555,7 +561,6 @@ function getRotationInterval(event) {
|
||||
function getRotationObject() {
|
||||
if (Format.bone_rig && Group.selected) return Group.selected;
|
||||
if (Format.rotate_cubes && Cube.selected.length) return Cube.selected;
|
||||
if (Locator.selected.length) return Locator.selected[0].parent;
|
||||
}
|
||||
function rotateOnAxis(value, fixed, axis) {
|
||||
if (Format.bone_rig && Group.selected) {
|
||||
@ -643,16 +648,23 @@ BARS.defineActions(function() {
|
||||
selected.forEach(function(obj, i) {
|
||||
if (obj.movable) {
|
||||
var val = value;
|
||||
var size = obj.size(axis)
|
||||
if (!fixed) {
|
||||
val += obj.from[axis]
|
||||
}
|
||||
val = limitToBox(limitToBox(val, -obj.inflate) + size, obj.inflate) - size
|
||||
if (Format.canvas_limit) {
|
||||
var size = obj.resizable ? obj.size(axis) : 0;
|
||||
val = limitToBox(limitToBox(val, -obj.inflate) + size, obj.inflate) - size
|
||||
}
|
||||
val -= obj.from[axis]
|
||||
obj.to[axis] += val;
|
||||
|
||||
obj.from[axis] += val;
|
||||
obj.mapAutoUV()
|
||||
Canvas.adaptObjectPosition(obj);
|
||||
if (obj.resizable) {
|
||||
obj.to[axis] += val;
|
||||
}
|
||||
if (obj instanceof Cube) {
|
||||
obj.mapAutoUV()
|
||||
Canvas.adaptObjectPosition(obj);
|
||||
}
|
||||
}
|
||||
})
|
||||
TickUpdates.selection = true;
|
||||
@ -864,26 +876,28 @@ BARS.defineActions(function() {
|
||||
|
||||
//Origin
|
||||
function moveOriginOnAxis(value, fixed, axis) {
|
||||
if (Group.selected) {
|
||||
var rotation_object = getRotationObject()
|
||||
|
||||
if (rotation_object instanceof Group) {
|
||||
var diff = value
|
||||
if (fixed) {
|
||||
diff -= Group.selected.origin[axis]
|
||||
diff -= rotation_object.origin[axis]
|
||||
}
|
||||
Group.selected.origin[axis] += diff
|
||||
rotation_object.origin[axis] += diff
|
||||
Canvas.updatePositions()
|
||||
if (Format.bone_rig) {
|
||||
Canvas.updateAllBones()
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
rotation_object.forEach(function(obj, i) {
|
||||
var diff = value
|
||||
if (fixed) {
|
||||
diff -= obj.origin[axis]
|
||||
}
|
||||
obj.origin[axis] += diff
|
||||
})
|
||||
Canvas.updatePositions()
|
||||
}
|
||||
selected.forEach(function(obj, i) {
|
||||
var diff = value
|
||||
if (fixed) {
|
||||
diff -= obj.origin[axis]
|
||||
}
|
||||
obj.origin[axis] += diff
|
||||
})
|
||||
Canvas.updatePositions()
|
||||
}
|
||||
new NumSlider('slider_origin_x', {
|
||||
condition: () => (Modes.edit && getRotationObject()),
|
||||
|
@ -145,6 +145,7 @@ function trimFloatNumber(val) {
|
||||
if (val == '') return val;
|
||||
var string = val.toFixed(4)
|
||||
string = string.replace(/0+$/g, '').replace(/\.$/g, '')
|
||||
if (string == -0) return 0;
|
||||
return string;
|
||||
}
|
||||
function getAxisLetter(number) {
|
||||
|
20
js/uv.js
20
js/uv.js
@ -276,7 +276,7 @@ class UVEditor {
|
||||
p.top = o.top + (p.top - o.top)
|
||||
|
||||
p.left = limitNumber(p.left, 0, scope.inner_size-scope.jquery.size.width()+1)
|
||||
p.top = limitNumber(p.top, 0, scope.inner_size-scope.jquery.size.height()+1)
|
||||
p.top = limitNumber(p.top, 0, scope.inner_height-scope.jquery.size.height()+1)
|
||||
|
||||
p.left = p.left - p.left % (scope.inner_size/scope.grid);
|
||||
p.top = p.top - p.top % (scope.inner_size/scope.grid);
|
||||
@ -377,7 +377,7 @@ class UVEditor {
|
||||
message(msg, vars) {
|
||||
msg = tl(msg, vars)
|
||||
var box = $('<div class="uv_message_box">' + msg + '</div>')
|
||||
this.jquery.frame.append(box)
|
||||
this.jquery.main.append(box)
|
||||
setTimeout(function() {
|
||||
box.fadeOut(200)
|
||||
setTimeout(function() {
|
||||
@ -1036,14 +1036,14 @@ class UVEditor {
|
||||
face.uv[0] = Math.min(face.uv[0], face.uv[2]);
|
||||
face.uv[1] = Math.min(face.uv[1], face.uv[3]);
|
||||
if (side == 'north' || side == 'south') {
|
||||
left2 = limitNumber(obj.size('0'), 0, 16)
|
||||
top2 = limitNumber(obj.size('1'), 0, 16)
|
||||
left2 = limitNumber(obj.size('0'), 0, Project.texture_width)
|
||||
top2 = limitNumber(obj.size('1'), 0, Project.texture_height)
|
||||
} else if (side == 'east' || side == 'west') {
|
||||
left2 = limitNumber(obj.size('2'), 0, 16)
|
||||
top2 = limitNumber(obj.size('1'), 0, 16)
|
||||
left2 = limitNumber(obj.size('2'), 0, Project.texture_width)
|
||||
top2 = limitNumber(obj.size('1'), 0, Project.texture_height)
|
||||
} else if (side == 'up' || side == 'down') {
|
||||
left2 = limitNumber(obj.size('0'), 0, 16)
|
||||
top2 = limitNumber(obj.size('2'), 0, 16)
|
||||
left2 = limitNumber(obj.size('0'), 0, Project.texture_width)
|
||||
top2 = limitNumber(obj.size('2'), 0, Project.texture_height)
|
||||
}
|
||||
if (face.rotation % 180) {
|
||||
[left2, top2] = [top2, left2];
|
||||
@ -1378,7 +1378,7 @@ class UVEditor {
|
||||
'uv_maximize',
|
||||
'uv_auto',
|
||||
'uv_rel_auto',
|
||||
{icon: 'rotate_90_degrees_ccw', condition: () => Format.id == 'java_block', name: 'menu.uv.mapping.rotation', children: function() {
|
||||
{icon: 'rotate_90_degrees_ccw', condition: () => Format.id == 'java_block' || Format.id == 'free', name: 'menu.uv.mapping.rotation', children: function() {
|
||||
var off = 'radio_button_unchecked'
|
||||
var on = 'radio_button_checked'
|
||||
return [
|
||||
@ -1791,7 +1791,7 @@ BARS.defineActions(function() {
|
||||
|
||||
new BarSlider('uv_rotation', {
|
||||
category: 'uv',
|
||||
condition: () => !Project.box_uv && Format.id == 'java_block' && Cube.selected.length,
|
||||
condition: () => !Project.box_uv && (Format.id == 'java_block' || Format.id == 'free') && Cube.selected.length,
|
||||
min: 0, max: 270, step: 90, width: 80,
|
||||
onBefore: () => {
|
||||
Undo.initEdit({elements: Cube.selected, uv_only: true})
|
||||
|
@ -983,5 +983,7 @@
|
||||
"format.optifine_part": "OptiFine Part",
|
||||
"format.optifine_part.desc": "JPM Part für OptiFine-Entitymodelle",
|
||||
"action.reverse_keyframes": "Keyframes umkehren",
|
||||
"action.reverse_keyframes.desc": "Kehrt die Reihenfolge der ausgewählten Keyframes um"
|
||||
"action.reverse_keyframes.desc": "Kehrt die Reihenfolge der ausgewählten Keyframes um",
|
||||
"message.no_format_import.title": "Nicht-lesbares Format",
|
||||
"message.no_format_import.message": "Dieses Format kann nur exportiert und nicht wieder geladen werden. Um das Modell später erneut öffnen zu können, speichere es zusätzlich als Projekt."
|
||||
}
|
@ -109,6 +109,8 @@
|
||||
"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.message": "Blockbench could not find the requested file. Make sure it is saved locally and not in a cloud.",
|
||||
"message.no_format_import.title": "Write-only Format",
|
||||
"message.no_format_import.message": "Please note that this export format is write-only. To be able to open the model again, you need to also save it as a project.",
|
||||
"message.recover_backup.title": "Recover Model",
|
||||
"message.recover_backup.message": "Blockbench was closed without saving. Do you want to recover the model?",
|
||||
"message.screenshot.title": "Screenshot",
|
||||
|
52
lang/es.json
52
lang/es.json
@ -959,29 +959,31 @@
|
||||
"panel.element.size": "Tamaño",
|
||||
"panel.element.origin": "Punto de Pivote",
|
||||
"panel.element.rotation": "Rotación",
|
||||
"message.canvas_limit_error.title": "Canvas Limit Error",
|
||||
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the pivot point to prevent this.",
|
||||
"data.effect": "Effect",
|
||||
"generic.name": "Name",
|
||||
"settings.recent_projects": "Recent Model Cap",
|
||||
"settings.recent_projects.desc": "Maximum number of recent models to remember",
|
||||
"settings.volume": "Volume",
|
||||
"settings.volume.desc": "Volume control for sound effects in animations",
|
||||
"action.change_keyframe_file": "Select File",
|
||||
"action.change_keyframe_file.desc": "Select an audio file to preview a sound effect.",
|
||||
"action.clear_timeline": "Clear Timeline",
|
||||
"action.clear_timeline.desc": "Clear all unselected bones from the timeline",
|
||||
"action.select_effect_animator": "Animate Effects",
|
||||
"action.select_effect_animator.desc": "Opens timeline to add sound and particle effects",
|
||||
"action.timeline_focus": "Channel",
|
||||
"action.timeline_focus.desc": "Select the animation channels to display in the timeline",
|
||||
"action.timeline_focus.all": "All",
|
||||
"timeline.particle": "Particle",
|
||||
"timeline.sound": "Sound",
|
||||
"timeline.effects": "Effects",
|
||||
"data.format": "Format",
|
||||
"format.optifine_part": "OptiFine Part",
|
||||
"format.optifine_part.desc": "JPM part for OptiFine entity models",
|
||||
"action.reverse_keyframes": "Reverse Keyframes",
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes"
|
||||
"message.canvas_limit_error.title": "Error de Límite del Lienzo",
|
||||
"message.canvas_limit_error.message": "La acción no pudo ser ejecutada correctamente porque el formato limita el lienzo a 48 unidades. Cambia el punto pivote para prevenir esto.",
|
||||
"data.effect": "Efecto",
|
||||
"generic.name": "Nombre",
|
||||
"settings.recent_projects": "Límite de Modelos Recientes",
|
||||
"settings.recent_projects.desc": "Número máximo de modelos recientes para recordar",
|
||||
"settings.volume": "Volumen",
|
||||
"settings.volume.desc": "Control del volumen para efectos de sonido en animaciones",
|
||||
"action.change_keyframe_file": "Seleccionar Archivo",
|
||||
"action.change_keyframe_file.desc": "Selecciona un archivo de audio para previsualizar un efecto de sonido",
|
||||
"action.clear_timeline": "Limpiar Línea de Tiempo",
|
||||
"action.clear_timeline.desc": "Borra todos los huesos no seleccionados en la línea de tiempo",
|
||||
"action.select_effect_animator": "Animar Efectos",
|
||||
"action.select_effect_animator.desc": "Abre la línea de tiempo para añadir sonidos y efectos de partícula",
|
||||
"action.timeline_focus": "Canal",
|
||||
"action.timeline_focus.desc": "Selecciona los canales de animación para mostrar en la línea de tiempo",
|
||||
"action.timeline_focus.all": "Todos",
|
||||
"timeline.particle": "Partícula",
|
||||
"timeline.sound": "Sonido",
|
||||
"timeline.effects": "Efectos",
|
||||
"data.format": "Formato",
|
||||
"format.optifine_part": "Parte de Optifima",
|
||||
"format.optifine_part.desc": "Parte JPM para modelos de entidad de OptiFine",
|
||||
"action.reverse_keyframes": "Invertir Frames Clave",
|
||||
"action.reverse_keyframes.desc": "Invierte el orden de los frames clave seleccionados",
|
||||
"message.no_format_import.title": "Write-only Format",
|
||||
"message.no_format_import.message": "Please note that this export format is write-only. To be able to open the model again, you need to also save it as a project."
|
||||
}
|
862
lang/fr.json
862
lang/fr.json
File diff suppressed because it is too large
Load Diff
@ -983,5 +983,7 @@
|
||||
"format.optifine_part": "OptiFine Part",
|
||||
"format.optifine_part.desc": "JPM part for OptiFine entity models",
|
||||
"action.reverse_keyframes": "Reverse Keyframes",
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes"
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes",
|
||||
"message.no_format_import.title": "Write-only Format",
|
||||
"message.no_format_import.message": "Please note that this export format is write-only. To be able to open the model again, you need to also save it as a project."
|
||||
}
|
16
lang/ja.json
16
lang/ja.json
@ -831,7 +831,7 @@
|
||||
"dialog.sketchfab_uploader.tags": "Tag",
|
||||
"settings.sketchfab_token": "Sketchfab Token",
|
||||
"settings.sketchfab_token.desc": "BlockbenchにSketchfabアカウントへのアップロードを許可する",
|
||||
"panel.color": "カラー",
|
||||
"panel.color": "Color",
|
||||
"data.origin": "原点",
|
||||
"message.sketchfab.success": "モデルのアップロードに成功",
|
||||
"message.sketchfab.error": "Sketchfab:モデルアップロードに失敗しました",
|
||||
@ -954,22 +954,22 @@
|
||||
"action.import_optifine_part.desc": "OptiFineエンティティモデルをインポートします",
|
||||
"data.locator": "ロケーター",
|
||||
"mode.start.no_recents": "最近開いたモデルはありません",
|
||||
"panel.element": "エレメント",
|
||||
"panel.element": "Element",
|
||||
"panel.element.position": "Position",
|
||||
"panel.element.size": "Size",
|
||||
"panel.element.origin": "Center",
|
||||
"panel.element.rotation": "Rotation",
|
||||
"message.canvas_limit_error.title": "キャンバス制限エラー",
|
||||
"message.canvas_limit_error.message": "フォーマットによってキャンバスが48単位に制限されているため、アクションを正しく実行できませんでした。",
|
||||
"data.effect": "Effect",
|
||||
"generic.name": "Name",
|
||||
"data.effect": "エフェクト",
|
||||
"generic.name": "名前",
|
||||
"settings.recent_projects": "Recent Model Cap",
|
||||
"settings.recent_projects.desc": "Maximum number of recent models to remember",
|
||||
"settings.volume": "Volume",
|
||||
"settings.volume.desc": "Volume control for sound effects in animations",
|
||||
"action.change_keyframe_file": "Select File",
|
||||
"action.change_keyframe_file": "ファイルを選択",
|
||||
"action.change_keyframe_file.desc": "Select an audio file to preview a sound effect.",
|
||||
"action.clear_timeline": "Clear Timeline",
|
||||
"action.clear_timeline": "タイムラインをクリアー",
|
||||
"action.clear_timeline.desc": "Clear all unselected bones from the timeline",
|
||||
"action.select_effect_animator": "Animate Effects",
|
||||
"action.select_effect_animator.desc": "Opens timeline to add sound and particle effects",
|
||||
@ -983,5 +983,7 @@
|
||||
"format.optifine_part": "OptiFine Part",
|
||||
"format.optifine_part.desc": "JPM part for OptiFine entity models",
|
||||
"action.reverse_keyframes": "Reverse Keyframes",
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes"
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes",
|
||||
"message.no_format_import.title": "Write-only Format",
|
||||
"message.no_format_import.message": "Please note that this export format is write-only. To be able to open the model again, you need to also save it as a project."
|
||||
}
|
@ -983,5 +983,7 @@
|
||||
"format.optifine_part": "OptiFine Part",
|
||||
"format.optifine_part.desc": "JPM part for OptiFine entity models",
|
||||
"action.reverse_keyframes": "Reverse Keyframes",
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes"
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes",
|
||||
"message.no_format_import.title": "Write-only Format",
|
||||
"message.no_format_import.message": "Please note that this export format is write-only. To be able to open the model again, you need to also save it as a project."
|
||||
}
|
@ -983,5 +983,7 @@
|
||||
"format.optifine_part": "OptiFine Part",
|
||||
"format.optifine_part.desc": "JPM part for OptiFine entity models",
|
||||
"action.reverse_keyframes": "Reverse Keyframes",
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes"
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes",
|
||||
"message.no_format_import.title": "Write-only Format",
|
||||
"message.no_format_import.message": "Please note that this export format is write-only. To be able to open the model again, you need to also save it as a project."
|
||||
}
|
@ -983,5 +983,7 @@
|
||||
"format.optifine_part": "OptiFine Part",
|
||||
"format.optifine_part.desc": "JPM part for OptiFine entity models",
|
||||
"action.reverse_keyframes": "Reverse Keyframes",
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes"
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes",
|
||||
"message.no_format_import.title": "Write-only Format",
|
||||
"message.no_format_import.message": "Please note that this export format is write-only. To be able to open the model again, you need to also save it as a project."
|
||||
}
|
34
lang/ru.json
34
lang/ru.json
@ -1,19 +1,19 @@
|
||||
{
|
||||
"dialog.ok": "Ок",
|
||||
"dialog.cancel": "Отмена",
|
||||
"dialog.confirm": "Подтвердить",
|
||||
"dialog.close": "Закрыть",
|
||||
"dialog.import": "Импорт",
|
||||
"dialog.save": "Сохранить",
|
||||
"dialog.discard": "Не сохранять",
|
||||
"dialog.dontshowagain": "Не показывать снова",
|
||||
"data.cube": "Куб",
|
||||
"data.group": "Группа",
|
||||
"data.texture": "Текстура",
|
||||
"data.plugin": "Плагин",
|
||||
"data.preview": "Предпросмотр",
|
||||
"data.toolbar": "Инструменты",
|
||||
"data.image": "Изображение",
|
||||
"dialog.ok": "OK",
|
||||
"dialog.cancel": "Cancel",
|
||||
"dialog.confirm": "Confirm",
|
||||
"dialog.close": "Close",
|
||||
"dialog.import": "Import",
|
||||
"dialog.save": "Save",
|
||||
"dialog.discard": "Discard",
|
||||
"dialog.dontshowagain": "Don't Show Again",
|
||||
"data.cube": "Cube",
|
||||
"data.group": "Group",
|
||||
"data.texture": "Texture",
|
||||
"data.plugin": "Plugin",
|
||||
"data.preview": "Preview",
|
||||
"data.toolbar": "Toolbar",
|
||||
"data.image": "Image",
|
||||
"keys.ctrl": "Control",
|
||||
"keys.shift": "Shift",
|
||||
"keys.alt": "Alt",
|
||||
@ -983,5 +983,7 @@
|
||||
"format.optifine_part": "OptiFine Part",
|
||||
"format.optifine_part.desc": "JPM part for OptiFine entity models",
|
||||
"action.reverse_keyframes": "Reverse Keyframes",
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes"
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes",
|
||||
"message.no_format_import.title": "Write-only Format",
|
||||
"message.no_format_import.message": "Please note that this export format is write-only. To be able to open the model again, you need to also save it as a project."
|
||||
}
|
@ -983,5 +983,7 @@
|
||||
"format.optifine_part": "OptiFine Part",
|
||||
"format.optifine_part.desc": "JPM part for OptiFine entity models",
|
||||
"action.reverse_keyframes": "Reverse Keyframes",
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes"
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes",
|
||||
"message.no_format_import.title": "Write-only Format",
|
||||
"message.no_format_import.message": "Please note that this export format is write-only. To be able to open the model again, you need to also save it as a project."
|
||||
}
|
@ -983,5 +983,7 @@
|
||||
"format.optifine_part": "OptiFine Part",
|
||||
"format.optifine_part.desc": "JPM part for OptiFine entity models",
|
||||
"action.reverse_keyframes": "Reverse Keyframes",
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes"
|
||||
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes",
|
||||
"message.no_format_import.title": "Write-only Format",
|
||||
"message.no_format_import.message": "Please note that this export format is write-only. To be able to open the model again, you need to also save it as a project."
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Blockbench",
|
||||
"description": "Model editing and animation software",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.1",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "JannisX11",
|
||||
|
Loading…
x
Reference in New Issue
Block a user