check
close
diff --git a/js/OBJExporter.js b/js/OBJExporter.js
index ca8208592..bc4ec5d43 100644
--- a/js/OBJExporter.js
+++ b/js/OBJExporter.js
@@ -8,7 +8,6 @@ THREE.OBJExporter = function () {};
THREE.OBJExporter.prototype = {
constructor: THREE.OBJExporter,
-
parse: function ( object, mtlFileName ) {
var output = '# Made in Blockbench '+appVersion+'\n';
@@ -44,13 +43,9 @@ THREE.OBJExporter.prototype = {
vertex.applyMatrix4( mesh.matrixWorld );
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
-
nbVertex ++;
-
}
-
// uvs
-
var faces = geometry.faces;
var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
var hasVertexUvs = faces.length === faceVertexUvs.length;
@@ -64,15 +59,10 @@ THREE.OBJExporter.prototype = {
for ( var j = 0, jl = vertexUvs.length; j < jl; j ++ ) {
var uv = vertexUvs[ j ];
-
output += 'vt ' + uv.x + ' ' + uv.y + '\n';
-
nbVertexUvs ++;
-
}
-
}
-
}
// normals
@@ -95,9 +85,7 @@ THREE.OBJExporter.prototype = {
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
nbNormals ++;
-
}
-
} else {
var normal = face.normal.clone();
@@ -106,69 +94,49 @@ THREE.OBJExporter.prototype = {
for ( var j = 0; j < 3; j ++ ) {
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
-
nbNormals ++;
-
}
-
}
-
}
// material
- for (var key in element.faces) {
- if (element.faces.hasOwnProperty(key)) {
- var id = element.faces[key].texture
- if (id !== undefined && id !== null) {
- id = id.replace('#', '')
- if (materials[id] === undefined) {
- materials[id] = getTextureById(id)
- }
- }
+ for (var face in element.faces) {
+ var tex = element.faces[face].getTexture()
+ if (tex && tex.uuid && !materials[tex.id]) {
+ materials[tex.id] = tex
}
}
-
-
for ( var i = 0, j = 1, l = faces.length; i < l; i ++, j += 3 ) {
var f_mat = getMtlFace(element, i)
-
if (f_mat) {
var face = faces[ i ];
-
if (i % 2 === 0) {
output += f_mat
}
-
output += 'f ';
output += ( indexVertex + face.a + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j ) : '' ) + '/' + ( indexNormals + j ) + ' ';
output += ( indexVertex + face.b + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 1 ) : '' ) + '/' + ( indexNormals + j + 1 ) + ' ';
output += ( indexVertex + face.c + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 2 ) : '' ) + '/' + ( indexNormals + j + 2 ) + '\n';
-
}
}
-
} else {
-
console.warn( 'THREE.OBJExporter.parseMesh(): geometry type unsupported', mesh );
// TODO: Support only BufferGeometry and use use setFromObject()
-
}
// update index
indexVertex += nbVertex;
indexVertexUvs += nbVertexUvs;
indexNormals += nbNormals;
-
};
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) parseMesh( child );
-
} );
// mtl output
@@ -190,7 +158,6 @@ THREE.OBJExporter.prototype = {
}
}
-
};
function getMtlFace(obj, index) {
if (index % 2 == 1) index--;
@@ -204,14 +171,13 @@ function getMtlFace(obj, index) {
case 6: key = 'down'; break;
}
- var id = obj.faces[key].texture
+ var tex = obj.faces[key].getTexture()
- if (id === null) {
+ if (tex === null) {
return false
- } else if (id === undefined) {
+ } else if (typeof tex === 'string') {
return 'usemtl none\n'
} else {
- id = id.replace('#', '')
- return 'usemtl ' + id + '\n';
+ return 'usemtl ' + tex.id + '\n';
}
}
\ No newline at end of file
diff --git a/js/TransformControls.js b/js/TransformControls.js
index a0671fbff..7fb992db7 100644
--- a/js/TransformControls.js
+++ b/js/TransformControls.js
@@ -548,6 +548,7 @@
var _mode = "translate";
var _dragging = false;
+ var _has_groups = false;
var _plane = "XY";
var _gizmo = {
@@ -866,7 +867,16 @@
obj.oldScale = obj.size(axisnr)
})
}
- Undo.initEdit({cubes: selected})
+ _has_groups = Blockbench.entity_mode && selected_group && selected_group.matchesSelection() && Toolbox.selected.transformerMode == 'translate';
+ var rotate_group = Blockbench.entity_mode && selected_group && Toolbox.selected.transformerMode == 'rotate';
+
+ if (rotate_group) {
+ Undo.initEdit({cubes: selected, group: selected_group})
+ } else if (_has_groups) {
+ Undo.initEdit({cubes: selected, outliner: true})
+ } else {
+ Undo.initEdit({cubes: selected})
+ }
} else if (Modes.id === 'animate') {
@@ -984,15 +994,17 @@
})
}
if (!overlapping) {
- /*var group = Blockbench.entity_mode && selected_group && selected_group.matchesSelection();
- if (group) {
- selected_group.origin[axisNumber] += difference
- }*/
+ if (_has_groups && Blockbench.globalMovement) {
+ selected_group.forEachChild(g => {
+ g.origin[axisNumber] += difference
+ }, 'group', true)
+
+ }
selected.forEach(function(obj, i) {
var mesh = scope.objects[i]
var valx = obj.from[axisNumber]
valx += difference
- moveCube(obj, valx, axisNumber/*, group*/)
+ moveCube(obj, valx, axisNumber, _has_groups)
})
Canvas.updatePositions(true)
centerTransformer()
diff --git a/js/actions.js b/js/actions.js
index d9e993b5d..92079b919 100644
--- a/js/actions.js
+++ b/js/actions.js
@@ -29,29 +29,26 @@ class BarItem {
return !!this.condition
}
}
- addLabel(in_bar) {
- $(this.node).attr('title', this.description)
+ addLabel(in_bar, action) {
+ if (!action || this instanceof BarItem) {
+ action = this;
+ }
+ $(action.node).attr('title', action.description)
if (in_bar) {
- $(this.node).prepend('
')
+ $(action.node).prepend('
')
} else {
- $(this.node).append('
'+this.name+'
')
+ $(action.node).prepend('
'+action.name+'
')
.on('mouseenter', function() {
var tooltip = $(this).find('div.tooltip')
if (!tooltip || typeof tooltip.offset() !== 'object') return;
- //Left
- if (tooltip.css('left') === '-4px') {
- tooltip.css('left', 'auto')
- }
- if (-tooltip.offset().left > 4) {
- tooltip.css('left', '-4px')
- }
- //Right
- if (tooltip.css('right') === '-4px') {
- tooltip.css('right', 'auto')
- }
- if ((tooltip.offset().left + tooltip.width()) - $(window).width() > 4) {
- tooltip.css('right', '-4px')
+
+ tooltip.css('margin-left', '0')
+ var offset = tooltip.offset()
+ offset.right = offset.left + parseInt(tooltip.css('width').replace(/px/, '')) - $(window).width()
+
+ if (offset.right > 4) {
+ tooltip.css('margin-left', -offset.right+'px')
}
})
}
@@ -127,6 +124,7 @@ class Action extends BarItem {
}
this.keybind.setAction(this.id)
this.work_in_dialog = data.work_in_dialog === true
+ this.uses = 0;
//Icon
this.icon = data.icon
this.color = data.color
@@ -142,9 +140,9 @@ class Action extends BarItem {
this.icon_node = Blockbench.getIconNode(this.icon, this.color)
this.node = $(`
`).get(0)
this.nodes = [this.node]
- this.addLabel(data.label)
this.menu_node = $(`
${this.name}`).get(0)
- $(this.node).add(this.menu_node).prepend(this.icon_node)
+ $(this.node).add(this.menu_node).append(this.icon_node)
+ this.addLabel(data.label)
$(this.node).click(function(e) {scope.trigger(e)})
if (data.linked_setting) {
@@ -164,6 +162,7 @@ class Action extends BarItem {
return true;
}
scope.click(event)
+ scope.uses++;
$(scope.nodes).each(function() {
$(this).css('color', 'var(--color-light)')
@@ -227,6 +226,7 @@ class Tool extends Action {
}
Toolbox.selected = this;
delete Toolbox.original;
+ this.uses++;
if (this.transformerMode) {
Transformer.setMode(this.transformerMode)
@@ -309,8 +309,8 @@ class NumSlider extends Widget {
}
var scope = this;
this.node = $( `
`).get(0);
this.jq_outer = $(this.node)
this.jq_inner = this.jq_outer.find('.nslide');
@@ -651,10 +651,15 @@ class Toolbar {
var scope = this;
this.children = [];
this.default_children = data.children.slice()
- this.node = $('
')
+ this.node = jq.get(0)
+ BarItem.prototype.addLabel(false, {
+ name: tl('data.toolbar'),
+ node: jq.find('.tool.toolbar_menu').get(0)
+ })
$(this.node).find('div.toolbar_menu').click(function(event) {scope.contextmenu(event)})
if (data) {
this.id = data.id
@@ -928,7 +933,12 @@ const BARS = {
id: 'project_window',
icon: 'featured_play_list',
category: 'file',
- click: function () {showDialog('project_settings');}
+ click: function () {
+ showDialog('project_settings');
+ if (Blockbench.entity_mode) {
+ Undo.initEdit({resolution: true})
+ }
+ }
})
new Action({
id: 'open_model_folder',
@@ -1005,10 +1015,18 @@ const BARS = {
id: 'duplicate',
icon: 'content_copy',
category: 'edit',
- condition: () => (!display_mode && !Animator.open && selected.length),
+ condition: () => (!display_mode && !Animator.open && (selected.length || selected_group)),
keybind: new Keybind({key: 68, ctrl: true}),
click: function () {
- duplicateCubes();
+ if (selected_group && (selected_group.matchesSelection() || selected.length === 0)) {
+ var cubes_before = elements.length
+ Undo.initEdit({outliner: true, cubes: [], selection: true})
+ var g = selected_group.duplicate()
+ g.select().isOpen = true;
+ Undo.finishEdit('duplicate_group', {outliner: true, cubes: elements.slice().slice(cubes_before), selection: true})
+ } else {
+ duplicateCubes();
+ }
}
})
new Action({
@@ -1080,7 +1098,7 @@ const BARS = {
id: 'move_up',
icon: 'arrow_upward',
category: 'transform',
- condition: () => (selected.length && !open_interface && !open_menu),
+ condition: () => (selected.length && !open_menu),
keybind: new Keybind({key: 38, ctrl: null, shift: null}),
click: function (e) {moveCubesRelative(-1, 2, e)}
})
@@ -1088,7 +1106,7 @@ const BARS = {
id: 'move_down',
icon: 'arrow_downward',
category: 'transform',
- condition: () => (selected.length && !open_interface && !open_menu),
+ condition: () => (selected.length && !open_menu),
keybind: new Keybind({key: 40, ctrl: null, shift: null}),
click: function (e) {moveCubesRelative(1, 2, e)}
})
@@ -1096,7 +1114,7 @@ const BARS = {
id: 'move_left',
icon: 'arrow_back',
category: 'transform',
- condition: () => (selected.length && !open_interface && !open_menu),
+ condition: () => (selected.length && !open_menu),
keybind: new Keybind({key: 37, ctrl: null, shift: null}),
click: function (e) {moveCubesRelative(-1, 0, e)}
})
@@ -1104,7 +1122,7 @@ const BARS = {
id: 'move_right',
icon: 'arrow_forward',
category: 'transform',
- condition: () => (selected.length && !open_interface && !open_menu),
+ condition: () => (selected.length && !open_menu),
keybind: new Keybind({key: 39, ctrl: null, shift: null}),
click: function (e) {moveCubesRelative(1, 0, e)}
})
@@ -1112,7 +1130,7 @@ const BARS = {
id: 'move_forth',
icon: 'keyboard_arrow_up',
category: 'transform',
- condition: () => (selected.length && !open_interface && !open_menu),
+ condition: () => (selected.length && !open_menu),
keybind: new Keybind({key: 33, ctrl: null, shift: null}),
click: function (e) {moveCubesRelative(-1, 1, e)}
})
@@ -1120,7 +1138,7 @@ const BARS = {
id: 'move_back',
icon: 'keyboard_arrow_down',
category: 'transform',
- condition: () => (selected.length && !open_interface && !open_menu),
+ condition: () => (selected.length && !open_menu),
keybind: new Keybind({key: 34, ctrl: null, shift: null}),
click: function (e) {moveCubesRelative(1, 1, e)}
})
@@ -1207,6 +1225,17 @@ const BARS = {
click: function () {setZoomLevel('reset')}
})
+ //Find Action
+ new Action({
+ id: 'select_action',
+ icon: 'fullscreen',
+ category: 'blockbench',
+ condition: isApp,
+ keybind: new Keybind({key: 70}),
+ click: function () {
+ ActionControl.select()
+ }
+ })
BARS.action_definers.forEach((definer) => {
if (typeof definer === 'function') {
@@ -1218,7 +1247,7 @@ const BARS = {
//
Toolbars = {}
var stored = localStorage.getItem('toolbars')
- if (stored) {
+ if (stored && localStorage.getItem('welcomed_version') == appVersion) {
stored = JSON.parse(stored)
if (typeof stored === 'object') {
BARS.stored = stored
@@ -1298,6 +1327,10 @@ const BARS = {
'uv_auto',
'uv_transparent',
'uv_rotation',
+ //Box
+ 'toggle_uv_overlay',
+ 'uv_shift',
+ 'toggle_mirror_uv',
],
default_place: true
})
@@ -1367,6 +1400,7 @@ const BARS = {
id: 'brush',
children: [
'brush_mode',
+ 'fill_mode',
'brush_color',
'slider_brush_size',
'slider_brush_opacity',
@@ -1408,7 +1442,6 @@ const BARS = {
},
computed: {
searchedBarItems() {
-
var name = $('#action_search_bar').val().toUpperCase()
var list = [{
icon: 'bookmark',
@@ -1472,6 +1505,44 @@ const BARS = {
BARS.list._data.showAll = !BARS.list._data.showAll
BARS.list._data.showAll = !BARS.list._data.showAll
}
+
+ ActionControl.vue = new Vue({
+ el: '#action_selector',
+ data: {
+ open: false,
+ search_input: '',
+ index: 0,
+ length: 0,
+ list: []
+ },
+ computed: {
+ actions: function() {
+ var search_input = this._data.search_input.toUpperCase()
+ var list = this._data.list.empty()
+ for (var i = 0; i < Keybinds.actions.length; i++) {
+ var item = Keybinds.actions[i];
+ if (
+ search_input.length == 0 ||
+ item.name.toUpperCase().includes(search_input) ||
+ item.id.toUpperCase().includes(search_input)
+ ) {
+ if (item instanceof Action && BARS.condition(item.condition)) {
+ list.push(item)
+ if (list.length > ActionControl.max_length) i = Infinity;
+ }
+ }
+ }
+ this._data.length = list.length;
+ if (this._data.index < 0) {
+ this._data.index = 0;
+ }
+ if (this._data.index >= list.length) {
+ this._data.index = list.length-1;
+ }
+ return list;
+ }
+ }
+ })
},
updateConditions: function() {
for (var key in Toolbars) {
@@ -1505,6 +1576,57 @@ const BARS = {
}
}
}
+const ActionControl = {
+ get open() {return ActionControl.vue._data.open},
+ set open(state) {ActionControl.vue._data.open = !!state},
+ type: 'action_selector',
+ max_length: 16,
+ select: function() {
+ ActionControl.open = true;
+ open_interface = ActionControl;
+ ActionControl.vue._data.index = 0;
+ Vue.nextTick(_ => {
+ $('#action_selector > input').focus().select();
+ })
+ },
+ hide: function() {
+ open_interface = false;
+ ActionControl.open = false;
+ },
+ confirm: function(e) {
+ var data = ActionControl.vue._data
+ var action = data.list[data.index]
+ ActionControl.hide()
+ if (action) {
+ action.trigger(e)
+ }
+ },
+ cancel: function() {
+ ActionControl.hide()
+ },
+ click: function(action, e) {
+ action.trigger(e)
+ ActionControl.hide()
+ },
+ handleKeys: function(e) {
+ var data = ActionControl.vue._data
+
+ if (e.which === 38) {
+ data.index--;
+ if (data.index < 0) {
+ data.index = data.length-1;
+ }
+ } else if (e.which === 40) {
+ data.index++;
+ if (data.index >= data.length) {
+ data.index = 0;
+ }
+ } else {
+ return false;
+ }
+ return true;
+ }
+}
//Menu
class Menu {
@@ -1649,7 +1771,7 @@ class Menu {
entry = $('
' + tl(s.name) + '')
entry.prepend(icon)
if (typeof s.click === 'function') {
- entry.click(function() {s.click(context)})
+ entry.click(function(e) {s.click(context, e)})
}
//Submenu
if (typeof s.children == 'function' || typeof s.children == 'object') {
@@ -1838,7 +1960,7 @@ const MenuBar = {
'project_window',
{name: 'menu.file.new', id: 'new', icon: 'insert_drive_file', children: [
'new_block_model',
- 'new_entity_model'
+ 'new_entity_model',
]},
{name: 'menu.file.recent', id: 'recent', icon: 'history', condition: function() {return isApp && recent_projects.length}, children: function() {
var arr = []
@@ -1848,8 +1970,8 @@ const MenuBar = {
name: p.name,
path: p.path,
icon: entity ? 'view_list' : 'insert_drive_file',
- click: function() {
- readFile(p.path, true)
+ click: function(c, event) {
+ readFile(p.path, !event.shiftKey)
}
})
})
@@ -1872,7 +1994,6 @@ const MenuBar = {
'_',
'settings_window',
'update_window',
- 'show_tip',
'donate',
'reload'
])
@@ -1881,9 +2002,9 @@ const MenuBar = {
'redo',
'_',
'add_cube',
+ 'add_group',
'duplicate',
'delete',
- 'sort_outliner',
'_',
'local_move',
'_',
@@ -1916,6 +2037,7 @@ const MenuBar = {
'toggle_export',
'toggle_autouv',
'toggle_shade',
+ 'toggle_mirror_uv',
'rename'
]}
@@ -2088,7 +2210,7 @@ const Keybinds = {
Keybinds.save()
}
}
-if (localStorage.getItem('keybindings') && localStorage.getItem('welcomed_version') == appVersion) {
+if (localStorage.getItem('keybindings')) {
try {
Keybinds.stored = JSON.parse(localStorage.getItem('keybindings'))
} catch (err) {}
diff --git a/js/animations.js b/js/animations.js
index 238449b9a..5c2f3017e 100644
--- a/js/animations.js
+++ b/js/animations.js
@@ -120,6 +120,7 @@ class Animation {
if (selected_group) {
centerTransformer()
}
+ Blockbench.dispatchEvent('display_animation_frame')
}
add() {
if (!Animator.animations.includes(this)) {
@@ -132,6 +133,7 @@ class Animation {
Animator.selected = false
}
Animator.animations.remove(this)
+ Blockbench.dispatchEvent('remove_animation', {animation: this})
return this;
}
getMaxLength() {
@@ -1140,9 +1142,7 @@ const Timeline = {
Timeline.loop()
},
loop: function() {
- if (Animator.selected) {
- Animator.selected.displayFrame(Timeline.second)
- }
+ Animator.preview()
if (Animator.selected && Timeline.second < (Animator.selected.length||1e3)) {
Animator.interval = setTimeout(Timeline.loop, 16.66)
Timeline.setTime(Timeline.second + 1/60)
@@ -1206,6 +1206,25 @@ const Timeline = {
])
}
+onVueSetup(function() {
+ Animator.vue = new Vue({
+ el: '#animations_list',
+ data: {
+ animations: Animator.animations
+ }
+ })
+ Timeline.vue = new Vue({
+ el: '#timeline_inner',
+ data: {
+ size: 150,
+ length: 10,
+ timecodes: [],
+ keyframes: [],
+ marker: Timeline.second
+ }
+ })
+})
+
BARS.defineActions(function() {
new Action({
id: 'add_animation',
@@ -1230,7 +1249,7 @@ BARS.defineActions(function() {
var exp = new RegExp(osfs.replace('\\', '\\\\')+'models'+osfs.replace('\\', '\\\\'))
var m_index = path.search(exp)
if (m_index > 3) {
- path = path.substr(0, m_index) + osfs + 'animations' + osfs + pathToName(Prop.file_path, true)
+ path = path.substr(0, m_index) + osfs + 'animations' + osfs + pathToName(Prop.file_path).replace(/\.geo/, '.animation')
}
}
Blockbench.import({
@@ -1341,4 +1360,4 @@ BARS.defineActions(function() {
keybind: new Keybind({key: 46}),
click: function () {removeSelectedKeyframes()}
})
-})
\ No newline at end of file
+})
diff --git a/js/api.js b/js/api.js
index 6f914c3e9..ad12444de 100644
--- a/js/api.js
+++ b/js/api.js
@@ -10,7 +10,12 @@ class API {
this.drag_handlers = {}
this.entity_mode = false
if (isApp) {
- this.platform = require('os').platform()
+ this.platform = process.platform
+ switch (this.platform) {
+ case 'win32': this.operating_system = 'Windows'; break;
+ case 'darwin': this.operating_system = 'macOS'; break;
+ default: this.operating_system = 'Linux'; break;
+ }
if (this.platform.includes('win32') === true) osfs = '\\'
}
}
@@ -32,7 +37,7 @@ class API {
return Blockbench.entity_mode;
}
registerEdit() {
- console.error('Blockbench.registerEdit is outdated. Please use Undo.initEdit and Undo.finishEdit')
+ console.warn('Blockbench.registerEdit is outdated. Please use Undo.initEdit and Undo.finishEdit')
}
//Interface
@@ -189,7 +194,8 @@ class API {
})
}
addMenuEntry(name, icon, click) {
- MenuBar.addAction({icon: icon, name: name, id: name, click: click}, 'filter')
+ var action = new Action({icon: icon, name: name, id: name, click: click})
+ MenuBar.addAction(action, 'filter')
}
removeMenuEntry(name) {
MenuBar.removeAction('filter.'+name)
@@ -430,15 +436,10 @@ class API {
if (options.custom_writer) {
options.custom_writer(options.content, file_path)
} else {
- fs.writeFile(file_path, options.content, function (err) {
- if (err) {
- console.log('Error exporting file: '+err)
- return;
- }
- if (cb) {
- cb(file_path)
- }
- })
+ fs.writeFileSync(file_path, options.content)
+ if (cb) {
+ cb(file_path)
+ }
}
if (options.project_file) {
Prop.file_path = file_path
@@ -654,18 +655,20 @@ document.body.ondrop = function(event) {
(function() {
var path = fileNames[i].path
var this_i = i;
- fs.readFile(path, 'utf-8', function (err, data) {
- if (err) {
- console.log(err)
- if (!errant && handler.errorbox !== false) {
- Blockbench.showMessageBox({
- translateKey: 'file_not_found',
- icon: 'error_outline'
- })
- }
- errant = true
- return;
+ var data;
+ try {
+ data = fs.readFileSync(path, 'utf-8')
+ } catch (err) {
+ console.log(err)
+ if (!errant && handler.errorbox !== false) {
+ Blockbench.showMessageBox({
+ translateKey: 'file_not_found',
+ icon: 'error_outline'
+ })
}
+ errant = true
+ }
+ if (data) {
results[this_i] = {
name: pathToName(path, true),
path: path,
@@ -675,7 +678,7 @@ document.body.ondrop = function(event) {
if (result_count === fileNames.length) {
handler.cb(results, event)
}
- })
+ }
})()
}
} else {
diff --git a/js/app.js b/js/app.js
index f3007e8a8..73e694551 100644
--- a/js/app.js
+++ b/js/app.js
@@ -24,17 +24,20 @@ $(document).ready(function() {
shell.openExternal(event.target.href);
return true;
});
+ Prop.zoom = 100 + currentwindow.webContents._getZoomLevel()*12
if (fs.existsSync(app.getPath('userData')+osfs+'backups') === false) {
fs.mkdirSync( app.getPath('userData')+osfs+'backups')
}
createBackup(true)
$('.web_only').remove()
- if (__dirname.includes('C:\\xampp\\htdocs\\blockbench\\web')) {
+ if (__dirname.includes('C:\\xampp\\htdocs\\blockbench')) {
Blockbench.addFlag('dev')
}
-})
-
-getLatestVersion(true)
+});
+(function() {
+ console.log('Electron '+process.versions.electron+', Node '+process.versions.node)
+ getLatestVersion(true)
+})()
//Called on start to show message
function getLatestVersion(init) {
if (process.platform == 'linux') return;
@@ -211,7 +214,7 @@ function changeImageEditor(texture) {
function selectImageEditorFile(texture) {
electron.dialog.showOpenDialog(currentwindow, {
title: tl('message.image_editor.exe'),
- filters: [{name: 'Executable Program', extensions: ['exe']}]
+ filters: [{name: 'Executable Program', extensions: ['exe', 'app']}]
}, function(filePaths) {
if (filePaths) {
settings.image_editor.value = filePaths[0]
@@ -251,8 +254,6 @@ function openDefaultTexturePath() {
}
function findEntityTexture(mob, return_path) {
var textures = {
- 'chicken': 'chicken',
- 'blaze': 'blaze',
'llamaspit': 'llama/spit',
'llama': 'llama/llama_creamy',
'dragon': 'dragon/dragon',
@@ -260,7 +261,6 @@ function findEntityTexture(mob, return_path) {
'slime': 'slime/slime',
'slime.armor': 'slime/slime',
'lavaslime': 'slime/magmacube',
- 'silverfish': 'silverfish',
'shulker': 'shulker/shulker_undyed',
'rabbit': 'rabbit/brown',
'horse': 'horse/horse_brown',
@@ -276,41 +276,30 @@ function findEntityTexture(mob, return_path) {
'skeleton': 'skeleton/skeleton',
'skeleton.wither': 'skeleton/wither_skeleton',
'skeleton.stray': 'skeleton/stray',
- 'squid': 'squid',
'spider': 'spider/spider',
'cow': 'cow/cow',
'mooshroom': 'cow/mooshroom',
'sheep.sheared': 'sheep/sheep',
'sheep': 'sheep/sheep',
- 'phantom': 'phantom',
'pig': 'pig/pig',
- 'bat': 'bat',
- 'dolphin': 'dolphin',
'irongolem': 'iron_golem',
'snowgolem': 'snow_golem',
'zombie.villager': 'zombie_villager/zombie_farmer',
'evoker': 'illager/evoker',
'vex': 'vex/vex',
- 'vindicator': 'vindicator',
'wolf': 'wolf/wolf',
'ocelot': 'cat/ocelot',
'cat': 'cat/siamese',
- 'trident': 'trident',
- 'guardian': 'guardian',
- 'polarbear': 'polarbear',
'turtle': 'sea_turtle',
'villager': 'villager/farmer',
'villager.witch': 'witch',
'witherBoss': 'wither_boss/wither',
- 'agent': 'agent',
- 'armor_stand': 'armor_stand',
'parrot': 'parrot/parrot_red_blue',
'bed': 'bed/white',
'player_head': 'steve',
'mob_head': 'skeleton/skeleton',
'dragon_head': 'dragon/dragon',
'boat': 'boat/boat_oak',
- 'minecart': 'minecart',
'cod': 'fish/fish',
'pufferfish.small': 'fish/pufferfish',
'pufferfish.mid': 'fish/pufferfish',
@@ -318,7 +307,6 @@ function findEntityTexture(mob, return_path) {
'salmon': 'fish/salmon',
'tropicalfish_a': 'fish/tropical_a',
'tropicalfish_b': 'fish/tropical_b',
- 'endermite': 'endermite',
'panda': 'panda/panda',
}
mob = mob.split(':')[0].replace(/^geometry\./, '')
@@ -388,85 +376,90 @@ function saveFile(props) {
}
}
function writeFileEntity(content, filepath) {
+
+
Prop.file_path = filepath
var model_name = 'geometry.' + (Project.parent.replace(/^geometry\./, '')||'unknown')
- fs.readFile(filepath, 'utf-8', function (errx, data) {
- var obj = {}
- if (content.bones && content.bones.length) {
- var has_parents = false;
- for (var i = 0; i < content.bones.length && !has_parents; i++) {
- if (content.bones[i].parent) has_parents = true;
+ var data;
+ try {
+ data = fs.readFileSync(filepath, 'utf-8')
+ } catch (err) {}
+ var obj = {}
+ if (content.bones && content.bones.length) {
+ var has_parents = false;
+ for (var i = 0; i < content.bones.length && !has_parents; i++) {
+ if (content.bones[i].parent) has_parents = true;
+ }
+ if (has_parents) {
+ obj.format_version = '1.8.0'
+ }
+ }
+ if (data) {
+ try {
+ obj = JSON.parse(data.replace(/\/\*[^(\*\/)]*\*\/|\/\/.*/g, ''))
+ } catch (err) {
+ err = err+''
+ var answer = electron.dialog.showMessageBox(currentwindow, {
+ type: 'warning',
+ buttons: [
+ tl('message.bedrock_overwrite_error.backup_overwrite'),
+ tl('message.bedrock_overwrite_error.overwrite'),
+ tl('dialog.cancel')
+ ],
+ title: 'Blockbench',
+ message: tl('message.bedrock_overwrite_error.message'),
+ detail: err,
+ noLink: false
+ })
+ if (answer === 0) {
+ var backup_file_name = pathToName(filepath, true) + ' backup ' + new Date().toLocaleString().split(':').join('_')
+ backup_file_name = filepath.replace(pathToName(filepath, false), backup_file_name)
+ fs.writeFile(backup_file_name, data, function (err2) {
+ if (err2) {
+ console.log('Error saving backup model: ', err2)
+ }
+ })
}
- if (has_parents) {
- obj.format_version = '1.8.0'
+ if (answer === 2) {
+ return;
}
}
- if (!errx) {
- try {
- obj = JSON.parse(data.replace(/\/\*[^(\*\/)]*\*\/|\/\/.*/g, ''))
- } catch (err) {
- err = err+''
- var answer = electron.dialog.showMessageBox(currentwindow, {
- type: 'warning',
- buttons: [
- tl('message.bedrock_overwrite_error.backup_overwrite'),
- tl('message.bedrock_overwrite_error.overwrite'),
- tl('dialog.cancel')
- ],
- title: 'Blockbench',
- message: tl('message.bedrock_overwrite_error.message'),
- detail: err,
- noLink: false
- })
- if (answer === 0) {
- var backup_file_name = pathToName(filepath, true) + ' backup ' + new Date().toLocaleString().split(':').join('_')
- backup_file_name = filepath.replace(pathToName(filepath, false), backup_file_name)
- fs.writeFile(backup_file_name, data, function (err2) {
- if (err2) {
- console.log('Error saving backup model: ', err2)
+ if (typeof obj === 'object') {
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key) &&
+ obj[key].bones &&
+ typeof obj[key].bones === 'object' &&
+ obj[key].bones.constructor.name === 'Array'
+ ) {
+ obj[key].bones.forEach(function(bone) {
+ if (typeof bone.cubes === 'object' &&
+ bone.cubes.constructor.name === 'Array'
+ ) {
+ bone.cubes.forEach(function(c, ci) {
+ bone.cubes[ci] = new oneLiner(c)
+ })
}
- })
- }
- if (answer === 2) {
- return;
- }
- }
- if (typeof obj === 'object') {
- for (var key in obj) {
- if (obj.hasOwnProperty(key) &&
- obj[key].bones &&
- typeof obj[key].bones === 'object' &&
- obj[key].bones.constructor.name === 'Array'
- ) {
- obj[key].bones.forEach(function(bone) {
- if (typeof bone.cubes === 'object' &&
- bone.cubes.constructor.name === 'Array'
- ) {
- bone.cubes.forEach(function(c, ci) {
- bone.cubes[ci] = new oneLiner(c)
- })
- }
- })
- }
+ })
}
}
}
- obj[model_name] = content
- content = autoStringify(obj)
+ }
+ obj[model_name] = content
+ content = autoStringify(obj)
- fs.writeFile(filepath, content, function (err) {
- if (err) {
- console.log('Error Saving Entity Model: '+err)
- }
- Blockbench.showQuickMessage('message.save_entity')
- Prop.project_saved = true;
- setProjectTitle(pathToName(filepath, false))
- addRecentProject({name: pathToName(filepath, 'mobs_id'), path: filepath})
- if (Blockbench.hasFlag('close_after_saving')) {
- closeBlockbenchWindow()
- }
- })
- })
+ try {
+ fs.writeFileSync(filepath, content)
+ } catch (err) {
+ console.log('Error Saving Entity Model: '+err)
+ return;
+ }
+ Blockbench.showQuickMessage('message.save_entity')
+ Prop.project_saved = true;
+ setProjectTitle(pathToName(filepath, false))
+ addRecentProject({name: pathToName(filepath, 'mobs_id'), path: filepath})
+ if (Blockbench.hasFlag('close_after_saving')) {
+ closeBlockbenchWindow()
+ }
}
function writeFileObj(content, filepath) {
if (filepath === undefined) {
@@ -566,7 +559,6 @@ function createBackup(init) {
})
//trimBackups
}
-
//Zoom
function setZoomLevel(mode) {
switch (mode) {
@@ -628,6 +620,7 @@ function showSaveDialog(close) {
}
function closeBlockbenchWindow() {
preventClosing = false;
+ Blockbench.dispatchEvent('before_closing')
if (!Blockbench.hasFlag('update_restart')) {
return currentwindow.close();
diff --git a/js/blockbench.js b/js/blockbench.js
index e8533329a..7e0660bc6 100644
--- a/js/blockbench.js
+++ b/js/blockbench.js
@@ -77,7 +77,10 @@ function initializeApp() {
//Misc
translateUI()
- console.log('Blockbench ' + appVersion + (isApp ? ' Desktop' : ' Web ('+capitalizeFirstLetter(Blockbench.browser)+')'))
+ console.log('Blockbench ' + appVersion + (isApp
+ ? (' Desktop (' + Blockbench.operating_system +')')
+ : (' Web ('+capitalizeFirstLetter(Blockbench.browser)+')')
+ ))
if (localStorage.getItem('donated') == 'true') {
$('#donation_hint').remove()
}
@@ -95,7 +98,11 @@ function initializeApp() {
main_uv = new UVEditor('main_uv', false, true)
main_uv.setToMainSlot()
- setupVue()
+ onVueSetup.funcs.forEach((func) => {
+ if (typeof func === 'function') {
+ func()
+ }
+ })
//JQuery UI
$('#cubes_list').droppable({
@@ -114,9 +121,6 @@ function initializeApp() {
$('#texture_list').contextmenu(function(event) {
Interface.Panels.textures.menu.show(event)
})
- $('#status_bar').contextmenu(function(event) {
- Interface.status_bar.menu.show(event)
- })
$(window).on( "unload", saveLocalStorages)
setupInterface()
@@ -124,161 +128,13 @@ function initializeApp() {
Modes.options.edit.select()
Blockbench.setup_successful = true
}
-function setupVue() {
- outliner = new Vue({
- el: '#cubes_list',
- data: {
- option: {
- root: {
- name: 'Model',
- isParent: true,
- isOpen: true,
- selected: false,
- onOpened: function () {},
- select: function() {},
- children: TreeElements
- }
- }
- }
- })
-
- texturelist = new Vue({
- el: '#texture_list',
- data: {textures},
- methods: {
- toggleP: function(texture) {
- textures.forEach(function(t) {
- if (t !== texture) {
- t.particle = false;
- }
- })
- texture.particle = !texture.particle
- },
- selectT: function(item, event) {
- var index = textures.indexOf(item)
- textures[index].select()
- }
- }
- })
- texturelist._data.elements = textures
-
- setupKeybindings()
-
- var structure = {}
- for (var key in settings) {
- var category = settings[key].category
- if (!category) category = 'general'
-
- if (!structure[category]) {
- structure[category] = {
- name: tl('settings.category.'+category),
- open: category === 'general',
- items: {}
- }
- }
- structure[category].items[key] = settings[key]
+function onVueSetup(func) {
+ if (!onVueSetup.funcs) {
+ onVueSetup.funcs = []
}
- var settingslist = new Vue({
- el: 'ul#settingslist',
- data: {structure},
- methods: {
- saveSettings: function() {
- localStorage.setItem('settings', JSON.stringify(settings))
- },
- toggleCategory: function(category) {
- if (!category.open) {
- for (var ct in structure) {
- structure[ct].open = false
- }
- }
- category.open = !category.open
- }
- }
- })
-
- var project_vue = new Vue({
- el: '#project_settings',
- data: {Project}
- })
-
- DisplayMode.vue = new Vue({
- el: '#display_sliders',
- data: {
- slot: new DisplaySlot()
- },
- methods: {
- isMirrored: (axis) => {
- if (display[display_slot]) {
- return display[display_slot].scale[axis] < 0;
- }
- },
- change: (axis, channel) => {
- if (channel === 'scale') {
- var val = limitNumber(DisplayMode.slot.scale[axis], 0, 4)
- DisplayMode.slot.scale[axis] = val;
- if (holding_shift) {
- DisplayMode.slot.scale[0] = val;
- DisplayMode.slot.scale[1] = val;
- DisplayMode.slot.scale[2] = val;
- }
- } else if (channel === 'translation') {
- DisplayMode.slot.translation[axis] = limitNumber(DisplayMode.slot.translation[axis], -80, 80)||0;
- } else {
- DisplayMode.slot.rotation[axis] = Math.trimDeg(DisplayMode.slot.rotation[axis])||0;
- }
- DisplayMode.updateDisplayBase()
- },
- resetChannel: (channel) => {
- Undo.initEdit({display_slots: [display_slot]})
- DisplayMode.slot.extend({[channel]: [0, 0, 0]})
- Undo.finishEdit('reset display')
- },
- invert: (axis) => {
- Undo.initEdit({display_slots: [display_slot]})
- DisplayMode.slot.mirror[axis] = !DisplayMode.slot.mirror[axis];
- DisplayMode.slot.update()
- Undo.finishEdit('mirror display')
- },
- start: () => {
- Undo.initEdit({display_slots: [display_slot]})
- },
- save: () => {
- Undo.finishEdit('change_display')
- }
- }
- })
-
- Animator.vue = new Vue({
- el: '#animations_list',
- data: {
- animations: Animator.animations
- }
- })
-
-
- Timeline.vue = new Vue({
- el: '#timeline_inner',
- data: {
- size: 150,
- length: 10,
- timecodes: [],
- keyframes: [],
- marker: Timeline.second
- }
- })
-
- var stats_bar_vue = new Vue({
- el: '#status_bar',
- data: {Prop}
- })
-
- Modes.vue = new Vue({
- el: '#mode_selector',
- data: {
- options: Modes.options
- }
- })
+ onVueSetup.funcs.push(func)
}
+
function canvasGridSize(shift, ctrl) {
if (!shift && !ctrl) {
return 16 / limitNumber(settings.edit_size.value, 1, 1024)
@@ -335,7 +191,6 @@ function updateSelection() {
}
Transformer.detach()
Transformer.hoverAxis = null;
-
if (display_mode) {
DisplayMode.centerTransformer()
}
@@ -361,12 +216,12 @@ function updateSelection() {
//Interface
if (selected.length > 0) {
$('.selection_only').css('visibility', 'visible')
+ main_uv.jquery.size.find('.uv_mapping_overlay').remove()
main_uv.loadData()
- } else if (selected.length === 0) {
+ } else {
$('.selection_only').css('visibility', 'hidden')
}
BarItems.cube_counter.update()
- $('.uv_mapping_overlay').remove()
updateNslideValues()
//Misc
Blockbench.globalMovement = isMovementGlobal()
@@ -536,6 +391,14 @@ const Modes = {
selected: false,
options: {},
};
+onVueSetup(function() {
+ Modes.vue = new Vue({
+ el: '#mode_selector',
+ data: {
+ options: Modes.options
+ }
+ })
+});
BARS.defineActions(function() {
new Mode({
id: 'edit',
@@ -987,7 +850,9 @@ var Vertexsnap = {
cube.mesh.updateMatrixWorld()
o_vertices.forEach(function(v, id) {
var outline_color = '0x'+app_colors.accent.hex.replace('#', '')
- var mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({color: parseInt(outline_color)}))
+ //Each vertex needs it's own material for hovering
+ var material = new THREE.MeshBasicMaterial({color: parseInt(outline_color)})
+ var mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material)
var pos = mesh.position.copy(v)
pos.applyMatrix4(cube.mesh.matrixWorld)
pos.addScalar(8)
@@ -1169,7 +1034,7 @@ const entityMode = {
$('.entity_mode_only').show()
Modes.options.edit.select()
//UV
- main_uv.buildDom().setToMainSlot().setFace('north')
+ //main_uv.buildDom(true).setToMainSlot().setFace('north')
main_uv.autoGrid = true
main_uv.setGrid()
//Update
@@ -1186,7 +1051,11 @@ const entityMode = {
//Rotation Menu
$('input#cube_rotate').attr('min', '-67.5').attr('max', '67.5').attr('step', '22.5').removeClass('entity_mode')
//UV
- main_uv.buildDom(true).setToMainSlot()
+ //main_uv.buildDom(true).setToMainSlot()
+ main_uv.autoGrid = false
+ main_uv.showing_overlays = false
+ main_uv.displayAllMappingOverlays()
+ main_uv.setGrid()
if (textures[0]) {
textures[0].load()
}
diff --git a/js/display.js b/js/display.js
index 7fe799664..a054ca4a1 100644
--- a/js/display.js
+++ b/js/display.js
@@ -37,9 +37,10 @@ class DisplaySlot {
if (!this.scale.allEqual(1) || !this.mirror.allEqual(false)) {
build.scale = this.scale.slice()
if (!this.mirror.allEqual(false)) {
- build.scale.forEach((s, i) => {
- build.scale[i] *= s ? -1 : 1;
- })
+
+ for (var i = 0; i < 3; i++) {
+ build.scale[i] *= this.mirror[i] ? -1 : 1;
+ }
}
}
if (Object.keys(build).length) {
@@ -53,6 +54,7 @@ class DisplaySlot {
if (data.translation) Merge.number(this.translation, data.translation, i)
if (data.mirror) Merge.boolean(this.mirror, data.mirror, i)
if (data.scale) Merge.number(this.scale, data.scale, i)
+ this.scale[i] = Math.abs(this.scale[i])
if (data.scale && data.scale[i] < 0) this.mirror[i] = true;
}
this.update()
@@ -141,20 +143,14 @@ class refModel {
break;
case 'monitor':
this.onload = function() {
- if (display_slot === 'firstperson_righthand') {
- setDisplayArea(-20.8, -8.4, 9, 0, 270, 0, 1,1,1)
- } else if (display_slot === 'firstperson_lefthand') {
- setDisplayArea(-20.5, -8.4, -9, 0, 270, 0, 1,1,1)
- }
+ var side = display_slot.includes('left') ? -1 : 1;
+ setDisplayArea(side*9, -8.4, 20.8, 0, 0, 0, 1,1,1)
}
break;
case 'bow':
this.onload = function() {
- if (display_slot === 'firstperson_righthand') {
- setDisplayArea(-24.7, -5.6, 5.4, 64, -115, 55, 1,1,1)
- } else if (display_slot === 'firstperson_lefthand') {
- setDisplayArea(-24.7, -5.6, -5.4, -64, -65, -55, 1,1,1)
- }
+ var side = display_slot.includes('left') ? -1 : 1;
+ setDisplayArea(side*5.4, -5.6, 24.7, side*64, side*-25, side*55, 1,1,1)
}
break;
}
@@ -286,9 +282,9 @@ class refModel {
//Body
"size": [8, 12, 4],
"pos": [0, 18, 0],
- "north": {"uv": [6.968, 5.032, 5.032, 7.968]},
+ "north": {"uv": [5.032, 5.032, 6.968, 7.968]},
"east": {"uv": [7.968, 5.032, 7.032, 7.968]},
- "south": {"uv": [9.968, 5.032, 8.032, 7.968]},
+ "south": {"uv": [8.032, 5.032, 9.968, 7.968]},
"west": {"uv": [4.968, 5.032, 4.032, 7.968]},
"up": {"uv": [5.032, 4.968, 6.968, 4.032]},
"down": {"uv": [7.032, 4.032, 8.968, 4.968]}
@@ -297,9 +293,9 @@ class refModel {
//Body Layer
"size": [8.5, 12.5, 4.5],
"pos": [0, 18, 0],
- "north": {"uv": [6.968, 9.032, 5.032, 11.968]},
+ "north": {"uv": [5.032, 9.032, 6.968, 11.968]},
"east": {"uv": [7.968, 9.032, 7.032, 11.968]},
- "south": {"uv": [9.968, 9.032, 8.032, 11.968]},
+ "south": {"uv": [8.032, 9.032, 9.968, 11.968]},
"west": {"uv": [4.968, 9.032, 4.032, 11.968]},
"up": {"uv": [5.032, 8.968, 6.968, 8.032]},
"down": {"uv": [7.032, 8.032, 8.968, 8.968]}
@@ -1175,10 +1171,10 @@ class refModel {
}
buildMonitor() {
this.buildModel([
- {"size": [0.1, 8, 8], "pos": [-31.2, 4.93, 0], "origin": [0, 0, 0], "north":{"uv":[0,0,0,0]},"east":{"uv":[0,0,0,0]},"south":{"uv":[0,0,0,0]},"west":{"uv":[0,0,16,16]},"up":{"uv":[0,0,0,0]},"down":{"uv":[0,0,0,0]}},
- {"size": [0.1, 8, 8], "pos": [-31.2, -4.93, 0], "origin": [0, 0, 0], "north":{"uv":[0,0,0,0]},"east":{"uv":[0,0,0,0]},"south":{"uv":[0,0,0,0]},"west":{"uv":[0,0,16,16]},"up":{"uv":[0,0,0,0]},"down":{"uv":[0,0,0,0]}},
- {"size": [0.1, 8, 8], "pos": [-31.2, 0, 5.65], "origin": [0, 0, 0], "north":{"uv":[0,0,0,0]},"east":{"uv":[0,0,0,0]},"south":{"uv":[0,0,0,0]},"west":{"uv":[0,0,16,16]},"up":{"uv":[0,0,0,0]},"down":{"uv":[0,0,0,0]}},
- {"size": [0.1, 8, 8], "pos": [-31.2, 0, -5.65], "origin": [0, 0, 0], "north":{"uv":[0,0,0,0]},"east":{"uv":[0,0,0,0]},"south":{"uv":[0,0,0,0]},"west":{"uv":[0,0,16,16]},"up":{"uv":[0,0,0,0]},"down":{"uv":[0,0,0,0]}}
+ {"size": [8, 8, 0.1], "pos": [0, 4.93, 31.20], "origin": [0, 0, 0], "north":{"uv":[0,0,0,0]},"east":{"uv":[0,0,0,0]},"south":{"uv":[0,0,0,0]},"west":{"uv":[0,0,16,16]},"up":{"uv":[0,0,0,0]},"down":{"uv":[0,0,0,0]}},
+ {"size": [8, 8, 0.1], "pos": [0, -4.93, 31.20], "origin": [0, 0, 0], "north":{"uv":[0,0,0,0]},"east":{"uv":[0,0,0,0]},"south":{"uv":[0,0,0,0]},"west":{"uv":[0,0,16,16]},"up":{"uv":[0,0,0,0]},"down":{"uv":[0,0,0,0]}},
+ {"size": [8, 8, 0.1], "pos": [5.65, 0, 31.2], "origin": [0, 0, 0], "north":{"uv":[0,0,0,0]},"east":{"uv":[0,0,0,0]},"south":{"uv":[0,0,0,0]},"west":{"uv":[0,0,16,16]},"up":{"uv":[0,0,0,0]},"down":{"uv":[0,0,0,0]}},
+ {"size": [8, 8, 0.1], "pos": [-5.65, 0, 31.2], "origin": [0, 0, 0], "north":{"uv":[0,0,0,0]},"east":{"uv":[0,0,0,0]},"south":{"uv":[0,0,0,0]},"west":{"uv":[0,0,16,16]},"up":{"uv":[0,0,0,0]},"down":{"uv":[0,0,0,0]}}
], 'black')
}
buildBlock() {
@@ -1234,8 +1230,13 @@ window.displayReferenceObjects = {
case 'icon-monitor': icon = 'fa fa-asterisk'; break;
}
var button = $(
- '
'
+ `
`
)
$('#display_ref_bar').append(button)
if (i === 0) {
@@ -1411,7 +1412,7 @@ DisplayMode.createPreset = function() {
display_presets.push(preset)
displayReferenceObjects.slots.forEach(function(s) {
- if ($('#'+s+'_save').is(':checked')) {
+ if ($('#'+s+'_save').is(':checked') && display[s]) {
preset.areas[s] = display[s].copy()
}
})
@@ -1459,7 +1460,6 @@ function loadDisp(key) { //Loads The Menu and slider values, common for all Radi
}
display_preview.controls.enabled = true;
ground_animation = false;
- $('input#translation_z').prop('disabled', false)
$('#display_crosshair').detach()
display_preview.camPers.setFocalLength(45)
@@ -1481,9 +1481,8 @@ DisplayMode.loadThirdLeft = function() { //Loader
}
DisplayMode.loadFirstRight = function() { //Loader
loadDisp('firstperson_righthand')
- setDisplayArea(-20.8, -8.4, 9, 0, 270, 0, 1,1,1)
display_preview.camPers.setFocalLength(12)
- display_preview.camPers.position.set(-32.4, 0, 0)
+ display_preview.camPers.position.set(0, 0, 32.4)
display_preview.controls.target.set(0,0,0)
display_preview.controls.enabled = false
displayReferenceObjects.bar(['monitor', 'bow'])
@@ -1491,9 +1490,8 @@ DisplayMode.loadFirstRight = function() { //Loader
}
DisplayMode.loadFirstLeft = function() { //Loader
loadDisp('firstperson_lefthand')
- setDisplayArea(-20.5, -8.4, -9, 0, 270, 0, 1,1,1)
display_preview.camPers.setFocalLength(12)
- display_preview.camPers.position.set(-32.4, 0, 0)
+ display_preview.camPers.position.set(0, 0, 32.4)
display_preview.controls.target.set(0,0,0)
display_preview.controls.enabled = false
displayReferenceObjects.bar(['monitor', 'bow'])
@@ -1508,7 +1506,6 @@ DisplayMode.loadGUI = function() { //Loader
setDisplayArea(0, 0, 0, 0, 0, 0, 0.4, 0.4, 0.4)
display_preview.camOrtho.zoom = 1
display_preview.controls.target.set(0,0,0)
- //controls.enabled = false
display_preview.setOrthographicCamera(2)
display_preview.camOrtho.position.set(0,0,32)
displayReferenceObjects.bar(['inventory_nine', 'inventory_full', 'hud'])
@@ -1688,11 +1685,67 @@ function updateDisplaySkin() {
}
//displayReferenceObjects.refmodels.player.material
}
+
+
+onVueSetup(function() {
+ DisplayMode.vue = new Vue({
+ el: '#display_sliders',
+ data: {
+ slot: new DisplaySlot()
+ },
+ methods: {
+ isMirrored: (axis) => {
+ if (display[display_slot]) {
+ return display[display_slot].scale[axis] < 0;
+ }
+ },
+ change: (axis, channel) => {
+ if (channel === 'scale') {
+ var val = limitNumber(DisplayMode.slot.scale[axis], 0, 4)
+ DisplayMode.slot.scale[axis] = val;
+ if (holding_shift) {
+ DisplayMode.slot.scale[0] = val;
+ DisplayMode.slot.scale[1] = val;
+ DisplayMode.slot.scale[2] = val;
+ }
+ } else if (channel === 'translation') {
+ DisplayMode.slot.translation[axis] = limitNumber(DisplayMode.slot.translation[axis], -80, 80)||0;
+ } else {
+ DisplayMode.slot.rotation[axis] = Math.trimDeg(DisplayMode.slot.rotation[axis])||0;
+ }
+ DisplayMode.updateDisplayBase()
+ },
+ resetChannel: (channel) => {
+ var v = channel === 'scale' ? 1 : 0;
+ Undo.initEdit({display_slots: [display_slot]})
+ DisplayMode.slot.extend({[channel]: [v, v, v]})
+ if (channel === 'scale') {
+ DisplayMode.slot.extend({mirror: [false, false, false]})
+ }
+ Undo.finishEdit('reset display')
+ },
+ invert: (axis) => {
+ Undo.initEdit({display_slots: [display_slot]})
+ DisplayMode.slot.mirror[axis] = !DisplayMode.slot.mirror[axis];
+ DisplayMode.slot.update()
+ Undo.finishEdit('mirror display')
+ },
+ start: () => {
+ Undo.initEdit({display_slots: [display_slot]})
+ },
+ save: () => {
+ Undo.finishEdit('change_display')
+ }
+ }
+ })
+})
+
BARS.defineActions(function() {
new Action({
id: 'add_display_preset',
icon: 'add',
category: 'display',
+ condition: () => display_mode,
click: function () {showDialog('create_preset')}
})
})
diff --git a/js/elements.js b/js/elements.js
index 033a33e82..91d6a4e83 100644
--- a/js/elements.js
+++ b/js/elements.js
@@ -81,8 +81,46 @@ var selected_group;
//Cubes
class Face {
- constructor() {
+ constructor(direction, data) {
+ this.direction = direction || 'north';
+ this.reset()
this.uv = [0, 0, canvasGridSize(), canvasGridSize()]
+ if (data) {
+ this.extend(data)
+ }
+ }
+ extend(object) {
+ if (object.texture === null) {
+ this.texture = null
+ } else {
+ Merge.string(this, object, 'texture')
+ }
+ Merge.string(this, object, 'cullface')
+ Merge.number(this, object, 'rotation')
+ Merge.number(this, object, 'tint')
+ if (object.uv) {
+ Merge.number(this.uv, object.uv, 0)
+ Merge.number(this.uv, object.uv, 1)
+ Merge.number(this.uv, object.uv, 2)
+ Merge.number(this.uv, object.uv, 3)
+ }
+ return this;
+ }
+ reset() {
+ this.uv = [0, 0, 0, 0];
+ this.rotation = 0;
+ this.texture = false;
+ this.cullface = '';
+ this.enabled = true;
+ this.tint = false;
+ return this;
+ }
+ getTexture() {
+ if (typeof this.texture === 'string') {
+ return textures.findInArray('uuid', this.texture)
+ } else {
+ return this.texture;
+ }
}
}
class OutlinerElement {
@@ -129,14 +167,20 @@ class OutlinerElement {
if (group.type === 'cube') {
if (group.parent === 'root') {
index = TreeElements.indexOf(group)
+ if (index === TreeElements.length-1) {
+ index++;
+ }
group = 'root'
} else {
index = group.parent.children.indexOf(group)
+ if (index === group.parent.children.length-1) {
+ index++;
+ }
group = group.parent
}
}
}
- if (group != 'root' && group.type === 'group') {
+ if (group.type === 'group') {
var i = 0
var level = group;
while (i < 50) {
@@ -312,6 +356,12 @@ class OutlinerElement {
}
return iterate(this.parent, 0)
}
+ get mirror_uv() {
+ return !this.shade;
+ }
+ set mirror_uv(val) {
+ this.shade = !val;
+ }
}
class Cube extends OutlinerElement {
constructor(data, uuid) {
@@ -336,7 +386,14 @@ class Cube extends OutlinerElement {
this.export = true;
this.parent = 'root';
- this.faces = {north: new Face(), east: new Face(), south: new Face(), west: new Face(), up: new Face(), down: new Face()}
+ this.faces = {
+ north: new Face('north'),
+ east: new Face('east'),
+ south: new Face('south'),
+ west: new Face('west'),
+ up: new Face('up'),
+ down: new Face('down')
+ }
if (data && typeof data === 'object') {
this.extend(data)
}
@@ -522,20 +579,7 @@ class Cube extends OutlinerElement {
if (object.faces) {
for (var face in this.faces) {
if (this.faces.hasOwnProperty(face) && object.faces.hasOwnProperty(face)) {
- if (object.faces[face].texture === null) {
- this.faces[face].texture = null
- } else {
- Merge.string(this.faces[face], object.faces[face], 'texture')
- }
- Merge.string(this.faces[face], object.faces[face], 'cullface')
- Merge.number(this.faces[face], object.faces[face], 'rotation')
- Merge.number(this.faces[face], object.faces[face], 'tintindex')
- if (object.faces[face].uv) {
- Merge.number(this.faces[face].uv, object.faces[face].uv, 0)
- Merge.number(this.faces[face].uv, object.faces[face].uv, 1)
- Merge.number(this.faces[face].uv, object.faces[face].uv, 2)
- Merge.number(this.faces[face].uv, object.faces[face].uv, 3)
- }
+ this.faces[face].extend(object.faces[face])
}
}
}
@@ -614,22 +658,22 @@ class Cube extends OutlinerElement {
this.faces.north.rotation= rotateUVFace(this.faces.north.rotation, 2)
this.faces.down.rotation = rotateUVFace(this.faces.down.rotation, 2)
- var temp = this.faces.north
- this.faces.north = this.faces.down
- this.faces.down = this.faces.south
- this.faces.south = this.faces.up
- this.faces.up = temp
+ var temp = new Face(true, this.faces.north)
+ this.faces.north.extend(this.faces.down)
+ this.faces.down.extend(this.faces.south)
+ this.faces.south.extend(this.faces.up)
+ this.faces.up.extend(temp)
} else if (axis === 1) {
this.faces.up.rotation= rotateUVFace(this.faces.up.rotation, 1)
this.faces.down.rotation = rotateUVFace(this.faces.down.rotation, 3)
- var temp = this.faces.north
- this.faces.north = this.faces.west
- this.faces.west = this.faces.south
- this.faces.south = this.faces.east
- this.faces.east = temp
+ var temp = new Face(true, this.faces.north)
+ this.faces.north.extend(this.faces.west)
+ this.faces.west.extend(this.faces.south)
+ this.faces.south.extend(this.faces.east)
+ this.faces.east.extend(temp)
} else if (axis === 2) {
@@ -641,11 +685,11 @@ class Cube extends OutlinerElement {
this.faces.west.rotation = rotateUVFace(this.faces.west.rotation, 3)
this.faces.down.rotation = rotateUVFace(this.faces.down.rotation, 3)
- var temp = this.faces.east
- this.faces.east = this.faces.down
- this.faces.down = this.faces.west
- this.faces.west = this.faces.up
- this.faces.up = temp
+ var temp = new Face(true, this.faces.east)
+ this.faces.east.extend(this.faces.down)
+ this.faces.down.extend(this.faces.west)
+ this.faces.west.extend(this.faces.up)
+ this.faces.up.extend(temp)
}
@@ -708,8 +752,8 @@ class Cube extends OutlinerElement {
case 2: switchFaces = ['south', 'north']; break;
}
var x = this.faces[switchFaces[0]]
- this.faces[switchFaces[0]] = this.faces[switchFaces[1]]
- this.faces[switchFaces[1]] = x
+ this.faces[switchFaces[0]].extend(this.faces[switchFaces[1]])
+ this.faces[switchFaces[1]].extend(x)
//UV
if (axis === 1) {
@@ -735,6 +779,58 @@ class Cube extends OutlinerElement {
Canvas.adaptObjectFaces(this)
Canvas.updateUV(this)
}
+ transferOrigin(origin) {
+ if (!this.mesh) return;
+ var q = this.mesh.getWorldQuaternion(new THREE.Quaternion())
+ var shift = new THREE.Vector3(
+ this.origin[0] - origin[0],
+ this.origin[1] - origin[1],
+ this.origin[2] - origin[2],
+ )
+ var dq = new THREE.Vector3().copy(shift)
+ dq.applyQuaternion(q)
+ shift.sub(dq)
+ shift.applyQuaternion(q.inverse())
+
+ this.from[0] += shift.x;
+ this.from[1] += shift.y;
+ this.from[2] += shift.z;
+ this.to[0] += shift.x;
+ this.to[1] += shift.y;
+ this.to[2] += shift.z;
+
+ this.origin = origin.slice();
+
+ Canvas.adaptObjectPosition(this)
+ return this;
+ }
+ getWorldCenter() {
+ var m = this.mesh;
+ var pos = new THREE.Vector3(
+ this.from[0] + this.size(0)/2,
+ this.from[1] + this.size(1)/2,
+ this.from[2] + this.size(2)/2
+ )
+ if (!Blockbench.entity_mode) {
+
+ pos.x -= this.origin[0]
+ pos.y -= this.origin[1]
+ pos.z -= this.origin[2]
+ var r = m.getWorldQuaternion(new THREE.Quaternion())
+ pos.applyQuaternion(r)
+ pos.x += this.origin[0]
+ pos.y += this.origin[1]
+ pos.z += this.origin[2]
+ } else {
+ var r = m.getWorldQuaternion(new THREE.Quaternion())
+ pos.applyQuaternion(r)
+ pos.add(m.getWorldPosition(new THREE.Vector3()))
+ pos.x += 8
+ pos.y += 8
+ pos.z += 8
+ }
+ return pos;
+ }
setColor(index) {
this.color = index;
if (this.visibility) {
@@ -797,8 +893,8 @@ class Cube extends OutlinerElement {
var sides = faces
}
var id = null
- if (texture && texture.id !== undefined) {
- id = '#'+texture.id
+ if (texture) {
+ id = texture.uuid
} else if (texture === 'blank') {
id = undefined;
}
@@ -888,14 +984,6 @@ class Cube extends OutlinerElement {
var sy = scope.faces[face].uv[1]
var rot = scope.faces[face].rotation
- //Use Texture resolution
- /*
- var tex = getTextureById(scope.faces[face].texture)
- if (tex && tex.res && tex.res != 16) {
- size[0] *= 16 / tex.res
- size[1] *= 16 / tex.res
- }*/
-
//Match To Rotation
if (rot === 90 || rot === 270) {
size.reverse()
@@ -1046,6 +1134,7 @@ class Group extends OutlinerElement {
this.export = true;
this.autouv = 0;
this.parent = 'root';
+ this.isOpen = false;
if (typeof data === 'object') {
this.extend(data)
@@ -1096,6 +1185,7 @@ class Group extends OutlinerElement {
})
}
updateSelection()
+ return this;
}
selectChildren(event) {
var scope = this;
@@ -1118,6 +1208,7 @@ class Group extends OutlinerElement {
s.selectLow()
})
updateSelection()
+ return this;
}
selectLow(highlight) {
//Only Select
@@ -1127,6 +1218,7 @@ class Group extends OutlinerElement {
this.children.forEach(function(s) {
s.selectLow(highlight)
})
+ return this;
}
unselect() {
if (this.selected === false) return;
@@ -1167,6 +1259,7 @@ class Group extends OutlinerElement {
Merge.number(this, object, 'autouv')
Merge.boolean(this, object, 'export')
Merge.boolean(this, object, 'visibility')
+ return this;
}
openUp() {
this.isOpen = true
@@ -1247,6 +1340,7 @@ class Group extends OutlinerElement {
}
showContextMenu(event) {
this.menu.open(event, this)
+ return this;
}
setMaterial(material) {
var scope = this;
@@ -1259,6 +1353,7 @@ class Group extends OutlinerElement {
}
Undo.finishEdit('bone_material')
})
+ return this;
}
sortContent() {
Undo.initEdit({outliner: true})
@@ -1267,22 +1362,26 @@ class Group extends OutlinerElement {
return sort_collator.compare(a.name, b.name)
});
Undo.finishEdit('sort')
+ return this;
}
duplicate(destination) {
function duplicateArray(g1, g2) {
var array = g1.children
var i = 0;
while (i < array.length) {
- if (array[i].type === 'cube') {
+ if (array[i].type !== 'group') {
var dupl = new Cube(array[i])
dupl.addTo(g2, false)
if (destination !== 'cache') {
- dupl.init()
+ dupl.init(false)
} else {
dupl.parent = undefined
}
} else {
var dupl = array[i].getChildlessCopy()
+ if (Blockbench.entity_mode && destination !== 'cache') {
+ dupl.createUniqueName()
+ }
duplicateArray(array[i], dupl)
dupl.addTo(g2, false)
}
@@ -1335,10 +1434,10 @@ class Group extends OutlinerElement {
obj.autouv = this.autouv;
}
if (this.origin.join('_') !== '8_8_8' || Blockbench.entity_mode) {
- obj.origin = this.origin
+ obj.origin = this.origin.slice()
}
if (this.rotation.join('_') !== '0_0_0') {
- obj.rotation = this.rotation
+ obj.rotation = this.rotation.slice()
}
if (this.reset) {
obj.reset = true
@@ -1657,13 +1756,12 @@ function loadOutlinerDraggable() {
} else if ($(ui.draggable).hasClass('texture')) {
//Texture
- var id = $(ui.helper).attr('texid')
- var sides = ['north', 'east', 'south', 'west', 'up', 'down']
+ var uuid = $(ui.helper).attr('texid')
if (target.type === 'group') {
- target.forEachChild(function(s) {
- sides.forEach(function(side) {
- s.faces[side].texture = '#'+id
- })
+ target.forEachChild(function(cube) {
+ for (var face in cube.faces) {
+ cube.faces[face].texture = uuid
+ }
}, 'cube')
} else {
var targets;
@@ -1673,10 +1771,10 @@ function loadOutlinerDraggable() {
targets = [target]
}
- targets.forEach(function(target) {
- sides.forEach(function(side) {
- target.faces[side].texture = '#'+id
- })
+ targets.forEach(function(cube) {
+ for (var face in cube.faces) {
+ cube.faces[face].texture = uuid
+ }
})
}
main_uv.loadData()
@@ -1718,19 +1816,20 @@ function dropOutlinerObjects(item, target, event) {
if (item && item !== target) {
if (event.altKey) {
if (item.type === 'cube') {
- var cube = new Cube(item).addTo(target).init()
+ var cube = new Cube(item).addTo(target, false).init(false)
selected.push(cube)
} else {
- item.duplicate().addTo(target).select()
+ item.duplicate().addTo(target, false).select()
}
} else {
- item.addTo(target)
+ item.addTo(target, false)
if (Blockbench.entity_mode) {
updatePosRecursive(item)
}
}
}
})
+ loadOutlinerDraggable()
if (event.altKey) {
updateSelection()
Undo.finishEdit('drag', {cubes: selected, outliner: true, selection: true})
@@ -1753,10 +1852,9 @@ function addCube() {
}
if (textures.length && Blockbench.entity_mode) {
- var sides = ['north', 'east', 'south', 'west', 'up', 'down']
- sides.forEach(function(side) {
- base_cube.faces[side].texture = '#'+textures[0].id
- })
+ for (var face in base_cube.faces) {
+ base_cube.faces[face].texture = textures[0].uuid
+ }
main_uv.loadData()
}
if (Blockbench.entity_mode) {
@@ -1878,6 +1976,11 @@ function stopRenameCubes(save) {
}
$('.outliner_object input.renaming').attr('disabled', true).removeClass('renaming')
$('body').focus()
+ if (window.getSelection) {
+ window.getSelection().removeAllRanges()
+ } else if (document.selection) {
+ document.selection.empty()
+ }
Blockbench.removeFlag('renaming')
}
}
@@ -1906,9 +2009,31 @@ function toggleCubeProperty(key) {
if (key === 'visibility') {
Canvas.updateVisibility()
}
+ if (key === 'shade' && Blockbench.entity_mode) {
+ Canvas.updateUVs()
+ }
Undo.finishEdit('toggle_prop')
}
+onVueSetup(function() {
+ outliner = new Vue({
+ el: '#cubes_list',
+ data: {
+ option: {
+ root: {
+ name: 'Model',
+ isParent: true,
+ isOpen: true,
+ selected: false,
+ onOpened: function () {},
+ select: function() {},
+ children: TreeElements
+ }
+ }
+ }
+ })
+})
+
BARS.defineActions(function() {
new Action({
id: 'add_cube',
diff --git a/js/interface.js b/js/interface.js
index 9a6069737..a6df59de0 100644
--- a/js/interface.js
+++ b/js/interface.js
@@ -384,6 +384,11 @@ function setupInterface() {
}
})
+ var stats_bar_vue = new Vue({
+ el: '#status_bar',
+ data: {Prop}
+ })
+
//Clickbinds
$('header' ).click( function() { setActivePanel('header' )})
$('#preview' ).click(function() { setActivePanel('preview' )})
@@ -400,6 +405,9 @@ function setupInterface() {
if (open_menu && $('.contextMenu').find(event.target).length === 0 && $('.menu_bar_point.opened:hover').length === 0) {
open_menu.hide();
}
+ if (ActionControl.open && $('#action_selector').find(event.target).length === 0) {
+ ActionControl.hide();
+ }
if ($(event.target).is('input.cube_name:not([disabled])') === false) {
stopRenameCubes()
}
@@ -743,6 +751,7 @@ var splashScreen = {
});
}
showDialog('welcome_screen')
+ Blockbench.dispatchEvent('show_splash_screen')
localStorage.setItem('welcomed_version', appVersion)
})
},
diff --git a/js/io.js b/js/io.js
index a94bc4c81..f0e377e5e 100644
--- a/js/io.js
+++ b/js/io.js
@@ -33,6 +33,7 @@ function newProject(entity_mode) {
entityMode.leave();
}
$('#var_placeholder_area').val('')
+ Blockbench.dispatchEvent('new_project')
return true;
} else {
return false;
@@ -70,15 +71,15 @@ function setupDragHandlers() {
function(files, event) {
var texture_li = $(event.target).parents('li.texture')
if (texture_li.length) {
- var tex = getTextureById(texture_li.attr('texid'))
+ var tex = textures.findInArray('uuid', texture_li.attr('texid'))
if (tex) {
tex.fromFile(files[0])
+ return;
}
- } else {
- files.forEach(function(f) {
- new Texture().fromFile(f).add().fillParticle()
- })
}
+ files.forEach(function(f) {
+ new Texture().fromFile(f).add().fillParticle()
+ })
}
)
}
@@ -162,6 +163,9 @@ function loadBlockModel(model, filepath, add) {
if (obj.faces[face].texture === '#missing') {
delete base_cube.faces[face].texture;
}
+ if (obj.faces[face].tintindex !== undefined) {
+ base_cube.faces[face].tint = true;
+ }
}
}
if (!uv_stated) {
@@ -247,29 +251,23 @@ function loadBlockModel(model, filepath, add) {
}
}
//Get Rid Of ID overlapping
- textures.forEach(function(t, i) {
- if (i >= previous_texture_length) {
- if (getTexturesById(t.id).length > 1) {
- var before = t.id
- t.id = Prop.added_models + '_' + t.id
- elements.forEach(function(s, si) {
- if (si >= previous_length) {
- for (var face in s.faces) {
- if (s.faces[face].texture === '#'+before) {
- s.faces[face].texture = '#'+t.id
- }
- }
- }
- })
- }
+ for (var i = previous_texture_length; i < textures.length; i++) {
+ var t = textures[i]
+ var import_id = t.id;
+ if (getTexturesById(t.id).length > 1) {
+ t.id = Prop.added_models + '_' + t.id
}
- })
+ elements.forEach(function(s, si) {
+ for (var face in s.faces) {
+ if (s.faces[face].texture === '#'+import_id) {
+ s.faces[face].texture = t.uuid
+ }
+ }
+ })
+ }
//Select Last Texture
if (textures.length > 0) {
- textures.forEach(function(s) {
- s.selected = false;
- })
- textures[textures.length-1].selected = true;
+ textures[textures.length-1].select();
}
}
@@ -336,7 +334,7 @@ function loadJEMModel(model) {
name: b.part,
origin: b.translate,
rotation: b.rotate,
- shade: !(b.mirrorTexture && b.mirrorTexture.includes('u'))
+ mirror_uv: (b.mirrorTexture && b.mirrorTexture.includes('u'))
})
group.origin[1] *= -1
group.origin[2] *= -1
@@ -595,7 +593,7 @@ function loadPEModel(data) {
group.rotation[ri] *= -1
})
- group.shade = !b.mirror
+ group.mirror_uv = b.mirror === true
group.reset = b.reset === true
if (b.cubes) {
@@ -618,9 +616,9 @@ function loadPEModel(data) {
base_cube.inflate = s.inflate
}
if (s.mirror === undefined) {
- base_cube.shade = group.shade
+ base_cube.mirror_uv = group.mirror_uv
} else {
- base_cube.shade = !s.mirror
+ base_cube.mirror_uv = s.mirror === true
}
elements.push(base_cube)
base_cube.addTo(group, false)
@@ -805,20 +803,20 @@ var Extruder = {
}
draw_y++;
}
- var current_cube = new Cube({name: cube_name+'_'+cube_nr, autouv: 0})
-
- current_cube.from = [rect.x*scale_i, 0, rect.y*scale_i]
- current_cube.to = [(rect.x2+1)*scale_i, scale_i, (rect.y2+1)*scale_i]
-
- //Sides
- current_cube.faces.up = {uv:[rect.x*scale_i, rect.y*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index}
- current_cube.faces.down = {uv:[rect.x*scale_i, (rect.y2+1)*scale_i, (rect.x2+1)*scale_i, rect.y*scale_i], texture: texture_index}
-
- current_cube.faces.north = {uv:[(rect.x2+1)*scale_i, rect.y*scale_i, rect.x*scale_i, (rect.y+1)*scale_i], texture: texture_index}
- current_cube.faces.south = {uv:[rect.x*scale_i, rect.y2*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index}
-
- current_cube.faces.east = {uv:[rect.x2*scale_i, rect.y*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index, rotation: 90}
- current_cube.faces.west = {uv:[rect.x*scale_i, rect.y*scale_i, (rect.x+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index, rotation: 270}
+ var current_cube = new Cube({
+ name: cube_name+'_'+cube_nr,
+ autouv: 0,
+ from: [rect.x*scale_i, 0, rect.y*scale_i],
+ to: [(rect.x2+1)*scale_i, scale_i, (rect.y2+1)*scale_i],
+ faces: {
+ up: {uv:[rect.x*scale_i, rect.y*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index},
+ down: {uv:[rect.x*scale_i, (rect.y2+1)*scale_i, (rect.x2+1)*scale_i, rect.y*scale_i], texture: texture_index},
+ north: {uv:[(rect.x2+1)*scale_i, rect.y*scale_i, rect.x*scale_i, (rect.y+1)*scale_i], texture: texture_index},
+ south: {uv:[rect.x*scale_i, rect.y2*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index},
+ east: {uv:[rect.x2*scale_i, rect.y*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index, rotation: 90},
+ west: {uv:[rect.x*scale_i, rect.y*scale_i, (rect.x+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index, rotation: 270}
+ }
+ })
elements.push(current_cube)
selected.push(elements[elements.length-1])
@@ -847,17 +845,6 @@ var Extruder = {
}
}
//Export
-class oneLiner {
- constructor(data) {
- if (data !== undefined) {
- for (var key in data) {
- if (data.hasOwnProperty(key)) {
- this[key] = data[key]
- }
- }
- }
- }
-}
function buildBlockModel(options) {
if (options === undefined) options = {}
var clear_elements = []
@@ -917,31 +904,28 @@ function buildBlockModel(options) {
tag.rotation = s.faces[face].rotation
}
if (s.faces[face].texture) {
- tag.texture = s.faces[face].texture
+ var tex = s.faces[face].getTexture()
+ if (tex) {
+ tag.texture = '#' + tex.id
+ textures_used.safePush(tex)
+ }
element_has_texture = true
- } else {
+ }
+ if (!tag.texture) {
tag.texture = '#missing'
}
- if (s.faces[face].cullface !== undefined) {
+ if (s.faces[face].cullface) {
tag.cullface = s.faces[face].cullface
}
- if (s.faces[face].tintindex !== undefined) {
- tag.tintindex = s.faces[face].tintindex
+ if (s.faces[face].tint) {
+ tag.tintindex = 0
}
e_faces[face] = tag
}
}
}
//Gather Textures
- if (element_has_texture) {
- for (var face in s.faces) {
- if (s.faces.hasOwnProperty(face)) {
- if (!textures_used.includes(s.faces[face].texture)) {
- textures_used.push(s.faces[face].texture)
- }
- }
- }
- } else {
+ if (!element_has_texture) {
element.color = s.color
}
element.faces = e_faces
@@ -992,7 +976,7 @@ function buildBlockModel(options) {
var texturesObj = {}
var hasUnsavedTextures = false
textures.forEach(function(t, i){
- if (!textures_used.includes('#'+t.id) && !isTexturesOnlyModel) return;
+ if (!textures_used.includes(t) && !isTexturesOnlyModel) return;
texturesObj[t.id] = t.javaTextureLink(options.backup)
if (t.particle) {
@@ -1038,12 +1022,9 @@ function buildBlockModel(options) {
var entries = 0;
for (var i in DisplayMode.slots) {
var key = DisplayMode.slots[i]
- if (DisplayMode.slots.hasOwnProperty(i) && display[key]) {
- var slot = display[key].export()
- if (slot) {
- new_display[key] = display[key].export()
- entries++;
- }
+ if (DisplayMode.slots.hasOwnProperty(i) && display[key] && display[key].export) {
+ new_display[key] = display[key].export()
+ entries++;
}
}
if (entries) {
@@ -1081,7 +1062,25 @@ function buildEntityModel(options) {
var cube_count = 0;
var visible_box = new THREE.Box3()
- getAllOutlinerGroups().forEach(function(g) {
+ var groups = getAllOutlinerGroups()
+ var loose_cubes = [];
+ TreeElements.forEach(obj => {
+ if (obj.type === 'cube') {
+ loose_cubes.push(obj)
+ }
+ })
+ if (loose_cubes.length) {
+ groups.splice(0, 0, {
+ type: 'group',
+ parent: 'root',
+ name: 'unknown_bone',
+ origin: [0, 0, 0],
+ rotation: [0],
+ children: loose_cubes
+ })
+ }
+
+ groups.forEach(function(g) {
if (g.type !== 'group') return;
//Bone
var bone = {}
@@ -1091,7 +1090,7 @@ function buildEntityModel(options) {
}
bone.pivot = g.origin.slice()
bone.pivot[0] *= -1
- if (g.rotation.join('_') !== '0_0_0') {
+ if (!g.rotation.allEqual(0)) {
bone.rotation = g.rotation.slice()
bone.rotation.forEach(function(br, ri) {
bone.rotation[ri] *= -1
@@ -1100,7 +1099,7 @@ function buildEntityModel(options) {
if (g.reset) {
bone.reset = true
}
- if (!g.shade) {
+ if (g.mirror_uv) {
bone.mirror = true
}
if (g.material) {
@@ -1121,8 +1120,8 @@ function buildEntityModel(options) {
if (s.inflate && typeof s.inflate === 'number') {
cube.inflate = s.inflate
}
- if (s.shade === !!bone.mirror) {
- cube.mirror = !s.shade
+ if (s.mirror_uv === !bone.mirror) {
+ cube.mirror = s.mirror_uv
}
//Visible Bounds
var mesh = s.mesh
@@ -1212,7 +1211,6 @@ function buildJPMModel(options) {
} else {
boxes.push(box)
}
- submodels.push(submodel)
})
if (boxes.length) {
jpm.boxes = boxes
@@ -1250,7 +1248,7 @@ function buildJEMModel(options) {
if (g.rotation.join('_') !== '0_0_0') {
bone.rotate = g.rotation.slice()
}
- if (g.shade === false) {
+ if (g.mirror_uv) {
bone.mirrorTexture = 'u'
}
//Cubes
@@ -1282,7 +1280,7 @@ function buildJEMModel(options) {
if (s.inflate && typeof s.inflate === 'number') {
cube.sizeAdd = s.inflate
}
- if (s.shade === g.shade) {
+ if (s.mirror_uv === g.mirror_uv) {
bone.boxes.push(cube)
} else {
mirrored_boxes.push(cube)
@@ -1397,7 +1395,7 @@ function buildClassModel(options) {
obj.size(1, true),
obj.size(2, true),
F(obj.inflate),
- !obj.shade
+ obj.mirror_uv
]
bone.lines.push(
`${id}.cubeList.add(new ModelBox(${ values.join(', ') }));`
diff --git a/js/keyboard.js b/js/keyboard.js
index 47a07a9db..177927a12 100644
--- a/js/keyboard.js
+++ b/js/keyboard.js
@@ -165,7 +165,7 @@ class Keybind {
}
}
-function setupKeybindings() {
+onVueSetup(function() {
Keybinds.vue = new Vue({
el: 'ul#keybindlist',
data: {structure: Keybinds.structure},
@@ -203,14 +203,9 @@ function setupKeybindings() {
}
category.open = !category.open
}
- /*
- change
- reset
- clear
- */
}
})
-}
+})
$(document).keydown(function(e) {
if (Keybinds.recording) return;
@@ -283,13 +278,16 @@ $(document).keydown(function(e) {
} else if (open_interface && typeof open_interface == 'object' && open_interface.hide) {
if (Keybinds.extra.confirm.keybind.isTriggered(e)) {
- open_interface.confirm()
+ open_interface.confirm(e)
used = true
} else if (Keybinds.extra.cancel.keybind.isTriggered(e)) {
- open_interface.hide()
+ open_interface.hide(e)
used = true
}
}
+ if (ActionControl.open) {
+ used = ActionControl.handleKeys(e) || used
+ }
if (used) {
e.preventDefault()
}
diff --git a/js/molang.js b/js/molang.js
index ee475c6df..00fd46fab 100644
--- a/js/molang.js
+++ b/js/molang.js
@@ -250,7 +250,7 @@ function previewVariableValue(name, time) {
return 1
} else if (name === 'false') {
return 0
- } else if (name === 'global.anim_time' || name === 'Params.AnimTime' || name === 'Params.LifeTime' || name === 'global.life_time' ) {
+ } else if (name === 'global.anim_time' || name === 'time' || name === 'query.life_time' ) {
return time
} else {
var inputs = $('#var_placeholder_area').val().split('\n')
diff --git a/js/painter.js b/js/painter.js
index 59039adb7..15edd5be0 100644
--- a/js/painter.js
+++ b/js/painter.js
@@ -59,12 +59,7 @@ class BBPainter {
})
} else {
Painter.current.texture = texture
- var c = Painter.current.canvas = document.createElement('canvas')
- var ctx = c.getContext('2d');
- c.width = texture.res;
- c.height = texture.img.naturalHeight;
- ctx.drawImage(texture.img, 0, 0)
-
+ var c = Painter.current.canvas = Painter.getCanvas(texture)
cb(c)
texture.updateSource(c.toDataURL())
@@ -76,7 +71,7 @@ class BBPainter {
}
startBrushCanvas(data, event) {
Painter.current.x = Painter.current.y = 0
- var texture = getTextureById(data.cube.faces[data.face].texture)
+ var texture = data.cube.faces[data.face].getTexture()
if (!texture) {
Blockbench.showQuickMessage('message.untextured')
}
@@ -93,7 +88,7 @@ class BBPainter {
moveBrushCanvas(force) {
var data = Canvas.raycast()
if (data) {
- var texture = getTextureById(data.cube.faces[data.face].texture)
+ var texture = data.cube.faces[data.face].getTexture()
if (texture) {
var x, y, new_face;
var end_x = x = Math.floor( data.intersects[0].uv.x * texture.img.naturalWidth )
@@ -148,17 +143,25 @@ class BBPainter {
Painter.colorPicker(texture, x, y)
}
}
+ getCanvas(texture) {
+ var c = document.createElement('canvas')
+ var ctx = c.getContext('2d');
+ c.width = texture.res;
+ c.height = texture.img.naturalHeight;
+ ctx.drawImage(texture.img, 0, 0)
+ return c;
+ }
colorPicker(texture, x, y) {
- function getPxColor(image) {
- var c = image.getPixelColor(x,y)
- c = tinycolor(Jimp.intToRGBA(c))
- BarItems.brush_color.set(c)
- }
- if (texture.mode == 'bitmap') {
- Jimp.read(Buffer.from(texture.source.replace('data:image/png;base64,', ''), 'base64')).then(getPxColor)
- } else {
- Jimp.read(texture.source).then(getPxColor)
- }
+ var ctx = Painter.getCanvas(texture).getContext('2d')
+ Painter.scanCanvas(ctx, x, y, 1, 1, (x, y, px) => {
+ var t = tinycolor({
+ r: px[0],
+ g: px[1],
+ b: px[2],
+ a: px[3]/256
+ })
+ BarItems.brush_color.set(t)
+ })
}
useBrush(texture, x, y, uvTag, no_update) {
if ((Painter.currentPixel[0] !== x || Painter.currentPixel[1] !== y)) {
@@ -185,39 +188,90 @@ class BBPainter {
uvTag[3] / 16 * texture.img.naturalHeight
]
} else {
- var rect = Painter.editing_area = [0, 0, texture.red, texture.red]
+ var rect = Painter.editing_area = [0, 0, texture.img.naturalWidth, texture.img.naturalHeight]
}
for (var t = 0; t < 2; t++) {
if (rect[t] > rect[t+2]) {
[rect[t], rect[t+2]] = [rect[t+2], rect[t]]
}
+ rect[t] = Math.floor(rect[t])
+ rect[t+2] = Math.ceil(rect[t+2])
}
- ctx.rect(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1])
+ var [w, h] = [rect[2] - rect[0], rect[3] - rect[1]]
+ ctx.rect(rect[0], rect[1], w, h)
if (tool === 'fill_tool') {
ctx.fillStyle = BarItems.brush_color.get().toRgbString()
- ctx.fill()
- } else {
- ctx.clip()
- /*ctx.beginPath();
- ctx.moveTo((Painter.current.x||x)+.5, (Painter.current.y||y)+.5)
- ctx.lineTo(x+.5, y+.5)
- if (softness) {
- ctx.filter = `blur(${ softness*size/2 }px)`;
- } else {
- ctx.imageSmoothingEnabled = false
- }
- ctx.lineWidth = size
- ctx.lineCap = 'round'
- if (brush_mode === 'eraser') {
- ctx.globalCompositeOperation = 'destination-out'
- ctx.strokeStyle = 'rgba(0,0,0,0)';
+ var fill_mode = BarItems.fill_mode.get()
+ var cube = selected[0]
+
+ if (cube && fill_mode === 'cube') {
+ for (var face in cube.faces) {
+ var tag = cube.faces[face]
+ if (tag.texture === Painter.current.texture.uuid) {
+ var rect = getRectangle(
+ Math.floor(tag.uv[0] / 16 * texture.img.naturalWidth),
+ Math.floor(tag.uv[1] / 16 * texture.img.naturalHeight),
+ Math.ceil(tag.uv[2] / 16 * texture.img.naturalWidth),
+ Math.ceil(tag.uv[3] / 16 * texture.img.naturalHeight)
+ )
+ ctx.rect(rect.ax, rect.ay, rect.x, rect.y)
+ ctx.fill()
+ }
+ }
+
+ } else if (fill_mode === 'face') {
+ ctx.fill()
} else {
- ctx.strokeStyle = color
+
+ var pxcol = [];
+ var map = {}
+ Painter.scanCanvas(ctx, x, y, 1, 1, (x, y, px) => {
+ px.forEach((val, i) => {
+ pxcol[i] = val
+ })
+ })
+ Painter.scanCanvas(ctx, rect[0], rect[1], w, h, (x, y, px) => {
+ if (pxcol.equals(px)) {
+ if (!map[x]) map[x] = {}
+ map[x][y] = true
+ }
+ })
+ function checkPx(x, y) {
+ if (map[x] && map[x][y]) {
+ map[x][y] = false;
+
+ checkPx(x+1, y)
+ checkPx(x-1, y)
+ checkPx(x, y+1)
+ checkPx(x, y-1)
+ }
+ }
+ checkPx(x, y)
+ Painter.scanCanvas(ctx, rect[0], rect[1], w, h, (x, y, px) => {
+ if (map[x] && map[x][y] === false) {
+ var pxcolor = {
+ r: px[0],
+ g: px[1],
+ b: px[2],
+ a: px[3]/255
+ }
+ var result_color = Painter.combineColors(pxcolor, color, 1);
+ px[0] = result_color.r
+ px[1] = result_color.g
+ px[2] = result_color.b
+ px[3] = result_color.a*255
+ }
+ })
+
}
- ctx.stroke()*/
+
+
+ } else {
+ ctx.clip()
+
if (tool === 'brush_tool') {
Painter.editCircle(ctx, x, y, size, softness, function(pxcolor, opacity) {
var result_color = Painter.combineColors(pxcolor, color, opacity*b_opacity*(noise?Math.random():1));
@@ -417,6 +471,7 @@ class BBPainter {
lines.push({label: 'dialog.create_texture.folder', node: '
'})
if (elements.length > 0) {
lines.push({label: 'dialog.create_texture.template', node: '
'})
+ lines.push({label: 'dialog.create_texture.compress', node: '
'})
}
lines.push({widget: Painter.background_color})
lines.push({label: 'dialog.create_texture.resolution', node: '
'})
@@ -433,7 +488,11 @@ class BBPainter {
}
})
dialog.show()
+ $('#bitmap_compressTemplate').parent().hide()
+
$('.dialog#add_bitmap input#bitmap_doTemplate').click(function() {
+ var checked = $('.dialog#add_bitmap input#bitmap_doTemplate').is(':checked')
+ $('#bitmap_compressTemplate').parent()[ checked ? 'show' : 'hide' ]()
if (Painter.background_color.get().toHex8() === 'ffffffff') {
Painter.background_color.set('#00000000')
}
@@ -457,7 +516,8 @@ class BBPainter {
name: $('.dialog#add_bitmap input#bitmap_name').val(),
folder: $('.dialog#add_bitmap input#bitmap_folder').val(),
particle: 'auto',
- entity_template: $('.dialog#add_bitmap input#bitmap_doTemplate').is(':checked')
+ entity_template: $('.dialog#add_bitmap input#bitmap_doTemplate').is(':checked'),
+ compress: $('.dialog#add_bitmap input#bitmap_compressTemplate').is(':checked')
})
}
addBitmap(options, after) {
@@ -493,16 +553,19 @@ class BBPainter {
if (typeof after === 'function') {
after(texture)
}
+ if (options.entity_template) {
+ Undo.finishEdit('create template', {textures: [texture], bitmap: true, cubes: Blockbench.entity_mode ? elements : selected, uv_only: true})
+ } else {
+ Undo.finishEdit('create blank texture', {textures: [texture], bitmap: true})
+ }
return texture.add(false);
}
if (options.entity_template === true) {
- Undo.initEdit({textures: [], cubes: Blockbench.entity_mode ? elements : selected, uv_only: true})
- Painter.generateTemplate(options.res, options.color, makeTexture, options.texture)
- Undo.finishEdit({textures: [texture], cubes: Blockbench.entity_mode ? elements : selected, uv_only: true})
+ Undo.initEdit({textures: Blockbench.entity_mode ? textures : [], cubes: Blockbench.entity_mode ? elements : selected, uv_only: true})
+ Painter.generateTemplate(options, makeTexture)
} else {
Undo.initEdit({textures: []})
Painter.generateBlank(options.res, options.res, options.color, makeTexture)
- Undo.finishEdit({textures: [texture]})
}
}
generateBlank(height, width, color, cb) {
@@ -515,15 +578,18 @@ class BBPainter {
ctx.fillRect(0, 0, width, height)
cb(canvas.toDataURL())
-
}
- generateTemplate(res, background_color, cb, texture) {
+ generateTemplate(options, cb) {
+ var res = options.res
+ var background_color = options.color
+ var texture = options.texture
function cubeTempl(obj) {
var min = Blockbench.entity_mode ? 0 : 1
this.x = obj.size(0, true) || min
this.y = obj.size(1, true) || min
this.z = obj.size(2, true) || min
this.obj = obj
+ this.template_size = (obj.size(2, true) + obj.size(1, true)) + (obj.size(2, true) + obj.size(0, true))*2
this.height = this.z + this.y
this.width = 2* (this.x + this.z)
@@ -532,103 +598,143 @@ class BBPainter {
var res_multiple = res / 16
var templates = []
- var max_x_pos = 0
- var line_y_pos = 0;
- var valid_cubes = 0;
-
- var lines = [[]]
- var line_length = Math.sqrt(elements.length/2)
- var o = 0
-
- var cubes = Blockbench.entity_mode ? elements.slice() : selected.slice()
+ var extend_x = 0;
+ var extend_y = 0;
var avg_size = 0;
+ var cubes = Blockbench.entity_mode ? elements.slice() : selected.slice()
var i = cubes.length-1
while (i >= 0) {
let obj = cubes[i]
- if (obj.visibility === false) {
- cubes.splice(i,1)
- } else {
- obj.template_size = (obj.size(2, true) + obj.size(1, true)) + (obj.size(2, true) + obj.size(0, true))*2
- avg_size += obj.template_size
+ if (obj.visibility === true) {
+ templates.push(new cubeTempl(obj))
+ avg_size += templates[templates.length-1].template_size
}
i--;
}
- avg_size /= cubes.length
- cubes.sort(function(a,b) {
- return b.template_size - a.template_size
- })
-
- i = 0
- var ox = 0
- cubes.forEach(function(obj) {
- if (ox >= line_length) {
- o = 0
- ox = 0
- i++
- lines[i] = []
- }
- lines[i][o] = obj
- o++;
- ox += obj.template_size/avg_size
- })
-
- lines.forEach(function(b) {
-
- //Data
- var temps = []
- b.forEach(function(s, si) {
- if (s.type === 'cube') {
- temps.push(new cubeTempl(s))
- valid_cubes++;
- }
- })
- //Defaults
- //Find the maximum height of the line
- var max_height = 0
- temps.forEach(function(t) {
- max_height = Math.max(max_height, t.height)
- })
- var x_pos = 0
- var y_pos = 0 //Y Position of current area relative to this bone
- var filled_x_pos = 0;
- //Algorithm
- temps.forEach(function(t) {
- if (y_pos > 0 && (y_pos + t.height) <= max_height) {
- //same column
- t.posx = x_pos
- t.posy = y_pos + line_y_pos
- filled_x_pos = Math.max(filled_x_pos, x_pos+t.width)
- y_pos += t.height
- } else {
- //new column
- x_pos = filled_x_pos
- y_pos = t.height
- t.posx = x_pos
- t.posy = line_y_pos
- filled_x_pos = Math.max(filled_x_pos, x_pos+t.width)
- }
- //size of widest bone
- max_x_pos = Math.max(max_x_pos, filled_x_pos)
- templates.push(t)
- })
- line_y_pos += max_height
+ templates.sort(function(a,b) {
+ return b.template_size - a.template_size;
})
//Cancel if no cubes
- if (valid_cubes == 0) {
+ if (templates.length == 0) {
Blockbench.showMessage('No valid cubes', 'center')
return;
}
- function getNextPower(num, min) {
- var i = min ? min : 2
- while (i < num && i < 4000) {
- i *= 2
+ /*
+ TEMPLATE MENU
+ condensed
+ use old texture
+ */
+ if (options.compress) {
+
+ var fill_map = {}
+ function occupy(x, y) {
+ if (!fill_map[x]) fill_map[x] = {}
+ fill_map[x][y] = true
}
- return i;
+ function check(x, y) {
+ return fill_map[x] && fill_map[x][y]
+ }
+ function forTemplatePixel(tpl, sx, sy, cb) {
+ for (var x = 0; x < tpl.width; x++) {
+ for (var y = 0; y < tpl.height; y++) {
+ if (y >= tpl.z || (x >= tpl.z && x < (tpl.z + 2*tpl.x))) {
+ if (cb(sx+x, sy+y)) return;
+ }
+ }
+ }
+ }
+ function place(tpl, x, y) {
+ var works = true;
+ forTemplatePixel(tpl, x, y, (tx, ty) => {
+ if (check(tx, ty)) {
+ works = false;
+ return true;
+ }
+ })
+ if (works) {
+ forTemplatePixel(tpl, x, y, occupy)
+ tpl.posx = x;
+ tpl.posy = y;
+ extend_x = Math.max(extend_x, x + tpl.width);
+ extend_y = Math.max(extend_y, y + tpl.height);
+ return true;
+ }
+ }
+ templates.forEach(tpl => {
+ var vert = extend_x > extend_y;
+ //Scan for empty spot
+ for (var line = 0; line < 2e3; line++) {
+ for (var x = 0; x < line; x++) {
+ if (place(tpl, x, line)) return;
+ }
+ for (var y = 0; y < line; y++) {
+ if (place(tpl, line, y)) return;
+ }
+ }
+ })
+ } else {
+ //OLD -------------------------------------------
+ var lines = [[]]
+ var line_length = Math.sqrt(elements.length/2)
+ avg_size /= templates.length
+ var o = 0
+ var i = 0
+ var ox = 0
+ templates.forEach(function(tpl) {
+ if (ox >= line_length) {
+ o = ox = 0
+ i++
+ lines[i] = []
+ }
+ lines[i][o] = tpl
+ o++;
+ ox += tpl.template_size/avg_size
+ })
+
+ lines.forEach(function(temps) {
+
+ var x_pos = 0
+ var y_pos = 0 //Y Position of current area relative to this bone
+ var filled_x_pos = 0;
+ var max_height = 0
+ //Find the maximum height of the line
+ temps.forEach(function(t) {
+ max_height = Math.max(max_height, t.height)
+ })
+ //Place
+ temps.forEach(function(t) {
+ if (y_pos > 0 && (y_pos + t.height) <= max_height) {
+ //same column
+ t.posx = x_pos
+ t.posy = y_pos + extend_y
+ filled_x_pos = Math.max(filled_x_pos, x_pos+t.width)
+ y_pos += t.height
+ } else {
+ //new column
+ x_pos = filled_x_pos
+ y_pos = t.height
+ t.posx = x_pos
+ t.posy = extend_y
+ filled_x_pos = Math.max(filled_x_pos, x_pos+t.width)
+ }
+ //size of widest bone
+ extend_x = Math.max(extend_x, filled_x_pos)
+ })
+ extend_y += max_height
+ })
}
+
//Size
- var max_size = Math.max(max_x_pos, line_y_pos)
- max_size = Math.ceil(max_size/16)*16//getNextPower(max_size, 16)
+ //function getNextPower(num, min) {
+ // var i = min ? min : 2
+ // while (i < num && i < 4000) {
+ // i *= 2
+ // }
+ // return i;
+ //}
+ var max_size = Math.max(extend_x, extend_y)
+ max_size = Math.ceil(max_size/16)*16
if (background_color.getAlpha() != 0) {
background_color = background_color.toInteger()
@@ -664,22 +770,52 @@ class BBPainter {
function drawTexture(face, coords) {
if (!Blockbench.entity_mode) {
if (face.texture === undefined || face.texture === null) return false;
- texture = getTextureById(face.texture)
+ texture = face.getTexture()
}
if (!texture || !texture.img) return false;
- var uv = face.uv;
+
+ ctx.save()
+ var uv = face.uv.slice();
+
+ if (face.direction === 'up') {
+ uv = [uv[2], uv[3], uv[0], uv[1]]
+ } else if (face.direction === 'down') {
+ uv = [uv[2], uv[1], uv[0], uv[3]]
+ }
+
var src = getRectangle(uv[0], uv[1], uv[2], uv[3])
+ var flip = [
+ uv[0] > uv[2] ? -1 : 1,
+ uv[1] > uv[3] ? -1 : 1
+ ]
+ if (flip[0] + flip[1] < 1) {
+ ctx.scale(flip[0], flip[1])
+ }
+ if (face.rotation) {
+ ctx.rotate(Math.degToRad(face.rotation))
+ let rot = face.rotation
+
+ if (rot <= 180) flip[1] *= -1;
+ if (rot >= 180) flip[0] *= -1;
+
+ while (rot > 0) {
+ [coords.x, coords.y] = [coords.y, coords.x];
+ [coords.w, coords.h] = [coords.h, coords.w];
+ rot -= 90;
+ }
+ }
ctx.drawImage(
texture.img,
src.ax/16 * texture.img.naturalWidth,
src.ay/16 * texture.img.naturalHeight,
src.x /16 * texture.img.naturalWidth,
src.y /16 * texture.img.naturalHeight,
- coords.x*res_multiple,
- coords.y*res_multiple,
- coords.w*res_multiple,
- coords.h*res_multiple
+ coords.x*res_multiple*flip[0],
+ coords.y*res_multiple*flip[1],
+ coords.w*res_multiple*flip[0],
+ coords.h*res_multiple*flip[1]
)
+ ctx.restore()
return true;
}
@@ -693,8 +829,9 @@ class BBPainter {
}
//Drawing
-
templates.forEach(function(t) {
+ let obj = t.obj
+
for (var face in face_data) {
let d = face_data[face]
@@ -704,7 +841,6 @@ class BBPainter {
drawTemplateRectangle(d.c1, d.c2, d.place(t))
}
}
- let obj = t.obj
obj.uv_offset[0] = t.posx
obj.uv_offset[1] = t.posy
@@ -719,15 +855,16 @@ class BBPainter {
{face: 'up', fIndex: 4, from: [size[2]+size[0], size[2]], size: [-size[0], -size[2]]},
{face: 'down', fIndex: 6, from: [size[2]+size[0]*2, 0], size: [-size[0], size[2]]}
]
-
face_list.forEach(function(f) {
- obj.faces[f.face].uv[0] = (f.from[0] + Math.floor(obj.uv_offset[0]+0.0000001)) / max_size * 16,
- obj.faces[f.face].uv[1] = (f.from[1] + Math.floor(obj.uv_offset[1]+0.0000001)) / max_size * 16,
- obj.faces[f.face].uv[2] = (f.from[0] + f.size[0] + Math.floor(obj.uv_offset[0]+0.0000001)) / max_size * 16,
- obj.faces[f.face].uv[3] = (f.from[1] + f.size[1] + Math.floor(obj.uv_offset[1]+0.0000001)) / max_size * 16
-
+ obj.faces[f.face].uv[0] = (f.from[0] + Math.floor(obj.uv_offset[0]+0.0000001)) / max_size * 16;
+ obj.faces[f.face].uv[1] = (f.from[1] + Math.floor(obj.uv_offset[1]+0.0000001)) / max_size * 16;
+ obj.faces[f.face].uv[2] = (f.from[0] + f.size[0] + Math.floor(obj.uv_offset[0]+0.0000001)) / max_size * 16;
+ obj.faces[f.face].uv[3] = (f.from[1] + f.size[1] + Math.floor(obj.uv_offset[1]+0.0000001)) / max_size * 16;
+ obj.faces[f.face].rotation = 0;
})
+ } else {
+ obj.mirror_uv = false
}
})
var dataUrl = canvas.toDataURL()
@@ -854,6 +991,15 @@ BARS.defineActions(function() {
noise: true
}
})
+ new BarSelect({
+ id: 'fill_mode',
+ condition: () => Toolbox && Toolbox.selected.id === 'fill_tool',
+ options: {
+ face: true,
+ color: true,
+ cube: true
+ }
+ })
new NumSlider({
id: 'slider_brush_size',
diff --git a/js/plugin_loader.js b/js/plugin_loader.js
index 99c28a870..d79b02023 100644
--- a/js/plugin_loader.js
+++ b/js/plugin_loader.js
@@ -1,14 +1,10 @@
-/*
-Plugin Loader for Blockbench
-By JannisX11
-*/
var onUninstall, onInstall;
const Plugins = {
apipath: 'https://raw.githubusercontent.com/JannisX11/blockbench-plugins/master/plugins.json',
Vue: [], //Vue Object
installed: [], //Simple List of Names
json: undefined, //Json from website
- data: [], //Vue Object Data
+ all: [], //Vue Object Data
loadingStep: false,
updateSearch: function() {
Plugins.Vue._data.showAll = !Plugins.Vue._data.showAll
@@ -16,16 +12,182 @@ const Plugins = {
},
devReload: function() {
var reloads = 0;
- Plugins.data.forEach(function(pl) {
- if (pl.fromFile) {
- pl.reload()
+ for (var i = Plugins.all.length-1; i >= 0; i--) {
+ if (Plugins.all[i].fromFile) {
+ Plugins.all[i].reload()
reloads++;
}
- })
+ }
+ Blockbench.showQuickMessage(tl('message.plugin_reload', [reloads]))
console.log('Reloaded '+reloads+ ' plugin'+pluralS(reloads))
}
}
+class Plugin {
+ constructor(id, data) {
+ this.id = id;
+ this.installed = false;
+ this.expanded = false;
+ this.title = '';
+ this.author = '';
+ this.description = '';
+ this.about = '';
+ this.icon = '';
+ this.variant = '';
+ this.min_version = '';
+ if (data) {
+ this.extend(data)
+ }
+ }
+ extend(data) {
+ Merge.boolean(this, data, 'installed')
+ Merge.boolean(this, data, 'expanded')
+ Merge.string(this, data, 'title')
+ Merge.string(this, data, 'author')
+ Merge.string(this, data, 'description')
+ Merge.string(this, data, 'about')
+ Merge.string(this, data, 'icon')
+ Merge.string(this, data, 'variant')
+ Merge.string(this, data, 'min_version')
+ return this;
+ }
+ install(first, cb) {
+ var scope = this;
+ $.getScript(Plugins.path + scope.id + '.js', function() {
+ scope.bindGlobalData(first)
+ if (cb) cb()
+ }).fail(function() {
+ if (isApp) {
+ console.log('Could not find file of plugin "'+scope.id+'". Uninstalling it instead.')
+ scope.uninstall()
+ }
+ })
+ Plugins.installed.safePush(scope.id)
+ scope.installed = true;
+ return scope;
+ }
+ bindGlobalData(first) {
+ var scope = this;
+ if (onUninstall) {
+ scope.onUninstall = onUninstall
+ }
+ if (first && onInstall) {
+ onInstall()
+ }
+ window.onInstall = window.onUninstall = window.plugin_data = undefined
+ return this;
+ }
+ download(first) {
+ var scope = this;
+ if (!isApp) {
+ scope.install(first)
+ return this;
+ }
+ var file = originalFs.createWriteStream(Plugins.path+this.id+'.js')
+ var request = https.get('https://raw.githubusercontent.com/JannisX11/blockbench-plugins/master/plugins/'+this.id+'.js', function(response) {
+ response.pipe(file);
+ response.on('end', function() {
+ setTimeout(function() {
+ scope.install(first)
+ }, 50)
+ })
+ });
+ return this;
+ }
+ loadFromFile(file, hideWarning) {
+ var scope = this;
+ var path = file.path
+ localStorage.setItem('plugin_dev_path', file.path)
+ onInstall = undefined
+
+ if (!hideWarning) {
+ if (isApp) {
+ if (!confirm(tl('message.load_plugin_app'))) return;
+ } else {
+ if (!confirm(tl('message.load_plugin_web'))) return;
+ }
+ }
+ $.getScript(file.path, function() {
+ scope.id = (plugin_data && plugin_data.id)||pathToName(file.path)
+ scope.installed = true
+ scope.fromFile = true
+ scope.path = file.path
+ scope.extend(plugin_data)
+ scope.bindGlobalData(true)
+ Plugins.installed.safePush(scope.path)
+ saveInstalledPlugins()
+ Plugins.all.sort(function(a,b) {
+ return sort_collator.compare(a.title, b.title)
+ });
+ })
+ Plugins.all.safePush(this)
+ return this;
+ }
+ uninstall() {
+ var scope = this;
+ if (isApp && this.fromFile) {
+ if (this.onUninstall) {
+ this.onUninstall()
+ }
+ Plugins.all.remove(this)
+ Plugins.installed.remove(this.path)
+ } else {
+ if (isApp) {
+ var filepath = Plugins.path + scope.id + '.js'
+ if (fs.existsSync(filepath)) {
+ fs.unlink(filepath, (err) => {
+ if (err) {
+ console.log(err);
+ }
+ });
+ }
+ }
+ Plugins.installed.remove(scope.id)
+ scope.installed = false
+ if (scope.onUninstall) {
+ scope.onUninstall()
+ }
+ }
+ saveInstalledPlugins()
+ return this;
+ }
+ reload() {
+ if (!isApp) return this;
+ this.uninstall()
+ this.loadFromFile({path: this.path}, true)
+ return this;
+ }
+ isInstallable() {
+ var scope = this;
+ var result =
+ scope.variant === 'both' ||
+ (
+ isApp === (scope.variant === 'desktop') &&
+ isApp !== (scope.variant === 'web')
+ );
+ if (result && scope.min_version) {
+ result = compareVersions(scope.min_version, appVersion) ? 'outdated' : true
+ } else if (result === false) {
+ result = (scope.variant === 'web') ? 'web_only' : 'app_only'
+ }
+ return (result === true) ? true : tl('dialog.plugins.'+result);
+ }
+ toggleInfo(force) {
+ var scope = this;
+ Plugins.all.forEach(function(p) {
+ if (p !== scope && p.expanded) p.expanded = false;
+ })
+ if (force !== undefined) {
+ this.expanded = force === true
+ } else {
+ this.expanded = this.expanded !== true
+ }
+ }
+ get expandicon() {
+ return this.expanded ? 'expand_less' : 'expand_more'
+ }
+}
+
if (isApp) {
Plugins.path = app.getPath('userData')+osfs+'plugins'+osfs
fs.readdir(Plugins.path, function(err) {
@@ -33,102 +195,78 @@ if (isApp) {
fs.mkdir(Plugins.path, function(a) {})
}
})
+} else {
+ Plugins.path = 'https://cdn.jsdelivr.net/gh/JannisX11/blockbench-plugins/plugins/';
}
$.getJSON(Plugins.apipath, function(data) {
Plugins.json = data
- if (Plugins.loadingStep === true) {
- loadInstalledPlugins()
- } else {
- Plugins.loadingStep = true
- }
+ loadInstalledPlugins()
}).fail(function() {
console.log('Could not connect to plugin server')
$('#plugin_available_empty').text('Could not connect to plugin server')
- if (Plugins.loadingStep === true) {
- loadInstalledPlugins()
- } else {
- Plugins.loadingStep = true
- }
+ loadInstalledPlugins()
})
-
$(document).ready(function() {
- if (Plugins.loadingStep === true) {
- loadInstalledPlugins()
- } else {
- Plugins.loadingStep = true
- }
+ loadInstalledPlugins()
})
function loadInstalledPlugins() {
+ if (!Plugins.loadingStep) {
+ Plugins.loadingStep = true
+ return;
+ }
var storage_data = localStorage.getItem('installed_plugins')
if (storage_data !== null) {
Plugins.installed = JSON.parse(storage_data)
}
if (Plugins.json !== undefined) {
+ //From Store
for (var id in Plugins.json) {
- var plugin = Plugins.json[id]
- var obj = {
- id: id,
- title: plugin.title,
- author: plugin.author,
- description: plugin.description,
- about: plugin.about,
- icon: plugin.icon,
- variant: plugin.variant,
- min_version: plugin.min_version,
- installed: Plugins.installed.includes(id),
- expanded: false
- }
- if (obj.installed) {
- if (isApp) {
- downloadPlugin(id)
- } else {
- loadPlugin(id)
- }
+ var plugin = new Plugin(id, Plugins.json[id])
+ if (Plugins.installed.includes(id)) {
+ plugin.download()
}
- Plugins.data.push(obj)
- Plugins.data.sort(function(a,b) {
- return sort_collator.compare(a.title, b.title)
- });
+ Plugins.all.push(plugin)
}
- } else if (Plugins.installed.length > 0) {
- //Only show downloaded plugins in the plugin window
+ Plugins.all.sort(function(a,b) {
+ return sort_collator.compare(a.title, b.title)
+ });
+ } else if (Plugins.installed.length > 0 && isApp) {
Plugins.installed.forEach(function(id) {
- loadPlugin(id, function() {
- //Plugin Data Comes from the plugin file
- if (plugin_data === undefined) return;
- var obj = {
- id: id,
- title: plugin_data.title,
- author: plugin_data.author,
- description: plugin_data.description,
- about: plugin_data.about,
- icon: plugin_data.icon,
- variant: plugin_data.variant,
- min_version: plugin_data.min_version,
- installed: true,
- expanded: false
- }
- Plugins.data.push(obj)
- Plugins.data.sort(function(a,b) {
- return sort_collator.compare(a.title, b.title)
- });
- })
+
+ if (id.substr(-3) !== '.js') {
+ //downloaded public plugin
+ var plugin = new Plugin(id).install(false, () => {
+ if (typeof plugin_data === 'object') {
+ plugin.extend(plugin_data)
+ Plugins.all.push(plugin)
+ Plugins.all.sort(function(a,b) {
+ return sort_collator.compare(a.title, b.title)
+ });
+ }
+ })
+ }
})
}
if (Plugins.installed.length > 0) {
+ Plugins.installed.forEach(function(id) {
+
+ if (id.substr(-3) === '.js') {
+ //Dev Plugins
+ var plugin = new Plugin().loadFromFile({path: id}, true)
+ }
+ })
console.log('Loaded '+Plugins.installed.length+' plugin'+pluralS(Plugins.installed.length))
}
-
Plugins.Vue = new Vue({
el: '#plugin_list',
data: {
showAll: false,
- items: Plugins.data
+ items: Plugins.all
},
computed: {
- installedPlugins() {
+ plugin_search() {
var name = $('#plugin_search_bar').val().toUpperCase()
return this.items.filter(item => {
if (this.showAll !== item.installed) {
@@ -145,196 +283,14 @@ function loadInstalledPlugins() {
return false;
})
}
- },
- methods: {
- install: function(plugin) {
- if (isApp) {
- downloadPlugin(plugin.id)
- } else {
- loadPlugin(plugin.id)
- }
- },
- uninstall: function(plugin) {
- uninstallPlugin(plugin.id)
- },
- update: function(plugin) {
- if (isApp) {
- downloadPlugin(plugin.id)
- }
- },
- checkIfInstallable: function(plugin) {
- var result =
- plugin.variant === 'both' ||
- (
- isApp === (plugin.variant === 'desktop') &&
- isApp !== (plugin.variant === 'web')
- );
- if (result && plugin.min_version) {
- result = compareVersions(plugin.min_version, appVersion) ? 'outdated' : true
- } else if (result === false) {
- result = (plugin.variant === 'web') ? 'web_only' : 'app_only'
- }
- return (result === true) ? true : tl('dialog.plugins.'+result);
- },
- toggleInfo: function(plugin, force) {
- Plugins.data.forEach(function(p) {
- if (p !== plugin && p.expanded) p.expanded = false;
- })
- plugin.expanded = plugin.expanded !== true
- if (force !== undefined) {
- plugin.expanded = force === true
- }
- if (plugin.expanded) {
- plugin.expandicon = 'expand_less'
- } else {
- plugin.expandicon = 'expand_more'
- }
- }
}
})
}
function saveInstalledPlugins() {
localStorage.setItem('installed_plugins', JSON.stringify(Plugins.installed))
- hideDialog()
-}
-function loadPlugin(id, cb, install) {
- if (isApp === true) {
- $.getScript(Plugins.path + id + '.js', function(a) {
- if (onUninstall) {
- Plugins.data.findInArray('id', id).uninstall = onUninstall
- onUninstall = undefined
- }
- if (install && onInstall) {
- onInstall()
- }
- onInstall = undefined
- if (cb !== undefined) cb()
- }).fail(function() {
- console.log('Could not find file of plugin "'+id+'". Uninstalling it instead.')
- uninstallPlugin(id)
- saveInstalledPlugins()
- })
- } else {
- $.getScript('https://raw.githubusercontent.com/JannisX11/blockbench-plugins/master/plugins/'+id+'.js', function() {
- if (onUninstall) {
- Plugins.data.findInArray('id', id).uninstall = onUninstall
- onUninstall = undefined
- }
- if (install && onInstall) {
- onInstall()
- }
- onInstall = undefined
- if (cb) cb()
- })
- }
- if (Plugins.installed.includes(id) === false) {
- Plugins.installed.push(id)
- }
- Plugins.data.findInArray('id', id).installed = true
}
-function loadPluginFromFile(file, hideWarning) {
- var hideWarning;
- var content = file.content
- var path = file.path
- localStorage.setItem('plugin_dev_path', path)
- onInstall = undefined
-
- if (!hideWarning) {
- if (isApp) {
- if (!confirm(tl('message.load_plugin_app'))) return;
- } else {
- if (!confirm(tl('message.load_plugin_web'))) return;
- }
- }
- try {
- eval(content)
- } catch (err) {
- Blockbench.showQuickMessage('message.invalid_plugin')
- console.error(err)
- return;
- }
- var obj = {
- author: 'unknown',
- icon: 'extension',
- installed: true,
- id: 'test',
- title: 'Plugin',
- variant: 'both',
- description: '',
- about: '',
- fromFile: true,
- filePath: path,
- expanded: false,
- uninstall: function() {
- var index = Plugins.data.indexOf(this)
- if (index >= 0) Plugins.data.splice(index, 1)
- if (this.uninstallMethod) {
- this.uninstallMethod()
- }
- },
- reload: function() {
- if (isApp) {
- obj.uninstall()
- fs.readFile(path, 'utf-8', function (err, data) {
- if (err) {
- console.log(err)
- return;
- }
- loadPluginFromFile({
- content: data,
- path: path
- }, true)
- })
- }
- },
- uninstallMethod: false
- }
- $.extend(true, obj, plugin_data)
- obj.uninstallMethod = onUninstall
- onUninstall = undefined
- if (onInstall) onInstall()
- onInstall = undefined
- Plugins.data.push(obj)
- Plugins.data.sort(function(a,b) {
- return sort_collator.compare(a.title, b.title)
- });
-}
-function downloadPlugin(id, is_install) {
- //$('.uc_btn').attr('disabled', true)
-
- var file = originalFs.createWriteStream(Plugins.path+id+'.js')
- var request = https.get('https://raw.githubusercontent.com/JannisX11/blockbench-plugins/master/plugins/'+id+'.js', function(response) {
- response.pipe(file);
- response.on('end', function() {
- setTimeout(function() {
- loadPlugin(id, undefined, is_install)
- }, 100)
- })
- });
-}
-function uninstallPlugin(id) {
- if (isApp) {
- var filepath = Plugins.path + id + '.js'
- if (fs.existsSync(filepath)) {
- fs.unlink(filepath, (err) => {
- if (err) {
- console.log(err);
- return;
- }
- });
- } else {
- //File does not exist
- }
- }
- var index = Plugins.installed.indexOf(id)
- if (index > -1) {
- Plugins.installed.splice(index, 1)
- }
- var data_obj = Plugins.data.findInArray('id', id)
- data_obj.installed = false
- if (data_obj.uninstall) {
- data_obj.uninstall()
- }
+function loadPluginFromFile(file) {
+ var plugin = new Plugin().loadFromFile(file, false)
}
function switchPluginTabs(installed) {
$('#plugins .tab').removeClass('open')
@@ -357,13 +313,22 @@ BARS.defineActions(function() {
$('#plugin_list').css('max-height', limitNumber($(window).height()-300, 80, 600)+'px')
}
})
+ new Action({
+ id: 'reload_plugins',
+ icon: 'sync',
+ category: 'blockbench',
+ keybind: new Keybind({ctrl: true, key: 74}),
+ click: function () {
+ Plugins.devReload()
+ }
+ })
new Action({
id: 'load_plugin',
icon: 'fa-file-code-o',
category: 'blockbench',
click: function () {
Blockbench.import({
- extensions: ['bbplugin', 'js'],
+ extensions: ['js'],
type: 'Blockbench Plugin',
startpath: localStorage.getItem('plugin_dev_path')
}, function(files) {
diff --git a/js/preview.js b/js/preview.js
index d13f560e4..f9747f187 100644
--- a/js/preview.js
+++ b/js/preview.js
@@ -35,7 +35,6 @@ class Preview {
this.camOrtho = new THREE.OrthographicCamera(-600, 600, -400, 400, 1, 100)
this.camOrtho.backgroundHandle = [{n: false, a: 'x'}, {n: false, a: 'y'}]
this.camOrtho.axis = null
- this.camPers.position.set(-20, 20, -20)
this.camPers.preview = this.camOrtho.preview = this;
//Controls
@@ -46,6 +45,8 @@ class Preview {
this.controls.enableKeys = false;
this.controls.zoomSpeed = 1.5
+ this.resetCamera(true)
+
//Keybinds
this.controls.mouseButtons.ZOOM = undefined;
@@ -255,10 +256,13 @@ class Preview {
this.controls.updateSceneScale();
return this;
}
- resetCamera() {
+ resetCamera(init) {
+ var dis = 24
this.controls.target.set(0, -3, 0);
- this.camPers.position.set(-20, 20, -20)
- this.setNormalCamera()
+ this.camPers.position.set(-dis, dis*0.8, -dis)
+ if (!init) {
+ this.setNormalCamera()
+ }
return this;
}
getFacingDirection() {
@@ -303,7 +307,7 @@ class Preview {
this.static_rclick = false
if (Toolbox.selected.selectCubes && Modes.selected.selectCubes && data.type === 'cube') {
if (Toolbox.selected.selectFace) {
- main_uv.setFace(data.face)
+ main_uv.setFace(data.face, false)
}
Blockbench.dispatchEvent( 'canvas_select', data )
if (Animator.open || (Toolbox.selected.id === 'rotate_tool' && Blockbench.entity_mode)) {
@@ -441,10 +445,10 @@ class Preview {
)
selected.length = 0;
elements.forEach(function(cube) {
-
+
if ((event.shiftKey || event.ctrlKey) && scope.selection.old_selected.indexOf(cube) >= 0) {
var isSelected = true
- } else {
+ } else if (cube.visibility) {
var mesh = cube.mesh
var from = new THREE.Vector3().copy(mesh.geometry.vertices[6]).applyMatrix4(mesh.matrixWorld)
var to = new THREE.Vector3().copy(mesh.geometry.vertices[0]).applyMatrix4(mesh.matrixWorld)
@@ -711,6 +715,7 @@ class Preview {
}
return [
{icon: getBtn(0, true), name: 'menu.preview.perspective.normal', click: function(preview) {preview.setNormalCamera()}},
+ 'camera_reset',
{icon: getBtn(0), name: 'direction.top', color: 'y', click: function(preview) {preview.setOrthographicCamera(0)}},
{icon: getBtn(1), name: 'direction.bottom', color: 'y', click: function(preview) {preview.setOrthographicCamera(1)}},
{icon: getBtn(2), name: 'direction.south', color: 'z', click: function(preview) {preview.setOrthographicCamera(2)}},
@@ -847,29 +852,41 @@ function initCanvas() {
Sun = new THREE.AmbientLight( 0xffffff );
Sun.name = 'sun'
scene.add(Sun);
+ Sun.intensity = 0.44
lights = new THREE.Object3D()
lights.name = 'lights'
- var light_top = new THREE.DirectionalLight( 0x777777 );
+ var light_top = new THREE.DirectionalLight( /*0x777777*/ );
+ light_top.name = 'light_top'
light_top.position.set(8, 100, 8)
lights.add(light_top);
+
+ light_top.intensity = 0.66
- var light_west = new THREE.DirectionalLight( 0x222222 );
+ var light_north = new THREE.DirectionalLight( /*0x444444*/ );
+ light_north.name = 'light_north'
+ light_north.position.set(8, 8, -100)
+ lights.add(light_north);
+
+ var light_south = new THREE.DirectionalLight( /*0x444444*/ );
+ light_south.name = 'light_south'
+ light_south.position.set(8, 8, 100)
+ lights.add(light_south);
+
+ light_north.intensity = light_south.intensity = 0.44
+
+ var light_west = new THREE.DirectionalLight( /*0x222222*/ );
+ light_west.name = 'light_west'
light_west.position.set(-100, 8, 8)
lights.add(light_west);
- var light_east = new THREE.DirectionalLight( 0x222222 );
+ var light_east = new THREE.DirectionalLight( /*0x222222*/ );
+ light_east.name = 'light_east'
light_east.position.set(100, 8, 8)
lights.add(light_east);
- var light_north = new THREE.DirectionalLight( 0x444444 );
- light_north.position.set(8, 8, -100)
- lights.add(light_north);
-
- var light_south = new THREE.DirectionalLight( 0x444444 );
- light_south.position.set(8, 8, 100)
- lights.add(light_south);
+ light_west.intensity = light_east.intensity = 0.22
setShading()
@@ -951,14 +968,11 @@ function animate() {
function setShading() {
scene.remove(lights)
display_scene.remove(lights)
- Sun.intensity = 1
+ Sun.intensity = settings.brightness.value/100;
if (settings.shading.value === true) {
- Sun.intensity = 0.65
- if (display_mode) {
- display_scene.add(lights)
- } else {
- scene.add(lights)
- }
+ (display_mode ? display_scene : scene).add(lights)
+ } else {
+ Sun.intensity *= (1/0.6)
}
}
//Helpers
@@ -1089,13 +1103,6 @@ function centerTransformer(offset) {
Transformer.position.z += 8;
Transformer.rotation.set(0, 0, 0)
Transformer.update()
-
- //if (!rotate_tool) {
- // var quat = new THREE.Quaternion()
- // g_mesh.getWorldQuaternion(quat)
- // Transformer.rotation.setFromQuaternion(quat, 'ZYX')
- //} else {
- //}
return;
}
@@ -1104,57 +1111,18 @@ function centerTransformer(offset) {
Canvas.updateAllBones()
}
if (!rotate_tool) {
- var first_obj
- var center = [0, 0, 0]
- var i = 0;
- selected.forEach(function(obj) {
- var m = obj.mesh
- if (obj.visibility && m) {
- var pos = new THREE.Vector3(
- obj.from[0] + obj.size(0)/2,
- obj.from[1] + obj.size(1)/2,
- obj.from[2] + obj.size(2)/2
- )
- if (!Blockbench.entity_mode) {
-
- pos.x -= obj.origin[0]
- pos.y -= obj.origin[1]
- pos.z -= obj.origin[2]
- var r = m.getWorldQuaternion(new THREE.Quaternion())
- pos.applyQuaternion(r)
- pos.x += obj.origin[0]
- pos.y += obj.origin[1]
- pos.z += obj.origin[2]
- } else {
- var r = m.getWorldQuaternion(new THREE.Quaternion())
- pos.applyQuaternion(r)
- pos.add(m.getWorldPosition(new THREE.Vector3()))
- pos.x += 8
- pos.y += 8
- pos.z += 8
- }
-
- center[0] += pos.x
- center[1] += pos.y
- center[2] += pos.z
-
- if (!first_obj) {
- first_obj = obj
- }
+ var first_obj;
+ var center = getSelectionCenter()
+ for (var i = 0; i < selected.length && !first_obj; i++) {
+ if (selected[i].visibility) {
+ first_obj = selected[i];
}
- })
- if (!first_obj) {
- return;
- }
- i = 0;
- while (i < 3) {
- center[i] = center[i] / selected.length
- i++;
}
} else {
var first_obj = selected[0]
var center = first_obj.origin
}
+ if (!first_obj || !first_obj.visibility) return;
var vec = new THREE.Vector3(center[0], center[1], center[2])
//Position + Rotation
@@ -1357,7 +1325,7 @@ class CanvasController {
if (texture) {
used = false;
for (var face in obj.faces) {
- if (obj.faces[face] && obj.faces[face].texture === '#'+texture.id) {
+ if (obj.faces[face].texture === texture.uuid) {
used = true;
}
}
@@ -1420,9 +1388,7 @@ class CanvasController {
}
}
arr.forEach(function(obj) {
- if (obj.visibility == true) {
- Canvas.adaptObjectPosition(obj)
- }
+ Canvas.adaptObjectPosition(obj)
})
if (leave_selection !== true) {
updateSelection()
@@ -1608,22 +1574,22 @@ class CanvasController {
}
iterate(el, elmesh)
}
- adaptObjectFaces(obj, mesh) {
- if (!mesh) mesh = obj.mesh
+ adaptObjectFaces(cube, mesh) {
+ if (!mesh) mesh = cube.mesh
if (!mesh) return;
if (!Prop.wireframe) {
var materials = []
this.face_order.forEach(function(face) {
- if (obj.faces[face].texture === null) {
+ if (cube.faces[face].texture === null) {
materials.push(Canvas.transparentMaterial)
} else {
- var tex = getTextureById(obj.faces[face].texture)
- if (typeof tex === 'object') {
+ var tex = cube.faces[face].getTexture()
+ if (tex && tex.uuid) {
materials.push(Canvas.materials[tex.uuid])
} else {
- materials.push(emptyMaterials[obj.color])
+ materials.push(emptyMaterials[cube.color])
}
}
})
@@ -1717,7 +1683,7 @@ class CanvasController {
stretch = 1
frame = 0
if (obj[face].texture && obj[face].texture !== null) {
- var tex = getTextureById(obj[face].texture)
+ var tex = obj[face].getTexture()
if (typeof tex === 'object' && tex.constructor.name === 'Texture' && tex.frameCount) {
stretch = tex.frameCount
if (animation === true && tex.currentFrame) {
@@ -1830,6 +1796,9 @@ BARS.defineActions(function() {
click: function () {
Prop.wireframe = !Prop.wireframe
Canvas.updateAll()
+ if (Modes.id === 'animate') {
+ Animator.preview()
+ }
}
})
@@ -1888,6 +1857,7 @@ BARS.defineActions(function() {
id: 'toggle_quad_view',
icon: 'widgets',
category: 'view',
+ condition: () => (Modes.id === 'edit' || Modes.id === 'paint'),
keybind: new Keybind({key: 9}),
click: function () {
main_preview.toggleFullscreen()
@@ -1895,8 +1865,8 @@ BARS.defineActions(function() {
})
new Action({
id: 'camera_reset',
- name: 'direction.top',
- description: 'direction.top',
+ name: 'menu.preview.perspective.reset',
+ description: 'menu.preview.perspective.reset',
icon: 'videocam',
category: 'view',
keybind: new Keybind({key: 96}),
diff --git a/js/settings.js b/js/settings.js
index 57334187a..aa894ee05 100644
--- a/js/settings.js
+++ b/js/settings.js
@@ -16,6 +16,7 @@ function settingSetup() {
//focal_length: {category: 'preview', value: 70, type: 'number'},
display_skin: {category: 'preview', value: false, type: 'click', condition: isApp, icon: 'icon-player', click: function() { changeDisplaySkin() }},
seethrough_outline: {category: 'preview', value: false},
+ brightness: {category: 'preview', value: 50, type: 'number'},
shading: {category: 'preview', value: true},
transparency: {category: 'preview', value: true},
texture_fps: {category: 'preview', value: 2, type: 'number'},
@@ -242,7 +243,7 @@ function saveSettings(force_update) {
}
}
Canvas.outlineMaterial.depthTest = !settings.seethrough_outline.value
- if (hasSettingChanged('shading')) {
+ if (hasSettingChanged('shading') || hasSettingChanged('brightness')) {
setShading()
}
if (hasSettingChanged('texture_fps')) {
@@ -265,7 +266,10 @@ function saveProjectSettings() {
if (uv_dialog.editors) {
uv_dialog.editors.single.setGrid()
}
- entityMode.setResolution()
+ if (entityMode.old_res.x !== Project.texture_width || entityMode.old_res.y !== Project.texture_height) {
+ entityMode.setResolution()
+ Undo.finishEdit('changed resolution')
+ }
}
hideDialog()
}
@@ -279,3 +283,41 @@ function toggleSetting(setting) {
}
function toggleWireframe() {
}
+
+onVueSetup(function() {
+ var structure = {}
+ for (var key in settings) {
+ var category = settings[key].category
+ if (!category) category = 'general'
+
+ if (!structure[category]) {
+ structure[category] = {
+ name: tl('settings.category.'+category),
+ open: category === 'general',
+ items: {}
+ }
+ }
+ structure[category].items[key] = settings[key]
+ }
+ var settingslist = new Vue({
+ el: 'ul#settingslist',
+ data: {structure},
+ methods: {
+ saveSettings: function() {
+ localStorage.setItem('settings', JSON.stringify(settings))
+ },
+ toggleCategory: function(category) {
+ if (!category.open) {
+ for (var ct in structure) {
+ structure[ct].open = false
+ }
+ }
+ category.open = !category.open
+ }
+ }
+ })
+ var project_vue = new Vue({
+ el: '#project_settings',
+ data: {Project}
+ })
+})
\ No newline at end of file
diff --git a/js/textures.js b/js/textures.js
index 947340934..a0abb5b4a 100644
--- a/js/textures.js
+++ b/js/textures.js
@@ -478,7 +478,7 @@ class Texture {
var sides = ['north', 'east', 'south', 'west', 'up', 'down']
elements.forEach(function(s) {
sides.forEach(function(side) {
- s.faces[side].texture = '#'+scope.id
+ s.faces[side].texture = scope.uuid
})
})
Canvas.updateAllFaces()
@@ -537,15 +537,16 @@ class Texture {
if (selected.length === 0) return;
var scope = this;
Undo.initEdit({cubes: selected})
- if (all || Blockbench.entity_mode) {
- var sides = ['north', 'east', 'south', 'west', 'up', 'down']
- } else {
- var sides = [main_uv.face]
- }
+
selected.forEach(function(obj) {
- sides.forEach(function(side) {
- obj.faces[side].texture = '#'+scope.id
- })
+ for (var face in obj.faces) {
+ if (all || Blockbench.entity_mode || face === main_uv.face) {
+ var f = obj.faces[face]
+ if (all !== 'blank' || (f.texture !== null && !f.getTexture())) {
+ f.texture = scope.uuid
+ }
+ }
+ }
})
Canvas.updateSelectedFaces()
main_uv.loadData()
@@ -713,6 +714,12 @@ class Texture {
condition: function() {return !Blockbench.entity_mode && selected.length > 0},
click: function(texture) {texture.apply()}
},
+ {
+ icon: 'texture',
+ name: 'menu.texture.blank',
+ condition: function() {return !Blockbench.entity_mode && selected.length > 0},
+ click: function(texture) {texture.apply('blank')}
+ },
{
icon: 'fa-cube',
name: 'menu.texture.cube',
@@ -876,7 +883,7 @@ function loadTextureDraggable() {
if ($('canvas.preview:hover').length > 0) {
var data = Canvas.getCurrentPreview().raycast()
if (data.cube && data.face) {
- var tex = getTextureById(ui.helper.attr('texid'))
+ var tex = textures.findInArray('uuid', ui.helper.attr('texid'));
if (tex) {
data.cube.applyTexture(tex, [data.face])
}
@@ -928,7 +935,7 @@ function changeTexturesFolder() {
}
function getTextureById(id) {
- if (id === undefined) return;
+ if (id === undefined || id === false) return;
if (id == null) {
return {material: transparentMaterial};
}
@@ -937,10 +944,18 @@ function getTextureById(id) {
}
function getTexturesById(id) {
if (id === undefined) return;
- id = id.split('#').join('');
+ id = id.replace('#', '');
return $.grep(textures, function(e) {return e.id == id});
}
+onVueSetup(function() {
+ texturelist = new Vue({
+ el: '#texture_list',
+ data: {textures}
+ })
+ texturelist._data.elements = textures
+})
+
BARS.defineActions(function() {
new Action({
id: 'import_texture',
diff --git a/js/transform.js b/js/transform.js
index 7dda61ea0..22a06df0b 100644
--- a/js/transform.js
+++ b/js/transform.js
@@ -1,71 +1,52 @@
//Actions
function origin2geometry() {
- Undo.initEdit({cubes: selected})
+
if (Blockbench.entity_mode) {
+ Undo.initEdit({group: selected_group})
+
if (!selected_group || selected_group.children.length === 0) return;
var position = [0, 0, 0]
selected_group.children.forEach(function(obj) {
- position[0] += obj.from[0] + obj.size(0)/2
- position[1] += obj.from[1] + obj.size(1)/2
- position[2] += obj.from[2] + obj.size(2)/2
+ if (obj.type === 'cube') {
+ position[0] += obj.from[0] + obj.size(0)/2
+ position[1] += obj.from[1] + obj.size(1)/2
+ position[2] += obj.from[2] + obj.size(2)/2
+ }
})
position.forEach(function(p, pi) {
position[pi] = p / selected_group.children.length
})
selected_group.origin = position
- } else if (selected.length > 1) {
-
- var center = [0, 0, 0]
- var i = 0;
- selected.forEach(function(obj) {
- i = 0;
- while (i < 3) {
- center[i] += obj.from[i]
- center[i] += obj.to[i]
- i++;
- }
- })
- i = 0;
- while (i < 3) {
- center[i] = center[i] / (selected.length * 2)
- i++;
- }
- selected.forEach(function(obj) {
- obj.origin = center.slice()
- })
-
} else {
+ Undo.initEdit({cubes: selected})
- var obj = selected[0]
- var element_size = obj.size()
- var element_center = new THREE.Vector3(
- (element_size[0] / 2) + obj.from[0],
- (element_size[1] / 2) + obj.from[1],
- (element_size[2] / 2) + obj.from[2]
- )
-
- element_center.x -= obj.origin[0]
- element_center.y -= obj.origin[1]
- element_center.z -= obj.origin[2]
+ var center = getSelectionCenter()
+
+ selected.forEach(cube => {
+ cube.transferOrigin(center)
+ })
+ }
+ Canvas.updatePositions()
+ Undo.finishEdit('origin to geometry')
+}
+function getSelectionCenter() {
+ var center = [0, 0, 0]
+ var i = 0;
+ selected.forEach(cube => {
+ var m = cube.mesh
+ if (cube.visibility && m) {
- if (obj.mesh) {
- element_center.applyEuler(obj.mesh.rotation)
+ var pos = cube.getWorldCenter()
+ center[0] += pos.x
+ center[1] += pos.y
+ center[2] += pos.z
}
- obj.origin[0] += element_center.x
- obj.origin[1] += element_center.y
- obj.origin[2] += element_center.z
-
- obj.to[0] = obj.origin[0] + element_size[0] / 2
- obj.to[1] = obj.origin[1] + element_size[1] / 2
- obj.to[2] = obj.origin[2] + element_size[2] / 2
-
- obj.from[0] = obj.origin[0] - element_size[0] / 2
- obj.from[1] = obj.origin[1] - element_size[1] / 2
- obj.from[2] = obj.origin[2] - element_size[2] / 2
+ })
+ for (var i = 0; i < 3; i++) {
+ center[i] = center[i] / selected.length
}
- Canvas.updatePositions()
- Undo.finishEdit('origin2geometry')
+ return center;
}
function isMovementGlobal() {
if (selected.length === 0 || (!settings.local_move.value && Toolbox.selected.id !== 'resize_tool')) {
@@ -356,8 +337,10 @@ function scaleAll(save, size) {
}
if (clip && Blockbench.entity_mode === false) {
$('#scaling_clipping_warning').text('Model clipping: Your model is too large for the canvas')
+ $('#scale_overflow_btn').css('display', 'inline-block')
} else {
$('#scaling_clipping_warning').text('')
+ $('#scale_overflow_btn').hide()
}
Canvas.updatePositions()
if (save === true) {
@@ -393,6 +376,26 @@ function cancelScaleAll() {
Canvas.updatePositions()
hideDialog()
}
+function scaleAllSelectOverflow() {
+ var overflow = [];
+ selected.forEach(function(obj) {
+ var clip = false
+ obj.from.forEach(function(ogn, i) {
+
+ if (obj.from[i] > 32 || obj.from[i] < -16) clip = true
+ if (obj.to[i] > 32 || obj.to[i] < -16) clip = true
+ })
+ if (clip) {
+ overflow.push(obj)
+ }
+ })
+ cancelScaleAll()
+ selected.length = 0;
+ overflow.forEach(cube => {
+ selected.push(cube)
+ })
+ updateSelection();
+}
//Center
function centerCubesAll(axis) {
centerCubes(0, false)
@@ -474,19 +477,24 @@ function rotateOnAxis(value, fixed, axis) {
var axis_letter = getAxisLetter(axis)
var origin = selected[0].origin
selected.forEach(function(obj, i) {
- if (!obj.rotation.equals([0,0,0])) {
+ if (!obj.rotation.allEqual(0)) {
origin = obj.origin
}
})
+ if (origin.allEqual(8)) {
+ origin = getSelectionCenter()
+ origin.forEach((n, ni) => {
+ origin[ni] = Math.round(n*2)/2
+ })
+ }
selected.forEach(function(obj, i) {
- if (obj.rotation.equals([0,0,0])) {
+ if (obj.rotation.allEqual(0)) {
obj.origin = origin.slice()
}
var obj_val = value;
if (!fixed) {
obj_val += obj.rotation[axis]
}
-
obj_val = Math.trimDeg(obj_val)
if (settings.limited_rotation.value) {
//Limit To 1 Axis
@@ -813,6 +821,7 @@ BARS.defineActions(function() {
}, 'group', true)
}
showDialog('scaling')
+ scaleAll(false, 1)
}
})
new Action({
@@ -964,6 +973,14 @@ BARS.defineActions(function() {
id: 'toggle_shade',
icon: 'wb_sunny',
category: 'transform',
+ condition: () => !Blockbench.entity_mode,
+ click: function () {toggleCubeProperty('shade')}
+ })
+ new Action({
+ id: 'toggle_mirror_uv',
+ icon: 'icon-mirror_x',
+ category: 'transform',
+ condition: () => Blockbench.entity_mode,
click: function () {toggleCubeProperty('shade')}
})
new Action({
diff --git a/js/undo.js b/js/undo.js
index 4d81c01a8..7728f7c6c 100644
--- a/js/undo.js
+++ b/js/undo.js
@@ -12,8 +12,10 @@ var Undo = {
Undo.current_save = new Undo.save(aspects)
},
finishEdit: function(action, aspects) {
+ if (!Undo.current_save) return;
aspects = aspects || Undo.current_save.aspects
//After
+ Blockbench.dispatchEvent('finish_edit', {aspects})
var entry = {
before: Undo.current_save,
post: new Undo.save(aspects),
@@ -34,6 +36,7 @@ var Undo = {
if (!aspects || !aspects.keep_saved) {
Prop.project_saved = false;
}
+ Blockbench.dispatchEvent('finished_edit', {aspects})
},
cancelEdit: function() {
if (!Undo.current_save) return;
@@ -50,7 +53,7 @@ var Undo = {
var entry = Undo.history[Undo.index]
Undo.loadSave(entry.before, entry.post)
console.log('Undo: '+entry.action)
- Blockbench.dispatchEvent('undo', {entry: entry})
+ Blockbench.dispatchEvent('undo', {entry})
},
redo: function() {
if (Undo.history.length <= 0) return;
@@ -63,7 +66,7 @@ var Undo = {
var entry = Undo.history[Undo.index-1]
Undo.loadSave(entry.post, entry.before)
console.log('Redo: '+entry.action)
- Blockbench.dispatchEvent('redo', {})
+ Blockbench.dispatchEvent('redo', {entry})
},
getItemByUUID: function(list, uuid) {
if (!list || typeof list !== 'object' || !list.length) {return false;}
@@ -75,7 +78,6 @@ var Undo = {
i++;
}
return false;
-
},
save: function(aspects) {
var scope = this;
@@ -168,7 +170,7 @@ var Undo = {
var obj = elements.findInArray('uuid', uuid)
if (obj) {
for (var face in obj.faces) {
- obj.faces[face] = {uv: []}
+ obj.faces[face].reset()
}
obj.extend(data)
Canvas.adaptObjectPosition(obj)
diff --git a/js/util.js b/js/util.js
index f06abdd8b..d102a1fc6 100644
--- a/js/util.js
+++ b/js/util.js
@@ -60,6 +60,17 @@ const Condition = function(condition, context) {
return !!condition
}
}
+class oneLiner {
+ constructor(data) {
+ if (data !== undefined) {
+ for (var key in data) {
+ if (data.hasOwnProperty(key)) {
+ this[key] = data[key]
+ }
+ }
+ }
+ }
+}
var cl = console.log
var asyncLoop = function(o){
var i=-1;
@@ -81,6 +92,20 @@ function guid() {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
+function bbuid(l) {
+ l = l || 1
+ let chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ var s = '';
+ while (l > 0) {
+ var n = Math.floor(Math.random()*62)
+ if (n > 9) {
+ n = chars[n-10]
+ }
+ s += n
+ l--;
+ }
+ return s;
+}
Math.radToDeg = function(rad) {
return rad / Math.PI * 180
}
@@ -125,6 +150,7 @@ function limitNumber(number, min, max) {
if (number < min || isNaN(number)) number = min;
return number;
}
+Math.clamp = limitNumber;
function getRectangle(a, b, c, d) {
var rect = {};
if (!b && typeof a === 'object') {
@@ -203,6 +229,7 @@ Array.prototype.remove = function (item) { {
}
Array.prototype.empty = function() {
this.length = 0;
+ return this;
}
Array.prototype.findInArray = function(key, value) {
for (var i = 0; i < this.length; i++) {
diff --git a/js/uv.js b/js/uv.js
index 102f2f6ec..dfef1b595 100644
--- a/js/uv.js
+++ b/js/uv.js
@@ -115,7 +115,10 @@ class UVEditor {
Undo.initEdit({cubes: selected})
}
var onAfter = function() {
- Undo.finishEdit('dones')
+ Undo.finishEdit('edit UV')
+ if (Blockbench.entity_mode) {
+ scope.displayAllMappingOverlays()
+ }
}
var getInterval = function(event) {
return Blockbench.entity_mode
@@ -226,16 +229,6 @@ class UVEditor {
$(this).find('.uv_mapping_overlay').remove()
})
- this.jquery.main.on('mousewheel', function() {
- if (Blockbench.entity_mode) {
- scope.displayMappingOverlay()
- scope.jquery.main.on('mousemove', function() {
- $(scope.jquery.size).find('.uv_mapping_overlay').remove()
- scope.jquery.main.off('mousemove')
- })
- }
- })
-
if (toolbar) {
this.jquery.bar = $(Toolbars.main_uv.node)
this.jquery.main.append(this.jquery.bar)
@@ -289,6 +282,9 @@ class UVEditor {
Undo.finishEdit('uv_change')
scope.disableAutoUV()
scope.updateDragHandle(ui.position)
+ if (Blockbench.entity_mode) {
+ scope.displayAllMappingOverlays()
+ }
}
})
@@ -309,13 +305,25 @@ class UVEditor {
})
this.jquery.frame.mousedown(function(event) {
- if (Toolbox.selected.id === 'brush_tool') {
+ if (Toolbox.selected.paintTool) {
scope.startBrush(event)
}
})
this.setSize(this.size)
return this;
}
+ message(msg, vars) {
+ msg = tl(msg, vars)
+ var box = $('
' + msg + '
')
+ this.jquery.frame.append(box)
+ setTimeout(function() {
+ box.fadeOut(200)
+ setTimeout(function() {
+ box.remove()
+ }, 300)
+ }, 1000)
+ }
+ //Brush
getBrushCoordinates(event, tex) {
var scope = this;
var multiplier = (Blockbench.entity_mode && tex) ? tex.res/Project.texture_width : 1
@@ -332,11 +340,10 @@ class UVEditor {
var texture = scope.getTexture()
if (texture) {
Painter.current.x = Painter.current.y = 0
- var x = scope.getBrushCoordinates(event, texture).x
- var y = scope.getBrushCoordinates(event, texture).y
- Painter.startBrush(texture, x, y, undefined, event)
+ var coords = scope.getBrushCoordinates(event, texture)
+ Painter.startBrush(texture, coords.x, coords.y, undefined, event)
}
- if (event.altKey === false && texture && texture.mode !== 'link') {
+ if (Toolbox.selected.id !== 'color_picker' && texture) {
scope.jquery.frame.get(0).addEventListener('mousemove', scope.moveBrush, false );
document.addEventListener('mouseup', scope.stopBrush, false );
}
@@ -386,17 +393,6 @@ class UVEditor {
document.removeEventListener( 'mouseup', scope.stopBrush, false );
Painter.stopBrush()
}
- message(msg, vars) {
- msg = tl(msg, vars)
- var box = $('
' + msg + '
')
- this.jquery.frame.append(box)
- setTimeout(function() {
- box.fadeOut(200)
- setTimeout(function() {
- box.remove()
- }, 300)
- }, 1000)
- }
//Get
getPixelSize() {
if (Blockbench.entity_mode) {
@@ -426,7 +422,7 @@ class UVEditor {
}
}
getTexture() {
- return getTextureById(selected[0].faces[this.face].texture)
+ return selected[0].faces[this.face].getTexture()
}
forCubes(cb) {
var i = 0;
@@ -437,6 +433,7 @@ class UVEditor {
}
//Set
setSize(size, cancel_load) {
+ var old_size = this.size;
this.size = size
this.jquery.frame.width(size)
if (uv_dialog.editors !== undefined && this === uv_dialog.editors.single) {
@@ -447,6 +444,9 @@ class UVEditor {
this.height = size / (Project.texture_width/Project.texture_height)
this.jquery.frame.height(this.height)
$('.panel#textures').css('top', 133+(size / (Project.texture_width/Project.texture_height))+'px')
+ if (old_size !== size) {
+ this.displayAllMappingOverlays(true)
+ }
} else {
this.height = size
this.jquery.frame.height(size)
@@ -489,12 +489,14 @@ class UVEditor {
}
if (load !== false) this.loadData()
}
- setFace(face) {
+ setFace(face, update) {
this.face = face
- this.loadData()
if (this.id === 'main_uv') {
$('input#'+face+'_radio').prop("checked", true)
}
+ if (update !== false) {
+ this.loadData()
+ }
return this;
}
setFrameColor(black) {
@@ -542,12 +544,14 @@ class UVEditor {
//Set Rotation
BarItems.uv_rotation.set(face.rotation||0)
- this.displayTexture(face.texture)
+ this.displayTexture(face)
this.displayFrame()//and transform info
this.displayTools()
this.displaySliders()
this.updateDragHandle()
-
+ if (Blockbench.entity_mode) {
+ this.displayAllMappingOverlays()
+ }
if (this.id !== 'main_uv') {
this.displayTools()
}
@@ -570,12 +574,14 @@ class UVEditor {
})
} else {
-
+ var trim = v => Math.round(v*1000+0.3)/1000;
var pixelSize = this.size/16
- var left = this.jquery.size.position().left / pixelSize
- var top = this.jquery.size.position().top / pixelSize * (Project.texture_width/Project.texture_height)
- var left2 = (this.jquery.size.width()) / pixelSize + left
- var top2 = (this.jquery.size.height()) / pixelSize + top
+
+ var left = trim( this.jquery.size.position().left / pixelSize);
+ var top = trim( this.jquery.size.position().top / pixelSize * (Project.texture_width/Project.texture_height));
+ var left2= Math.clamp(trim( (this.jquery.size.width()) / pixelSize + left), 0, 16);
+ var top2 = Math.clamp(trim( (this.jquery.size.height()) / pixelSize + top), 0, 16);
+
var uvTag = this.getUVTag()
if (uvTag[0] > uvTag[2]) {
@@ -600,25 +606,21 @@ class UVEditor {
main_uv.loadData()
}
}
- applyTexture(id) {
+ applyTexture(uuid) {
var scope = this;
Undo.initEdit({cubes: selected, uv_only: true})
this.forCubes(obj => {
- obj.faces[scope.face].texture = '#'+id
+ obj.faces[scope.face].texture = uuid
})
this.loadData()
Canvas.updateSelectedFaces()
Undo.finishEdit('apply_texture')
}
- displayTexture(id) {
- if (!id || id === null) {
+ displayTexture(face) {
+ var tex = face.getTexture()
+ if (!tex || typeof tex !== 'object' || tex.error) {
this.displayEmptyTexture()
} else {
- var tex = getTextureById(id+'')
- if (tex === undefined || tex.error) {
- this.displayEmptyTexture()
- return;
- }
this.setFrameColor(tex.dark_box)
var css = 'url("'+tex.source.split('\\').join('\\\\').replace(/ /g, '%20')+'")'
this.jquery.frame.css('background-image', css)
@@ -717,24 +719,40 @@ class UVEditor {
this.updateDragHandle()
this.displayTransformInfo()
}
+ //Overlay
displayMappingOverlay() {
if (!Blockbench.entity_mode) return this;
var scope = this;
+ var sides = this.getMappingOverlay()
+
+ $(scope.jquery.size).find('.uv_mapping_overlay').remove()
+ scope.jquery.size.append(sides)
+
+ return this;
+ }
+ getMappingOverlay(cube, absolute) {
+ var scope = this;
+ var sides = $('
')
var pixels = scope.getPixelSize()
+ if (!cube) cube = selected[0]
function addElement(x, y, width, height, n, color) {
+ if (absolute) {
+ x += cube.uv_offset[0];
+ y += cube.uv_offset[1];
+ }
x *= pixels;
y *= pixels;
width = limitNumber(width *pixels + x, 0, scope.size) - x;
height = limitNumber(height*pixels + y, 0, scope.height)- y;
- scope.jquery.size.append('
')
+ sides.append($(`
`))
}
- var size = selected[0].size(undefined, true)
+ var size = cube.size(undefined, true)
- $(scope.jquery.size).find('.uv_mapping_overlay').remove()
+ sides.attr('size_hash', `${cube.uv_offset[0]}_${cube.uv_offset[1]}_${size[0]}_${size[1]}_${size[2]}`)
addElement(size[2], 0, size[0], size[2], '#b4d4e1', '#ecf8fd')
addElement(size[2]+size[0], 0, size[0], size[2], '#536174', '#6e788c')
@@ -742,7 +760,32 @@ class UVEditor {
addElement(size[2], size[2], size[0], size[1], '#5bbcf4', '#7BD4FF')
addElement(size[2]+size[0], size[2], size[2], size[1], '#f48686', '#FFA7A4')
addElement(2*size[2]+size[0], size[2], size[0], size[1],'#f8dd72', '#FFF899')
+
+ return sides;
}
+ displayAllMappingOverlays(force_reload) {
+ var scope = this;
+ var cycle = bbuid(4)
+ if (this.showing_overlays) {
+ elements.forEach(cube => {
+ var size = cube.size(undefined, true)
+ var hash = `${cube.uv_offset[0]}_${cube.uv_offset[1]}_${size[0]}_${size[1]}_${size[2]}`
+ var c = scope.jquery.frame.find(`.mapping_overlay_cube:not(.${cycle})[size_hash="${hash}"]`).first()
+ if (force_reload || !c.length) {
+ var sides = scope.getMappingOverlay(cube, true)
+ sides.addClass(cycle)
+ scope.jquery.frame.append(sides)
+ } else {
+ c.addClass(cycle)
+ }
+ })
+ $(`.mapping_overlay_cube:not(.${cycle})`).remove()
+ $('.mapping_overlay_cube').removeClass(cycle)
+ } else {
+ $(scope.jquery.frame).find('.mapping_overlay_cube').remove()
+ }
+ }
+ //UI
displaySliders() {
this.sliders.pos_x.update()
this.sliders.pos_y.update()
@@ -753,7 +796,7 @@ class UVEditor {
//Cullface
var face = selected[0].faces[this.face]
BarItems.cullface.set(face.cullface||'off')
- BarItems.face_tint.setIcon(face.tintindex !== undefined ? 'check_box' : 'check_box_outline_blank')
+ BarItems.face_tint.setIcon(face.tint ? 'check_box' : 'check_box_outline_blank')
}
updateDragHandle() {
var pos = this.jquery.size.position()
@@ -914,10 +957,10 @@ class UVEditor {
break;
case 'east':
uv = [
- 16 - obj.from[2],
- 16 - obj.from[1],
16 - obj.to[2],
16 - obj.to[1],
+ 16 - obj.from[2],
+ 16 - obj.from[1],
];
break;
case 'up':
@@ -1024,15 +1067,11 @@ class UVEditor {
}
switchTint(event) {
var scope = this;
- var val = selected[0].faces[scope.face].tintindex === undefined
+ var val = !selected[0].faces[scope.face].tint
if (event === true || event === false) val = event
this.forCubes(obj => {
- if (val) {
- obj.faces[scope.face].tintindex = 0
- } else {
- delete obj.faces[scope.face].tintindex
- }
+ obj.faces[scope.face].tint = val
})
if (val) {
this.message('uv_editor.tint_on')
@@ -1043,13 +1082,9 @@ class UVEditor {
}
rotate() {
var scope = this;
- var value = BarItems.uv_rotation.get()
+ var value = parseInt(BarItems.uv_rotation.get())
this.forCubes(obj => {
- if (value == 0) {
- delete obj.faces[scope.face].rotation
- } else {
- obj.faces[scope.face].rotation = parseInt(value)
- }
+ obj.faces[scope.face].rotation = value
Canvas.updateUV(obj)
})
this.displayTransformInfo()
@@ -1057,12 +1092,9 @@ class UVEditor {
}
setRotation(value) {
var scope = this;
+ value = parseInt(value)
this.forCubes(obj => {
- if (value == 0) {
- delete obj.faces[scope.face].rotation
- } else {
- obj.faces[scope.face].rotation = parseInt(value)
- }
+ obj.faces[scope.face].rotation = value
Canvas.updateUV(obj)
})
this.loadData()
@@ -1105,15 +1137,7 @@ class UVEditor {
return;
}
var tag = selected[0].faces[face]
- var new_tag = {
- uv: tag.uv.slice(),
- face: face
- }
- if (tag.texture !== undefined) new_tag.texture = tag.texture
- if (tag.cullface) new_tag.cullface = tag.cullface
- if (tag.rotation) new_tag.rotation = tag.rotation
- if (tag.enabled !== undefined) new_tag.enabled = tag.enabled
- if (tag.tintindex !== undefined) new_tag.tintindex = tag.tintindex
+ var new_tag = new Face().extend(tag)
uv_dialog.clipboard.push(new_tag)
}
if (event.shiftKey) {
@@ -1141,15 +1165,7 @@ class UVEditor {
function applyFace(tag, face) {
if (!face) face = tag.face
selected.forEach(function(obj) {
- var target = obj.faces[face]
- target.uv = tag.uv.slice()
-
- if (tag.texture !== undefined || target.texture !== undefined) target.texture = tag.texture
- if (tag.cullface || target.cullface) target.cullface = tag.cullface
- if (tag.rotation || target.rotation) target.rotation = tag.rotation
- if (tag.enabled !== undefined || target.enabled !== undefined) target.enabled = tag.enabled
- if (tag.tintindex !== undefined || target.texture !== undefined) target.tintindex = tag.tintindex
-
+ obj.faces[face].extend(tag)
Canvas.updateUV(obj)
})
}
@@ -1194,12 +1210,7 @@ class UVEditor {
var scope = this;
this.forCubes(obj => {
scope.getFaces(event).forEach(function(side) {
- obj.faces[side].uv = [0, 0, 1, 1]
- delete obj.faces[side].texture;
- delete obj.faces[side].rotation;
- delete obj.faces[side].tintindex;
- delete obj.faces[side].enabled;
- delete obj.faces[side].cullface;
+ obj.faces[side].reset()
})
Canvas.adaptObjectFaces(obj)
})
@@ -1213,6 +1224,9 @@ class UVEditor {
}
}
UVEditor.prototype.menu = new Menu([
+ 'copy',
+ 'paste',
+ /*
{icon: 'content_copy', name: 'menu.uv.copy', click: function(editor) {
editor.copy(event)
}},
@@ -1220,28 +1234,16 @@ class UVEditor {
Undo.initEdit({cubes: selected, uv_only: true})
editor.paste(event)
Undo.finishEdit('uv_paste')
- }},
+ }},*/
{icon: 'photo_size_select_large', name: 'menu.uv.mapping', children: function(editor) { return [
{icon: editor.reference_face.enabled!==false ? 'check_box' : 'check_box_outline_blank', name: 'menu.uv.mapping.export', click: function(editor) {
Undo.initEdit({cubes: selected, uv_only: true})
editor.toggleUV(event)
Undo.finishEdit('uv_toggle')
}},
- {icon: 'zoom_out_map', name: 'menu.uv.mapping.maximize', click: function(editor) {
- Undo.initEdit({cubes: selected, uv_only: true})
- editor.maximize(event)
- Undo.finishEdit('uv_maximize')
- }},
- {icon: 'brightness_auto', name: 'menu.uv.mapping.auto', click: function(editor) {
- Undo.initEdit({cubes: selected, uv_only: true})
- editor.setAutoSize(event)
- Undo.finishEdit('uv_auto')
- }},
- {icon: 'brightness_auto', name: 'menu.uv.mapping.rel_auto', click: function(editor) {
- Undo.initEdit({cubes: selected, uv_only: true})
- editor.setRelativeAutoSize(event)
- Undo.finishEdit('uv_auto')
- }},
+ 'uv_maximize',
+ 'uv_auto',
+ 'uv_rel_auto',
{icon: 'rotate_90_degrees_ccw', name: 'menu.uv.mapping.rotation', children: function() {
var off = 'radio_button_unchecked'
var on = 'radio_button_checked'
@@ -1275,7 +1277,8 @@ class UVEditor {
Undo.initEdit({cubes: selected, uv_only: true})
editor.mirrorX(event)
Undo.finishEdit('uv_mirror')
- }},
+ }
+ },
{
icon: (editor.reference_face.uv[1] > editor.reference_face.uv[3] ? 'check_box' : 'check_box_outline_blank'),
name: 'menu.uv.mapping.mirror_y',
@@ -1283,13 +1286,14 @@ class UVEditor {
Undo.initEdit({cubes: selected, uv_only: true})
editor.mirrorY(event)
Undo.finishEdit('uv_mirror')
- }},
+ }
+ },
]}},
{
- icon: (editor) => (editor.reference_face.tintindex === 0 ? 'check_box' : 'check_box_outline_blank'),
+ icon: (editor) => (editor.reference_face.tint ? 'check_box' : 'check_box_outline_blank'),
name: 'menu.uv.tint', click: function(editor) {
Undo.initEdit({cubes: selected, uv_only: true})
- editor.switchTint(selected[0].faces[editor.face].tintindex !== 0)
+ editor.switchTint(selected[0].faces[editor.face].tint)
Undo.finishEdit('face_tint')
}
},
@@ -1313,7 +1317,7 @@ class UVEditor {
arr.push({
name: t.name,
icon: (t.mode === 'link' ? t.img : t.source),
- click: function(editor) {editor.applyTexture(t.id)}
+ click: function(editor) {editor.applyTexture(t.uuid)}
})
})
return arr;
@@ -1552,16 +1556,7 @@ const uv_dialog = {
function addToClipboard(face) {
var tag = selected[0].faces[face]
- var new_tag = {
- uv: tag.uv.slice(),
- face: face
- }
- if (tag.texture) new_tag.texture = tag.texture
- if (tag.cullface) new_tag.cullface = tag.cullface
- if (tag.rotation) new_tag.rotation = tag.rotation
- if (tag.enabled !== undefined) new_tag.enabled = tag.enabled
- if (tag.tintindex !== undefined) new_tag.tintindex = tag.tintindex
- uv_dialog.clipboard.push(new_tag)
+ uv_dialog.clipboard.push(new Face(tag))
}
if (uv_dialog.hoveredSide) {
addToClipboard(uv_dialog.hoveredSide)
@@ -1583,15 +1578,7 @@ const uv_dialog = {
function applyFace(tag, face) {
if (!face) face = tag.face
selected.forEach(function(obj) {
- var target = obj.faces[face]
- target.uv = tag.uv.slice()
-
- if (tag.texture || target.texture) target.texture = tag.texture
- if (tag.cullface || target.cullface) target.cullface = tag.cullface
- if (tag.rotation || target.rotation) target.rotation = tag.rotation
- if (tag.enabled !== undefined || target.enabled !== undefined) target.enabled = tag.enabled
- if (tag.tintindex !== undefined || target.texture !== undefined) target.tintindex = tag.tintindex
-
+ obj.faces[face].extend(tag)
Canvas.updateUV(obj)
})
}
@@ -1646,7 +1633,7 @@ BARS.defineActions(function() {
onChange: function(slider) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('rotate')
- Undo.finishEdit('uv')
+ Undo.finishEdit('uv rotate')
}
})
new BarSelect({
@@ -1677,7 +1664,7 @@ BARS.defineActions(function() {
click: function (event) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('maximize', event)
- Undo.finishEdit('uv')
+ Undo.finishEdit('uv maximize')
}
})
new Action({
@@ -1688,7 +1675,7 @@ BARS.defineActions(function() {
click: function (event) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('setAutoSize', event)
- Undo.finishEdit('uv')
+ Undo.finishEdit('auto uv')
}
})
new Action({
@@ -1699,7 +1686,7 @@ BARS.defineActions(function() {
click: function (event) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('setRelativeAutoSize', event)
- Undo.finishEdit('uv')
+ Undo.finishEdit('auto uv')
}
})
new Action({
@@ -1710,7 +1697,7 @@ BARS.defineActions(function() {
click: function (event) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('mirrorX', event)
- Undo.finishEdit('uv')
+ Undo.finishEdit('mirror uv')
}
})
new Action({
@@ -1721,7 +1708,7 @@ BARS.defineActions(function() {
click: function (event) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('mirrorY', event)
- Undo.finishEdit('uv')
+ Undo.finishEdit('mirror uv')
}
})
new Action({
@@ -1732,7 +1719,7 @@ BARS.defineActions(function() {
click: function (event) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('clear', event)
- Undo.finishEdit('uv')
+ Undo.finishEdit('remove face')
}
})
new Action({
@@ -1743,7 +1730,7 @@ BARS.defineActions(function() {
click: function (event) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('reset', event)
- Undo.finishEdit('uv')
+ Undo.finishEdit('reset uv')
}
})
new Action({
@@ -1754,7 +1741,7 @@ BARS.defineActions(function() {
click: function (e) {
Undo.initEdit({cubes: selected, uv_only: true})
main_uv.applyAll(e)
- Undo.finishEdit('uv')
+ Undo.finishEdit('uv apply all')
}
})
new BarSelect({
@@ -1773,7 +1760,7 @@ BARS.defineActions(function() {
onChange: function(sel, event) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('switchCullface')
- Undo.finishEdit('uv')
+ Undo.finishEdit('cullface')
}
})
new Action({
@@ -1784,7 +1771,7 @@ BARS.defineActions(function() {
click: function (event) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('autoCullface', event)
- Undo.finishEdit('uv')
+ Undo.finishEdit('auto cullface')
}
})
new Action({
@@ -1794,7 +1781,7 @@ BARS.defineActions(function() {
click: function (event) {
Undo.initEdit({cubes: selected, uv_only: true})
uv_dialog.forSelection('switchTint', event)
- Undo.finishEdit('uv')
+ Undo.finishEdit('tint')
}
})
new Action({
@@ -1806,4 +1793,15 @@ BARS.defineActions(function() {
showUVShiftDialog()
}
})
+ new Action({
+ id: 'toggle_uv_overlay',
+ condition: () => Blockbench.entity_mode,
+ icon: 'crop_landscape',//'crop_landscape'
+ category: 'uv',
+ click: function () {
+ main_uv.showing_overlays = !main_uv.showing_overlays
+ BarItems.toggle_uv_overlay.setIcon(main_uv.showing_overlays ? 'view_quilt' : 'crop_landscape')
+ main_uv.displayAllMappingOverlays()
+ }
+ })
})
diff --git a/js/web.js b/js/web.js
index 5f1d19e62..3f9c66e7e 100644
--- a/js/web.js
+++ b/js/web.js
@@ -22,12 +22,10 @@ function tryLoadPOSTModel() {
if ($('#post_textures').text() !== '') {
var data = JSON.parse( $('#post_textures').text() )
for (var key in data) {
- if (data.hasOwnProperty(key)) {
- var tex = getTextureById(key+'');
- if (tex) {
- tex.img.src = ''
- tex.source = 'data:image/png;base64,'+data[key]
- }
+ var tex = textures.findInArray('id', key+'');
+ if (tex) {
+ tex.img.src = ''
+ tex.source = 'data:image/png;base64,'+data[key]
}
}
textures.forEach(function(tex) {
diff --git a/lang/de.json b/lang/de.json
index 321daef96..0dd46898d 100644
--- a/lang/de.json
+++ b/lang/de.json
@@ -561,13 +561,8 @@
"menu.preview.quadview": "Vierfachansicht",
"menu.preview.fullview": "Vollansicht",
"menu.preview.stop_drag": "Hintergrundpositionierung beenden",
- "menu.uv.copy": "Kopieren",
- "menu.uv.paste": "Einfügen",
"menu.uv.mapping": "UV Mapping",
"menu.uv.mapping.export": "Exportieren",
- "menu.uv.mapping.maximize": "Maximieren",
- "menu.uv.mapping.auto": "Auto UV",
- "menu.uv.mapping.rel_auto": "Rel. Auto UV",
"menu.uv.mapping.rotation": "Drehung",
"menu.uv.mapping.mirror_x": "Spiegeln X",
"menu.uv.mapping.mirror_y": "Spiegeln Y",
@@ -825,5 +820,21 @@
"action.open_backup_folder": "Backup-Ordner öffnen",
"action.open_backup_folder.desc": "Öffnet den Backup-Ordner von Blockbench",
"switches.mirror": "UV Spiegeln",
- "language_name": "Deutsch"
+ "language_name": "Deutsch",
+ "message.plugin_reload": "%0 lokale Plugins wurden neugeladen",
+ "settings.brightness": "Helligkeit",
+ "settings.brightness.desc": "Helligkeit der Vorschau. Standardwert ist 50",
+ "menu.preview.perspective.reset": "Kamera zurücksetzen",
+ "action.fill_mode": "Füllmodus",
+ "action.fill_mode.desc": "Modus des Farbeimers",
+ "action.fill_mode.face": "Fläche",
+ "action.fill_mode.color": "Farbe",
+ "action.fill_mode.cube": "Element",
+ "action.toggle_mirror_uv": "UV spiegeln",
+ "action.toggle_mirror_uv.desc": "UV Mapping der ausgewählten Elemente auf der X Achse spiegeln.",
+ "action.toggle_uv_overlay": "UV Maske einblenden",
+ "action.toggle_uv_overlay.desc": "Blendet UV Masken für alle Elemente über der Textur ein",
+ "menu.texture.blank": "Auf leere Flächen anwenden",
+ "dialog.scale.select_overflow": "Überstehendes auswählen",
+ "dialog.create_texture.compress": "Template verdichten"
}
\ No newline at end of file
diff --git a/lang/en.json b/lang/en.json
index d83d4695a..955006d1e 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -142,6 +142,7 @@
"message.invalid_plugin": "Invalid Plugin File, See Console",
"message.load_plugin_app": "Do you want to allow this plugin to make changes to your PC? Only load plugins from people you trust.",
"message.load_plugin_web": "Do you want to load this plugin? Only load plugins from people you trust.",
+ "message.plugin_reload": "Reloaded %0 local plugins",
"message.preset_no_info": "Preset does not contain information for this slot",
"message.restart_to_update": "Restart Blockbench to apply changes",
"message.save_file": "Saved as %0",
@@ -201,6 +202,7 @@
"dialog.scale.scale": "Scale",
"dialog.scale.clipping": "Model clipping: Your model is too large for the canvas",
"dialog.scale.confirm": "Scale",
+ "dialog.scale.select_overflow": "Select Overflow",
"dialog.plugins.title": "Plugins",
"dialog.plugins.installed": "Installed",
@@ -228,6 +230,7 @@
"dialog.create_texture.name": "Name",
"dialog.create_texture.folder": "Folder",
"dialog.create_texture.template": "Template",
+ "dialog.create_texture.compress": "Compress Template",
"dialog.create_texture.resolution": "Resolution",
"dialog.create_gif.title": "Record GIF",
@@ -325,6 +328,8 @@
"settings.display_skin.desc": "Skin used for the display reference player model",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects",
+ "settings.brightness": "Brightness",
+ "settings.brightness.desc": "Brightness of the preview. Default is 50",
"settings.shading": "Shading",
"settings.shading.desc": "Enable shading",
"settings.transparency": "Transparency",
@@ -441,6 +446,11 @@
"action.brush_mode.desc": "Mode of the brush",
"action.brush_mode.brush": "Round",
"action.brush_mode.noise": "Noise",
+ "action.fill_mode": "Fill Mode",
+ "action.fill_mode.desc": "Mode of the fill tool",
+ "action.fill_mode.face": "Face",
+ "action.fill_mode.color": "Color",
+ "action.fill_mode.cube": "Cube",
"action.brush_color": "Color",
"action.brush_color.desc": "Color of the brush",
"action.slider_brush_size": "Size",
@@ -614,6 +624,8 @@
"action.toggle_autouv.desc": "Toggle the auto UV setting of the selected cubes.",
"action.toggle_shade": "Toggle Shading",
"action.toggle_shade.desc": "Toggle the shading of the selected cubes.",
+ "action.toggle_mirror_uv": "Mirror UV",
+ "action.toggle_mirror_uv.desc": "Toggle the UV mirroring on the X axis of the selected cubes.",
"action.rename": "Rename",
"action.rename.desc": "Change the name of the selected cubes.",
"action.update_autouv": "Update Auto UV",
@@ -710,6 +722,8 @@
"action.face_tint.desc": "Enables the tint option for the current face",
"action.uv_shift": "Shift UV",
"action.uv_shift.desc": "Shift all UV regions by a fixed amount or mathematical expression",
+ "action.toggle_uv_overlay": "Toggle UV Overlay",
+ "action.toggle_uv_overlay.desc": "When enabled, displays all UV mapping overlays above the texture.",
"action.add_animation": "Add Animation",
"action.add_animation.desc": "Create a blank animation",
@@ -768,6 +782,7 @@
"menu.group.resolve": "Resolve",
"menu.texture.face": "Apply to Face",
+ "menu.texture.blank": "Apply to Untextured Faces",
"menu.texture.cube": "Apply to Cubes",
"menu.texture.file": "File",
"menu.texture.refresh": "Refresh",
@@ -788,17 +803,13 @@
"menu.preview.screenshot": "Screenshot",
"menu.preview.perspective": "Perspective",
"menu.preview.perspective.normal": "Normal",
+ "menu.preview.perspective.reset": "Reset Camera",
"menu.preview.quadview": "Quad View",
"menu.preview.fullview": "Full View",
"menu.preview.stop_drag": "Stop Background Positioning",
- "menu.uv.copy": "Copy",
- "menu.uv.paste": "Paste",
"menu.uv.mapping": "UV Mapping",
"menu.uv.mapping.export": "Export",
- "menu.uv.mapping.maximize": "Maximize",
- "menu.uv.mapping.auto": "Auto UV",
- "menu.uv.mapping.rel_auto": "Rel. Auto UV",
"menu.uv.mapping.rotation": "Rotation",
"menu.uv.mapping.mirror_x": "Mirror X",
"menu.uv.mapping.mirror_y": "Mirror Y",
diff --git a/lang/es.json b/lang/es.json
index 208594934..89a556fc8 100644
--- a/lang/es.json
+++ b/lang/es.json
@@ -561,13 +561,8 @@
"menu.preview.quadview": "Vista Cuádruple",
"menu.preview.fullview": "Vista Completa",
"menu.preview.stop_drag": "Parar la Colocación del Fondo",
- "menu.uv.copy": "Copiar",
- "menu.uv.paste": "Pegar",
"menu.uv.mapping": "Mapeado del UV",
"menu.uv.mapping.export": "Exportar",
- "menu.uv.mapping.maximize": "Maximizar",
- "menu.uv.mapping.auto": "Auto UV",
- "menu.uv.mapping.rel_auto": "Rel. Auto UV",
"menu.uv.mapping.rotation": "Rotación",
"menu.uv.mapping.mirror_x": "Invertir X",
"menu.uv.mapping.mirror_y": "Invertir Y",
@@ -824,6 +819,22 @@
"action.color_picker.desc": "Herramienta para seleccionar el color de píxeles en tu textura",
"action.open_backup_folder": "Abrir Carpeta de Backups",
"action.open_backup_folder.desc": "Abre la carpeta de backups de Blockbench",
- "switches.mirror": "Mirror UV",
- "language_name": "English"
+ "switches.mirror": "Invertir UV",
+ "language_name": "Inglés",
+ "message.plugin_reload": "Reloaded %0 local plugins",
+ "settings.brightness": "Brightness",
+ "settings.brightness.desc": "Brightness of the preview. Default is 50",
+ "menu.preview.perspective.reset": "Reset Camera",
+ "action.fill_mode": "Fill Mode",
+ "action.fill_mode.desc": "Mode of the fill tool",
+ "action.fill_mode.face": "Face",
+ "action.fill_mode.color": "Color",
+ "action.fill_mode.cube": "Cube",
+ "action.toggle_mirror_uv": "Mirror UV",
+ "action.toggle_mirror_uv.desc": "Toggle the UV mirroring on the X axis of the selected cubes.",
+ "action.toggle_uv_overlay": "Toggle UV Overlay",
+ "action.toggle_uv_overlay.desc": "When enabled, displays all UV mapping overlays above the texture.",
+ "menu.texture.blank": "Apply to Untextured Faces",
+ "dialog.scale.select_overflow": "Select Overflow",
+ "dialog.create_texture.compress": "Compress Template"
}
\ No newline at end of file
diff --git a/lang/fr.json b/lang/fr.json
index 19e47b116..27751c4ec 100644
--- a/lang/fr.json
+++ b/lang/fr.json
@@ -561,13 +561,8 @@
"menu.preview.quadview": "Quadruple vue",
"menu.preview.fullview": "Vue complète",
"menu.preview.stop_drag": "Arrêter le positionnement en arrière-plan",
- "menu.uv.copy": "Copier",
- "menu.uv.paste": "Coller",
"menu.uv.mapping": "Cartographie UV",
"menu.uv.mapping.export": "Exporter",
- "menu.uv.mapping.maximize": "Maximiser",
- "menu.uv.mapping.auto": "UV automatique",
- "menu.uv.mapping.rel_auto": "Rel. UV automatique",
"menu.uv.mapping.rotation": "Rotation",
"menu.uv.mapping.mirror_x": "Miroir X",
"menu.uv.mapping.mirror_y": "Miroir Y",
@@ -825,5 +820,21 @@
"action.open_backup_folder": "Ouvrir le dossier de sauvegarde",
"action.open_backup_folder.desc": "Ouvre le dossier de sauvegarde de Blockbench",
"switches.mirror": "Mirror UV",
- "language_name": "English"
+ "language_name": "English",
+ "message.plugin_reload": "Reloaded %0 local plugins",
+ "settings.brightness": "Brightness",
+ "settings.brightness.desc": "Brightness of the preview. Default is 50",
+ "menu.preview.perspective.reset": "Reset Camera",
+ "action.fill_mode": "Fill Mode",
+ "action.fill_mode.desc": "Mode of the fill tool",
+ "action.fill_mode.face": "Face",
+ "action.fill_mode.color": "Color",
+ "action.fill_mode.cube": "Cube",
+ "action.toggle_mirror_uv": "Mirror UV",
+ "action.toggle_mirror_uv.desc": "Toggle the UV mirroring on the X axis of the selected cubes.",
+ "action.toggle_uv_overlay": "Toggle UV Overlay",
+ "action.toggle_uv_overlay.desc": "When enabled, displays all UV mapping overlays above the texture.",
+ "menu.texture.blank": "Apply to Untextured Faces",
+ "dialog.scale.select_overflow": "Select Overflow",
+ "dialog.create_texture.compress": "Compress Template"
}
\ No newline at end of file
diff --git a/lang/ja.json b/lang/ja.json
index 35957ecac..907ca0cbb 100644
--- a/lang/ja.json
+++ b/lang/ja.json
@@ -5,7 +5,7 @@
"dialog.close": "閉じる",
"dialog.import": "インポート",
"dialog.save": "保存",
- "dialog.discard": "削除",
+ "dialog.discard": "保存しない",
"dialog.dontshowagain": "二度と表示しないようにします",
"data.cube": "キューブ",
"data.cubes": "キューブ",
@@ -561,13 +561,8 @@
"menu.preview.quadview": "クワッドビュー",
"menu.preview.fullview": "全景",
"menu.preview.stop_drag": "背景のポジショニングを停止する",
- "menu.uv.copy": "コピー",
- "menu.uv.paste": "ペースト",
"menu.uv.mapping": "UVマッピング",
"menu.uv.mapping.export": "エクスポート",
- "menu.uv.mapping.maximize": "最大化",
- "menu.uv.mapping.auto": "自動UV",
- "menu.uv.mapping.rel_auto": "小.自動UV",
"menu.uv.mapping.rotation": "回転",
"menu.uv.mapping.mirror_x": "ミラーX",
"menu.uv.mapping.mirror_y": "ミラーY",
@@ -743,15 +738,15 @@
"layout.color.wireframe": "ワイヤーフレーム",
"layout.color.wireframe.desc": "Wireframe view lines",
"action.add_animation": "アニメーションを加える",
- "action.add_animation.desc": "action.add_animation.desc",
+ "action.add_animation.desc": "Create a blank animation",
"action.load_animation_file": "アニメーションをインポートする",
- "action.load_animation_file.desc": "action.load_animation_file.desc",
+ "action.load_animation_file.desc": "Import an animation file",
"action.play_animation": "アニメーションを再生する",
- "action.play_animation.desc": "action.play_animation.desc",
+ "action.play_animation.desc": "Preview the selected animation",
"action.export_animation_file": "アニメーションをエクスポートする",
- "action.export_animation_file.desc": "action.export_animation_file.desc",
+ "action.export_animation_file.desc": "Export a json file with the current animations",
"action.slider_keyframe_time": "タイムコード",
- "action.slider_keyframe_time.desc": "action.slider_keyframe_time.desc",
+ "action.slider_keyframe_time.desc": "Change the timecode of the selected keyframes",
"timeline.rotation": "ローテーション",
"timeline.position": "ポジション",
"timeline.scale": "スケール",
@@ -807,23 +802,39 @@
"settings.seethrough_outline": "X-Rey アウトライン",
"settings.seethrough_outline.desc": "オブジェクトを通してアウトラインを表示する",
"mode.edit": "編集",
- "mode.paint": "ペイント",
- "mode.display": "ディスプレイ",
+ "mode.paint": "Paint",
+ "mode.display": "Display",
"mode.animate": "生き物",
- "status_bar.recording_gif": "Recording GIF",
- "status_bar.processing_gif": "Processing GIF",
- "settings.backup_retain": "Backup Retain Duration",
- "settings.backup_retain.desc": "Set how long Blockbench retains old backups in days",
+ "status_bar.recording_gif": "GIFの録音",
+ "status_bar.processing_gif": "GIFの加工処理",
+ "settings.backup_retain": "バックアップ保持期間",
+ "settings.backup_retain.desc": "Blockbenchがバックアップデーターを保持する期間を設定します",
"action.rotate_tool": "回転",
- "action.rotate_tool.desc": "Tool to select and rotate elements",
- "action.fill_tool": "Paint Bucket",
- "action.fill_tool.desc": "Paint bucket to fill entire faces with one color",
- "action.eraser": "Eraser",
- "action.eraser.desc": "Eraser tool to replace colors on a texture with transparency",
- "action.color_picker": "Color Picker",
- "action.color_picker.desc": "Tool to pick the color of pixels on your texture",
- "action.open_backup_folder": "Open Backup Folder",
- "action.open_backup_folder.desc": "Opens the Blockbench backup folder",
- "switches.mirror": "Mirror UV",
- "language_name": "English"
+ "action.rotate_tool.desc": "選択中の要素を回転させることができます",
+ "action.fill_tool": "バケツ",
+ "action.fill_tool.desc": "選択欄を塗りつぶすことができます",
+ "action.eraser": "消しゴム",
+ "action.eraser.desc": "テクスチャの色を消去できます",
+ "action.color_picker": "カラーピッカー",
+ "action.color_picker.desc": "テクスチャの色を選択できます",
+ "action.open_backup_folder": "バックアップフォルダーを開く",
+ "action.open_backup_folder.desc": "Blockbenchのバックアップフォルダーを開きます",
+ "switches.mirror": "ミラーUV",
+ "language_name": "English",
+ "message.plugin_reload": "Reloaded %0 local plugins",
+ "settings.brightness": "Brightness",
+ "settings.brightness.desc": "Brightness of the preview. Default is 50",
+ "menu.preview.perspective.reset": "Reset Camera",
+ "action.fill_mode": "Fill Mode",
+ "action.fill_mode.desc": "Mode of the fill tool",
+ "action.fill_mode.face": "Face",
+ "action.fill_mode.color": "Color",
+ "action.fill_mode.cube": "Cube",
+ "action.toggle_mirror_uv": "Mirror UV",
+ "action.toggle_mirror_uv.desc": "Toggle the UV mirroring on the X axis of the selected cubes.",
+ "action.toggle_uv_overlay": "Toggle UV Overlay",
+ "action.toggle_uv_overlay.desc": "When enabled, displays all UV mapping overlays above the texture.",
+ "menu.texture.blank": "Apply to Untextured Faces",
+ "dialog.scale.select_overflow": "Select Overflow",
+ "dialog.create_texture.compress": "Compress Template"
}
\ No newline at end of file
diff --git a/lang/nl.json b/lang/nl.json
index 69d742588..cde4a308f 100644
--- a/lang/nl.json
+++ b/lang/nl.json
@@ -561,13 +561,8 @@
"menu.preview.quadview": "Vierdelige Weergave",
"menu.preview.fullview": "Volledige Weergave",
"menu.preview.stop_drag": "Stop Achtergrong Positionering",
- "menu.uv.copy": "Kopiëren",
- "menu.uv.paste": "Plakken",
"menu.uv.mapping": "UV Mapping",
"menu.uv.mapping.export": "Exporteren",
- "menu.uv.mapping.maximize": "Maximaliseer",
- "menu.uv.mapping.auto": "Auto UV",
- "menu.uv.mapping.rel_auto": "Rel. Auto UV",
"menu.uv.mapping.rotation": "Rotatie",
"menu.uv.mapping.mirror_x": "Spiegel X",
"menu.uv.mapping.mirror_y": "Spiegel Y",
@@ -825,5 +820,21 @@
"action.open_backup_folder": "Open Backup Folder",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder",
"switches.mirror": "Mirror UV",
- "language_name": "English"
+ "language_name": "English",
+ "message.plugin_reload": "Reloaded %0 local plugins",
+ "settings.brightness": "Brightness",
+ "settings.brightness.desc": "Brightness of the preview. Default is 50",
+ "menu.preview.perspective.reset": "Reset Camera",
+ "action.fill_mode": "Fill Mode",
+ "action.fill_mode.desc": "Mode of the fill tool",
+ "action.fill_mode.face": "Face",
+ "action.fill_mode.color": "Color",
+ "action.fill_mode.cube": "Cube",
+ "action.toggle_mirror_uv": "Mirror UV",
+ "action.toggle_mirror_uv.desc": "Toggle the UV mirroring on the X axis of the selected cubes.",
+ "action.toggle_uv_overlay": "Toggle UV Overlay",
+ "action.toggle_uv_overlay.desc": "When enabled, displays all UV mapping overlays above the texture.",
+ "menu.texture.blank": "Apply to Untextured Faces",
+ "dialog.scale.select_overflow": "Select Overflow",
+ "dialog.create_texture.compress": "Compress Template"
}
\ No newline at end of file
diff --git a/lang/pl.json b/lang/pl.json
index d21196878..aec983e23 100644
--- a/lang/pl.json
+++ b/lang/pl.json
@@ -11,7 +11,7 @@
"data.cubes": "Kostki",
"data.group": "Grupa",
"data.texture": "Tekstura",
- "data.plugin": "Plugin",
+ "data.plugin": "Wtyczka",
"data.preview": "Podgląd",
"data.toolbar": "Pasek narzędzi",
"data.image": "Obraz",
@@ -561,13 +561,8 @@
"menu.preview.quadview": "Widok Quad",
"menu.preview.fullview": "Pełny widok",
"menu.preview.stop_drag": "Skończ pozycjonowanie tła",
- "menu.uv.copy": "Kopiuj",
- "menu.uv.paste": "Wklej",
"menu.uv.mapping": "Mapowanie UV",
"menu.uv.mapping.export": "Eksport",
- "menu.uv.mapping.maximize": "Maksymalizuj",
- "menu.uv.mapping.auto": "Automatyczne UV",
- "menu.uv.mapping.rel_auto": "Względne automatyczne UV",
"menu.uv.mapping.rotation": "Rotacja",
"menu.uv.mapping.mirror_x": "Odbicie X",
"menu.uv.mapping.mirror_y": "Odbicie Y",
@@ -784,46 +779,62 @@
"action.slider_animation_length": "Długość animacji",
"action.slider_animation_length.desc": "Zmień długość zaznaczonej animacji",
"menu.group.material": "Ustal materiał",
- "action.camera_reset": "Reset Camera",
- "action.camera_reset.desc": "Reset the current preview to the default camera angle",
- "panel.variable_placeholders": "Variable Placeholders",
- "panel.variable_placeholders.info": "List the variables you want to preview via name=value",
- "status_bar.vertex_distance": "Distance: %0",
- "dialog.create_gif.title": "Record GIF",
- "dialog.create_gif.length": "Length (Seconds)",
+ "action.camera_reset": "Zresetój Kamerę",
+ "action.camera_reset.desc": "\n Zresetuj bieżący podgląd do domyślnego kąta kamery",
+ "panel.variable_placeholders": "\n Zmienne symbole zastępcze",
+ "panel.variable_placeholders.info": " Wymień zmienne, które chcesz podglądnąć za pomocą nazwy = wartość",
+ "status_bar.vertex_distance": "Odległość: 0%",
+ "dialog.create_gif.title": "Zapisz GIF",
+ "dialog.create_gif.length": "Długość (sekundy)",
"dialog.create_gif.fps": "FPS",
- "dialog.create_gif.compression": "Compression Amount",
- "dialog.create_gif.play": "Start Animation",
- "category.animation": "Animation",
- "action.record_model_gif": "Record GIF",
- "action.record_model_gif.desc": "Record an animated GIF of the model from the current angle",
- "display.mirror": "Mirror",
+ "dialog.create_gif.compression": "Ilość kompresji",
+ "dialog.create_gif.play": "Rozpocznij animację",
+ "category.animation": "Animacja",
+ "action.record_model_gif": "Zapisz GIF",
+ "action.record_model_gif.desc": "\n Nagraj animowany GIF modelu z bieżącego kąta",
+ "display.mirror": "Lustro",
"data.separator": "Separator",
- "message.set_background_position.title": "Background Position",
- "menu.preview.background.set_position": "Set Position",
- "dialog.toolbar_edit.hidden": "Hidden",
- "action.export_class_entity": "Export Java Entity",
- "action.export_class_entity.desc": "Export the entity model as a Java class",
- "settings.seethrough_outline": "X-Ray Outlines",
- "settings.seethrough_outline.desc": "Show outlines through objects",
- "mode.edit": "Edit",
- "mode.paint": "Paint",
- "mode.display": "Display",
- "mode.animate": "Animate",
- "status_bar.recording_gif": "Recording GIF",
- "status_bar.processing_gif": "Processing GIF",
- "settings.backup_retain": "Backup Retain Duration",
- "settings.backup_retain.desc": "Set how long Blockbench retains old backups in days",
- "action.rotate_tool": "Rotate",
- "action.rotate_tool.desc": "Tool to select and rotate elements",
- "action.fill_tool": "Paint Bucket",
- "action.fill_tool.desc": "Paint bucket to fill entire faces with one color",
- "action.eraser": "Eraser",
- "action.eraser.desc": "Eraser tool to replace colors on a texture with transparency",
- "action.color_picker": "Color Picker",
- "action.color_picker.desc": "Tool to pick the color of pixels on your texture",
- "action.open_backup_folder": "Open Backup Folder",
- "action.open_backup_folder.desc": "Opens the Blockbench backup folder",
- "switches.mirror": "Mirror UV",
- "language_name": "English"
+ "message.set_background_position.title": "Pozycja tła",
+ "menu.preview.background.set_position": "Ustaw pozycję",
+ "dialog.toolbar_edit.hidden": "\n Ukryty",
+ "action.export_class_entity": "Eksportuj byt Java",
+ "action.export_class_entity.desc": "Wyeksportuj model bytu jako klasę Java",
+ "settings.seethrough_outline": "Kontury X-Ray",
+ "settings.seethrough_outline.desc": "Pokaż kontury przez obiekty",
+ "mode.edit": "Edytować",
+ "mode.paint": "Farba",
+ "mode.display": "Ekspozycja",
+ "mode.animate": "Animować",
+ "status_bar.recording_gif": "Nagrywanie GIF",
+ "status_bar.processing_gif": "Przetwarzanie GIF",
+ "settings.backup_retain": "Czas podtrzymania kopii zapasowej",
+ "settings.backup_retain.desc": "Ustaw jak długo Blockbench zachowuje stare kopie zapasowe w dniach",
+ "action.rotate_tool": "Narzędzie oobracania",
+ "action.rotate_tool.desc": "Narzędzie do wybierania i obracania elementów",
+ "action.fill_tool": "Wiaderko farby",
+ "action.fill_tool.desc": "Wiaderko farby zalewa maluje obszar na jeden kolor",
+ "action.eraser": "Gumka",
+ "action.eraser.desc": "Gumka zastępuje teksturę przeżroczystością",
+ "action.color_picker": "Prubnik koloru",
+ "action.color_picker.desc": "Narzędzie do wyboru koloru pikseli na teksturze",
+ "action.open_backup_folder": "Otwórz folder kopii zapasowej",
+ "action.open_backup_folder.desc": "Otwórz folder kopii zapasowej BlockBench",
+ "switches.mirror": "Lustro UV",
+ "language_name": "Polski",
+ "message.plugin_reload": "Reloaded %0 local plugins",
+ "settings.brightness": "Brightness",
+ "settings.brightness.desc": "Brightness of the preview. Default is 50",
+ "menu.preview.perspective.reset": "Reset Camera",
+ "action.fill_mode": "Fill Mode",
+ "action.fill_mode.desc": "Mode of the fill tool",
+ "action.fill_mode.face": "Face",
+ "action.fill_mode.color": "Color",
+ "action.fill_mode.cube": "Cube",
+ "action.toggle_mirror_uv": "Mirror UV",
+ "action.toggle_mirror_uv.desc": "Toggle the UV mirroring on the X axis of the selected cubes.",
+ "action.toggle_uv_overlay": "Toggle UV Overlay",
+ "action.toggle_uv_overlay.desc": "When enabled, displays all UV mapping overlays above the texture.",
+ "menu.texture.blank": "Apply to Untextured Faces",
+ "dialog.scale.select_overflow": "Select Overflow",
+ "dialog.create_texture.compress": "Compress Template"
}
\ No newline at end of file
diff --git a/lang/ru.json b/lang/ru.json
index c1257ad30..592368084 100644
--- a/lang/ru.json
+++ b/lang/ru.json
@@ -561,13 +561,8 @@
"menu.preview.quadview": "Четыре вида",
"menu.preview.fullview": "Полный вид",
"menu.preview.stop_drag": "Закончить изменение позиции",
- "menu.uv.copy": "Копировать",
- "menu.uv.paste": "Вставить",
"menu.uv.mapping": "UV-преобразование",
"menu.uv.mapping.export": "Экспортировать",
- "menu.uv.mapping.maximize": "Максимизировать",
- "menu.uv.mapping.auto": "Авто UV",
- "menu.uv.mapping.rel_auto": "Относительный авто UV",
"menu.uv.mapping.rotation": "Поворот",
"menu.uv.mapping.mirror_x": "Отразить ось X",
"menu.uv.mapping.mirror_y": "Отразить ось Y",
@@ -825,5 +820,21 @@
"action.open_backup_folder": "Открыть папку автосохранений",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder",
"switches.mirror": "Mirror UV",
- "language_name": "English"
+ "language_name": "English",
+ "message.plugin_reload": "Reloaded %0 local plugins",
+ "settings.brightness": "Brightness",
+ "settings.brightness.desc": "Brightness of the preview. Default is 50",
+ "menu.preview.perspective.reset": "Reset Camera",
+ "action.fill_mode": "Fill Mode",
+ "action.fill_mode.desc": "Mode of the fill tool",
+ "action.fill_mode.face": "Face",
+ "action.fill_mode.color": "Color",
+ "action.fill_mode.cube": "Cube",
+ "action.toggle_mirror_uv": "Mirror UV",
+ "action.toggle_mirror_uv.desc": "Toggle the UV mirroring on the X axis of the selected cubes.",
+ "action.toggle_uv_overlay": "Toggle UV Overlay",
+ "action.toggle_uv_overlay.desc": "When enabled, displays all UV mapping overlays above the texture.",
+ "menu.texture.blank": "Apply to Untextured Faces",
+ "dialog.scale.select_overflow": "Select Overflow",
+ "dialog.create_texture.compress": "Compress Template"
}
\ No newline at end of file
diff --git a/lang/sv.json b/lang/sv.json
index 9ab96aaf7..f2c25387d 100644
--- a/lang/sv.json
+++ b/lang/sv.json
@@ -561,13 +561,8 @@
"menu.preview.quadview": "Fyrvy",
"menu.preview.fullview": "Fullvy",
"menu.preview.stop_drag": "Stoppa bakgrundspositionering",
- "menu.uv.copy": "Kopiera",
- "menu.uv.paste": "Klistra in",
"menu.uv.mapping": "UV kartläggning",
"menu.uv.mapping.export": "Exportera",
- "menu.uv.mapping.maximize": "Maximera",
- "menu.uv.mapping.auto": "Auto UV",
- "menu.uv.mapping.rel_auto": "Rel. Auto UV",
"menu.uv.mapping.rotation": "Rotation",
"menu.uv.mapping.mirror_x": "Spegla X",
"menu.uv.mapping.mirror_y": "Spegla Y",
@@ -825,5 +820,21 @@
"action.open_backup_folder": "Open Backup Folder",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder",
"switches.mirror": "Mirror UV",
- "language_name": "English"
+ "language_name": "English",
+ "message.plugin_reload": "Reloaded %0 local plugins",
+ "settings.brightness": "Brightness",
+ "settings.brightness.desc": "Brightness of the preview. Default is 50",
+ "menu.preview.perspective.reset": "Reset Camera",
+ "action.fill_mode": "Fill Mode",
+ "action.fill_mode.desc": "Mode of the fill tool",
+ "action.fill_mode.face": "Face",
+ "action.fill_mode.color": "Color",
+ "action.fill_mode.cube": "Cube",
+ "action.toggle_mirror_uv": "Mirror UV",
+ "action.toggle_mirror_uv.desc": "Toggle the UV mirroring on the X axis of the selected cubes.",
+ "action.toggle_uv_overlay": "Toggle UV Overlay",
+ "action.toggle_uv_overlay.desc": "When enabled, displays all UV mapping overlays above the texture.",
+ "menu.texture.blank": "Apply to Untextured Faces",
+ "dialog.scale.select_overflow": "Select Overflow",
+ "dialog.create_texture.compress": "Compress Template"
}
\ No newline at end of file
diff --git a/lang/zh.json b/lang/zh.json
index 9e90fd744..a1c8ae738 100644
--- a/lang/zh.json
+++ b/lang/zh.json
@@ -288,7 +288,7 @@
"category.blockbench": "Blockbench",
"category.edit": "编辑",
"category.transform": "转换",
- "category.filter": "滤器",
+ "category.filter": "过滤",
"category.view": "视图",
"category.display": "显示设置",
"category.textures": "贴图",
@@ -514,7 +514,7 @@
"action.reload.desc": "重载 Blockbench,这将删除所有未保存的进度",
"menu.file": "文件",
"menu.edit": "编辑",
- "menu.transform": "尺寸",
+ "menu.transform": "模型控制",
"menu.filter": "插件目录",
"menu.display": "物品显示",
"menu.view": "视图",
@@ -561,13 +561,8 @@
"menu.preview.quadview": "四视图",
"menu.preview.fullview": "大视图",
"menu.preview.stop_drag": "停止背景定位",
- "menu.uv.copy": "复制",
- "menu.uv.paste": "粘贴",
"menu.uv.mapping": "UV贴图射映",
"menu.uv.mapping.export": "导出",
- "menu.uv.mapping.maximize": "最大化",
- "menu.uv.mapping.auto": "自动UV",
- "menu.uv.mapping.rel_auto": "自动相对 UV",
"menu.uv.mapping.rotation": "旋转",
"menu.uv.mapping.mirror_x": "镜像 X 轴",
"menu.uv.mapping.mirror_y": "镜像 Y 轴",
@@ -624,8 +619,8 @@
"display.reference.player": "玩家",
"display.reference.zombie": "僵尸",
"display.reference.armor_stand": "盔甲架",
- "display.reference.baby_zombie": "幼年僵尸",
- "display.reference.armor_stand_small": "小盔甲架",
+ "display.reference.baby_zombie": "小僵尸",
+ "display.reference.armor_stand_small": "小形盔甲架",
"display.reference.monitor": "普通",
"display.reference.bow": "弓",
"display.reference.block": "方块",
@@ -824,6 +819,22 @@
"action.color_picker.desc": "用于选择材质纹理上像素颜色的工具",
"action.open_backup_folder": "打开备份文件夹",
"action.open_backup_folder.desc": "打开Blockbench备份文件夹",
- "switches.mirror": "Mirror UV",
- "language_name": "中文"
+ "switches.mirror": "镜像 UV",
+ "language_name": "中文",
+ "message.plugin_reload": "Reloaded %0 local plugins",
+ "settings.brightness": "Brightness",
+ "settings.brightness.desc": "Brightness of the preview. Default is 50",
+ "menu.preview.perspective.reset": "Reset Camera",
+ "action.fill_mode": "Fill Mode",
+ "action.fill_mode.desc": "Mode of the fill tool",
+ "action.fill_mode.face": "Face",
+ "action.fill_mode.color": "Color",
+ "action.fill_mode.cube": "Cube",
+ "action.toggle_mirror_uv": "Mirror UV",
+ "action.toggle_mirror_uv.desc": "Toggle the UV mirroring on the X axis of the selected cubes.",
+ "action.toggle_uv_overlay": "Toggle UV Overlay",
+ "action.toggle_uv_overlay.desc": "When enabled, displays all UV mapping overlays above the texture.",
+ "menu.texture.blank": "Apply to Untextured Faces",
+ "dialog.scale.select_overflow": "Select Overflow",
+ "dialog.create_texture.compress": "Compress Template"
}
\ No newline at end of file
diff --git a/main.js b/main.js
index e752fa65d..bb9792085 100644
--- a/main.js
+++ b/main.js
@@ -1,11 +1,14 @@
-const {app, BrowserWindow} = require('electron')
+const {app, BrowserWindow, Menu} = require('electron')
const path = require('path')
const url = require('url')
-let win
+let orig_win;
-function createWindow () {
- win = new BrowserWindow({
+function createWindow() {
+ if (!app.requestSingleInstanceLock()) {
+ return;
+ }
+ let win = new BrowserWindow({
icon:'icon.ico',
show: false,
backgroundColor: '#21252b',
@@ -16,11 +19,43 @@ function createWindow () {
nodeIntegration: true
}
})
+ if (!orig_win) orig_win = win;
var index_path = path.join(__dirname, 'index.html')
- /*if (__dirname.includes('xampp\\htdocs\\')) {
- index_path = path.join(__dirname, 'index.php')
- }*/
- win.setMenu(null);
+ if (process.platform === 'darwin') {
+ var template = [{
+ label: 'File',
+ submenu: [{
+ label: 'Quit',
+ accelerator: 'CmdOrCtrl+Q',
+ click: function() {
+ app.quit();
+ }
+ }]
+ }, {
+ label: 'Edit',
+ submenu: [{
+ label: 'Cut',
+ accelerator: 'CmdOrCtrl+X',
+ selector: 'cut:'
+ }, {
+ label: 'Copy',
+ accelerator: 'CmdOrCtrl+C',
+ selector: 'copy:'
+ }, {
+ label: 'Paste',
+ accelerator: 'CmdOrCtrl+V',
+ selector: 'paste:'
+ }, {
+ label: 'Select All',
+ accelerator: 'CmdOrCtrl+A',
+ selector: 'selectAll:'
+ }]
+ }]
+ var osxMenu = Menu.buildFromTemplate(template);
+ Menu.setApplicationMenu(osxMenu)
+ } else {
+ win.setMenu(null);
+ }
win.maximize()
win.show()
win.loadURL(url.format({
@@ -34,6 +69,11 @@ function createWindow () {
//win.webContents.openDevTools()
}
+app.on('second-instance', function (event, argv, cwd) {
+ process.argv = argv
+ createWindow()
+})
+
app.commandLine.appendSwitch('ignore-gpu-blacklist')
app.on('ready', createWindow)
diff --git a/package.json b/package.json
index eea1374e5..02dcbbf15 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "Blockbench",
"description": "Minecraft Block Model Editor",
- "version": "2.3.2",
+ "version": "2.4.0",
"license": "MIT",
"author": {
"name": "JannisX11",